diff --git a/composer.lock b/composer.lock index 5d70e659..6e6585b0 100644 --- a/composer.lock +++ b/composer.lock @@ -481,25 +481,29 @@ }, { "name": "doctrine/deprecations", - "version": "v1.0.0", + "version": "v1.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de" + "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", - "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", + "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", "shasum": "" }, "require": { - "php": "^7.1|^8.0" + "php": "^7.1 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^9", - "phpunit/phpunit": "^7.5|^8.5|^9.5", - "psr/log": "^1|^2|^3" + "phpstan/phpstan": "1.4.10 || 1.10.15", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "0.18.4", + "psr/log": "^1 || ^2 || ^3", + "vimeo/psalm": "4.30.0 || 5.12.0" }, "suggest": { "psr/log": "Allows logging deprecations via PSR-3 logger implementation" @@ -518,9 +522,9 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/v1.0.0" + "source": "https://github.com/doctrine/deprecations/tree/v1.1.1" }, - "time": "2022-05-02T15:47:09+00:00" + "time": "2023-06-03T09:27:29+00:00" }, { "name": "felixfbecker/advanced-json-rpc", @@ -782,16 +786,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.15.5", + "version": "v4.16.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" + "reference": "19526a33fb561ef417e822e85f08a00db4059c17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", - "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17", + "reference": "19526a33fb561ef417e822e85f08a00db4059c17", "shasum": "" }, "require": { @@ -832,9 +836,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0" }, - "time": "2023-05-19T20:20:00+00:00" + "time": "2023-06-25T14:52:30+00:00" }, { "name": "phan/phan", @@ -1027,16 +1031,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.7.1", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "dfc078e8af9c99210337325ff5aa152872c98714" + "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/dfc078e8af9c99210337325ff5aa152872c98714", - "reference": "dfc078e8af9c99210337325ff5aa152872c98714", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b2fe4d22a5426f38e014855322200b97b5362c0d", + "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d", "shasum": "" }, "require": { @@ -1079,9 +1083,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.1" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.2" }, - "time": "2023-03-27T19:02:04+00:00" + "time": "2023-05-30T18:13:47+00:00" }, { "name": "phpstan/extension-installer", @@ -1129,22 +1133,23 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.21.0", + "version": "1.23.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "6df62b08faef4f899772bc7c3bbabb93d2b7a21c" + "reference": "a2b24135c35852b348894320d47b3902a94bc494" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6df62b08faef4f899772bc7c3bbabb93d2b7a21c", - "reference": "6df62b08faef4f899772bc7c3bbabb93d2b7a21c", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a2b24135c35852b348894320d47b3902a94bc494", + "reference": "a2b24135c35852b348894320d47b3902a94bc494", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { + "doctrine/annotations": "^2.0", "nikic/php-parser": "^4.15", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", @@ -1169,22 +1174,22 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.21.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.23.0" }, - "time": "2023-05-17T13:13:44+00:00" + "time": "2023-07-23T22:17:56+00:00" }, { "name": "phpstan/phpstan", - "version": "1.10.15", + "version": "1.10.26", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd" + "reference": "5d660cbb7e1b89253a47147ae44044f49832351f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/762c4dac4da6f8756eebb80e528c3a47855da9bd", - "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/5d660cbb7e1b89253a47147ae44044f49832351f", + "reference": "5d660cbb7e1b89253a47147ae44044f49832351f", "shasum": "" }, "require": { @@ -1233,7 +1238,7 @@ "type": "tidelift" } ], - "time": "2023-05-09T15:28:01+00:00" + "time": "2023-07-19T12:44:37+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -1471,16 +1476,16 @@ }, { "name": "spatie/array-to-xml", - "version": "3.1.6", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/spatie/array-to-xml.git", - "reference": "e210b98957987c755372465be105d32113f339a4" + "reference": "f9ab39c808500c347d5a8b6b13310bd5221e39e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/e210b98957987c755372465be105d32113f339a4", - "reference": "e210b98957987c755372465be105d32113f339a4", + "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/f9ab39c808500c347d5a8b6b13310bd5221e39e7", + "reference": "f9ab39c808500c347d5a8b6b13310bd5221e39e7", "shasum": "" }, "require": { @@ -1518,7 +1523,7 @@ "xml" ], "support": { - "source": "https://github.com/spatie/array-to-xml/tree/3.1.6" + "source": "https://github.com/spatie/array-to-xml/tree/3.2.0" }, "funding": [ { @@ -1530,27 +1535,27 @@ "type": "github" } ], - "time": "2023-05-11T14:04:07+00:00" + "time": "2023-07-19T18:30:26+00:00" }, { "name": "symfony/console", - "version": "v6.2.11", + "version": "v6.3.2", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "5aa03db8ef0a5457c316ec580e69562d97734c77" + "reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/5aa03db8ef0a5457c316ec580e69562d97734c77", - "reference": "5aa03db8ef0a5457c316ec580e69562d97734c77", + "url": "https://api.github.com/repos/symfony/console/zipball/aa5d64ad3f63f2e48964fc81ee45cb318a723898", + "reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/deprecation-contracts": "^2.1|^3", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/service-contracts": "^1.1|^2|^3", + "symfony/service-contracts": "^2.5|^3", "symfony/string": "^5.4|^6.0" }, "conflict": { @@ -1572,12 +1577,6 @@ "symfony/process": "^5.4|^6.0", "symfony/var-dumper": "^5.4|^6.0" }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" - }, "type": "library", "autoload": { "psr-4": { @@ -1610,7 +1609,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.2.11" + "source": "https://github.com/symfony/console/tree/v6.3.2" }, "funding": [ { @@ -1626,20 +1625,20 @@ "type": "tidelift" } ], - "time": "2023-05-26T08:16:21+00:00" + "time": "2023-07-19T20:17:28+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.2.1", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e" + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e", - "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", "shasum": "" }, "require": { @@ -1648,7 +1647,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -1677,7 +1676,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0" }, "funding": [ { @@ -1693,20 +1692,20 @@ "type": "tidelift" } ], - "time": "2023-03-01T10:25:55+00:00" + "time": "2023-05-23T14:45:45+00:00" }, { "name": "symfony/filesystem", - "version": "v6.2.10", + "version": "v6.3.1", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "fd588debf7d1bc16a2c84b4b3b71145d9946b894" + "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/fd588debf7d1bc16a2c84b4b3b71145d9946b894", - "reference": "fd588debf7d1bc16a2c84b4b3b71145d9946b894", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/edd36776956f2a6fcf577edb5b05eb0e3bdc52ae", + "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae", "shasum": "" }, "require": { @@ -1740,7 +1739,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.2.10" + "source": "https://github.com/symfony/filesystem/tree/v6.3.1" }, "funding": [ { @@ -1756,7 +1755,7 @@ "type": "tidelift" } ], - "time": "2023-04-18T13:46:08+00:00" + "time": "2023-06-01T08:30:39+00:00" }, { "name": "symfony/polyfill-ctype", @@ -2173,16 +2172,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.2.1", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "a8c9cedf55f314f3a186041d19537303766df09a" + "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/a8c9cedf55f314f3a186041d19537303766df09a", - "reference": "a8c9cedf55f314f3a186041d19537303766df09a", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", + "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", "shasum": "" }, "require": { @@ -2192,13 +2191,10 @@ "conflict": { "ext-psr": "<1.1|>=2" }, - "suggest": { - "symfony/service-implementation": "" - }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -2238,7 +2234,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.2.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.3.0" }, "funding": [ { @@ -2254,20 +2250,20 @@ "type": "tidelift" } ], - "time": "2023-03-01T10:32:47+00:00" + "time": "2023-05-23T14:45:45+00:00" }, { "name": "symfony/string", - "version": "v6.2.8", + "version": "v6.3.2", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef" + "reference": "53d1a83225002635bca3482fcbf963001313fb68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/193e83bbd6617d6b2151c37fff10fa7168ebddef", - "reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef", + "url": "https://api.github.com/repos/symfony/string/zipball/53d1a83225002635bca3482fcbf963001313fb68", + "reference": "53d1a83225002635bca3482fcbf963001313fb68", "shasum": "" }, "require": { @@ -2278,13 +2274,13 @@ "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/translation-contracts": "<2.0" + "symfony/translation-contracts": "<2.5" }, "require-dev": { "symfony/error-handler": "^5.4|^6.0", "symfony/http-client": "^5.4|^6.0", "symfony/intl": "^6.2", - "symfony/translation-contracts": "^2.0|^3.0", + "symfony/translation-contracts": "^2.5|^3.0", "symfony/var-exporter": "^5.4|^6.0" }, "type": "library", @@ -2324,7 +2320,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.2.8" + "source": "https://github.com/symfony/string/tree/v6.3.2" }, "funding": [ { @@ -2340,7 +2336,7 @@ "type": "tidelift" } ], - "time": "2023-03-20T16:06:02+00:00" + "time": "2023-07-05T08:41:27+00:00" }, { "name": "tysonandre/var_representation_polyfill", @@ -2406,16 +2402,16 @@ }, { "name": "vimeo/psalm", - "version": "5.12.0", + "version": "5.14.1", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "f90118cdeacd0088e7215e64c0c99ceca819e176" + "reference": "b9d355e0829c397b9b3b47d0c0ed042a8a70284d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/f90118cdeacd0088e7215e64c0c99ceca819e176", - "reference": "f90118cdeacd0088e7215e64c0c99ceca819e176", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/b9d355e0829c397b9b3b47d0c0ed042a8a70284d", + "reference": "b9d355e0829c397b9b3b47d0c0ed042a8a70284d", "shasum": "" }, "require": { @@ -2436,8 +2432,8 @@ "felixfbecker/language-server-protocol": "^1.5.2", "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1", "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", - "nikic/php-parser": "^4.14", - "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0", + "nikic/php-parser": "^4.16", + "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", "sebastian/diff": "^4.0 || ^5.0", "spatie/array-to-xml": "^2.17.0 || ^3.0", "symfony/console": "^4.1.6 || ^5.0 || ^6.0", @@ -2506,9 +2502,9 @@ ], "support": { "issues": "https://github.com/vimeo/psalm/issues", - "source": "https://github.com/vimeo/psalm/tree/5.12.0" + "source": "https://github.com/vimeo/psalm/tree/5.14.1" }, - "time": "2023-05-22T21:19:03+00:00" + "time": "2023-08-01T05:16:55+00:00" }, { "name": "webmozart/assert", diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index b453d2e1..a3b81d46 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -441,31 +441,35 @@ }, { "name": "doctrine/deprecations", - "version": "v1.0.0", - "version_normalized": "1.0.0.0", + "version": "v1.1.1", + "version_normalized": "1.1.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de" + "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", - "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", + "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", "shasum": "" }, "require": { - "php": "^7.1|^8.0" + "php": "^7.1 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^9", - "phpunit/phpunit": "^7.5|^8.5|^9.5", - "psr/log": "^1|^2|^3" + "phpstan/phpstan": "1.4.10 || 1.10.15", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "0.18.4", + "psr/log": "^1 || ^2 || ^3", + "vimeo/psalm": "4.30.0 || 5.12.0" }, "suggest": { "psr/log": "Allows logging deprecations via PSR-3 logger implementation" }, - "time": "2022-05-02T15:47:09+00:00", + "time": "2023-06-03T09:27:29+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -481,7 +485,7 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/v1.0.0" + "source": "https://github.com/doctrine/deprecations/tree/v1.1.1" }, "install-path": "../doctrine/deprecations" }, @@ -760,17 +764,17 @@ }, { "name": "nikic/php-parser", - "version": "v4.15.5", - "version_normalized": "4.15.5.0", + "version": "v4.16.0", + "version_normalized": "4.16.0.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" + "reference": "19526a33fb561ef417e822e85f08a00db4059c17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", - "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17", + "reference": "19526a33fb561ef417e822e85f08a00db4059c17", "shasum": "" }, "require": { @@ -781,7 +785,7 @@ "ircmaxell/php-yacc": "^0.0.7", "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" }, - "time": "2023-05-19T20:20:00+00:00", + "time": "2023-06-25T14:52:30+00:00", "bin": [ "bin/php-parse" ], @@ -813,7 +817,7 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0" }, "install-path": "../nikic/php-parser" }, @@ -1017,17 +1021,17 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.7.1", - "version_normalized": "1.7.1.0", + "version": "1.7.2", + "version_normalized": "1.7.2.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "dfc078e8af9c99210337325ff5aa152872c98714" + "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/dfc078e8af9c99210337325ff5aa152872c98714", - "reference": "dfc078e8af9c99210337325ff5aa152872c98714", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b2fe4d22a5426f38e014855322200b97b5362c0d", + "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d", "shasum": "" }, "require": { @@ -1046,7 +1050,7 @@ "rector/rector": "^0.13.9", "vimeo/psalm": "^4.25" }, - "time": "2023-03-27T19:02:04+00:00", + "time": "2023-05-30T18:13:47+00:00", "type": "library", "extra": { "branch-alias": { @@ -1072,7 +1076,7 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.1" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.2" }, "install-path": "../phpdocumentor/type-resolver" }, @@ -1125,23 +1129,24 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.21.0", - "version_normalized": "1.21.0.0", + "version": "1.23.0", + "version_normalized": "1.23.0.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "6df62b08faef4f899772bc7c3bbabb93d2b7a21c" + "reference": "a2b24135c35852b348894320d47b3902a94bc494" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6df62b08faef4f899772bc7c3bbabb93d2b7a21c", - "reference": "6df62b08faef4f899772bc7c3bbabb93d2b7a21c", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a2b24135c35852b348894320d47b3902a94bc494", + "reference": "a2b24135c35852b348894320d47b3902a94bc494", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { + "doctrine/annotations": "^2.0", "nikic/php-parser": "^4.15", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", @@ -1151,7 +1156,7 @@ "phpunit/phpunit": "^9.5", "symfony/process": "^5.2" }, - "time": "2023-05-17T13:13:44+00:00", + "time": "2023-07-23T22:17:56+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1168,23 +1173,23 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.21.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.23.0" }, "install-path": "../phpstan/phpdoc-parser" }, { "name": "phpstan/phpstan", - "version": "1.10.15", - "version_normalized": "1.10.15.0", + "version": "1.10.26", + "version_normalized": "1.10.26.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd" + "reference": "5d660cbb7e1b89253a47147ae44044f49832351f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/762c4dac4da6f8756eebb80e528c3a47855da9bd", - "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/5d660cbb7e1b89253a47147ae44044f49832351f", + "reference": "5d660cbb7e1b89253a47147ae44044f49832351f", "shasum": "" }, "require": { @@ -1193,7 +1198,7 @@ "conflict": { "phpstan/phpstan-shim": "*" }, - "time": "2023-05-09T15:28:01+00:00", + "time": "2023-07-19T12:44:37+00:00", "bin": [ "phpstan", "phpstan.phar" @@ -1538,17 +1543,17 @@ }, { "name": "spatie/array-to-xml", - "version": "3.1.6", - "version_normalized": "3.1.6.0", + "version": "3.2.0", + "version_normalized": "3.2.0.0", "source": { "type": "git", "url": "https://github.com/spatie/array-to-xml.git", - "reference": "e210b98957987c755372465be105d32113f339a4" + "reference": "f9ab39c808500c347d5a8b6b13310bd5221e39e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/e210b98957987c755372465be105d32113f339a4", - "reference": "e210b98957987c755372465be105d32113f339a4", + "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/f9ab39c808500c347d5a8b6b13310bd5221e39e7", + "reference": "f9ab39c808500c347d5a8b6b13310bd5221e39e7", "shasum": "" }, "require": { @@ -1560,7 +1565,7 @@ "pestphp/pest": "^1.21", "spatie/pest-plugin-snapshots": "^1.1" }, - "time": "2023-05-11T14:04:07+00:00", + "time": "2023-07-19T18:30:26+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1588,7 +1593,7 @@ "xml" ], "support": { - "source": "https://github.com/spatie/array-to-xml/tree/3.1.6" + "source": "https://github.com/spatie/array-to-xml/tree/3.2.0" }, "funding": [ { @@ -1604,24 +1609,24 @@ }, { "name": "symfony/console", - "version": "v6.2.11", - "version_normalized": "6.2.11.0", + "version": "v6.3.2", + "version_normalized": "6.3.2.0", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "5aa03db8ef0a5457c316ec580e69562d97734c77" + "reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/5aa03db8ef0a5457c316ec580e69562d97734c77", - "reference": "5aa03db8ef0a5457c316ec580e69562d97734c77", + "url": "https://api.github.com/repos/symfony/console/zipball/aa5d64ad3f63f2e48964fc81ee45cb318a723898", + "reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/deprecation-contracts": "^2.1|^3", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/service-contracts": "^1.1|^2|^3", + "symfony/service-contracts": "^2.5|^3", "symfony/string": "^5.4|^6.0" }, "conflict": { @@ -1643,13 +1648,7 @@ "symfony/process": "^5.4|^6.0", "symfony/var-dumper": "^5.4|^6.0" }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" - }, - "time": "2023-05-26T08:16:21+00:00", + "time": "2023-07-19T20:17:28+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1683,7 +1682,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.2.11" + "source": "https://github.com/symfony/console/tree/v6.3.2" }, "funding": [ { @@ -1703,27 +1702,27 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.2.1", - "version_normalized": "3.2.1.0", + "version": "v3.3.0", + "version_normalized": "3.3.0.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e" + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e", - "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", "shasum": "" }, "require": { "php": ">=8.1" }, - "time": "2023-03-01T10:25:55+00:00", + "time": "2023-05-23T14:45:45+00:00", "type": "library", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -1753,7 +1752,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0" }, "funding": [ { @@ -1773,17 +1772,17 @@ }, { "name": "symfony/filesystem", - "version": "v6.2.10", - "version_normalized": "6.2.10.0", + "version": "v6.3.1", + "version_normalized": "6.3.1.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "fd588debf7d1bc16a2c84b4b3b71145d9946b894" + "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/fd588debf7d1bc16a2c84b4b3b71145d9946b894", - "reference": "fd588debf7d1bc16a2c84b4b3b71145d9946b894", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/edd36776956f2a6fcf577edb5b05eb0e3bdc52ae", + "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae", "shasum": "" }, "require": { @@ -1791,7 +1790,7 @@ "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, - "time": "2023-04-18T13:46:08+00:00", + "time": "2023-06-01T08:30:39+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1819,7 +1818,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.2.10" + "source": "https://github.com/symfony/filesystem/tree/v6.3.1" }, "funding": [ { @@ -2267,17 +2266,17 @@ }, { "name": "symfony/service-contracts", - "version": "v3.2.1", - "version_normalized": "3.2.1.0", + "version": "v3.3.0", + "version_normalized": "3.3.0.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "a8c9cedf55f314f3a186041d19537303766df09a" + "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/a8c9cedf55f314f3a186041d19537303766df09a", - "reference": "a8c9cedf55f314f3a186041d19537303766df09a", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", + "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", "shasum": "" }, "require": { @@ -2287,14 +2286,11 @@ "conflict": { "ext-psr": "<1.1|>=2" }, - "suggest": { - "symfony/service-implementation": "" - }, - "time": "2023-03-01T10:32:47+00:00", + "time": "2023-05-23T14:45:45+00:00", "type": "library", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -2335,7 +2331,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.2.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.3.0" }, "funding": [ { @@ -2355,17 +2351,17 @@ }, { "name": "symfony/string", - "version": "v6.2.8", - "version_normalized": "6.2.8.0", + "version": "v6.3.2", + "version_normalized": "6.3.2.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef" + "reference": "53d1a83225002635bca3482fcbf963001313fb68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/193e83bbd6617d6b2151c37fff10fa7168ebddef", - "reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef", + "url": "https://api.github.com/repos/symfony/string/zipball/53d1a83225002635bca3482fcbf963001313fb68", + "reference": "53d1a83225002635bca3482fcbf963001313fb68", "shasum": "" }, "require": { @@ -2376,16 +2372,16 @@ "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/translation-contracts": "<2.0" + "symfony/translation-contracts": "<2.5" }, "require-dev": { "symfony/error-handler": "^5.4|^6.0", "symfony/http-client": "^5.4|^6.0", "symfony/intl": "^6.2", - "symfony/translation-contracts": "^2.0|^3.0", + "symfony/translation-contracts": "^2.5|^3.0", "symfony/var-exporter": "^5.4|^6.0" }, - "time": "2023-03-20T16:06:02+00:00", + "time": "2023-07-05T08:41:27+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2424,7 +2420,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.2.8" + "source": "https://github.com/symfony/string/tree/v6.3.2" }, "funding": [ { @@ -2509,17 +2505,17 @@ }, { "name": "vimeo/psalm", - "version": "5.12.0", - "version_normalized": "5.12.0.0", + "version": "5.14.1", + "version_normalized": "5.14.1.0", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "f90118cdeacd0088e7215e64c0c99ceca819e176" + "reference": "b9d355e0829c397b9b3b47d0c0ed042a8a70284d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/f90118cdeacd0088e7215e64c0c99ceca819e176", - "reference": "f90118cdeacd0088e7215e64c0c99ceca819e176", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/b9d355e0829c397b9b3b47d0c0ed042a8a70284d", + "reference": "b9d355e0829c397b9b3b47d0c0ed042a8a70284d", "shasum": "" }, "require": { @@ -2540,8 +2536,8 @@ "felixfbecker/language-server-protocol": "^1.5.2", "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1", "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", - "nikic/php-parser": "^4.14", - "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0", + "nikic/php-parser": "^4.16", + "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", "sebastian/diff": "^4.0 || ^5.0", "spatie/array-to-xml": "^2.17.0 || ^3.0", "symfony/console": "^4.1.6 || ^5.0 || ^6.0", @@ -2570,7 +2566,7 @@ "ext-curl": "In order to send data to shepherd", "ext-igbinary": "^2.0.5 is required, used to serialize caching data" }, - "time": "2023-05-22T21:19:03+00:00", + "time": "2023-08-01T05:16:55+00:00", "bin": [ "psalm", "psalm-language-server", @@ -2612,7 +2608,7 @@ ], "support": { "issues": "https://github.com/vimeo/psalm/issues", - "source": "https://github.com/vimeo/psalm/tree/5.12.0" + "source": "https://github.com/vimeo/psalm/tree/5.14.1" }, "install-path": "../vimeo/psalm" }, diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 2059fa41..3d504b02 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -65,9 +65,9 @@ 'dev_requirement' => true, ), 'doctrine/deprecations' => array( - 'pretty_version' => 'v1.0.0', - 'version' => '1.0.0.0', - 'reference' => '0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de', + 'pretty_version' => 'v1.1.1', + 'version' => '1.1.1.0', + 'reference' => '612a3ee5ab0d5dd97b7cf3874a6efe24325efac3', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/deprecations', 'aliases' => array(), @@ -128,9 +128,9 @@ 'dev_requirement' => true, ), 'nikic/php-parser' => array( - 'pretty_version' => 'v4.15.5', - 'version' => '4.15.5.0', - 'reference' => '11e2663a5bc9db5d714eedb4277ee300403b4a9e', + 'pretty_version' => 'v4.16.0', + 'version' => '4.16.0.0', + 'reference' => '19526a33fb561ef417e822e85f08a00db4059c17', 'type' => 'library', 'install_path' => __DIR__ . '/../nikic/php-parser', 'aliases' => array(), @@ -164,9 +164,9 @@ 'dev_requirement' => true, ), 'phpdocumentor/type-resolver' => array( - 'pretty_version' => '1.7.1', - 'version' => '1.7.1.0', - 'reference' => 'dfc078e8af9c99210337325ff5aa152872c98714', + 'pretty_version' => '1.7.2', + 'version' => '1.7.2.0', + 'reference' => 'b2fe4d22a5426f38e014855322200b97b5362c0d', 'type' => 'library', 'install_path' => __DIR__ . '/../phpdocumentor/type-resolver', 'aliases' => array(), @@ -182,18 +182,18 @@ 'dev_requirement' => true, ), 'phpstan/phpdoc-parser' => array( - 'pretty_version' => '1.21.0', - 'version' => '1.21.0.0', - 'reference' => '6df62b08faef4f899772bc7c3bbabb93d2b7a21c', + 'pretty_version' => '1.23.0', + 'version' => '1.23.0.0', + 'reference' => 'a2b24135c35852b348894320d47b3902a94bc494', 'type' => 'library', 'install_path' => __DIR__ . '/../phpstan/phpdoc-parser', 'aliases' => array(), 'dev_requirement' => true, ), 'phpstan/phpstan' => array( - 'pretty_version' => '1.10.15', - 'version' => '1.10.15.0', - 'reference' => '762c4dac4da6f8756eebb80e528c3a47855da9bd', + 'pretty_version' => '1.10.26', + 'version' => '1.10.26.0', + 'reference' => '5d660cbb7e1b89253a47147ae44044f49832351f', 'type' => 'library', 'install_path' => __DIR__ . '/../phpstan/phpstan', 'aliases' => array(), @@ -211,7 +211,7 @@ 'psalm/psalm' => array( 'dev_requirement' => true, 'provided' => array( - 0 => '5.12.0', + 0 => '5.14.1', ), ), 'psr/container' => array( @@ -257,36 +257,36 @@ 'dev_requirement' => true, ), 'spatie/array-to-xml' => array( - 'pretty_version' => '3.1.6', - 'version' => '3.1.6.0', - 'reference' => 'e210b98957987c755372465be105d32113f339a4', + 'pretty_version' => '3.2.0', + 'version' => '3.2.0.0', + 'reference' => 'f9ab39c808500c347d5a8b6b13310bd5221e39e7', 'type' => 'library', 'install_path' => __DIR__ . '/../spatie/array-to-xml', 'aliases' => array(), 'dev_requirement' => true, ), 'symfony/console' => array( - 'pretty_version' => 'v6.2.11', - 'version' => '6.2.11.0', - 'reference' => '5aa03db8ef0a5457c316ec580e69562d97734c77', + 'pretty_version' => 'v6.3.2', + 'version' => '6.3.2.0', + 'reference' => 'aa5d64ad3f63f2e48964fc81ee45cb318a723898', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/console', 'aliases' => array(), 'dev_requirement' => true, ), 'symfony/deprecation-contracts' => array( - 'pretty_version' => 'v3.2.1', - 'version' => '3.2.1.0', - 'reference' => 'e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e', + 'pretty_version' => 'v3.3.0', + 'version' => '3.3.0.0', + 'reference' => '7c3aff79d10325257a001fcf92d991f24fc967cf', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', 'aliases' => array(), 'dev_requirement' => true, ), 'symfony/filesystem' => array( - 'pretty_version' => 'v6.2.10', - 'version' => '6.2.10.0', - 'reference' => 'fd588debf7d1bc16a2c84b4b3b71145d9946b894', + 'pretty_version' => 'v6.3.1', + 'version' => '6.3.1.0', + 'reference' => 'edd36776956f2a6fcf577edb5b05eb0e3bdc52ae', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/filesystem', 'aliases' => array(), @@ -338,18 +338,18 @@ 'dev_requirement' => true, ), 'symfony/service-contracts' => array( - 'pretty_version' => 'v3.2.1', - 'version' => '3.2.1.0', - 'reference' => 'a8c9cedf55f314f3a186041d19537303766df09a', + 'pretty_version' => 'v3.3.0', + 'version' => '3.3.0.0', + 'reference' => '40da9cc13ec349d9e4966ce18b5fbcd724ab10a4', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/service-contracts', 'aliases' => array(), 'dev_requirement' => true, ), 'symfony/string' => array( - 'pretty_version' => 'v6.2.8', - 'version' => '6.2.8.0', - 'reference' => '193e83bbd6617d6b2151c37fff10fa7168ebddef', + 'pretty_version' => 'v6.3.2', + 'version' => '6.3.2.0', + 'reference' => '53d1a83225002635bca3482fcbf963001313fb68', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/string', 'aliases' => array(), @@ -365,9 +365,9 @@ 'dev_requirement' => true, ), 'vimeo/psalm' => array( - 'pretty_version' => '5.12.0', - 'version' => '5.12.0.0', - 'reference' => 'f90118cdeacd0088e7215e64c0c99ceca819e176', + 'pretty_version' => '5.14.1', + 'version' => '5.14.1.0', + 'reference' => 'b9d355e0829c397b9b3b47d0c0ed042a8a70284d', 'type' => 'library', 'install_path' => __DIR__ . '/../vimeo/psalm', 'aliases' => array(), diff --git a/vendor/doctrine/deprecations/README.md b/vendor/doctrine/deprecations/README.md index 22f0cced..93caf83f 100644 --- a/vendor/doctrine/deprecations/README.md +++ b/vendor/doctrine/deprecations/README.md @@ -19,13 +19,16 @@ Enable Doctrine deprecations to be sent to a PSR3 logger: ``` Enable Doctrine deprecations to be sent as `@trigger_error($message, E_USER_DEPRECATED)` -messages. +messages by setting the `DOCTRINE_DEPRECATIONS` environment variable to `trigger`. +Alternatively, call: ```php \Doctrine\Deprecations\Deprecation::enableWithTriggerError(); ``` -If you only want to enable deprecation tracking, without logging or calling `trigger_error` then call: +If you only want to enable deprecation tracking, without logging or calling `trigger_error` +then set the `DOCTRINE_DEPRECATIONS` environment variable to `track`. +Alternatively, call: ```php \Doctrine\Deprecations\Deprecation::enableTrackingDeprecations(); diff --git a/vendor/doctrine/deprecations/composer.json b/vendor/doctrine/deprecations/composer.json index c79e38cd..f8319f9a 100644 --- a/vendor/doctrine/deprecations/composer.json +++ b/vendor/doctrine/deprecations/composer.json @@ -1,22 +1,28 @@ { "name": "doctrine/deprecations", - "type": "library", "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", - "homepage": "https://www.doctrine-project.org/", "license": "MIT", + "type": "library", + "homepage": "https://www.doctrine-project.org/", "require": { - "php": "^7.1|^8.0" + "php": "^7.1 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^7.5|^8.5|^9.5", - "psr/log": "^1|^2|^3", - "doctrine/coding-standard": "^9" + "doctrine/coding-standard": "^9", + "phpstan/phpstan": "1.4.10 || 1.10.15", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "0.18.4", + "psr/log": "^1 || ^2 || ^3", + "vimeo/psalm": "4.30.0 || 5.12.0" }, "suggest": { "psr/log": "Allows logging deprecations via PSR-3 logger implementation" }, "autoload": { - "psr-4": {"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"} + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } }, "autoload-dev": { "psr-4": { diff --git a/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php b/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php index 1029372f..07cb43b6 100644 --- a/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php +++ b/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php @@ -8,6 +8,7 @@ use Psr\Log\LoggerInterface; use function array_key_exists; use function array_reduce; +use function assert; use function debug_backtrace; use function sprintf; use function strpos; @@ -46,8 +47,8 @@ class Deprecation private const TYPE_TRIGGER_ERROR = 2; private const TYPE_PSR_LOGGER = 4; - /** @var int */ - private static $type = self::TYPE_NONE; + /** @var int-mask-of|null */ + private static $type; /** @var LoggerInterface|null */ private static $logger; @@ -56,6 +57,9 @@ class Deprecation private static $ignoredPackages = []; /** @var array */ + private static $triggeredDeprecations = []; + + /** @var array */ private static $ignoredLinks = []; /** @var bool */ @@ -68,21 +72,27 @@ class Deprecation * deprecation. It is additionally used to de-duplicate the trigger of the * same deprecation during a request. * - * @param mixed $args + * @param float|int|string $args */ public static function trigger(string $package, string $link, string $message, ...$args): void { - if (self::$type === self::TYPE_NONE) { + $type = self::$type ?? self::getTypeFromEnv(); + + if ($type === self::TYPE_NONE) { return; } - if (array_key_exists($link, self::$ignoredLinks)) { - self::$ignoredLinks[$link]++; - } else { - self::$ignoredLinks[$link] = 1; + if (isset(self::$ignoredLinks[$link])) { + return; } - if (self::$deduplication === true && self::$ignoredLinks[$link] > 1) { + if (array_key_exists($link, self::$triggeredDeprecations)) { + self::$triggeredDeprecations[$link]++; + } else { + self::$triggeredDeprecations[$link] = 1; + } + + if (self::$deduplication === true && self::$triggeredDeprecations[$link] > 1) { return; } @@ -114,18 +124,20 @@ class Deprecation * deprecation tracking is enabled even during deduplication, because it * needs to call {@link debug_backtrace()} * - * @param mixed $args + * @param float|int|string $args */ public static function triggerIfCalledFromOutside(string $package, string $link, string $message, ...$args): void { - if (self::$type === self::TYPE_NONE) { + $type = self::$type ?? self::getTypeFromEnv(); + + if ($type === self::TYPE_NONE) { return; } $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); // first check that the caller is not from a tests folder, in which case we always let deprecations pass - if (strpos($backtrace[1]['file'], DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR) === false) { + if (isset($backtrace[1]['file'], $backtrace[0]['file']) && strpos($backtrace[1]['file'], DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR) === false) { $path = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package . DIRECTORY_SEPARATOR; if (strpos($backtrace[0]['file'], $path) === false) { @@ -137,13 +149,17 @@ class Deprecation } } - if (array_key_exists($link, self::$ignoredLinks)) { - self::$ignoredLinks[$link]++; - } else { - self::$ignoredLinks[$link] = 1; + if (isset(self::$ignoredLinks[$link])) { + return; } - if (self::$deduplication === true && self::$ignoredLinks[$link] > 1) { + if (array_key_exists($link, self::$triggeredDeprecations)) { + self::$triggeredDeprecations[$link]++; + } else { + self::$triggeredDeprecations[$link] = 1; + } + + if (self::$deduplication === true && self::$triggeredDeprecations[$link] > 1) { return; } @@ -157,31 +173,35 @@ class Deprecation } /** - * @param array $backtrace + * @param list $backtrace */ private static function delegateTriggerToBackend(string $message, array $backtrace, string $link, string $package): void { - if ((self::$type & self::TYPE_PSR_LOGGER) > 0) { + $type = self::$type ?? self::getTypeFromEnv(); + + if (($type & self::TYPE_PSR_LOGGER) > 0) { $context = [ - 'file' => $backtrace[0]['file'], - 'line' => $backtrace[0]['line'], + 'file' => $backtrace[0]['file'] ?? null, + 'line' => $backtrace[0]['line'] ?? null, 'package' => $package, 'link' => $link, ]; + assert(self::$logger !== null); + self::$logger->notice($message, $context); } - if (! ((self::$type & self::TYPE_TRIGGER_ERROR) > 0)) { + if (! (($type & self::TYPE_TRIGGER_ERROR) > 0)) { return; } $message .= sprintf( ' (%s:%d called by %s:%d, %s, package %s)', - self::basename($backtrace[0]['file']), - $backtrace[0]['line'], - self::basename($backtrace[1]['file']), - $backtrace[1]['line'], + self::basename($backtrace[0]['file'] ?? 'native code'), + $backtrace[0]['line'] ?? 0, + self::basename($backtrace[1]['file'] ?? 'native code'), + $backtrace[1]['line'] ?? 0, $link, $package ); @@ -205,16 +225,19 @@ class Deprecation public static function enableTrackingDeprecations(): void { + self::$type = self::$type ?? 0; self::$type |= self::TYPE_TRACK_DEPRECATIONS; } public static function enableWithTriggerError(): void { + self::$type = self::$type ?? 0; self::$type |= self::TYPE_TRIGGER_ERROR; } public static function enableWithPsrLogger(LoggerInterface $logger): void { + self::$type = self::$type ?? 0; self::$type |= self::TYPE_PSR_LOGGER; self::$logger = $logger; } @@ -229,9 +252,10 @@ class Deprecation self::$type = self::TYPE_NONE; self::$logger = null; self::$deduplication = true; + self::$ignoredLinks = []; - foreach (self::$ignoredLinks as $link => $count) { - self::$ignoredLinks[$link] = 0; + foreach (self::$triggeredDeprecations as $link => $count) { + self::$triggeredDeprecations[$link] = 0; } } @@ -243,13 +267,13 @@ class Deprecation public static function ignoreDeprecations(string ...$links): void { foreach ($links as $link) { - self::$ignoredLinks[$link] = 0; + self::$ignoredLinks[$link] = true; } } public static function getUniqueTriggeredDeprecationsCount(): int { - return array_reduce(self::$ignoredLinks, static function (int $carry, int $count) { + return array_reduce(self::$triggeredDeprecations, static function (int $carry, int $count) { return $carry + $count; }, 0); } @@ -261,6 +285,28 @@ class Deprecation */ public static function getTriggeredDeprecations(): array { - return self::$ignoredLinks; + return self::$triggeredDeprecations; + } + + /** + * @return int-mask-of + */ + private static function getTypeFromEnv(): int + { + switch ($_SERVER['DOCTRINE_DEPRECATIONS'] ?? $_ENV['DOCTRINE_DEPRECATIONS'] ?? null) { + case 'trigger': + self::$type = self::TYPE_TRIGGER_ERROR; + break; + + case 'track': + self::$type = self::TYPE_TRACK_DEPRECATIONS; + break; + + default: + self::$type = self::TYPE_NONE; + break; + } + + return self::$type; } } diff --git a/vendor/doctrine/deprecations/phpstan.neon b/vendor/doctrine/deprecations/phpstan.neon new file mode 100644 index 00000000..4ee286b8 --- /dev/null +++ b/vendor/doctrine/deprecations/phpstan.neon @@ -0,0 +1,9 @@ +parameters: + level: 6 + paths: + - lib + - tests + +includes: + - vendor/phpstan/phpstan-phpunit/extension.neon + - vendor/phpstan/phpstan-phpunit/rules.neon diff --git a/vendor/doctrine/deprecations/psalm.xml b/vendor/doctrine/deprecations/psalm.xml new file mode 100644 index 00000000..ad76e32e --- /dev/null +++ b/vendor/doctrine/deprecations/psalm.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/nikic/php-parser/grammar/php5.y b/vendor/nikic/php-parser/grammar/php5.y index 2920dead..77e4fb7e 100644 --- a/vendor/nikic/php-parser/grammar/php5.y +++ b/vendor/nikic/php-parser/grammar/php5.y @@ -1008,7 +1008,7 @@ array_pair: | expr { $$ = Expr\ArrayItem[$1, null, false]; } | expr T_DOUBLE_ARROW ampersand variable { $$ = Expr\ArrayItem[$4, $1, true]; } | ampersand variable { $$ = Expr\ArrayItem[$2, null, true]; } - | T_ELLIPSIS expr { $$ = Expr\ArrayItem[$2, null, false, attributes(), true]; } + | T_ELLIPSIS expr { $$ = new Expr\ArrayItem($2, null, false, attributes(), true); } ; encaps_list: diff --git a/vendor/nikic/php-parser/grammar/php7.y b/vendor/nikic/php-parser/grammar/php7.y index fc7862c3..2d65d484 100644 --- a/vendor/nikic/php-parser/grammar/php7.y +++ b/vendor/nikic/php-parser/grammar/php7.y @@ -1194,7 +1194,7 @@ array_pair: | expr T_DOUBLE_ARROW expr { $$ = Expr\ArrayItem[$3, $1, false]; } | expr T_DOUBLE_ARROW ampersand variable { $$ = Expr\ArrayItem[$4, $1, true]; } | expr T_DOUBLE_ARROW list_expr { $$ = Expr\ArrayItem[$3, $1, false]; } - | T_ELLIPSIS expr { $$ = Expr\ArrayItem[$2, null, false, attributes(), true]; } + | T_ELLIPSIS expr { $$ = new Expr\ArrayItem($2, null, false, attributes(), true); } | /* empty */ { $$ = null; } ; diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Name.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Name.php index 17bd1c0f..f0a564ff 100644 --- a/vendor/nikic/php-parser/lib/PhpParser/Node/Name.php +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Name.php @@ -6,7 +6,10 @@ use PhpParser\NodeAbstract; class Name extends NodeAbstract { - /** @var string[] Parts of the name */ + /** + * @var string[] Parts of the name + * @deprecated Use getParts() instead + */ public $parts; private static $specialClassNames = [ @@ -30,6 +33,15 @@ class Name extends NodeAbstract return ['parts']; } + /** + * Get parts of name (split by the namespace separator). + * + * @return string[] Parts of name + */ + public function getParts(): array { + return $this->parts; + } + /** * Gets the first part of the name, i.e. everything before the first namespace separator. * diff --git a/vendor/nikic/php-parser/lib/PhpParser/Parser/Php5.php b/vendor/nikic/php-parser/lib/PhpParser/Parser/Php5.php index 351db9ed..a4306710 100644 --- a/vendor/nikic/php-parser/lib/PhpParser/Parser/Php5.php +++ b/vendor/nikic/php-parser/lib/PhpParser/Parser/Php5.php @@ -2627,7 +2627,7 @@ class Php5 extends \PhpParser\ParserAbstract $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos-(2-2)], null, true, $this->startAttributeStack[$stackPos-(2-1)] + $this->endAttributes); }, 552 => function ($stackPos) { - $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos-(2-2)], null, false, $this->startAttributeStack[$stackPos-(2-1)] + $this->endAttributes, true, $this->startAttributeStack[$stackPos-(2-1)] + $this->endAttributes); + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos-(2-2)], null, false, $this->startAttributeStack[$stackPos-(2-1)] + $this->endAttributes, true); }, 553 => function ($stackPos) { $this->semStack[$stackPos-(2-1)][] = $this->semStack[$stackPos-(2-2)]; $this->semValue = $this->semStack[$stackPos-(2-1)]; diff --git a/vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.php b/vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.php index c6b9abd0..cede4419 100644 --- a/vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.php +++ b/vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.php @@ -2818,7 +2818,7 @@ class Php7 extends \PhpParser\ParserAbstract $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos-(3-3)], $this->semStack[$stackPos-(3-1)], false, $this->startAttributeStack[$stackPos-(3-1)] + $this->endAttributes); }, 592 => function ($stackPos) { - $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos-(2-2)], null, false, $this->startAttributeStack[$stackPos-(2-1)] + $this->endAttributes, true, $this->startAttributeStack[$stackPos-(2-1)] + $this->endAttributes); + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos-(2-2)], null, false, $this->startAttributeStack[$stackPos-(2-1)] + $this->endAttributes, true); }, 593 => function ($stackPos) { $this->semValue = null; diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/StringValue.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/StringValue.php index c22eff07..10b1f516 100644 --- a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/StringValue.php +++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/StringValue.php @@ -15,7 +15,7 @@ namespace phpDocumentor\Reflection\PseudoTypes; use phpDocumentor\Reflection\PseudoType; use phpDocumentor\Reflection\Type; -use phpDocumentor\Reflection\Types\Float_; +use phpDocumentor\Reflection\Types\String_; use function sprintf; @@ -36,7 +36,7 @@ class StringValue implements PseudoType public function underlyingType(): Type { - return new Float_(); + return new String_(); } public function __toString(): string diff --git a/vendor/phpstan/phpdoc-parser/README.md b/vendor/phpstan/phpdoc-parser/README.md index 2d2f6c82..3b321b22 100644 --- a/vendor/phpstan/phpdoc-parser/README.md +++ b/vendor/phpstan/phpdoc-parser/README.md @@ -15,6 +15,8 @@ For the complete list of supported PHPDoc features check out PHPStan documentati * [PHPDoc Types](https://phpstan.org/writing-php-code/phpdoc-types) (list of PHPDoc types) * [phpdoc-parser API Reference](https://phpstan.github.io/phpdoc-parser/namespace-PHPStan.PhpDocParser.html) with all the AST node types etc. +This parser also supports parsing [Doctrine Annotations](https://github.com/doctrine/annotations). The AST nodes live in the [PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine namespace](https://phpstan.github.io/phpdoc-parser/namespace-PHPStan.PhpDocParser.Ast.PhpDoc.Doctrine.html). The support needs to be turned on by setting `bool $parseDoctrineAnnotations` to `true` in `Lexer` and `PhpDocParser` class constructors. + ## Installation ``` @@ -91,12 +93,13 @@ $phpDocNode = $phpDocParser->parse($tokens); // PhpDocNode $cloningTraverser = new NodeTraverser([new CloningVisitor()]); /** @var PhpDocNode $newPhpDocNode */ -$printer = new Printer(); [$newPhpDocNode] = $cloningTraverser->traverse([$phpDocNode]); // change something in $newPhpDocNode $newPhpDocNode->getParamTagValues()[0]->type = new IdentifierTypeNode('Ipsum'); +// print changed PHPDoc +$printer = new Printer(); $newPhpDoc = $printer->printFormatPreserving($newPhpDocNode, $phpDocNode, $tokens); echo $newPhpDoc; // '/** @param Ipsum $a */' ``` diff --git a/vendor/phpstan/phpdoc-parser/composer.json b/vendor/phpstan/phpdoc-parser/composer.json index 30b879b7..f1c648e5 100644 --- a/vendor/phpstan/phpdoc-parser/composer.json +++ b/vendor/phpstan/phpdoc-parser/composer.json @@ -6,6 +6,7 @@ "php": "^7.2 || ^8.0" }, "require-dev": { + "doctrine/annotations": "^2.0", "nikic/php-parser": "^4.15", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php b/vendor/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php index 32d1a04a..2b9c10ec 100644 --- a/vendor/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php +++ b/vendor/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php @@ -8,7 +8,7 @@ namespace PHPStan\PhpDocParser\Ast; * Copyright (c) 2011, Nikita Popov * All rights reserved. */ -abstract class AbstractNodeVisitor implements NodeVisitor +abstract class AbstractNodeVisitor implements NodeVisitor // phpcs:ignore SlevomatCodingStandard.Classes.SuperfluousAbstractClassNaming.SuperfluousPrefix { public function beforeTraverse(array $nodes): ?array diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.php new file mode 100644 index 00000000..3a93f5aa --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.php @@ -0,0 +1,35 @@ + */ + public $arguments; + + /** + * @param list $arguments + */ + public function __construct(string $name, array $arguments) + { + $this->name = $name; + $this->arguments = $arguments; + } + + public function __toString(): string + { + $arguments = implode(', ', $this->arguments); + return $this->name . '(' . $arguments . ')'; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.php new file mode 100644 index 00000000..f30812cf --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.php @@ -0,0 +1,43 @@ +key = $key; + $this->value = $value; + } + + + public function __toString(): string + { + if ($this->key === null) { + return (string) $this->value; + } + + return $this->key . '=' . $this->value; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.php new file mode 100644 index 00000000..e740567d --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.php @@ -0,0 +1,32 @@ + */ + public $items; + + /** + * @param list $items + */ + public function __construct(array $items) + { + $this->items = $items; + } + + public function __toString(): string + { + $items = implode(', ', $this->items); + + return '{' . $items . '}'; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArrayItem.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArrayItem.php new file mode 100644 index 00000000..d2dbf2b6 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArrayItem.php @@ -0,0 +1,47 @@ +key = $key; + $this->value = $value; + } + + + public function __toString(): string + { + if ($this->key === null) { + return (string) $this->value; + } + + return $this->key . '=' . $this->value; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.php new file mode 100644 index 00000000..84f7b18b --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.php @@ -0,0 +1,36 @@ +annotation = $annotation; + $this->description = $description; + } + + + public function __toString(): string + { + return trim("{$this->annotation} {$this->description}"); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php index 856cc3f1..d20746fc 100644 --- a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php @@ -3,6 +3,7 @@ namespace PHPStan\PhpDocParser\Ast\PhpDoc; use PHPStan\PhpDocParser\Ast\NodeAttributes; +use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineTagValueNode; use function trim; class PhpDocTagNode implements PhpDocChildNode @@ -25,6 +26,10 @@ class PhpDocTagNode implements PhpDocChildNode public function __toString(): string { + if ($this->value instanceof DoctrineTagValueNode) { + return (string) $this->value; + } + return trim("{$this->name} {$this->value}"); } diff --git a/vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php b/vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php index ccae6bef..86ae8239 100644 --- a/vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php +++ b/vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php @@ -30,23 +30,24 @@ class Lexer public const TOKEN_OPEN_PHPDOC = 15; public const TOKEN_CLOSE_PHPDOC = 16; public const TOKEN_PHPDOC_TAG = 17; - public const TOKEN_FLOAT = 18; - public const TOKEN_INTEGER = 19; - public const TOKEN_SINGLE_QUOTED_STRING = 20; - public const TOKEN_DOUBLE_QUOTED_STRING = 21; - public const TOKEN_IDENTIFIER = 22; - public const TOKEN_THIS_VARIABLE = 23; - public const TOKEN_VARIABLE = 24; - public const TOKEN_HORIZONTAL_WS = 25; - public const TOKEN_PHPDOC_EOL = 26; - public const TOKEN_OTHER = 27; - public const TOKEN_END = 28; - public const TOKEN_COLON = 29; - public const TOKEN_WILDCARD = 30; - public const TOKEN_OPEN_CURLY_BRACKET = 31; - public const TOKEN_CLOSE_CURLY_BRACKET = 32; - public const TOKEN_NEGATED = 33; - public const TOKEN_ARROW = 34; + public const TOKEN_DOCTRINE_TAG = 18; + public const TOKEN_FLOAT = 19; + public const TOKEN_INTEGER = 20; + public const TOKEN_SINGLE_QUOTED_STRING = 21; + public const TOKEN_DOUBLE_QUOTED_STRING = 22; + public const TOKEN_IDENTIFIER = 23; + public const TOKEN_THIS_VARIABLE = 24; + public const TOKEN_VARIABLE = 25; + public const TOKEN_HORIZONTAL_WS = 26; + public const TOKEN_PHPDOC_EOL = 27; + public const TOKEN_OTHER = 28; + public const TOKEN_END = 29; + public const TOKEN_COLON = 30; + public const TOKEN_WILDCARD = 31; + public const TOKEN_OPEN_CURLY_BRACKET = 32; + public const TOKEN_CLOSE_CURLY_BRACKET = 33; + public const TOKEN_NEGATED = 34; + public const TOKEN_ARROW = 35; public const TOKEN_LABELS = [ self::TOKEN_REFERENCE => '\'&\'', @@ -72,6 +73,7 @@ class Lexer self::TOKEN_OPEN_PHPDOC => '\'/**\'', self::TOKEN_CLOSE_PHPDOC => '\'*/\'', self::TOKEN_PHPDOC_TAG => 'TOKEN_PHPDOC_TAG', + self::TOKEN_DOCTRINE_TAG => 'TOKEN_DOCTRINE_TAG', self::TOKEN_PHPDOC_EOL => 'TOKEN_PHPDOC_EOL', self::TOKEN_FLOAT => 'TOKEN_FLOAT', self::TOKEN_INTEGER => 'TOKEN_INTEGER', @@ -90,9 +92,17 @@ class Lexer public const TYPE_OFFSET = 1; public const LINE_OFFSET = 2; + /** @var bool */ + private $parseDoctrineAnnotations; + /** @var string|null */ private $regexp; + public function __construct(bool $parseDoctrineAnnotations = false) + { + $this->parseDoctrineAnnotations = $parseDoctrineAnnotations; + } + /** * @return list */ @@ -160,17 +170,21 @@ class Lexer self::TOKEN_PHPDOC_TAG => '@(?:[a-z][a-z0-9-\\\\]+:)?[a-z][a-z0-9-\\\\]*+', self::TOKEN_PHPDOC_EOL => '\\r?+\\n[\\x09\\x20]*+(?:\\*(?!/)\\x20?+)?', - self::TOKEN_FLOAT => '(?:-?[0-9]++(_[0-9]++)*\\.[0-9]*(_[0-9]++)*+(?:e-?[0-9]++(_[0-9]++)*)?)|(?:-?[0-9]*+(_[0-9]++)*\\.[0-9]++(_[0-9]++)*(?:e-?[0-9]++(_[0-9]++)*)?)|(?:-?[0-9]++(_[0-9]++)*e-?[0-9]++(_[0-9]++)*)', - self::TOKEN_INTEGER => '-?(?:(?:0b[0-1]++(_[0-1]++)*)|(?:0o[0-7]++(_[0-7]++)*)|(?:0x[0-9a-f]++(_[0-9a-f]++)*)|(?:[0-9]++(_[0-9]++)*))', + self::TOKEN_FLOAT => '[+\-]?(?:(?:[0-9]++(_[0-9]++)*\\.[0-9]*+(_[0-9]++)*(?:e[+\-]?[0-9]++(_[0-9]++)*)?)|(?:[0-9]*+(_[0-9]++)*\\.[0-9]++(_[0-9]++)*(?:e[+\-]?[0-9]++(_[0-9]++)*)?)|(?:[0-9]++(_[0-9]++)*e[+\-]?[0-9]++(_[0-9]++)*))', + self::TOKEN_INTEGER => '[+\-]?(?:(?:0b[0-1]++(_[0-1]++)*)|(?:0o[0-7]++(_[0-7]++)*)|(?:0x[0-9a-f]++(_[0-9a-f]++)*)|(?:[0-9]++(_[0-9]++)*))', self::TOKEN_SINGLE_QUOTED_STRING => '\'(?:\\\\[^\\r\\n]|[^\'\\r\\n\\\\])*+\'', self::TOKEN_DOUBLE_QUOTED_STRING => '"(?:\\\\[^\\r\\n]|[^"\\r\\n\\\\])*+"', self::TOKEN_WILDCARD => '\\*', - - // anything but TOKEN_CLOSE_PHPDOC or TOKEN_HORIZONTAL_WS or TOKEN_EOL - self::TOKEN_OTHER => '(?:(?!\\*/)[^\\s])++', ]; + if ($this->parseDoctrineAnnotations) { + $patterns[self::TOKEN_DOCTRINE_TAG] = '@[a-z_\\\\][a-z0-9_\:\\\\]*[a-z_][a-z0-9_]*'; + } + + // anything but TOKEN_CLOSE_PHPDOC or TOKEN_HORIZONTAL_WS or TOKEN_EOL + $patterns[self::TOKEN_OTHER] = '(?:(?!\\*/)[^\\s])++'; + foreach ($patterns as $type => &$pattern) { $pattern = '(?:' . $pattern . ')(*MARK:' . $type . ')'; } diff --git a/vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php b/vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php index b6db8a2c..f97c260c 100644 --- a/vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php +++ b/vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php @@ -245,22 +245,14 @@ class ConstExprParser */ private function enrichWithAttributes(TokenIterator $tokens, Ast\ConstExpr\ConstExprNode $node, int $startLine, int $startIndex): Ast\ConstExpr\ConstExprNode { - $endLine = $tokens->currentTokenLine(); - $endIndex = $tokens->currentTokenIndex(); if ($this->useLinesAttributes) { $node->setAttribute(Ast\Attribute::START_LINE, $startLine); - $node->setAttribute(Ast\Attribute::END_LINE, $endLine); + $node->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine()); } if ($this->useIndexAttributes) { - $tokensArray = $tokens->getTokens(); - $endIndex--; - if ($tokensArray[$endIndex][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) { - $endIndex--; - } - $node->setAttribute(Ast\Attribute::START_INDEX, $startIndex); - $node->setAttribute(Ast\Attribute::END_INDEX, $endIndex); + $node->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken()); } return $node; diff --git a/vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php b/vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php index d3eed465..7b56e3bd 100644 --- a/vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php +++ b/vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php @@ -2,15 +2,25 @@ namespace PHPStan\PhpDocParser\Parser; +use LogicException; use PHPStan\PhpDocParser\Ast; +use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode; +use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode; +use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode; +use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Lexer\Lexer; use PHPStan\ShouldNotHappenException; use function array_key_exists; use function array_values; use function count; +use function rtrim; +use function str_replace; use function trim; +/** + * @phpstan-import-type ValueType from Doctrine\DoctrineArgument as DoctrineValueType + */ class PhpDocParser { @@ -31,12 +41,18 @@ class PhpDocParser /** @var bool */ private $preserveTypeAliasesWithInvalidTypes; + /** @var bool */ + private $parseDoctrineAnnotations; + /** @var bool */ private $useLinesAttributes; /** @var bool */ private $useIndexAttributes; + /** @var bool */ + private $textBetweenTagsBelongsToDescription; + /** * @param array{lines?: bool, indexes?: bool} $usedAttributes */ @@ -45,15 +61,19 @@ class PhpDocParser ConstExprParser $constantExprParser, bool $requireWhitespaceBeforeDescription = false, bool $preserveTypeAliasesWithInvalidTypes = false, - array $usedAttributes = [] + array $usedAttributes = [], + bool $parseDoctrineAnnotations = false, + bool $textBetweenTagsBelongsToDescription = false ) { $this->typeParser = $typeParser; $this->constantExprParser = $constantExprParser; $this->requireWhitespaceBeforeDescription = $requireWhitespaceBeforeDescription; $this->preserveTypeAliasesWithInvalidTypes = $preserveTypeAliasesWithInvalidTypes; + $this->parseDoctrineAnnotations = $parseDoctrineAnnotations; $this->useLinesAttributes = $usedAttributes['lines'] ?? false; $this->useIndexAttributes = $usedAttributes['indexes'] ?? false; + $this->textBetweenTagsBelongsToDescription = $textBetweenTagsBelongsToDescription; } @@ -64,10 +84,44 @@ class PhpDocParser $children = []; - if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { - $children[] = $this->parseChild($tokens); - while ($tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL) && !$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { + if ($this->parseDoctrineAnnotations) { + if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { + $lastChild = $this->parseChild($tokens); + $children[] = $lastChild; + while (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { + if ( + $lastChild instanceof Ast\PhpDoc\PhpDocTagNode + && ( + $lastChild->value instanceof Doctrine\DoctrineTagValueNode + || $lastChild->value instanceof Ast\PhpDoc\GenericTagValueNode + ) + ) { + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { + break; + } + $lastChild = $this->parseChild($tokens); + $children[] = $lastChild; + continue; + } + + if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL)) { + break; + } + if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { + break; + } + + $lastChild = $this->parseChild($tokens); + $children[] = $lastChild; + } + } + } else { + if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { $children[] = $this->parseChild($tokens); + while ($tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL) && !$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { + $children[] = $this->parseChild($tokens); + } } } @@ -105,6 +159,7 @@ class PhpDocParser } + /** @phpstan-impure */ private function parseChild(TokenIterator $tokens): Ast\PhpDoc\PhpDocChildNode { if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG)) { @@ -113,6 +168,26 @@ class PhpDocParser return $this->enrichWithAttributes($tokens, $this->parseTag($tokens), $startLine, $startIndex); } + if ($tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_TAG)) { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + $tag = $tokens->currentTokenValue(); + $tokens->next(); + + $tagStartLine = $tokens->currentTokenLine(); + $tagStartIndex = $tokens->currentTokenIndex(); + + return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocTagNode( + $tag, + $this->enrichWithAttributes( + $tokens, + $this->parseDoctrineTagValue($tokens, $tag), + $tagStartLine, + $tagStartIndex + ) + ), $startLine, $startIndex); + } + $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); $text = $this->parseText($tokens); @@ -127,27 +202,14 @@ class PhpDocParser */ private function enrichWithAttributes(TokenIterator $tokens, Ast\Node $tag, int $startLine, int $startIndex): Ast\Node { - $endLine = $tokens->currentTokenLine(); - $endIndex = $tokens->currentTokenIndex(); - if ($this->useLinesAttributes) { $tag->setAttribute(Ast\Attribute::START_LINE, $startLine); - $tag->setAttribute(Ast\Attribute::END_LINE, $endLine); + $tag->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine()); } if ($this->useIndexAttributes) { - $tokensArray = $tokens->getTokens(); - if ($tokensArray[$endIndex][Lexer::TYPE_OFFSET] === Lexer::TOKEN_CLOSE_PHPDOC) { - $endIndex--; - if ($tokensArray[$endIndex][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) { - $endIndex--; - } - } elseif ($tokensArray[$endIndex][Lexer::TYPE_OFFSET] === Lexer::TOKEN_PHPDOC_EOL) { - $endIndex--; - } - $tag->setAttribute(Ast\Attribute::START_INDEX, $startIndex); - $tag->setAttribute(Ast\Attribute::END_INDEX, $endIndex); + $tag->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken()); } return $tag; @@ -158,29 +220,144 @@ class PhpDocParser { $text = ''; - while (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) { - $text .= $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END); + $endTokens = [Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END]; + if ($this->textBetweenTagsBelongsToDescription) { + $endTokens = [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END]; + } + $savepoint = false; + + // if the next token is EOL, everything below is skipped and empty string is returned + while ($this->textBetweenTagsBelongsToDescription || !$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) { + $tmpText = $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_EOL, ...$endTokens); + $text .= $tmpText; + + // stop if we're not at EOL - meaning it's the end of PHPDoc if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) { break; } + if ($this->textBetweenTagsBelongsToDescription) { + if (!$savepoint) { + $tokens->pushSavePoint(); + $savepoint = true; + } elseif ($tmpText !== '') { + $tokens->dropSavePoint(); + $tokens->pushSavePoint(); + } + } + $tokens->pushSavePoint(); $tokens->next(); - if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END)) { + // if we're at EOL, check what's next + // if next is a PHPDoc tag, EOL, or end of PHPDoc, stop + if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, ...$endTokens)) { $tokens->rollback(); break; } + // otherwise if the next is text, continue building the description string + $tokens->dropSavePoint(); - $text .= "\n"; + $text .= $tokens->getDetectedNewline() ?? "\n"; + } + + if ($savepoint) { + $tokens->rollback(); + $text = rtrim($text, $tokens->getDetectedNewline() ?? "\n"); } return new Ast\PhpDoc\PhpDocTextNode(trim($text, " \t")); } + private function parseOptionalDescriptionAfterDoctrineTag(TokenIterator $tokens): string + { + $text = ''; + + $endTokens = [Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END]; + if ($this->textBetweenTagsBelongsToDescription) { + $endTokens = [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END]; + } + + $savepoint = false; + + // if the next token is EOL, everything below is skipped and empty string is returned + while ($this->textBetweenTagsBelongsToDescription || !$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) { + $tmpText = $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, Lexer::TOKEN_PHPDOC_EOL, ...$endTokens); + $text .= $tmpText; + + // stop if we're not at EOL - meaning it's the end of PHPDoc + if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) { + if (!$tokens->isPrecededByHorizontalWhitespace()) { + return trim($text . $this->parseText($tokens)->text, " \t"); + } + if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG)) { + $tokens->pushSavePoint(); + $child = $this->parseChild($tokens); + if ($child instanceof Ast\PhpDoc\PhpDocTagNode) { + if ( + $child->value instanceof Ast\PhpDoc\GenericTagValueNode + || $child->value instanceof Doctrine\DoctrineTagValueNode + ) { + $tokens->rollback(); + break; + } + if ($child->value instanceof Ast\PhpDoc\InvalidTagValueNode) { + $tokens->rollback(); + $tokens->pushSavePoint(); + $tokens->next(); + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { + $tokens->rollback(); + break; + } + $tokens->rollback(); + return trim($text . $this->parseText($tokens)->text, " \t"); + } + } + + $tokens->rollback(); + return trim($text . $this->parseText($tokens)->text, " \t"); + } + break; + } + + if ($this->textBetweenTagsBelongsToDescription) { + if (!$savepoint) { + $tokens->pushSavePoint(); + $savepoint = true; + } elseif ($tmpText !== '') { + $tokens->dropSavePoint(); + $tokens->pushSavePoint(); + } + } + + $tokens->pushSavePoint(); + $tokens->next(); + + // if we're at EOL, check what's next + // if next is a PHPDoc tag, EOL, or end of PHPDoc, stop + if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, ...$endTokens)) { + $tokens->rollback(); + break; + } + + // otherwise if the next is text, continue building the description string + + $tokens->dropSavePoint(); + $text .= $tokens->getDetectedNewline() ?? "\n"; + } + + if ($savepoint) { + $tokens->rollback(); + $text = rtrim($text, $tokens->getDetectedNewline() ?? "\n"); + } + + return trim($text, " \t"); + } + + public function parseTag(TokenIterator $tokens): Ast\PhpDoc\PhpDocTagNode { $tag = $tokens->currentTokenValue(); @@ -312,7 +489,17 @@ class PhpDocParser break; default: + if ($this->parseDoctrineAnnotations) { + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { + $tagValue = $this->parseDoctrineTagValue($tokens, $tag); + } else { + $tagValue = new Ast\PhpDoc\GenericTagValueNode($this->parseOptionalDescriptionAfterDoctrineTag($tokens)); + } + break; + } + $tagValue = new Ast\PhpDoc\GenericTagValueNode($this->parseOptionalDescription($tokens)); + break; } @@ -327,6 +514,297 @@ class PhpDocParser } + private function parseDoctrineTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\PhpDocTagValueNode + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + + return new Doctrine\DoctrineTagValueNode( + $this->enrichWithAttributes( + $tokens, + new Doctrine\DoctrineAnnotation($tag, $this->parseDoctrineArguments($tokens, false)), + $startLine, + $startIndex + ), + $this->parseOptionalDescriptionAfterDoctrineTag($tokens) + ); + } + + + /** + * @return list + */ + private function parseDoctrineArguments(TokenIterator $tokens, bool $deep): array + { + if (!$tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { + return []; + } + + if (!$deep) { + $tokens->addEndOfLineToSkippedTokens(); + } + + $arguments = []; + + try { + $tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES); + + do { + if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) { + break; + } + $arguments[] = $this->parseDoctrineArgument($tokens); + } while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)); + } finally { + if (!$deep) { + $tokens->removeEndOfLineFromSkippedTokens(); + } + } + + $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES); + + return $arguments; + } + + + private function parseDoctrineArgument(TokenIterator $tokens): Doctrine\DoctrineArgument + { + if (!$tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + + return $this->enrichWithAttributes( + $tokens, + new Doctrine\DoctrineArgument(null, $this->parseDoctrineArgumentValue($tokens)), + $startLine, + $startIndex + ); + } + + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + + try { + $tokens->pushSavePoint(); + $currentValue = $tokens->currentTokenValue(); + $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + + $key = $this->enrichWithAttributes( + $tokens, + new IdentifierTypeNode($currentValue), + $startLine, + $startIndex + ); + $tokens->consumeTokenType(Lexer::TOKEN_EQUAL); + + $value = $this->parseDoctrineArgumentValue($tokens); + + $tokens->dropSavePoint(); + + return $this->enrichWithAttributes( + $tokens, + new Doctrine\DoctrineArgument($key, $value), + $startLine, + $startIndex + ); + } catch (ParserException $e) { + $tokens->rollback(); + + return $this->enrichWithAttributes( + $tokens, + new Doctrine\DoctrineArgument(null, $this->parseDoctrineArgumentValue($tokens)), + $startLine, + $startIndex + ); + } + } + + + /** + * @return DoctrineValueType + */ + private function parseDoctrineArgumentValue(TokenIterator $tokens) + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG)) { + $name = $tokens->currentTokenValue(); + $tokens->next(); + + return $this->enrichWithAttributes( + $tokens, + new Doctrine\DoctrineAnnotation($name, $this->parseDoctrineArguments($tokens, true)), + $startLine, + $startIndex + ); + } + + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET)) { + $items = []; + do { + if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) { + break; + } + $items[] = $this->parseDoctrineArrayItem($tokens); + } while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)); + + $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET); + + return $this->enrichWithAttributes( + $tokens, + new Doctrine\DoctrineArray($items), + $startLine, + $startIndex + ); + } + + $currentTokenValue = $tokens->currentTokenValue(); + $tokens->pushSavePoint(); // because of ConstFetchNode + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) { + $identifier = $this->enrichWithAttributes( + $tokens, + new Ast\Type\IdentifierTypeNode($currentTokenValue), + $startLine, + $startIndex + ); + if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) { + $tokens->dropSavePoint(); + return $identifier; + } + + $tokens->rollback(); // because of ConstFetchNode + } else { + $tokens->dropSavePoint(); // because of ConstFetchNode + } + + $exception = new ParserException( + $tokens->currentTokenValue(), + $tokens->currentTokenType(), + $tokens->currentTokenOffset(), + Lexer::TOKEN_IDENTIFIER, + null, + $tokens->currentTokenLine() + ); + + try { + $constExpr = $this->constantExprParser->parse($tokens, true); + if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) { + throw $exception; + } + + return $constExpr; + } catch (LogicException $e) { + throw $exception; + } + } + + + private function parseDoctrineArrayItem(TokenIterator $tokens): Doctrine\DoctrineArrayItem + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + + try { + $tokens->pushSavePoint(); + + $key = $this->parseDoctrineArrayKey($tokens); + if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL)) { + if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_COLON)) { + $tokens->consumeTokenType(Lexer::TOKEN_EQUAL); // will throw exception + } + } + + $value = $this->parseDoctrineArgumentValue($tokens); + + $tokens->dropSavePoint(); + + return $this->enrichWithAttributes( + $tokens, + new Doctrine\DoctrineArrayItem($key, $value), + $startLine, + $startIndex + ); + } catch (ParserException $e) { + $tokens->rollback(); + + return $this->enrichWithAttributes( + $tokens, + new Doctrine\DoctrineArrayItem(null, $this->parseDoctrineArgumentValue($tokens)), + $startLine, + $startIndex + ); + } + } + + + /** + * @return ConstExprIntegerNode|ConstExprStringNode|IdentifierTypeNode|ConstFetchNode + */ + private function parseDoctrineArrayKey(TokenIterator $tokens) + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) { + $key = new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $tokens->currentTokenValue())); + $tokens->next(); + + } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) { + $key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED); + $tokens->next(); + + } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) { + $key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED); + + $tokens->next(); + + } else { + $currentTokenValue = $tokens->currentTokenValue(); + $tokens->pushSavePoint(); // because of ConstFetchNode + if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) { + $tokens->dropSavePoint(); + throw new ParserException( + $tokens->currentTokenValue(), + $tokens->currentTokenType(), + $tokens->currentTokenOffset(), + Lexer::TOKEN_IDENTIFIER, + null, + $tokens->currentTokenLine() + ); + } + + if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) { + $tokens->dropSavePoint(); + + return $this->enrichWithAttributes( + $tokens, + new IdentifierTypeNode($currentTokenValue), + $startLine, + $startIndex + ); + } + + $tokens->rollback(); + $constExpr = $this->constantExprParser->parse($tokens, true); + if (!$constExpr instanceof Ast\ConstExpr\ConstFetchNode) { + throw new ParserException( + $tokens->currentTokenValue(), + $tokens->currentTokenType(), + $tokens->currentTokenOffset(), + Lexer::TOKEN_IDENTIFIER, + null, + $tokens->currentTokenLine() + ); + } + + return $constExpr; + } + + return $this->enrichWithAttributes($tokens, $key, $startLine, $startIndex); + } + + /** * @return Ast\PhpDoc\ParamTagValueNode|Ast\PhpDoc\TypelessParamTagValueNode */ diff --git a/vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php b/vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php index 4348ab79..9be7593d 100644 --- a/vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php +++ b/vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php @@ -9,6 +9,7 @@ use function assert; use function count; use function in_array; use function strlen; +use function substr; class TokenIterator { @@ -22,6 +23,12 @@ class TokenIterator /** @var int[] */ private $savePoints = []; + /** @var list */ + private $skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS]; + + /** @var string|null */ + private $newline = null; + /** * @param list $tokens */ @@ -30,11 +37,7 @@ class TokenIterator $this->tokens = $tokens; $this->index = $index; - if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== Lexer::TOKEN_HORIZONTAL_WS) { - return; - } - - $this->index++; + $this->skipIrrelevantTokens(); } @@ -103,6 +106,21 @@ class TokenIterator } + public function endIndexOfLastRelevantToken(): int + { + $endIndex = $this->currentTokenIndex(); + $endIndex--; + while (in_array($this->tokens[$endIndex][Lexer::TYPE_OFFSET], $this->skippedTokenTypes, true)) { + if (!isset($this->tokens[$endIndex - 1])) { + break; + } + $endIndex--; + } + + return $endIndex; + } + + public function isCurrentTokenValue(string $tokenValue): bool { return $this->tokens[$this->index][Lexer::VALUE_OFFSET] === $tokenValue; @@ -130,13 +148,14 @@ class TokenIterator $this->throwError($tokenType); } - $this->index++; - - if (($this->tokens[$this->index][Lexer::TYPE_OFFSET] ?? -1) !== Lexer::TOKEN_HORIZONTAL_WS) { - return; + if ($tokenType === Lexer::TOKEN_PHPDOC_EOL) { + if ($this->newline === null) { + $this->detectNewline(); + } } $this->index++; + $this->skipIrrelevantTokens(); } @@ -150,12 +169,7 @@ class TokenIterator } $this->index++; - - if (($this->tokens[$this->index][Lexer::TYPE_OFFSET] ?? -1) !== Lexer::TOKEN_HORIZONTAL_WS) { - return; - } - - $this->index++; + $this->skipIrrelevantTokens(); } @@ -167,10 +181,7 @@ class TokenIterator } $this->index++; - - if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) { - $this->index++; - } + $this->skipIrrelevantTokens(); return true; } @@ -183,16 +194,30 @@ class TokenIterator return false; } - $this->index++; - - if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) { - $this->index++; + if ($tokenType === Lexer::TOKEN_PHPDOC_EOL) { + if ($this->newline === null) { + $this->detectNewline(); + } } + $this->index++; + $this->skipIrrelevantTokens(); + return true; } + private function detectNewline(): void + { + $value = $this->currentTokenValue(); + if (substr($value, 0, 2) === "\r\n") { + $this->newline = "\r\n"; + } elseif (substr($value, 0, 1) === "\n") { + $this->newline = "\n"; + } + } + + public function getSkippedHorizontalWhiteSpaceIfAny(): string { if ($this->index > 0 && $this->tokens[$this->index - 1][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) { @@ -217,12 +242,34 @@ class TokenIterator public function next(): void { $this->index++; + $this->skipIrrelevantTokens(); + } - if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== Lexer::TOKEN_HORIZONTAL_WS) { + + private function skipIrrelevantTokens(): void + { + if (!isset($this->tokens[$this->index])) { return; } - $this->index++; + while (in_array($this->tokens[$this->index][Lexer::TYPE_OFFSET], $this->skippedTokenTypes, true)) { + if (!isset($this->tokens[$this->index + 1])) { + break; + } + $this->index++; + } + } + + + public function addEndOfLineToSkippedTokens(): void + { + $this->skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS, Lexer::TOKEN_PHPDOC_EOL]; + } + + + public function removeEndOfLineFromSkippedTokens(): void + { + $this->skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS]; } /** @phpstan-impure */ @@ -319,6 +366,11 @@ class TokenIterator return false; } + public function getDetectedNewline(): ?string + { + return $this->newline; + } + /** * Whether the given position is immediately surrounded by parenthesis. */ diff --git a/vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.php b/vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.php index 4b429809..645f544b 100644 --- a/vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.php +++ b/vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.php @@ -70,23 +70,14 @@ class TypeParser */ public function enrichWithAttributes(TokenIterator $tokens, Ast\Node $type, int $startLine, int $startIndex): Ast\Node { - $endLine = $tokens->currentTokenLine(); - $endIndex = $tokens->currentTokenIndex(); - if ($this->useLinesAttributes) { $type->setAttribute(Ast\Attribute::START_LINE, $startLine); - $type->setAttribute(Ast\Attribute::END_LINE, $endLine); + $type->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine()); } if ($this->useIndexAttributes) { - $tokensArray = $tokens->getTokens(); - $endIndex--; - if ($tokensArray[$endIndex][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) { - $endIndex--; - } - $type->setAttribute(Ast\Attribute::START_INDEX, $startIndex); - $type->setAttribute(Ast\Attribute::END_INDEX, $endIndex); + $type->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken()); } return $type; diff --git a/vendor/phpstan/phpdoc-parser/src/Printer/Printer.php b/vendor/phpstan/phpdoc-parser/src/Printer/Printer.php index bc07d10c..d7feaf91 100644 --- a/vendor/phpstan/phpdoc-parser/src/Printer/Printer.php +++ b/vendor/phpstan/phpdoc-parser/src/Printer/Printer.php @@ -10,6 +10,11 @@ use PHPStan\PhpDocParser\Ast\Node; use PHPStan\PhpDocParser\Ast\PhpDoc\AssertTagMethodValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\AssertTagPropertyValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\AssertTagValueNode; +use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineAnnotation; +use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineArgument; +use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineArray; +use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineArrayItem; +use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\ExtendsTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\ImplementsTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueNode; @@ -95,6 +100,8 @@ final class Printer GenericTypeNode::class . '->genericTypes' => ', ', ConstExprArrayNode::class . '->items' => ', ', MethodTagValueNode::class . '->parameters' => ', ', + DoctrineArray::class . '->items' => ', ', + DoctrineAnnotation::class . '->arguments' => ', ', ]; /** @@ -106,6 +113,8 @@ final class Printer CallableTypeNode::class . '->parameters' => ['(', '', ''], ArrayShapeNode::class . '->items' => ['{', '', ''], ObjectShapeNode::class . '->items' => ['{', '', ''], + DoctrineArray::class . '->items' => ['{', '', ''], + DoctrineAnnotation::class . '->arguments' => ['(', '', ''], ]; /** @var array>> */ @@ -186,6 +195,10 @@ final class Printer return $node->text; } if ($node instanceof PhpDocTagNode) { + if ($node->value instanceof DoctrineTagValueNode) { + return $this->print($node->value); + } + return trim(sprintf('%s %s', $node->name, $this->print($node->value))); } if ($node instanceof PhpDocTagValueNode) { @@ -211,6 +224,18 @@ final class Printer $isOptional = $node->isOptional ? '=' : ''; return trim("{$type}{$isReference}{$isVariadic}{$node->parameterName}") . $isOptional; } + if ($node instanceof DoctrineAnnotation) { + return (string) $node; + } + if ($node instanceof DoctrineArgument) { + return (string) $node; + } + if ($node instanceof DoctrineArray) { + return (string) $node; + } + if ($node instanceof DoctrineArrayItem) { + return (string) $node; + } throw new LogicException(sprintf('Unknown node type %s', get_class($node))); } @@ -491,7 +516,7 @@ final class Printer [$isMultiline, $beforeAsteriskIndent, $afterAsteriskIndent] = $this->isMultiline($tokenIndex, $originalNodes, $originalTokens); if ($insertStr === "\n * ") { - $insertStr = sprintf("\n%s*%s", $beforeAsteriskIndent, $afterAsteriskIndent); + $insertStr = sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent); } foreach ($diff as $i => $diffElem) { @@ -524,7 +549,7 @@ final class Printer } if ($insertNewline) { - $result .= $insertStr . sprintf("\n%s*%s", $beforeAsteriskIndent, $afterAsteriskIndent); + $result .= $insertStr . sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent); } else { $result .= $insertStr; } @@ -534,7 +559,8 @@ final class Printer } $parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) - && in_array(get_class($newNode), $this->parenthesesListMap[$mapKey], true); + && in_array(get_class($newNode), $this->parenthesesListMap[$mapKey], true) + && !in_array(get_class($originalNode), $this->parenthesesListMap[$mapKey], true); $addParentheses = $parenthesesNeeded && !$originalTokens->hasParentheses($itemStartPos, $itemEndPos); if ($addParentheses) { $result .= '('; @@ -567,7 +593,7 @@ final class Printer $itemEndPos = $tokenIndex - 1; if ($insertNewline) { - $result .= $insertStr . sprintf("\n%s*%s", $beforeAsteriskIndent, $afterAsteriskIndent); + $result .= $insertStr . sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent); } else { $result .= $insertStr; } @@ -636,7 +662,7 @@ final class Printer if (!$first) { $result .= $insertStr; if ($insertNewline) { - $result .= sprintf("\n%s*%s", $beforeAsteriskIndent, $afterAsteriskIndent); + $result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent); } } @@ -777,6 +803,12 @@ final class Printer $mapKey = get_class($node) . '->' . $subNodeName; $parenthesesNeeded = isset($this->parenthesesMap[$mapKey]) && in_array(get_class($subNode), $this->parenthesesMap[$mapKey], true); + + if ($subNode->getAttribute(Attribute::ORIGINAL_NODE) !== null) { + $parenthesesNeeded = $parenthesesNeeded + && !in_array(get_class($subNode->getAttribute(Attribute::ORIGINAL_NODE)), $this->parenthesesMap[$mapKey], true); + } + $addParentheses = $parenthesesNeeded && !$originalTokens->hasParentheses($subStartPos, $subEndPos); if ($addParentheses) { $result .= '('; diff --git a/vendor/phpstan/phpstan/phpstan.phar b/vendor/phpstan/phpstan/phpstan.phar index 3f043c71..7f766674 100755 Binary files a/vendor/phpstan/phpstan/phpstan.phar and b/vendor/phpstan/phpstan/phpstan.phar differ diff --git a/vendor/phpstan/phpstan/phpstan.phar.asc b/vendor/phpstan/phpstan/phpstan.phar.asc index 3c34229a..bbc2c3a4 100644 --- a/vendor/phpstan/phpstan/phpstan.phar.asc +++ b/vendor/phpstan/phpstan/phpstan.phar.asc @@ -1,16 +1,16 @@ -----BEGIN PGP SIGNATURE----- -iQIzBAABCgAdFiEEynwsejDI6OEnSoR2UcZzBf/C5cAFAmRaZmcACgkQUcZzBf/C -5cAn/Q//fbWiR/qaSvlHpk73KH7iDfoHwNvRrHSQODZdMa4PGiEbL+SXsKnRxFDo -kEJZwgU5qi3WMflt7Ml3dYDlQDgoDerdaiySYFoBcv1NXDWKoF7+Egy1AHxpfNq+ -FMCkZNR2ulSaYUCofM4GkTNap4yVkPCy289ZU6yUmRnJxF+hh/CFfdVPAPbwh/a6 -UqV3R2ENJZSbtA1pzSTBpUPQGQ9qcsqngKyNyxk1hEd9opdMg2eSFvO1e1ZZm/Tk -Kgh5wCbsbSJuRPGO4vbiybTeO/qXPDlHV6oA5SHnjJ4H24phCsHdyJHHvLQmrUeR -BKHgnH1y/b5J9cgr9OgEQJK9TMHHd6dii9//Qp+0rUZIDZ4Ym2lDSA/Vn/D9GoV3 -zo4QYzW3TvE3QMdnLcX/ZtaLliPdDYIaYUXOiyaYwLFGVxSWZWOC5IN0G0bLJb39 -Ca/z839nkWdMqg68q/oHC2Nk/v/KZnKg1RlRjYhj53T6nr0JDEiaYMyETSOIFsVX -AcCQnLLwMndUAibJAyORDnTk+ipg0SecFoPvvhea1BtlTfhSDIlrT4OPKZ5nExzd -nR/zGbIH8lCvsBc+hq+Kgodtfs5nauwEOwlVUwet26xL1YKOd0jxz+Zp6tgk0wba -cMf5L9fm85j83DQYr7Ukaaj81kmMujRWDo/dRojKhUlJUrNnjXA= -=jTtX +iQIzBAABCgAdFiEEynwsejDI6OEnSoR2UcZzBf/C5cAFAmS32poACgkQUcZzBf/C +5cCvmg/+JJmyX663fa+FHy7ED2SexVuChivpbp82dyLx1gRAl15rtNG4zjxNRfnW +6GpsysMhKqrN7p6xur18ZkLqdFKAjeNnpTunnh/ADetcrs8wzLNyAy7luQtyXAuj +SOv5f/Yitg9yvZ2GHrbzchQuSjkbUR2KroBYsRhwVTH7pMIgdvysRBYiENfbz350 +n91WOCApDnVCygzEhBbhkwA/xklJnUxkRJX3AlbbCwES9K64ELyGd0BqJ1Ohy2a7 +4cFjwRJq9/tXf99fyncamN8xyBdvYBXSNRNMPYcjKqKIZCOePlR8Q3b7nt154w+e +w2qnAevOB4dYzJaSjwJlaVQYR1YIQ7NlYkGboONq/lrtJlEejDdiRmGvgHZ8nSYW +Ob2JwqgYDfUPfsnXAwXM+whpUNJi30MDB7MSw3SiDlyw690HheT/DCKOJ9yNUiOB +TSGkbIGW/ASett78gowjwniYdryE5ufUPwZbkSaFC3CDysHfs6Jgc+lxe3wnOHtD +WyPl1TqDRNuLOZ26TgxI3gGEYqMcVDYQfmuiOakoebHx6j0bpvyEaP51j0/JFpu6 +okKulXgC1DUluKFWMPhobPQRZ8zC29macnU74JvmJIiUhfiP2Pl16D+XcjFW++zH +EDEghcCdgz0pIF6UI5j02rbNAfu7Oo685pnYeXq0DexgXjqoFOE= +=NF4z -----END PGP SIGNATURE----- diff --git a/vendor/spatie/array-to-xml/CHANGELOG.md b/vendor/spatie/array-to-xml/CHANGELOG.md index 0a086699..efa9aef1 100755 --- a/vendor/spatie/array-to-xml/CHANGELOG.md +++ b/vendor/spatie/array-to-xml/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to `array-to-xml` will be documented in this file +## 3.1.6 - 2023-05-11 + +### What's Changed + +- V3 - Code smell ('incorrect' method call) by @ExeQue in https://github.com/spatie/array-to-xml/pull/208 +- Bump dependabot/fetch-metadata from 1.3.5 to 1.3.6 by @dependabot in https://github.com/spatie/array-to-xml/pull/210 +- Bump dependabot/fetch-metadata from 1.3.6 to 1.4.0 by @dependabot in https://github.com/spatie/array-to-xml/pull/214 +- Add addXmlDeclaration parameter by @silnex in https://github.com/spatie/array-to-xml/pull/216 + +### New Contributors + +- @silnex made their first contribution in https://github.com/spatie/array-to-xml/pull/216 + +**Full Changelog**: https://github.com/spatie/array-to-xml/compare/3.1.5...3.1.6 + ## 3.1.5 - 2022-12-24 ### What's Changed diff --git a/vendor/spatie/array-to-xml/README.md b/vendor/spatie/array-to-xml/README.md index ec6a6ad8..954bc25a 100755 --- a/vendor/spatie/array-to-xml/README.md +++ b/vendor/spatie/array-to-xml/README.md @@ -239,6 +239,58 @@ This will result in: ``` +### Using Closure values +The package can use Closure values: + +```php +$users = [ + [ + 'name' => 'one', + 'age' => 10, + ], + [ + 'name' => 'two', + 'age' => 12, + ], +]; + +$array = [ + 'users' => function () use ($users) { + $new_users = []; + foreach ($users as $user) { + $new_users[] = array_merge( + $user, + [ + 'double_age' => $user['age'] * 2, + ] + ); + } + + return $new_users; + }, +]; + +ArrayToXml::convert($array) +``` + +This will result in: + +```xml + + + + one + 10 + 20 + + + two + 12 + 24 + + +``` + ### Handling numeric keys The package can also can handle numeric keys: diff --git a/vendor/spatie/array-to-xml/src/ArrayToXml.php b/vendor/spatie/array-to-xml/src/ArrayToXml.php index b84bdc86..eac1ec24 100644 --- a/vendor/spatie/array-to-xml/src/ArrayToXml.php +++ b/vendor/spatie/array-to-xml/src/ArrayToXml.php @@ -2,6 +2,7 @@ namespace Spatie\ArrayToXml; +use Closure; use DOMDocument; use DOMElement; use DOMException; @@ -143,6 +144,10 @@ class ArrayToXml protected function convertElement(DOMElement $element, mixed $value): void { + if ($value instanceof Closure) { + $value = $value(); + } + $sequential = $this->isArrayAllKeySequential($value); if (! is_array($value)) { diff --git a/vendor/symfony/console/Application.php b/vendor/symfony/console/Application.php index 41548a3e..b7aaa6a2 100644 --- a/vendor/symfony/console/Application.php +++ b/vendor/symfony/console/Application.php @@ -105,11 +105,14 @@ class Application implements ResetInterface /** * @final */ - public function setDispatcher(EventDispatcherInterface $dispatcher) + public function setDispatcher(EventDispatcherInterface $dispatcher): void { $this->dispatcher = $dispatcher; } + /** + * @return void + */ public function setCommandLoader(CommandLoaderInterface $commandLoader) { $this->commandLoader = $commandLoader; @@ -118,12 +121,15 @@ class Application implements ResetInterface public function getSignalRegistry(): SignalRegistry { if (!$this->signalRegistry) { - throw new RuntimeException('Signals are not supported. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); + throw new RuntimeException('Signals are not supported. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); } return $this->signalRegistry; } + /** + * @return void + */ public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent) { $this->signalsToDispatchEvent = $signalsToDispatchEvent; @@ -317,10 +323,16 @@ class Application implements ResetInterface return $exitCode; } + /** + * @return void + */ public function reset() { } + /** + * @return void + */ public function setHelperSet(HelperSet $helperSet) { $this->helperSet = $helperSet; @@ -334,6 +346,9 @@ class Application implements ResetInterface return $this->helperSet ??= $this->getDefaultHelperSet(); } + /** + * @return void + */ public function setDefinition(InputDefinition $definition) { $this->definition = $definition; @@ -404,6 +419,8 @@ class Application implements ResetInterface /** * Sets whether to catch exceptions or not during commands execution. + * + * @return void */ public function setCatchExceptions(bool $boolean) { @@ -420,6 +437,8 @@ class Application implements ResetInterface /** * Sets whether to automatically exit after a command execution or not. + * + * @return void */ public function setAutoExit(bool $boolean) { @@ -436,7 +455,9 @@ class Application implements ResetInterface /** * Sets the application name. - **/ + * + * @return void + */ public function setName(string $name) { $this->name = $name; @@ -452,6 +473,8 @@ class Application implements ResetInterface /** * Sets the application version. + * + * @return void */ public function setVersion(string $version) { @@ -490,6 +513,8 @@ class Application implements ResetInterface * If a Command is not enabled it will not be added. * * @param Command[] $commands An array of commands + * + * @return void */ public function addCommands(array $commands) { @@ -687,9 +712,7 @@ class Application implements ResetInterface if ($alternatives = $this->findAlternatives($name, $allCommands)) { // remove hidden commands - $alternatives = array_filter($alternatives, function ($name) { - return !$this->get($name)->isHidden(); - }); + $alternatives = array_filter($alternatives, fn ($name) => !$this->get($name)->isHidden()); if (1 == \count($alternatives)) { $message .= "\n\nDid you mean this?\n "; @@ -840,9 +863,7 @@ class Application implements ResetInterface } if (str_contains($message, "@anonymous\0")) { - $message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) { - return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0]; - }, $message); + $message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $message); } $width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : \PHP_INT_MAX; @@ -903,6 +924,8 @@ class Application implements ResetInterface /** * Configures the input and output instances based on the user arguments and options. + * + * @return void */ protected function configureIO(InputInterface $input, OutputInterface $output) { @@ -977,44 +1000,62 @@ class Application implements ResetInterface } } - if ($this->signalsToDispatchEvent) { - $commandSignals = $command instanceof SignalableCommandInterface ? $command->getSubscribedSignals() : []; + $commandSignals = $command instanceof SignalableCommandInterface ? $command->getSubscribedSignals() : []; + if ($commandSignals || $this->dispatcher && $this->signalsToDispatchEvent) { + if (!$this->signalRegistry) { + throw new RuntimeException('Unable to subscribe to signal events. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); + } - if ($commandSignals || null !== $this->dispatcher) { - if (!$this->signalRegistry) { - throw new RuntimeException('Unable to subscribe to signal events. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); - } + if (Terminal::hasSttyAvailable()) { + $sttyMode = shell_exec('stty -g'); - if (Terminal::hasSttyAvailable()) { - $sttyMode = shell_exec('stty -g'); - - foreach ([\SIGINT, \SIGTERM] as $signal) { - $this->signalRegistry->register($signal, static function () use ($sttyMode) { - shell_exec('stty '.$sttyMode); - }); - } + foreach ([\SIGINT, \SIGTERM] as $signal) { + $this->signalRegistry->register($signal, static fn () => shell_exec('stty '.$sttyMode)); } } - if (null !== $this->dispatcher) { + if ($this->dispatcher) { + // We register application signals, so that we can dispatch the event foreach ($this->signalsToDispatchEvent as $signal) { $event = new ConsoleSignalEvent($command, $input, $output, $signal); - $this->signalRegistry->register($signal, function ($signal, $hasNext) use ($event) { + $this->signalRegistry->register($signal, function ($signal) use ($event, $command, $commandSignals) { $this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL); + $exitCode = $event->getExitCode(); - // No more handlers, we try to simulate PHP default behavior - if (!$hasNext) { - if (!\in_array($signal, [\SIGUSR1, \SIGUSR2], true)) { - exit(0); + // If the command is signalable, we call the handleSignal() method + if (\in_array($signal, $commandSignals, true)) { + $exitCode = $command->handleSignal($signal, $exitCode); + // BC layer for Symfony <= 5 + if (null === $exitCode) { + trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', get_debug_type($command)); + $exitCode = 0; } } + + if (false !== $exitCode) { + exit($exitCode); + } }); } + + // then we register command signals, but not if already handled after the dispatcher + $commandSignals = array_diff($commandSignals, $this->signalsToDispatchEvent); } foreach ($commandSignals as $signal) { - $this->signalRegistry->register($signal, [$command, 'handleSignal']); + $this->signalRegistry->register($signal, function (int $signal) use ($command): void { + $exitCode = $command->handleSignal($signal); + // BC layer for Symfony <= 5 + if (null === $exitCode) { + trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', get_debug_type($command)); + $exitCode = 0; + } + + if (false !== $exitCode) { + exit($exitCode); + } + }); } } @@ -1170,7 +1211,7 @@ class Application implements ResetInterface } } - $alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; }); + $alternatives = array_filter($alternatives, fn ($lev) => $lev < 2 * $threshold); ksort($alternatives, \SORT_NATURAL | \SORT_FLAG_CASE); return array_keys($alternatives); @@ -1261,7 +1302,7 @@ class Application implements ResetInterface return $namespaces; } - private function init() + private function init(): void { if ($this->initialized) { return; diff --git a/vendor/symfony/console/CHANGELOG.md b/vendor/symfony/console/CHANGELOG.md index 61c36b0e..3428a57d 100644 --- a/vendor/symfony/console/CHANGELOG.md +++ b/vendor/symfony/console/CHANGELOG.md @@ -1,6 +1,13 @@ CHANGELOG ========= +6.3 +--- + + * Add support for choosing exit code while handling signal, or to not exit at all + * Add `ProgressBar::setPlaceholderFormatter` to set a placeholder attached to a instance, instead of being global. + * Add `ReStructuredTextDescriptor` + 6.2 --- diff --git a/vendor/symfony/console/Command/Command.php b/vendor/symfony/console/Command/Command.php index 1e3c1a5a..704b112d 100644 --- a/vendor/symfony/console/Command/Command.php +++ b/vendor/symfony/console/Command/Command.php @@ -141,12 +141,17 @@ class Command * Ignores validation errors. * * This is mainly useful for the help command. + * + * @return void */ public function ignoreValidationErrors() { $this->ignoreValidationErrors = true; } + /** + * @return void + */ public function setApplication(Application $application = null) { if (1 > \func_num_args()) { @@ -162,6 +167,9 @@ class Command $this->fullDefinition = null; } + /** + * @return void + */ public function setHelperSet(HelperSet $helperSet) { $this->helperSet = $helperSet; @@ -198,6 +206,8 @@ class Command /** * Configures the current command. + * + * @return void */ protected function configure() { @@ -228,6 +238,8 @@ class Command * This method is executed before the InputDefinition is validated. * This means that this is the only place where the command can * interactively ask for values of missing required arguments. + * + * @return void */ protected function interact(InputInterface $input, OutputInterface $output) { @@ -242,6 +254,8 @@ class Command * * @see InputInterface::bind() * @see InputInterface::validate() + * + * @return void */ protected function initialize(InputInterface $input, OutputInterface $output) { @@ -378,7 +392,7 @@ class Command * * @internal */ - public function mergeApplicationDefinition(bool $mergeArgs = true) + public function mergeApplicationDefinition(bool $mergeArgs = true): void { if (null === $this->application) { return; @@ -702,7 +716,7 @@ class Command * * @throws InvalidArgumentException When the name is invalid */ - private function validateName(string $name) + private function validateName(string $name): void { if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) { throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name)); diff --git a/vendor/symfony/console/Command/CompleteCommand.php b/vendor/symfony/console/Command/CompleteCommand.php index dbf5d7dd..058578d8 100644 --- a/vendor/symfony/console/Command/CompleteCommand.php +++ b/vendor/symfony/console/Command/CompleteCommand.php @@ -74,7 +74,7 @@ final class CompleteCommand extends Command ; } - protected function initialize(InputInterface $input, OutputInterface $output) + protected function initialize(InputInterface $input, OutputInterface $output): void { $this->isDebug = filter_var(getenv('SYMFONY_COMPLETION_DEBUG'), \FILTER_VALIDATE_BOOL); } @@ -134,12 +134,12 @@ final class CompleteCommand extends Command $completionInput->bind($command->getDefinition()); if (CompletionInput::TYPE_OPTION_NAME === $completionInput->getCompletionType()) { - $this->log(' Completing option names for the '.\get_class($command instanceof LazyCommand ? $command->getCommand() : $command).' command.'); + $this->log(' Completing option names for the '.($command instanceof LazyCommand ? $command->getCommand() : $command)::class.' command.'); $suggestions->suggestOptions($command->getDefinition()->getOptions()); } else { $this->log([ - ' Completing using the '.\get_class($command instanceof LazyCommand ? $command->getCommand() : $command).' class.', + ' Completing using the '.($command instanceof LazyCommand ? $command->getCommand() : $command)::class.' class.', ' Completing '.$completionInput->getCompletionType().' for '.$completionInput->getCompletionName().'', ]); if (null !== $compval = $completionInput->getCompletionValue()) { @@ -155,7 +155,7 @@ final class CompleteCommand extends Command $this->log('Suggestions:'); if ($options = $suggestions->getOptionSuggestions()) { - $this->log(' --'.implode(' --', array_map(function ($o) { return $o->getName(); }, $options))); + $this->log(' --'.implode(' --', array_map(fn ($o) => $o->getName(), $options))); } elseif ($values = $suggestions->getValueSuggestions()) { $this->log(' '.implode(' ', $values)); } else { diff --git a/vendor/symfony/console/Command/DumpCompletionCommand.php b/vendor/symfony/console/Command/DumpCompletionCommand.php index cac944ec..51b613a1 100644 --- a/vendor/symfony/console/Command/DumpCompletionCommand.php +++ b/vendor/symfony/console/Command/DumpCompletionCommand.php @@ -39,7 +39,7 @@ final class DumpCompletionCommand extends Command private array $supportedShells; - protected function configure() + protected function configure(): void { $fullCommand = $_SERVER['PHP_SELF']; $commandName = basename($fullCommand); diff --git a/vendor/symfony/console/Command/HelpCommand.php b/vendor/symfony/console/Command/HelpCommand.php index d4134e17..e6447b05 100644 --- a/vendor/symfony/console/Command/HelpCommand.php +++ b/vendor/symfony/console/Command/HelpCommand.php @@ -27,6 +27,9 @@ class HelpCommand extends Command { private Command $command; + /** + * @return void + */ protected function configure() { $this->ignoreValidationErrors(); @@ -34,12 +37,8 @@ class HelpCommand extends Command $this ->setName('help') ->setDefinition([ - new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help', function () { - return array_keys((new ApplicationDescription($this->getApplication()))->getCommands()); - }), - new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', function () { - return (new DescriptorHelper())->getFormats(); - }), + new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help', fn () => array_keys((new ApplicationDescription($this->getApplication()))->getCommands())), + new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', fn () => (new DescriptorHelper())->getFormats()), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'), ]) ->setDescription('Display help for a command') @@ -58,6 +57,9 @@ EOF ; } + /** + * @return void + */ public function setCommand(Command $command) { $this->command = $command; diff --git a/vendor/symfony/console/Command/ListCommand.php b/vendor/symfony/console/Command/ListCommand.php index cab88b43..5850c3d7 100644 --- a/vendor/symfony/console/Command/ListCommand.php +++ b/vendor/symfony/console/Command/ListCommand.php @@ -25,18 +25,17 @@ use Symfony\Component\Console\Output\OutputInterface; */ class ListCommand extends Command { + /** + * @return void + */ protected function configure() { $this ->setName('list') ->setDefinition([ - new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name', null, function () { - return array_keys((new ApplicationDescription($this->getApplication()))->getNamespaces()); - }), + new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name', null, fn () => array_keys((new ApplicationDescription($this->getApplication()))->getNamespaces())), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'), - new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', function () { - return (new DescriptorHelper())->getFormats(); - }), + new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', fn () => (new DescriptorHelper())->getFormats()), new InputOption('short', null, InputOption::VALUE_NONE, 'To skip describing commands\' arguments'), ]) ->setDescription('List commands') diff --git a/vendor/symfony/console/Command/LockableTrait.php b/vendor/symfony/console/Command/LockableTrait.php index 67923a9e..c1006a65 100644 --- a/vendor/symfony/console/Command/LockableTrait.php +++ b/vendor/symfony/console/Command/LockableTrait.php @@ -32,7 +32,7 @@ trait LockableTrait private function lock(string $name = null, bool $blocking = false): bool { if (!class_exists(SemaphoreStore::class)) { - throw new LogicException('To enable the locking feature you must install the symfony/lock component.'); + throw new LogicException('To enable the locking feature you must install the symfony/lock component. Try running "composer require symfony/lock".'); } if (null !== $this->lock) { @@ -58,7 +58,7 @@ trait LockableTrait /** * Releases the command lock if there is one. */ - private function release() + private function release(): void { if ($this->lock) { $this->lock->release(); diff --git a/vendor/symfony/console/Command/SignalableCommandInterface.php b/vendor/symfony/console/Command/SignalableCommandInterface.php index d439728b..4d087600 100644 --- a/vendor/symfony/console/Command/SignalableCommandInterface.php +++ b/vendor/symfony/console/Command/SignalableCommandInterface.php @@ -25,6 +25,10 @@ interface SignalableCommandInterface /** * The method will be called when the application is signaled. + * + * @param int|false $previousExitCode + + * @return int|false The exit code to return or false to continue the normal execution */ - public function handleSignal(int $signal): void; + public function handleSignal(int $signal, /* int|false $previousExitCode = 0 */); } diff --git a/vendor/symfony/console/Completion/CompletionInput.php b/vendor/symfony/console/Completion/CompletionInput.php index 3ef8db5d..800b7235 100644 --- a/vendor/symfony/console/Completion/CompletionInput.php +++ b/vendor/symfony/console/Completion/CompletionInput.php @@ -34,7 +34,7 @@ final class CompletionInput extends ArgvInput private $tokens; private $currentIndex; private $completionType; - private $completionName = null; + private $completionName; private $completionValue = ''; /** diff --git a/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php b/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php index 62c80c3b..27705ddb 100644 --- a/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php +++ b/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php @@ -29,6 +29,9 @@ use Symfony\Component\DependencyInjection\TypedReference; */ class AddConsoleCommandPass implements CompilerPassInterface { + /** + * @return void + */ public function process(ContainerBuilder $container) { $commandServices = $container->findTaggedServiceIds('console.command', true); diff --git a/vendor/symfony/console/Descriptor/ApplicationDescription.php b/vendor/symfony/console/Descriptor/ApplicationDescription.php index 2158339e..f8ed1804 100644 --- a/vendor/symfony/console/Descriptor/ApplicationDescription.php +++ b/vendor/symfony/console/Descriptor/ApplicationDescription.php @@ -79,7 +79,7 @@ class ApplicationDescription return $this->commands[$name] ?? $this->aliases[$name]; } - private function inspectApplication() + private function inspectApplication(): void { $this->commands = []; $this->namespaces = []; diff --git a/vendor/symfony/console/Descriptor/Descriptor.php b/vendor/symfony/console/Descriptor/Descriptor.php index 1476f575..7b2509c6 100644 --- a/vendor/symfony/console/Descriptor/Descriptor.php +++ b/vendor/symfony/console/Descriptor/Descriptor.php @@ -26,12 +26,9 @@ use Symfony\Component\Console\Output\OutputInterface; */ abstract class Descriptor implements DescriptorInterface { - /** - * @var OutputInterface - */ - protected $output; + protected OutputInterface $output; - public function describe(OutputInterface $output, object $object, array $options = []) + public function describe(OutputInterface $output, object $object, array $options = []): void { $this->output = $output; @@ -45,10 +42,7 @@ abstract class Descriptor implements DescriptorInterface }; } - /** - * Writes content to output. - */ - protected function write(string $content, bool $decorated = false) + protected function write(string $content, bool $decorated = false): void { $this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW); } @@ -56,25 +50,25 @@ abstract class Descriptor implements DescriptorInterface /** * Describes an InputArgument instance. */ - abstract protected function describeInputArgument(InputArgument $argument, array $options = []); + abstract protected function describeInputArgument(InputArgument $argument, array $options = []): void; /** * Describes an InputOption instance. */ - abstract protected function describeInputOption(InputOption $option, array $options = []); + abstract protected function describeInputOption(InputOption $option, array $options = []): void; /** * Describes an InputDefinition instance. */ - abstract protected function describeInputDefinition(InputDefinition $definition, array $options = []); + abstract protected function describeInputDefinition(InputDefinition $definition, array $options = []): void; /** * Describes a Command instance. */ - abstract protected function describeCommand(Command $command, array $options = []); + abstract protected function describeCommand(Command $command, array $options = []): void; /** * Describes an Application instance. */ - abstract protected function describeApplication(Application $application, array $options = []); + abstract protected function describeApplication(Application $application, array $options = []): void; } diff --git a/vendor/symfony/console/Descriptor/DescriptorInterface.php b/vendor/symfony/console/Descriptor/DescriptorInterface.php index ebea3036..ab468a25 100644 --- a/vendor/symfony/console/Descriptor/DescriptorInterface.php +++ b/vendor/symfony/console/Descriptor/DescriptorInterface.php @@ -20,5 +20,8 @@ use Symfony\Component\Console\Output\OutputInterface; */ interface DescriptorInterface { + /** + * @return void + */ public function describe(OutputInterface $output, object $object, array $options = []); } diff --git a/vendor/symfony/console/Descriptor/JsonDescriptor.php b/vendor/symfony/console/Descriptor/JsonDescriptor.php index 6f79a17a..95630370 100644 --- a/vendor/symfony/console/Descriptor/JsonDescriptor.php +++ b/vendor/symfony/console/Descriptor/JsonDescriptor.php @@ -26,12 +26,12 @@ use Symfony\Component\Console\Input\InputOption; */ class JsonDescriptor extends Descriptor { - protected function describeInputArgument(InputArgument $argument, array $options = []) + protected function describeInputArgument(InputArgument $argument, array $options = []): void { $this->writeData($this->getInputArgumentData($argument), $options); } - protected function describeInputOption(InputOption $option, array $options = []) + protected function describeInputOption(InputOption $option, array $options = []): void { $this->writeData($this->getInputOptionData($option), $options); if ($option->isNegatable()) { @@ -39,17 +39,17 @@ class JsonDescriptor extends Descriptor } } - protected function describeInputDefinition(InputDefinition $definition, array $options = []) + protected function describeInputDefinition(InputDefinition $definition, array $options = []): void { $this->writeData($this->getInputDefinitionData($definition), $options); } - protected function describeCommand(Command $command, array $options = []) + protected function describeCommand(Command $command, array $options = []): void { $this->writeData($this->getCommandData($command, $options['short'] ?? false), $options); } - protected function describeApplication(Application $application, array $options = []) + protected function describeApplication(Application $application, array $options = []): void { $describedNamespace = $options['namespace'] ?? null; $description = new ApplicationDescription($application, $describedNamespace, true); @@ -81,7 +81,7 @@ class JsonDescriptor extends Descriptor /** * Writes data as json. */ - private function writeData(array $data, array $options) + private function writeData(array $data, array $options): void { $flags = $options['json_encoding'] ?? 0; diff --git a/vendor/symfony/console/Descriptor/MarkdownDescriptor.php b/vendor/symfony/console/Descriptor/MarkdownDescriptor.php index fbd9c534..b3f16ee9 100644 --- a/vendor/symfony/console/Descriptor/MarkdownDescriptor.php +++ b/vendor/symfony/console/Descriptor/MarkdownDescriptor.php @@ -28,7 +28,7 @@ use Symfony\Component\Console\Output\OutputInterface; */ class MarkdownDescriptor extends Descriptor { - public function describe(OutputInterface $output, object $object, array $options = []) + public function describe(OutputInterface $output, object $object, array $options = []): void { $decorated = $output->isDecorated(); $output->setDecorated(false); @@ -38,12 +38,12 @@ class MarkdownDescriptor extends Descriptor $output->setDecorated($decorated); } - protected function write(string $content, bool $decorated = true) + protected function write(string $content, bool $decorated = true): void { parent::write($content, $decorated); } - protected function describeInputArgument(InputArgument $argument, array $options = []) + protected function describeInputArgument(InputArgument $argument, array $options = []): void { $this->write( '#### `'.($argument->getName() ?: '')."`\n\n" @@ -54,7 +54,7 @@ class MarkdownDescriptor extends Descriptor ); } - protected function describeInputOption(InputOption $option, array $options = []) + protected function describeInputOption(InputOption $option, array $options = []): void { $name = '--'.$option->getName(); if ($option->isNegatable()) { @@ -75,15 +75,13 @@ class MarkdownDescriptor extends Descriptor ); } - protected function describeInputDefinition(InputDefinition $definition, array $options = []) + protected function describeInputDefinition(InputDefinition $definition, array $options = []): void { if ($showArguments = \count($definition->getArguments()) > 0) { $this->write('### Arguments'); foreach ($definition->getArguments() as $argument) { $this->write("\n\n"); - if (null !== $describeInputArgument = $this->describeInputArgument($argument)) { - $this->write($describeInputArgument); - } + $this->describeInputArgument($argument); } } @@ -95,14 +93,12 @@ class MarkdownDescriptor extends Descriptor $this->write('### Options'); foreach ($definition->getOptions() as $option) { $this->write("\n\n"); - if (null !== $describeInputOption = $this->describeInputOption($option)) { - $this->write($describeInputOption); - } + $this->describeInputOption($option); } } } - protected function describeCommand(Command $command, array $options = []) + protected function describeCommand(Command $command, array $options = []): void { if ($options['short'] ?? false) { $this->write( @@ -110,9 +106,7 @@ class MarkdownDescriptor extends Descriptor .str_repeat('-', Helper::width($command->getName()) + 2)."\n\n" .($command->getDescription() ? $command->getDescription()."\n\n" : '') .'### Usage'."\n\n" - .array_reduce($command->getAliases(), function ($carry, $usage) { - return $carry.'* `'.$usage.'`'."\n"; - }) + .array_reduce($command->getAliases(), fn ($carry, $usage) => $carry.'* `'.$usage.'`'."\n") ); return; @@ -125,9 +119,7 @@ class MarkdownDescriptor extends Descriptor .str_repeat('-', Helper::width($command->getName()) + 2)."\n\n" .($command->getDescription() ? $command->getDescription()."\n\n" : '') .'### Usage'."\n\n" - .array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), function ($carry, $usage) { - return $carry.'* `'.$usage.'`'."\n"; - }) + .array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), fn ($carry, $usage) => $carry.'* `'.$usage.'`'."\n") ); if ($help = $command->getProcessedHelp()) { @@ -142,7 +134,7 @@ class MarkdownDescriptor extends Descriptor } } - protected function describeApplication(Application $application, array $options = []) + protected function describeApplication(Application $application, array $options = []): void { $describedNamespace = $options['namespace'] ?? null; $description = new ApplicationDescription($application, $describedNamespace); @@ -157,16 +149,12 @@ class MarkdownDescriptor extends Descriptor } $this->write("\n\n"); - $this->write(implode("\n", array_map(function ($commandName) use ($description) { - return sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName())); - }, $namespace['commands']))); + $this->write(implode("\n", array_map(fn ($commandName) => sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName())), $namespace['commands']))); } foreach ($description->getCommands() as $command) { $this->write("\n\n"); - if (null !== $describeCommand = $this->describeCommand($command, $options)) { - $this->write($describeCommand); - } + $this->describeCommand($command, $options); } } diff --git a/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php b/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php new file mode 100644 index 00000000..d4423fd3 --- /dev/null +++ b/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php @@ -0,0 +1,272 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Descriptor; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\Helper; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\String\UnicodeString; + +class ReStructuredTextDescriptor extends Descriptor +{ + //

+ private string $partChar = '='; + //

+ private string $chapterChar = '-'; + //

+ private string $sectionChar = '~'; + //

+ private string $subsectionChar = '.'; + //

+ private string $subsubsectionChar = '^'; + //
+ private string $paragraphsChar = '"'; + + private array $visibleNamespaces = []; + + public function describe(OutputInterface $output, object $object, array $options = []): void + { + $decorated = $output->isDecorated(); + $output->setDecorated(false); + + parent::describe($output, $object, $options); + + $output->setDecorated($decorated); + } + + /** + * Override parent method to set $decorated = true. + */ + protected function write(string $content, bool $decorated = true): void + { + parent::write($content, $decorated); + } + + protected function describeInputArgument(InputArgument $argument, array $options = []): void + { + $this->write( + $argument->getName() ?: ''."\n".str_repeat($this->paragraphsChar, Helper::width($argument->getName()))."\n\n" + .($argument->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $argument->getDescription())."\n\n" : '') + .'- **Is required**: '.($argument->isRequired() ? 'yes' : 'no')."\n" + .'- **Is array**: '.($argument->isArray() ? 'yes' : 'no')."\n" + .'- **Default**: ``'.str_replace("\n", '', var_export($argument->getDefault(), true)).'``' + ); + } + + protected function describeInputOption(InputOption $option, array $options = []): void + { + $name = '\-\-'.$option->getName(); + if ($option->isNegatable()) { + $name .= '|\-\-no-'.$option->getName(); + } + if ($option->getShortcut()) { + $name .= '|-'.str_replace('|', '|-', $option->getShortcut()); + } + + $optionDescription = $option->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n\n", $option->getDescription())."\n\n" : ''; + $optionDescription = (new UnicodeString($optionDescription))->ascii(); + $this->write( + $name."\n".str_repeat($this->paragraphsChar, Helper::width($name))."\n\n" + .$optionDescription + .'- **Accept value**: '.($option->acceptValue() ? 'yes' : 'no')."\n" + .'- **Is value required**: '.($option->isValueRequired() ? 'yes' : 'no')."\n" + .'- **Is multiple**: '.($option->isArray() ? 'yes' : 'no')."\n" + .'- **Is negatable**: '.($option->isNegatable() ? 'yes' : 'no')."\n" + .'- **Default**: ``'.str_replace("\n", '', var_export($option->getDefault(), true)).'``'."\n" + ); + } + + protected function describeInputDefinition(InputDefinition $definition, array $options = []): void + { + if ($showArguments = ((bool) $definition->getArguments())) { + $this->write("Arguments\n".str_repeat($this->subsubsectionChar, 9))."\n\n"; + foreach ($definition->getArguments() as $argument) { + $this->write("\n\n"); + $this->describeInputArgument($argument); + } + } + + if ($nonDefaultOptions = $this->getNonDefaultOptions($definition)) { + if ($showArguments) { + $this->write("\n\n"); + } + + $this->write("Options\n".str_repeat($this->subsubsectionChar, 7)."\n\n"); + foreach ($nonDefaultOptions as $option) { + $this->describeInputOption($option); + $this->write("\n"); + } + } + } + + protected function describeCommand(Command $command, array $options = []): void + { + if ($options['short'] ?? false) { + $this->write( + '``'.$command->getName()."``\n" + .str_repeat($this->subsectionChar, Helper::width($command->getName()))."\n\n" + .($command->getDescription() ? $command->getDescription()."\n\n" : '') + ."Usage\n".str_repeat($this->paragraphsChar, 5)."\n\n" + .array_reduce($command->getAliases(), static fn ($carry, $usage) => $carry.'- ``'.$usage.'``'."\n") + ); + + return; + } + + $command->mergeApplicationDefinition(false); + + foreach ($command->getAliases() as $alias) { + $this->write('.. _'.$alias.":\n\n"); + } + $this->write( + $command->getName()."\n" + .str_repeat($this->subsectionChar, Helper::width($command->getName()))."\n\n" + .($command->getDescription() ? $command->getDescription()."\n\n" : '') + ."Usage\n".str_repeat($this->subsubsectionChar, 5)."\n\n" + .array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), static fn ($carry, $usage) => $carry.'- ``'.$usage.'``'."\n") + ); + + if ($help = $command->getProcessedHelp()) { + $this->write("\n"); + $this->write($help); + } + + $definition = $command->getDefinition(); + if ($definition->getOptions() || $definition->getArguments()) { + $this->write("\n\n"); + $this->describeInputDefinition($definition); + } + } + + protected function describeApplication(Application $application, array $options = []): void + { + $description = new ApplicationDescription($application, $options['namespace'] ?? null); + $title = $this->getApplicationTitle($application); + + $this->write($title."\n".str_repeat($this->partChar, Helper::width($title))); + $this->createTableOfContents($description, $application); + $this->describeCommands($application, $options); + } + + private function getApplicationTitle(Application $application): string + { + if ('UNKNOWN' === $application->getName()) { + return 'Console Tool'; + } + if ('UNKNOWN' !== $application->getVersion()) { + return sprintf('%s %s', $application->getName(), $application->getVersion()); + } + + return $application->getName(); + } + + private function describeCommands($application, array $options): void + { + $title = 'Commands'; + $this->write("\n\n$title\n".str_repeat($this->chapterChar, Helper::width($title))."\n\n"); + foreach ($this->visibleNamespaces as $namespace) { + if ('_global' === $namespace) { + $commands = $application->all(''); + $this->write('Global'."\n".str_repeat($this->sectionChar, Helper::width('Global'))."\n\n"); + } else { + $commands = $application->all($namespace); + $this->write($namespace."\n".str_repeat($this->sectionChar, Helper::width($namespace))."\n\n"); + } + + foreach ($this->removeAliasesAndHiddenCommands($commands) as $command) { + $this->describeCommand($command, $options); + $this->write("\n\n"); + } + } + } + + private function createTableOfContents(ApplicationDescription $description, Application $application): void + { + $this->setVisibleNamespaces($description); + $chapterTitle = 'Table of Contents'; + $this->write("\n\n$chapterTitle\n".str_repeat($this->chapterChar, Helper::width($chapterTitle))."\n\n"); + foreach ($this->visibleNamespaces as $namespace) { + if ('_global' === $namespace) { + $commands = $application->all(''); + } else { + $commands = $application->all($namespace); + $this->write("\n\n"); + $this->write($namespace."\n".str_repeat($this->sectionChar, Helper::width($namespace))."\n\n"); + } + $commands = $this->removeAliasesAndHiddenCommands($commands); + + $this->write("\n\n"); + $this->write(implode("\n", array_map(static fn ($commandName) => sprintf('- `%s`_', $commandName), array_keys($commands)))); + } + } + + private function getNonDefaultOptions(InputDefinition $definition): array + { + $globalOptions = [ + 'help', + 'quiet', + 'verbose', + 'version', + 'ansi', + 'no-interaction', + ]; + $nonDefaultOptions = []; + foreach ($definition->getOptions() as $option) { + // Skip global options. + if (!\in_array($option->getName(), $globalOptions)) { + $nonDefaultOptions[] = $option; + } + } + + return $nonDefaultOptions; + } + + private function setVisibleNamespaces(ApplicationDescription $description): void + { + $commands = $description->getCommands(); + foreach ($description->getNamespaces() as $namespace) { + try { + $namespaceCommands = $namespace['commands']; + foreach ($namespaceCommands as $key => $commandName) { + if (!\array_key_exists($commandName, $commands)) { + // If the array key does not exist, then this is an alias. + unset($namespaceCommands[$key]); + } elseif ($commands[$commandName]->isHidden()) { + unset($namespaceCommands[$key]); + } + } + if (!$namespaceCommands) { + // If the namespace contained only aliases or hidden commands, skip the namespace. + continue; + } + } catch (\Exception) { + } + $this->visibleNamespaces[] = $namespace['id']; + } + } + + private function removeAliasesAndHiddenCommands(array $commands): array + { + foreach ($commands as $key => $command) { + if ($command->isHidden() || \in_array($key, $command->getAliases(), true)) { + unset($commands[$key]); + } + } + unset($commands['completion']); + + return $commands; + } +} diff --git a/vendor/symfony/console/Descriptor/TextDescriptor.php b/vendor/symfony/console/Descriptor/TextDescriptor.php index 48a0b42a..d04d1023 100644 --- a/vendor/symfony/console/Descriptor/TextDescriptor.php +++ b/vendor/symfony/console/Descriptor/TextDescriptor.php @@ -28,7 +28,7 @@ use Symfony\Component\Console\Input\InputOption; */ class TextDescriptor extends Descriptor { - protected function describeInputArgument(InputArgument $argument, array $options = []) + protected function describeInputArgument(InputArgument $argument, array $options = []): void { if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) { $default = sprintf(' [default: %s]', $this->formatDefaultValue($argument->getDefault())); @@ -48,7 +48,7 @@ class TextDescriptor extends Descriptor ), $options); } - protected function describeInputOption(InputOption $option, array $options = []) + protected function describeInputOption(InputOption $option, array $options = []): void { if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) { $default = sprintf(' [default: %s]', $this->formatDefaultValue($option->getDefault())); @@ -83,7 +83,7 @@ class TextDescriptor extends Descriptor ), $options); } - protected function describeInputDefinition(InputDefinition $definition, array $options = []) + protected function describeInputDefinition(InputDefinition $definition, array $options = []): void { $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions()); foreach ($definition->getArguments() as $argument) { @@ -122,7 +122,7 @@ class TextDescriptor extends Descriptor } } - protected function describeCommand(Command $command, array $options = []) + protected function describeCommand(Command $command, array $options = []): void { $command->mergeApplicationDefinition(false); @@ -157,7 +157,7 @@ class TextDescriptor extends Descriptor } } - protected function describeApplication(Application $application, array $options = []) + protected function describeApplication(Application $application, array $options = []): void { $describedNamespace = $options['namespace'] ?? null; $description = new ApplicationDescription($application, $describedNamespace); @@ -193,9 +193,7 @@ class TextDescriptor extends Descriptor } // calculate max. width based on available commands per namespace - $width = $this->getColumnWidth(array_merge(...array_values(array_map(function ($namespace) use ($commands) { - return array_intersect($namespace['commands'], array_keys($commands)); - }, array_values($namespaces))))); + $width = $this->getColumnWidth(array_merge(...array_values(array_map(fn ($namespace) => array_intersect($namespace['commands'], array_keys($commands)), array_values($namespaces))))); if ($describedNamespace) { $this->writeText(sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options); @@ -204,9 +202,7 @@ class TextDescriptor extends Descriptor } foreach ($namespaces as $namespace) { - $namespace['commands'] = array_filter($namespace['commands'], function ($name) use ($commands) { - return isset($commands[$name]); - }); + $namespace['commands'] = array_filter($namespace['commands'], fn ($name) => isset($commands[$name])); if (!$namespace['commands']) { continue; @@ -230,7 +226,7 @@ class TextDescriptor extends Descriptor } } - private function writeText(string $content, array $options = []) + private function writeText(string $content, array $options = []): void { $this->write( isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content, diff --git a/vendor/symfony/console/Descriptor/XmlDescriptor.php b/vendor/symfony/console/Descriptor/XmlDescriptor.php index f4643a9a..72580fd9 100644 --- a/vendor/symfony/console/Descriptor/XmlDescriptor.php +++ b/vendor/symfony/console/Descriptor/XmlDescriptor.php @@ -120,27 +120,27 @@ class XmlDescriptor extends Descriptor return $dom; } - protected function describeInputArgument(InputArgument $argument, array $options = []) + protected function describeInputArgument(InputArgument $argument, array $options = []): void { $this->writeDocument($this->getInputArgumentDocument($argument)); } - protected function describeInputOption(InputOption $option, array $options = []) + protected function describeInputOption(InputOption $option, array $options = []): void { $this->writeDocument($this->getInputOptionDocument($option)); } - protected function describeInputDefinition(InputDefinition $definition, array $options = []) + protected function describeInputDefinition(InputDefinition $definition, array $options = []): void { $this->writeDocument($this->getInputDefinitionDocument($definition)); } - protected function describeCommand(Command $command, array $options = []) + protected function describeCommand(Command $command, array $options = []): void { $this->writeDocument($this->getCommandDocument($command, $options['short'] ?? false)); } - protected function describeApplication(Application $application, array $options = []) + protected function describeApplication(Application $application, array $options = []): void { $this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null, $options['short'] ?? false)); } @@ -148,7 +148,7 @@ class XmlDescriptor extends Descriptor /** * Appends document children to parent node. */ - private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent) + private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent): void { foreach ($importedParent->childNodes as $childNode) { $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, true)); @@ -158,7 +158,7 @@ class XmlDescriptor extends Descriptor /** * Writes DOM document. */ - private function writeDocument(\DOMDocument $dom) + private function writeDocument(\DOMDocument $dom): void { $dom->formatOutput = true; $this->write($dom->saveXML()); diff --git a/vendor/symfony/console/Event/ConsoleSignalEvent.php b/vendor/symfony/console/Event/ConsoleSignalEvent.php index 766af691..95af1f91 100644 --- a/vendor/symfony/console/Event/ConsoleSignalEvent.php +++ b/vendor/symfony/console/Event/ConsoleSignalEvent.php @@ -21,15 +21,36 @@ use Symfony\Component\Console\Output\OutputInterface; final class ConsoleSignalEvent extends ConsoleEvent { private int $handlingSignal; + private int|false $exitCode; - public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $handlingSignal) + public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $handlingSignal, int|false $exitCode = 0) { parent::__construct($command, $input, $output); $this->handlingSignal = $handlingSignal; + $this->exitCode = $exitCode; } public function getHandlingSignal(): int { return $this->handlingSignal; } + + public function setExitCode(int $exitCode): void + { + if ($exitCode < 0 || $exitCode > 255) { + throw new \InvalidArgumentException('Exit code must be between 0 and 255.'); + } + + $this->exitCode = $exitCode; + } + + public function abortExit(): void + { + $this->exitCode = false; + } + + public function getExitCode(): int|false + { + return $this->exitCode; + } } diff --git a/vendor/symfony/console/EventListener/ErrorListener.php b/vendor/symfony/console/EventListener/ErrorListener.php index 773a13a1..9925a5f7 100644 --- a/vendor/symfony/console/EventListener/ErrorListener.php +++ b/vendor/symfony/console/EventListener/ErrorListener.php @@ -31,6 +31,9 @@ class ErrorListener implements EventSubscriberInterface $this->logger = $logger; } + /** + * @return void + */ public function onConsoleError(ConsoleErrorEvent $event) { if (null === $this->logger) { @@ -48,6 +51,9 @@ class ErrorListener implements EventSubscriberInterface $this->logger->critical('Error thrown while running command "{command}". Message: "{message}"', ['exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()]); } + /** + * @return void + */ public function onConsoleTerminate(ConsoleTerminateEvent $event) { if (null === $this->logger) { diff --git a/vendor/symfony/console/Formatter/OutputFormatter.php b/vendor/symfony/console/Formatter/OutputFormatter.php index 38e75c31..9cb63104 100644 --- a/vendor/symfony/console/Formatter/OutputFormatter.php +++ b/vendor/symfony/console/Formatter/OutputFormatter.php @@ -81,6 +81,9 @@ class OutputFormatter implements WrappableOutputFormatterInterface $this->styleStack = new OutputFormatterStyleStack(); } + /** + * @return void + */ public function setDecorated(bool $decorated) { $this->decorated = $decorated; @@ -91,6 +94,9 @@ class OutputFormatter implements WrappableOutputFormatterInterface return $this->decorated; } + /** + * @return void + */ public function setStyle(string $name, OutputFormatterStyleInterface $style) { $this->styles[strtolower($name)] = $style; @@ -115,6 +121,9 @@ class OutputFormatter implements WrappableOutputFormatterInterface return $this->formatAndWrap($message, 0); } + /** + * @return string + */ public function formatAndWrap(?string $message, int $width) { if (null === $message) { diff --git a/vendor/symfony/console/Formatter/OutputFormatterInterface.php b/vendor/symfony/console/Formatter/OutputFormatterInterface.php index b94e51de..433cd419 100644 --- a/vendor/symfony/console/Formatter/OutputFormatterInterface.php +++ b/vendor/symfony/console/Formatter/OutputFormatterInterface.php @@ -20,6 +20,8 @@ interface OutputFormatterInterface { /** * Sets the decorated flag. + * + * @return void */ public function setDecorated(bool $decorated); @@ -30,6 +32,8 @@ interface OutputFormatterInterface /** * Sets a new style. + * + * @return void */ public function setStyle(string $name, OutputFormatterStyleInterface $style); diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyle.php b/vendor/symfony/console/Formatter/OutputFormatterStyle.php index 3394c9ad..346a474c 100644 --- a/vendor/symfony/console/Formatter/OutputFormatterStyle.php +++ b/vendor/symfony/console/Formatter/OutputFormatterStyle.php @@ -38,6 +38,9 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface $this->color = new Color($this->foreground = $foreground ?: '', $this->background = $background ?: '', $this->options = $options); } + /** + * @return void + */ public function setForeground(string $color = null) { if (1 > \func_num_args()) { @@ -46,6 +49,9 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface $this->color = new Color($this->foreground = $color ?: '', $this->background, $this->options); } + /** + * @return void + */ public function setBackground(string $color = null) { if (1 > \func_num_args()) { @@ -59,12 +65,18 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface $this->href = $url; } + /** + * @return void + */ public function setOption(string $option) { $this->options[] = $option; $this->color = new Color($this->foreground, $this->background, $this->options); } + /** + * @return void + */ public function unsetOption(string $option) { $pos = array_search($option, $this->options); @@ -75,6 +87,9 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface $this->color = new Color($this->foreground, $this->background, $this->options); } + /** + * @return void + */ public function setOptions(array $options) { $this->color = new Color($this->foreground, $this->background, $this->options = $options); diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php b/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php index 7ed67d9a..3b15098c 100644 --- a/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php +++ b/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php @@ -20,26 +20,36 @@ interface OutputFormatterStyleInterface { /** * Sets style foreground color. + * + * @return void */ public function setForeground(?string $color); /** * Sets style background color. + * + * @return void */ public function setBackground(?string $color); /** * Sets some specific style option. + * + * @return void */ public function setOption(string $option); /** * Unsets some specific style option. + * + * @return void */ public function unsetOption(string $option); /** * Sets multiple style options at once. + * + * @return void */ public function setOptions(array $options); diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php b/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php index 2c5cdf9b..f98c2eff 100644 --- a/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php +++ b/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php @@ -34,6 +34,8 @@ class OutputFormatterStyleStack implements ResetInterface /** * Resets stack (ie. empty internal arrays). + * + * @return void */ public function reset() { @@ -42,6 +44,8 @@ class OutputFormatterStyleStack implements ResetInterface /** * Pushes a style in the stack. + * + * @return void */ public function push(OutputFormatterStyleInterface $style) { diff --git a/vendor/symfony/console/Helper/DescriptorHelper.php b/vendor/symfony/console/Helper/DescriptorHelper.php index 3015ff08..eb32bce8 100644 --- a/vendor/symfony/console/Helper/DescriptorHelper.php +++ b/vendor/symfony/console/Helper/DescriptorHelper.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Descriptor\DescriptorInterface; use Symfony\Component\Console\Descriptor\JsonDescriptor; use Symfony\Component\Console\Descriptor\MarkdownDescriptor; +use Symfony\Component\Console\Descriptor\ReStructuredTextDescriptor; use Symfony\Component\Console\Descriptor\TextDescriptor; use Symfony\Component\Console\Descriptor\XmlDescriptor; use Symfony\Component\Console\Exception\InvalidArgumentException; @@ -38,6 +39,7 @@ class DescriptorHelper extends Helper ->register('xml', new XmlDescriptor()) ->register('json', new JsonDescriptor()) ->register('md', new MarkdownDescriptor()) + ->register('rst', new ReStructuredTextDescriptor()) ; } @@ -48,6 +50,8 @@ class DescriptorHelper extends Helper * * format: string, the output format name * * raw_text: boolean, sets output type as raw * + * @return void + * * @throws InvalidArgumentException when the given format is not supported */ public function describe(OutputInterface $output, ?object $object, array $options = []) diff --git a/vendor/symfony/console/Helper/Dumper.php b/vendor/symfony/console/Helper/Dumper.php index ac7571ce..8c6a94d5 100644 --- a/vendor/symfony/console/Helper/Dumper.php +++ b/vendor/symfony/console/Helper/Dumper.php @@ -40,14 +40,12 @@ final class Dumper return rtrim($dumper->dump(($this->cloner ??= new VarCloner())->cloneVar($var)->withRefHandles(false), true)); }; } else { - $this->handler = function ($var): string { - return match (true) { - null === $var => 'null', - true === $var => 'true', - false === $var => 'false', - \is_string($var) => '"'.$var.'"', - default => rtrim(print_r($var, true)), - }; + $this->handler = fn ($var): string => match (true) { + null === $var => 'null', + true === $var => 'true', + false === $var => 'false', + \is_string($var) => '"'.$var.'"', + default => rtrim(print_r($var, true)), }; } } diff --git a/vendor/symfony/console/Helper/Helper.php b/vendor/symfony/console/Helper/Helper.php index 920196e0..3631b30f 100644 --- a/vendor/symfony/console/Helper/Helper.php +++ b/vendor/symfony/console/Helper/Helper.php @@ -21,8 +21,11 @@ use Symfony\Component\String\UnicodeString; */ abstract class Helper implements HelperInterface { - protected $helperSet = null; + protected $helperSet; + /** + * @return void + */ public function setHelperSet(HelperSet $helperSet = null) { if (1 > \func_num_args()) { @@ -88,6 +91,9 @@ abstract class Helper implements HelperInterface return mb_substr($string, $from, $length, $encoding); } + /** + * @return string + */ public static function formatTime(int|float $secs) { static $timeFormats = [ @@ -117,6 +123,9 @@ abstract class Helper implements HelperInterface } } + /** + * @return string + */ public static function formatMemory(int $memory) { if ($memory >= 1024 * 1024 * 1024) { @@ -134,6 +143,9 @@ abstract class Helper implements HelperInterface return sprintf('%d B', $memory); } + /** + * @return string + */ public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string) { $isDecorated = $formatter->isDecorated(); diff --git a/vendor/symfony/console/Helper/HelperInterface.php b/vendor/symfony/console/Helper/HelperInterface.php index 2762cdf0..ab626c93 100644 --- a/vendor/symfony/console/Helper/HelperInterface.php +++ b/vendor/symfony/console/Helper/HelperInterface.php @@ -20,6 +20,8 @@ interface HelperInterface { /** * Sets the helper set associated with this helper. + * + * @return void */ public function setHelperSet(?HelperSet $helperSet); diff --git a/vendor/symfony/console/Helper/HelperSet.php b/vendor/symfony/console/Helper/HelperSet.php index cefe62be..dc5d499c 100644 --- a/vendor/symfony/console/Helper/HelperSet.php +++ b/vendor/symfony/console/Helper/HelperSet.php @@ -35,6 +35,9 @@ class HelperSet implements \IteratorAggregate } } + /** + * @return void + */ public function set(HelperInterface $helper, string $alias = null) { $this->helpers[$helper->getName()] = $helper; diff --git a/vendor/symfony/console/Helper/InputAwareHelper.php b/vendor/symfony/console/Helper/InputAwareHelper.php index ba81e377..6f822597 100644 --- a/vendor/symfony/console/Helper/InputAwareHelper.php +++ b/vendor/symfony/console/Helper/InputAwareHelper.php @@ -23,6 +23,9 @@ abstract class InputAwareHelper extends Helper implements InputAwareInterface { protected $input; + /** + * @return void + */ public function setInput(InputInterface $input) { $this->input = $input; diff --git a/vendor/symfony/console/Helper/ProgressBar.php b/vendor/symfony/console/Helper/ProgressBar.php index 0d112609..19faea47 100644 --- a/vendor/symfony/console/Helper/ProgressBar.php +++ b/vendor/symfony/console/Helper/ProgressBar.php @@ -59,6 +59,7 @@ final class ProgressBar private Terminal $terminal; private ?string $previousMessage = null; private Cursor $cursor; + private array $placeholders = []; private static array $formatters; private static array $formats; @@ -94,12 +95,12 @@ final class ProgressBar } /** - * Sets a placeholder formatter for a given name. + * Sets a placeholder formatter for a given name, globally for all instances of ProgressBar. * * This method also allow you to override an existing placeholder. * - * @param string $name The placeholder name (including the delimiter char like %) - * @param callable $callable A PHP callable + * @param string $name The placeholder name (including the delimiter char like %) + * @param callable(ProgressBar):string $callable A PHP callable */ public static function setPlaceholderFormatterDefinition(string $name, callable $callable): void { @@ -120,6 +121,26 @@ final class ProgressBar return self::$formatters[$name] ?? null; } + /** + * Sets a placeholder formatter for a given name, for this instance only. + * + * @param callable(ProgressBar):string $callable A PHP callable + */ + public function setPlaceholderFormatter(string $name, callable $callable): void + { + $this->placeholders[$name] = $callable; + } + + /** + * Gets the placeholder formatter for a given name. + * + * @param string $name The placeholder name (including the delimiter char like %) + */ + public function getPlaceholderFormatter(string $name): ?callable + { + return $this->placeholders[$name] ?? $this::getPlaceholderFormatterDefinition($name); + } + /** * Sets a format for a given name. * @@ -157,12 +178,12 @@ final class ProgressBar * @param string $message The text to associate with the placeholder * @param string $name The name of the placeholder */ - public function setMessage(string $message, string $name = 'message') + public function setMessage(string $message, string $name = 'message'): void { $this->messages[$name] = $message; } - public function getMessage(string $name = 'message') + public function getMessage(string $name = 'message'): string { return $this->messages[$name]; } @@ -215,7 +236,7 @@ final class ProgressBar return round((time() - $this->startTime) / ($this->step - $this->startingStep) * ($this->max - $this->step)); } - public function setBarWidth(int $size) + public function setBarWidth(int $size): void { $this->barWidth = max(1, $size); } @@ -225,7 +246,7 @@ final class ProgressBar return $this->barWidth; } - public function setBarCharacter(string $char) + public function setBarCharacter(string $char): void { $this->barChar = $char; } @@ -235,7 +256,7 @@ final class ProgressBar return $this->barChar ?? ($this->max ? '=' : $this->emptyBarChar); } - public function setEmptyBarCharacter(string $char) + public function setEmptyBarCharacter(string $char): void { $this->emptyBarChar = $char; } @@ -245,7 +266,7 @@ final class ProgressBar return $this->emptyBarChar; } - public function setProgressCharacter(string $char) + public function setProgressCharacter(string $char): void { $this->progressChar = $char; } @@ -255,7 +276,7 @@ final class ProgressBar return $this->progressChar; } - public function setFormat(string $format) + public function setFormat(string $format): void { $this->format = null; $this->internalFormat = $format; @@ -266,7 +287,7 @@ final class ProgressBar * * @param int|null $freq The frequency in steps */ - public function setRedrawFrequency(?int $freq) + public function setRedrawFrequency(?int $freq): void { $this->redrawFreq = null !== $freq ? max(1, $freq) : null; } @@ -325,7 +346,7 @@ final class ProgressBar * * @param int $step Number of steps to advance */ - public function advance(int $step = 1) + public function advance(int $step = 1): void { $this->setProgress($this->step + $step); } @@ -333,12 +354,12 @@ final class ProgressBar /** * Sets whether to overwrite the progressbar, false for new line. */ - public function setOverwrite(bool $overwrite) + public function setOverwrite(bool $overwrite): void { $this->overwrite = $overwrite; } - public function setProgress(int $step) + public function setProgress(int $step): void { if ($this->max && $step > $this->max) { $this->max = $step; @@ -371,7 +392,7 @@ final class ProgressBar } } - public function setMaxSteps(int $max) + public function setMaxSteps(int $max): void { $this->format = null; $this->max = max(0, $max); @@ -431,7 +452,7 @@ final class ProgressBar $this->overwrite(''); } - private function setRealFormat(string $format) + private function setRealFormat(string $format): void { // try to use the _nomax variant if available if (!$this->max && null !== self::getFormatDefinition($format.'_nomax')) { @@ -513,9 +534,7 @@ final class ProgressBar return $display; }, - 'elapsed' => function (self $bar) { - return Helper::formatTime(time() - $bar->getStartTime()); - }, + 'elapsed' => fn (self $bar) => Helper::formatTime(time() - $bar->getStartTime()), 'remaining' => function (self $bar) { if (!$bar->getMaxSteps()) { throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.'); @@ -530,18 +549,10 @@ final class ProgressBar return Helper::formatTime($bar->getEstimated()); }, - 'memory' => function (self $bar) { - return Helper::formatMemory(memory_get_usage(true)); - }, - 'current' => function (self $bar) { - return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT); - }, - 'max' => function (self $bar) { - return $bar->getMaxSteps(); - }, - 'percent' => function (self $bar) { - return floor($bar->getProgressPercent() * 100); - }, + 'memory' => fn (self $bar) => Helper::formatMemory(memory_get_usage(true)), + 'current' => fn (self $bar) => str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT), + 'max' => fn (self $bar) => $bar->getMaxSteps(), + 'percent' => fn (self $bar) => floor($bar->getProgressPercent() * 100), ]; } @@ -568,7 +579,7 @@ final class ProgressBar $regex = "{%([a-z\-_]+)(?:\:([^%]+))?%}i"; $callback = function ($matches) { - if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) { + if ($formatter = $this->getPlaceholderFormatter($matches[1])) { $text = $formatter($this, $this->output); } elseif (isset($this->messages[$matches[1]])) { $text = $this->messages[$matches[1]]; @@ -585,9 +596,7 @@ final class ProgressBar $line = preg_replace_callback($regex, $callback, $this->format); // gets string length for each sub line with multiline format - $linesLength = array_map(function ($subLine) { - return Helper::width(Helper::removeDecoration($this->output->getFormatter(), rtrim($subLine, "\r"))); - }, explode("\n", $line)); + $linesLength = array_map(fn ($subLine) => Helper::width(Helper::removeDecoration($this->output->getFormatter(), rtrim($subLine, "\r"))), explode("\n", $line)); $linesWidth = max($linesLength); diff --git a/vendor/symfony/console/Helper/ProgressIndicator.php b/vendor/symfony/console/Helper/ProgressIndicator.php index b5fa24c4..84dbef95 100644 --- a/vendor/symfony/console/Helper/ProgressIndicator.php +++ b/vendor/symfony/console/Helper/ProgressIndicator.php @@ -70,6 +70,8 @@ class ProgressIndicator /** * Sets the current indicator message. + * + * @return void */ public function setMessage(?string $message) { @@ -80,6 +82,8 @@ class ProgressIndicator /** * Starts the indicator output. + * + * @return void */ public function start(string $message) { @@ -98,6 +102,8 @@ class ProgressIndicator /** * Advances the indicator. + * + * @return void */ public function advance() { @@ -123,6 +129,8 @@ class ProgressIndicator /** * Finish the indicator with message. + * + * @return void */ public function finish(string $message) { @@ -148,6 +156,8 @@ class ProgressIndicator * Sets a placeholder formatter for a given name. * * This method also allow you to override an existing placeholder. + * + * @return void */ public static function setPlaceholderFormatterDefinition(string $name, callable $callable) { @@ -166,7 +176,7 @@ class ProgressIndicator return self::$formatters[$name] ?? null; } - private function display() + private function display(): void { if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) { return; @@ -195,7 +205,7 @@ class ProgressIndicator /** * Overwrites a previous message to the output. */ - private function overwrite(string $message) + private function overwrite(string $message): void { if ($this->output->isDecorated()) { $this->output->write("\x0D\x1B[2K"); @@ -216,18 +226,10 @@ class ProgressIndicator private static function initPlaceholderFormatters(): array { return [ - 'indicator' => function (self $indicator) { - return $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)]; - }, - 'message' => function (self $indicator) { - return $indicator->message; - }, - 'elapsed' => function (self $indicator) { - return Helper::formatTime(time() - $indicator->startTime); - }, - 'memory' => function () { - return Helper::formatMemory(memory_get_usage(true)); - }, + 'indicator' => fn (self $indicator) => $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)], + 'message' => fn (self $indicator) => $indicator->message, + 'elapsed' => fn (self $indicator) => Helper::formatTime(time() - $indicator->startTime), + 'memory' => fn () => Helper::formatMemory(memory_get_usage(true)), ]; } } diff --git a/vendor/symfony/console/Helper/QuestionHelper.php b/vendor/symfony/console/Helper/QuestionHelper.php index f26ca577..f32813c6 100644 --- a/vendor/symfony/console/Helper/QuestionHelper.php +++ b/vendor/symfony/console/Helper/QuestionHelper.php @@ -68,9 +68,7 @@ class QuestionHelper extends Helper return $this->doAsk($output, $question); } - $interviewer = function () use ($output, $question) { - return $this->doAsk($output, $question); - }; + $interviewer = fn () => $this->doAsk($output, $question); return $this->validateAttempts($interviewer, $output, $question); } catch (MissingInputException $exception) { @@ -91,6 +89,8 @@ class QuestionHelper extends Helper /** * Prevents usage of stty. + * + * @return void */ public static function disableStty() { @@ -170,7 +170,7 @@ class QuestionHelper extends Helper } if ($validator = $question->getValidator()) { - return \call_user_func($question->getValidator(), $default); + return \call_user_func($validator, $default); } elseif ($question instanceof ChoiceQuestion) { $choices = $question->getChoices(); @@ -190,6 +190,8 @@ class QuestionHelper extends Helper /** * Outputs the question prompt. + * + * @return void */ protected function writePrompt(OutputInterface $output, Question $question) { @@ -226,6 +228,8 @@ class QuestionHelper extends Helper /** * Outputs an error message. + * + * @return void */ protected function writeError(OutputInterface $output, \Exception $error) { @@ -325,9 +329,7 @@ class QuestionHelper extends Helper $matches = array_filter( $autocomplete($ret), - function ($match) use ($ret) { - return '' === $ret || str_starts_with($match, $ret); - } + fn ($match) => '' === $ret || str_starts_with($match, $ret) ); $numMatches = \count($matches); $ofs = -1; diff --git a/vendor/symfony/console/Helper/SymfonyQuestionHelper.php b/vendor/symfony/console/Helper/SymfonyQuestionHelper.php index 109045d0..8ebc8437 100644 --- a/vendor/symfony/console/Helper/SymfonyQuestionHelper.php +++ b/vendor/symfony/console/Helper/SymfonyQuestionHelper.php @@ -25,6 +25,9 @@ use Symfony\Component\Console\Style\SymfonyStyle; */ class SymfonyQuestionHelper extends QuestionHelper { + /** + * @return void + */ protected function writePrompt(OutputInterface $output, Question $question) { $text = OutputFormatter::escapeTrailingBackslash($question->getQuestion()); @@ -80,6 +83,9 @@ class SymfonyQuestionHelper extends QuestionHelper $output->write($prompt); } + /** + * @return void + */ protected function writeError(OutputInterface $output, \Exception $error) { if ($output instanceof SymfonyStyle) { diff --git a/vendor/symfony/console/Helper/Table.php b/vendor/symfony/console/Helper/Table.php index 907c9f50..cf714873 100644 --- a/vendor/symfony/console/Helper/Table.php +++ b/vendor/symfony/console/Helper/Table.php @@ -66,6 +66,8 @@ class Table /** * Sets a style definition. + * + * @return void */ public static function setStyleDefinition(string $name, TableStyle $style) { @@ -310,6 +312,8 @@ class Table * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | * +---------------+-----------------------+------------------+ + * + * @return void */ public function render() { @@ -450,7 +454,7 @@ class Table * * +-----+-----------+-------+ */ - private function renderRowSeparator(int $type = self::SEPARATOR_MID, string $title = null, string $titleFormat = null) + private function renderRowSeparator(int $type = self::SEPARATOR_MID, string $title = null, string $titleFormat = null): void { if (!$count = $this->numberOfColumns) { return; @@ -515,7 +519,7 @@ class Table * * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | */ - private function renderRow(array $row, string $cellFormat, string $firstCellFormat = null) + private function renderRow(array $row, string $cellFormat, string $firstCellFormat = null): void { $rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE); $columns = $this->getRowColumns($row); @@ -588,7 +592,7 @@ class Table /** * Calculate number of columns for this table. */ - private function calculateNumberOfColumns(array $rows) + private function calculateNumberOfColumns(array $rows): void { $columns = [0]; foreach ($rows as $row) { @@ -727,7 +731,7 @@ class Table /** * fill cells for a row that contains colspan > 1. */ - private function fillCells(iterable $row) + private function fillCells(iterable $row): iterable { $newRow = []; @@ -789,7 +793,7 @@ class Table /** * Calculates columns widths. */ - private function calculateColumnsWidth(iterable $groups) + private function calculateColumnsWidth(iterable $groups): void { for ($column = 0; $column < $this->numberOfColumns; ++$column) { $lengths = []; @@ -843,7 +847,7 @@ class Table /** * Called after rendering to cleanup cache data. */ - private function cleanup() + private function cleanup(): void { $this->effectiveColumnWidths = []; unset($this->numberOfColumns); diff --git a/vendor/symfony/console/Helper/TableCellStyle.php b/vendor/symfony/console/Helper/TableCellStyle.php index 65ae9e72..9419dcb4 100644 --- a/vendor/symfony/console/Helper/TableCellStyle.php +++ b/vendor/symfony/console/Helper/TableCellStyle.php @@ -67,9 +67,7 @@ class TableCellStyle { return array_filter( $this->getOptions(), - function ($key) { - return \in_array($key, self::TAG_OPTIONS) && isset($this->options[$key]); - }, + fn ($key) => \in_array($key, self::TAG_OPTIONS) && isset($this->options[$key]), \ARRAY_FILTER_USE_KEY ); } diff --git a/vendor/symfony/console/Input/ArgvInput.php b/vendor/symfony/console/Input/ArgvInput.php index c0c28bb5..59f9217e 100644 --- a/vendor/symfony/console/Input/ArgvInput.php +++ b/vendor/symfony/console/Input/ArgvInput.php @@ -55,11 +55,17 @@ class ArgvInput extends Input parent::__construct($definition); } + /** + * @return void + */ protected function setTokens(array $tokens) { $this->tokens = $tokens; } + /** + * @return void + */ protected function parse() { $parseOptions = true; @@ -89,7 +95,7 @@ class ArgvInput extends Input /** * Parses a short option. */ - private function parseShortOption(string $token) + private function parseShortOption(string $token): void { $name = substr($token, 1); @@ -110,7 +116,7 @@ class ArgvInput extends Input * * @throws RuntimeException When option given doesn't exist */ - private function parseShortOptionSet(string $name) + private function parseShortOptionSet(string $name): void { $len = \strlen($name); for ($i = 0; $i < $len; ++$i) { @@ -133,7 +139,7 @@ class ArgvInput extends Input /** * Parses a long option. */ - private function parseLongOption(string $token) + private function parseLongOption(string $token): void { $name = substr($token, 2); @@ -152,7 +158,7 @@ class ArgvInput extends Input * * @throws RuntimeException When too many arguments are given */ - private function parseArgument(string $token) + private function parseArgument(string $token): void { $c = \count($this->arguments); @@ -196,7 +202,7 @@ class ArgvInput extends Input * * @throws RuntimeException When option given doesn't exist */ - private function addShortOption(string $shortcut, mixed $value) + private function addShortOption(string $shortcut, mixed $value): void { if (!$this->definition->hasShortcut($shortcut)) { throw new RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut)); @@ -210,7 +216,7 @@ class ArgvInput extends Input * * @throws RuntimeException When option given doesn't exist */ - private function addLongOption(string $name, mixed $value) + private function addLongOption(string $name, mixed $value): void { if (!$this->definition->hasOption($name)) { if (!$this->definition->hasNegation($name)) { diff --git a/vendor/symfony/console/Input/ArrayInput.php b/vendor/symfony/console/Input/ArrayInput.php index 02fb4e8e..355de61d 100644 --- a/vendor/symfony/console/Input/ArrayInput.php +++ b/vendor/symfony/console/Input/ArrayInput.php @@ -113,6 +113,9 @@ class ArrayInput extends Input return implode(' ', $params); } + /** + * @return void + */ protected function parse() { foreach ($this->parameters as $key => $value) { @@ -134,7 +137,7 @@ class ArrayInput extends Input * * @throws InvalidOptionException When option given doesn't exist */ - private function addShortOption(string $shortcut, mixed $value) + private function addShortOption(string $shortcut, mixed $value): void { if (!$this->definition->hasShortcut($shortcut)) { throw new InvalidOptionException(sprintf('The "-%s" option does not exist.', $shortcut)); @@ -149,7 +152,7 @@ class ArrayInput extends Input * @throws InvalidOptionException When option given doesn't exist * @throws InvalidOptionException When a required value is missing */ - private function addLongOption(string $name, mixed $value) + private function addLongOption(string $name, mixed $value): void { if (!$this->definition->hasOption($name)) { if (!$this->definition->hasNegation($name)) { @@ -182,7 +185,7 @@ class ArrayInput extends Input * * @throws InvalidArgumentException When argument given doesn't exist */ - private function addArgument(string|int $name, mixed $value) + private function addArgument(string|int $name, mixed $value): void { if (!$this->definition->hasArgument($name)) { throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); diff --git a/vendor/symfony/console/Input/Input.php b/vendor/symfony/console/Input/Input.php index 7b90713c..0f5617cd 100644 --- a/vendor/symfony/console/Input/Input.php +++ b/vendor/symfony/console/Input/Input.php @@ -43,6 +43,9 @@ abstract class Input implements InputInterface, StreamableInputInterface } } + /** + * @return void + */ public function bind(InputDefinition $definition) { $this->arguments = []; @@ -54,17 +57,20 @@ abstract class Input implements InputInterface, StreamableInputInterface /** * Processes command line arguments. + * + * @return void */ abstract protected function parse(); + /** + * @return void + */ public function validate() { $definition = $this->definition; $givenArguments = $this->arguments; - $missingArguments = array_filter(array_keys($definition->getArguments()), function ($argument) use ($definition, $givenArguments) { - return !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired(); - }); + $missingArguments = array_filter(array_keys($definition->getArguments()), fn ($argument) => !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired()); if (\count($missingArguments) > 0) { throw new RuntimeException(sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments))); @@ -76,6 +82,9 @@ abstract class Input implements InputInterface, StreamableInputInterface return $this->interactive; } + /** + * @return void + */ public function setInteractive(bool $interactive) { $this->interactive = $interactive; @@ -95,6 +104,9 @@ abstract class Input implements InputInterface, StreamableInputInterface return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault(); } + /** + * @return void + */ public function setArgument(string $name, mixed $value) { if (!$this->definition->hasArgument($name)) { @@ -131,6 +143,9 @@ abstract class Input implements InputInterface, StreamableInputInterface return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); } + /** + * @return void + */ public function setOption(string $name, mixed $value) { if ($this->definition->hasNegation($name)) { @@ -157,11 +172,19 @@ abstract class Input implements InputInterface, StreamableInputInterface return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token); } + /** + * @param resource $stream + * + * @return void + */ public function setStream($stream) { $this->stream = $stream; } + /** + * @return resource + */ public function getStream() { return $this->stream; diff --git a/vendor/symfony/console/Input/InputArgument.php b/vendor/symfony/console/Input/InputArgument.php index 0e86e916..5cb15148 100644 --- a/vendor/symfony/console/Input/InputArgument.php +++ b/vendor/symfony/console/Input/InputArgument.php @@ -91,6 +91,8 @@ class InputArgument /** * Sets the default value. * + * @return void + * * @throws LogicException When incorrect default value is given */ public function setDefault(string|bool|int|float|array $default = null) diff --git a/vendor/symfony/console/Input/InputAwareInterface.php b/vendor/symfony/console/Input/InputAwareInterface.php index 5a288de5..0ad27b45 100644 --- a/vendor/symfony/console/Input/InputAwareInterface.php +++ b/vendor/symfony/console/Input/InputAwareInterface.php @@ -21,6 +21,8 @@ interface InputAwareInterface { /** * Sets the Console Input. + * + * @return void */ public function setInput(InputInterface $input); } diff --git a/vendor/symfony/console/Input/InputDefinition.php b/vendor/symfony/console/Input/InputDefinition.php index f4b14a1c..b7162d77 100644 --- a/vendor/symfony/console/Input/InputDefinition.php +++ b/vendor/symfony/console/Input/InputDefinition.php @@ -46,6 +46,8 @@ class InputDefinition /** * Sets the definition of the input. + * + * @return void */ public function setDefinition(array $definition) { @@ -67,6 +69,8 @@ class InputDefinition * Sets the InputArgument objects. * * @param InputArgument[] $arguments An array of InputArgument objects + * + * @return void */ public function setArguments(array $arguments = []) { @@ -81,6 +85,8 @@ class InputDefinition * Adds an array of InputArgument objects. * * @param InputArgument[] $arguments An array of InputArgument objects + * + * @return void */ public function addArguments(?array $arguments = []) { @@ -92,6 +98,8 @@ class InputDefinition } /** + * @return void + * * @throws LogicException When incorrect argument is given */ public function addArgument(InputArgument $argument) @@ -190,6 +198,8 @@ class InputDefinition * Sets the InputOption objects. * * @param InputOption[] $options An array of InputOption objects + * + * @return void */ public function setOptions(array $options = []) { @@ -203,6 +213,8 @@ class InputDefinition * Adds an array of InputOption objects. * * @param InputOption[] $options An array of InputOption objects + * + * @return void */ public function addOptions(array $options = []) { @@ -212,6 +224,8 @@ class InputDefinition } /** + * @return void + * * @throws LogicException When option given already exist */ public function addOption(InputOption $option) diff --git a/vendor/symfony/console/Input/InputInterface.php b/vendor/symfony/console/Input/InputInterface.php index 3af991a7..aaed5fd0 100644 --- a/vendor/symfony/console/Input/InputInterface.php +++ b/vendor/symfony/console/Input/InputInterface.php @@ -61,6 +61,8 @@ interface InputInterface /** * Binds the current Input instance with the given arguments and options. * + * @return void + * * @throws RuntimeException */ public function bind(InputDefinition $definition); @@ -68,6 +70,8 @@ interface InputInterface /** * Validates the input. * + * @return void + * * @throws RuntimeException When not enough arguments are given */ public function validate(); @@ -91,6 +95,8 @@ interface InputInterface /** * Sets an argument value by name. * + * @return void + * * @throws InvalidArgumentException When argument given doesn't exist */ public function setArgument(string $name, mixed $value); @@ -119,6 +125,8 @@ interface InputInterface /** * Sets an option value by name. * + * @return void + * * @throws InvalidArgumentException When option given doesn't exist */ public function setOption(string $name, mixed $value); @@ -135,6 +143,8 @@ interface InputInterface /** * Sets the input interactivity. + * + * @return void */ public function setInteractive(bool $interactive); } diff --git a/vendor/symfony/console/Input/InputOption.php b/vendor/symfony/console/Input/InputOption.php index 9a7032a0..fdf88dcc 100644 --- a/vendor/symfony/console/Input/InputOption.php +++ b/vendor/symfony/console/Input/InputOption.php @@ -178,6 +178,9 @@ class InputOption return self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode); } + /** + * @return void + */ public function setDefault(string|bool|int|float|array $default = null) { if (1 > \func_num_args()) { diff --git a/vendor/symfony/console/Input/StreamableInputInterface.php b/vendor/symfony/console/Input/StreamableInputInterface.php index d7e462f2..4b95fcb1 100644 --- a/vendor/symfony/console/Input/StreamableInputInterface.php +++ b/vendor/symfony/console/Input/StreamableInputInterface.php @@ -25,6 +25,8 @@ interface StreamableInputInterface extends InputInterface * This is mainly useful for testing purpose. * * @param resource $stream The input stream + * + * @return void */ public function setStream($stream); diff --git a/vendor/symfony/console/Output/AnsiColorMode.php b/vendor/symfony/console/Output/AnsiColorMode.php index c6cc5c12..5f9f744f 100644 --- a/vendor/symfony/console/Output/AnsiColorMode.php +++ b/vendor/symfony/console/Output/AnsiColorMode.php @@ -26,7 +26,7 @@ enum AnsiColorMode case Ansi4; /* - * 8-bit Ansi colors (240 differents colors + 16 duplicate color codes, ensuring backward compatibility). + * 8-bit Ansi colors (240 different colors + 16 duplicate color codes, ensuring backward compatibility). * Output syntax is: "ESC[38;5;${foreGroundColorcode};48;5;${backGroundColorcode}m" * Should be compatible with most terminals. */ @@ -78,25 +78,7 @@ enum AnsiColorMode private function degradeHexColorToAnsi4(int $r, int $g, int $b): int { - if (0 === round($this->getSaturation($r, $g, $b) / 50)) { - return 0; - } - - return (int) ((round($b / 255) << 2) | (round($g / 255) << 1) | round($r / 255)); - } - - private function getSaturation(int $r, int $g, int $b): int - { - $r = $r / 255; - $g = $g / 255; - $b = $b / 255; - $v = max($r, $g, $b); - - if (0 === $diff = $v - min($r, $g, $b)) { - return 0; - } - - return (int) ((int) $diff * 100 / $v); + return round($b / 255) << 2 | (round($g / 255) << 1) | round($r / 255); } /** diff --git a/vendor/symfony/console/Output/BufferedOutput.php b/vendor/symfony/console/Output/BufferedOutput.php index 94d4e414..ef5099bf 100644 --- a/vendor/symfony/console/Output/BufferedOutput.php +++ b/vendor/symfony/console/Output/BufferedOutput.php @@ -29,6 +29,9 @@ class BufferedOutput extends Output return $content; } + /** + * @return void + */ protected function doWrite(string $message, bool $newline) { $this->buffer .= $message; diff --git a/vendor/symfony/console/Output/ConsoleOutput.php b/vendor/symfony/console/Output/ConsoleOutput.php index e3aa92c7..c1eb7cd1 100644 --- a/vendor/symfony/console/Output/ConsoleOutput.php +++ b/vendor/symfony/console/Output/ConsoleOutput.php @@ -64,18 +64,27 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface return new ConsoleSectionOutput($this->getStream(), $this->consoleSectionOutputs, $this->getVerbosity(), $this->isDecorated(), $this->getFormatter()); } + /** + * @return void + */ public function setDecorated(bool $decorated) { parent::setDecorated($decorated); $this->stderr->setDecorated($decorated); } + /** + * @return void + */ public function setFormatter(OutputFormatterInterface $formatter) { parent::setFormatter($formatter); $this->stderr->setFormatter($formatter); } + /** + * @return void + */ public function setVerbosity(int $level) { parent::setVerbosity($level); @@ -87,6 +96,9 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface return $this->stderr; } + /** + * @return void + */ public function setErrorOutput(OutputInterface $error) { $this->stderr = $error; diff --git a/vendor/symfony/console/Output/ConsoleOutputInterface.php b/vendor/symfony/console/Output/ConsoleOutputInterface.php index 6b4babc6..9c0049c8 100644 --- a/vendor/symfony/console/Output/ConsoleOutputInterface.php +++ b/vendor/symfony/console/Output/ConsoleOutputInterface.php @@ -24,6 +24,9 @@ interface ConsoleOutputInterface extends OutputInterface */ public function getErrorOutput(): OutputInterface; + /** + * @return void + */ public function setErrorOutput(OutputInterface $error); public function section(): ConsoleSectionOutput; diff --git a/vendor/symfony/console/Output/ConsoleSectionOutput.php b/vendor/symfony/console/Output/ConsoleSectionOutput.php index c813c811..3f3f1434 100644 --- a/vendor/symfony/console/Output/ConsoleSectionOutput.php +++ b/vendor/symfony/console/Output/ConsoleSectionOutput.php @@ -60,6 +60,8 @@ class ConsoleSectionOutput extends StreamOutput * Clears previous output for this section. * * @param int $lines Number of lines to clear. If null, then the entire output of this section is cleared + * + * @return void */ public function clear(int $lines = null) { @@ -81,6 +83,8 @@ class ConsoleSectionOutput extends StreamOutput /** * Overwrites the previous output with a new message. + * + * @return void */ public function overwrite(string|iterable $message) { @@ -153,12 +157,15 @@ class ConsoleSectionOutput extends StreamOutput /** * @internal */ - public function addNewLineOfInputSubmit() + public function addNewLineOfInputSubmit(): void { $this->content[] = \PHP_EOL; ++$this->lines; } + /** + * @return void + */ protected function doWrite(string $message, bool $newline) { if (!$this->isDecorated()) { diff --git a/vendor/symfony/console/Output/NullOutput.php b/vendor/symfony/console/Output/NullOutput.php index 4884cbad..f3aa15b1 100644 --- a/vendor/symfony/console/Output/NullOutput.php +++ b/vendor/symfony/console/Output/NullOutput.php @@ -26,6 +26,9 @@ class NullOutput implements OutputInterface { private NullOutputFormatter $formatter; + /** + * @return void + */ public function setFormatter(OutputFormatterInterface $formatter) { // do nothing @@ -37,6 +40,9 @@ class NullOutput implements OutputInterface return $this->formatter ??= new NullOutputFormatter(); } + /** + * @return void + */ public function setDecorated(bool $decorated) { // do nothing @@ -47,6 +53,9 @@ class NullOutput implements OutputInterface return false; } + /** + * @return void + */ public function setVerbosity(int $level) { // do nothing @@ -77,11 +86,17 @@ class NullOutput implements OutputInterface return false; } + /** + * @return void + */ public function writeln(string|iterable $messages, int $options = self::OUTPUT_NORMAL) { // do nothing } + /** + * @return void + */ public function write(string|iterable $messages, bool $newline = false, int $options = self::OUTPUT_NORMAL) { // do nothing diff --git a/vendor/symfony/console/Output/Output.php b/vendor/symfony/console/Output/Output.php index 4cb71acb..3a06311a 100644 --- a/vendor/symfony/console/Output/Output.php +++ b/vendor/symfony/console/Output/Output.php @@ -44,6 +44,9 @@ abstract class Output implements OutputInterface $this->formatter->setDecorated($decorated); } + /** + * @return void + */ public function setFormatter(OutputFormatterInterface $formatter) { $this->formatter = $formatter; @@ -54,6 +57,9 @@ abstract class Output implements OutputInterface return $this->formatter; } + /** + * @return void + */ public function setDecorated(bool $decorated) { $this->formatter->setDecorated($decorated); @@ -64,6 +70,9 @@ abstract class Output implements OutputInterface return $this->formatter->isDecorated(); } + /** + * @return void + */ public function setVerbosity(int $level) { $this->verbosity = $level; @@ -94,11 +103,17 @@ abstract class Output implements OutputInterface return self::VERBOSITY_DEBUG <= $this->verbosity; } + /** + * @return void + */ public function writeln(string|iterable $messages, int $options = self::OUTPUT_NORMAL) { $this->write($messages, true, $options); } + /** + * @return void + */ public function write(string|iterable $messages, bool $newline = false, int $options = self::OUTPUT_NORMAL) { if (!is_iterable($messages)) { @@ -133,6 +148,8 @@ abstract class Output implements OutputInterface /** * Writes a message to the output. + * + * @return void */ abstract protected function doWrite(string $message, bool $newline); } diff --git a/vendor/symfony/console/Output/OutputInterface.php b/vendor/symfony/console/Output/OutputInterface.php index bc927c51..fb155772 100644 --- a/vendor/symfony/console/Output/OutputInterface.php +++ b/vendor/symfony/console/Output/OutputInterface.php @@ -36,6 +36,8 @@ interface OutputInterface * @param bool $newline Whether to add a newline * @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), * 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL + * + * @return void */ public function write(string|iterable $messages, bool $newline = false, int $options = 0); @@ -44,11 +46,15 @@ interface OutputInterface * * @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), * 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL + * + * @return void */ public function writeln(string|iterable $messages, int $options = 0); /** * Sets the verbosity of the output. + * + * @return void */ public function setVerbosity(int $level); @@ -79,6 +85,8 @@ interface OutputInterface /** * Sets the decorated flag. + * + * @return void */ public function setDecorated(bool $decorated); @@ -87,6 +95,9 @@ interface OutputInterface */ public function isDecorated(): bool; + /** + * @return void + */ public function setFormatter(OutputFormatterInterface $formatter); /** diff --git a/vendor/symfony/console/Output/StreamOutput.php b/vendor/symfony/console/Output/StreamOutput.php index 9ec524e4..155066ea 100644 --- a/vendor/symfony/console/Output/StreamOutput.php +++ b/vendor/symfony/console/Output/StreamOutput.php @@ -62,6 +62,9 @@ class StreamOutput extends Output return $this->stream; } + /** + * @return void + */ protected function doWrite(string $message, bool $newline) { if ($newline) { diff --git a/vendor/symfony/console/Output/TrimmedBufferOutput.php b/vendor/symfony/console/Output/TrimmedBufferOutput.php index 1ca5a13e..b00445ec 100644 --- a/vendor/symfony/console/Output/TrimmedBufferOutput.php +++ b/vendor/symfony/console/Output/TrimmedBufferOutput.php @@ -45,6 +45,9 @@ class TrimmedBufferOutput extends Output return $content; } + /** + * @return void + */ protected function doWrite(string $message, bool $newline) { $this->buffer .= $message; diff --git a/vendor/symfony/console/Question/Question.php b/vendor/symfony/console/Question/Question.php index b06db945..26896bb5 100644 --- a/vendor/symfony/console/Question/Question.php +++ b/vendor/symfony/console/Question/Question.php @@ -146,12 +146,11 @@ class Question if (\is_array($values)) { $values = $this->isAssoc($values) ? array_merge(array_keys($values), array_values($values)) : array_values($values); - $callback = static function () use ($values) { - return $values; - }; + $callback = static fn () => $values; } elseif ($values instanceof \Traversable) { - $valueCache = null; - $callback = static function () use ($values, &$valueCache) { + $callback = static function () use ($values) { + static $valueCache; + return $valueCache ??= iterator_to_array($values, false); }; } else { @@ -267,6 +266,9 @@ class Question return $this->normalizer; } + /** + * @return bool + */ protected function isAssoc(array $array) { return (bool) \count(array_filter(array_keys($array), 'is_string')); diff --git a/vendor/symfony/console/README.md b/vendor/symfony/console/README.md index c89b4a1a..bfd48810 100644 --- a/vendor/symfony/console/README.md +++ b/vendor/symfony/console/README.md @@ -4,6 +4,18 @@ Console Component The Console component eases the creation of beautiful and testable command line interfaces. +Sponsor +------- + +The Console component for Symfony 6.3 is [backed][1] by [Les-Tilleuls.coop][2]. + +Les-Tilleuls.coop is a team of 70+ Symfony experts who can help you design, develop and +fix your projects. They provide a wide range of professional services including development, +consulting, coaching, training and audits. They also are highly skilled in JS, Go and DevOps. +They are a worker cooperative! + +Help Symfony by [sponsoring][3] its development! + Resources --------- @@ -18,3 +30,7 @@ Credits `Resources/bin/hiddeninput.exe` is a third party binary provided within this component. Find sources and license at https://github.com/Seldaek/hidden-input. + +[1]: https://symfony.com/backers +[2]: https://les-tilleuls.coop +[3]: https://symfony.com/sponsor diff --git a/vendor/symfony/console/Resources/completion.bash b/vendor/symfony/console/Resources/completion.bash index ad69eab0..0d76eacc 100644 --- a/vendor/symfony/console/Resources/completion.bash +++ b/vendor/symfony/console/Resources/completion.bash @@ -6,6 +6,16 @@ # https://symfony.com/doc/current/contributing/code/license.html _sf_{{ COMMAND_NAME }}() { + + # Use the default completion for shell redirect operators. + for w in '>' '>>' '&>' '<'; do + if [[ $w = "${COMP_WORDS[COMP_CWORD-1]}" ]]; then + compopt -o filenames + COMPREPLY=($(compgen -f -- "${COMP_WORDS[COMP_CWORD]}")) + return 0 + fi + done + # Use newline as only separator to allow space in completion values IFS=$'\n' local sf_cmd="${COMP_WORDS[0]}" diff --git a/vendor/symfony/console/Style/OutputStyle.php b/vendor/symfony/console/Style/OutputStyle.php index b694bb53..ddfa8dec 100644 --- a/vendor/symfony/console/Style/OutputStyle.php +++ b/vendor/symfony/console/Style/OutputStyle.php @@ -30,6 +30,9 @@ abstract class OutputStyle implements OutputInterface, StyleInterface $this->output = $output; } + /** + * @return void + */ public function newLine(int $count = 1) { $this->output->write(str_repeat(\PHP_EOL, $count)); @@ -40,16 +43,25 @@ abstract class OutputStyle implements OutputInterface, StyleInterface return new ProgressBar($this->output, $max); } + /** + * @return void + */ public function write(string|iterable $messages, bool $newline = false, int $type = self::OUTPUT_NORMAL) { $this->output->write($messages, $newline, $type); } + /** + * @return void + */ public function writeln(string|iterable $messages, int $type = self::OUTPUT_NORMAL) { $this->output->writeln($messages, $type); } + /** + * @return void + */ public function setVerbosity(int $level) { $this->output->setVerbosity($level); @@ -60,6 +72,9 @@ abstract class OutputStyle implements OutputInterface, StyleInterface return $this->output->getVerbosity(); } + /** + * @return void + */ public function setDecorated(bool $decorated) { $this->output->setDecorated($decorated); @@ -70,6 +85,9 @@ abstract class OutputStyle implements OutputInterface, StyleInterface return $this->output->isDecorated(); } + /** + * @return void + */ public function setFormatter(OutputFormatterInterface $formatter) { $this->output->setFormatter($formatter); @@ -100,6 +118,9 @@ abstract class OutputStyle implements OutputInterface, StyleInterface return $this->output->isDebug(); } + /** + * @return OutputInterface + */ protected function getErrorOutput() { if (!$this->output instanceof ConsoleOutputInterface) { diff --git a/vendor/symfony/console/Style/StyleInterface.php b/vendor/symfony/console/Style/StyleInterface.php index 0bb12339..e25a65bd 100644 --- a/vendor/symfony/console/Style/StyleInterface.php +++ b/vendor/symfony/console/Style/StyleInterface.php @@ -20,51 +20,71 @@ interface StyleInterface { /** * Formats a command title. + * + * @return void */ public function title(string $message); /** * Formats a section title. + * + * @return void */ public function section(string $message); /** * Formats a list. + * + * @return void */ public function listing(array $elements); /** * Formats informational text. + * + * @return void */ public function text(string|array $message); /** * Formats a success result bar. + * + * @return void */ public function success(string|array $message); /** * Formats an error result bar. + * + * @return void */ public function error(string|array $message); /** * Formats an warning result bar. + * + * @return void */ public function warning(string|array $message); /** * Formats a note admonition. + * + * @return void */ public function note(string|array $message); /** * Formats a caution admonition. + * + * @return void */ public function caution(string|array $message); /** * Formats a table. + * + * @return void */ public function table(array $headers, array $rows); @@ -90,21 +110,29 @@ interface StyleInterface /** * Add newline(s). + * + * @return void */ public function newLine(int $count = 1); /** * Starts the progress output. + * + * @return void */ public function progressStart(int $max = 0); /** * Advances the progress output X steps. + * + * @return void */ public function progressAdvance(int $step = 1); /** * Finishes the progress output. + * + * @return void */ public function progressFinish(); } diff --git a/vendor/symfony/console/Style/SymfonyStyle.php b/vendor/symfony/console/Style/SymfonyStyle.php index 8fd6f849..cecce6c0 100644 --- a/vendor/symfony/console/Style/SymfonyStyle.php +++ b/vendor/symfony/console/Style/SymfonyStyle.php @@ -60,6 +60,8 @@ class SymfonyStyle extends OutputStyle /** * Formats a message as a block of text. + * + * @return void */ public function block(string|array $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true) { @@ -70,6 +72,9 @@ class SymfonyStyle extends OutputStyle $this->newLine(); } + /** + * @return void + */ public function title(string $message) { $this->autoPrependBlock(); @@ -80,6 +85,9 @@ class SymfonyStyle extends OutputStyle $this->newLine(); } + /** + * @return void + */ public function section(string $message) { $this->autoPrependBlock(); @@ -90,17 +98,21 @@ class SymfonyStyle extends OutputStyle $this->newLine(); } + /** + * @return void + */ public function listing(array $elements) { $this->autoPrependText(); - $elements = array_map(function ($element) { - return sprintf(' * %s', $element); - }, $elements); + $elements = array_map(fn ($element) => sprintf(' * %s', $element), $elements); $this->writeln($elements); $this->newLine(); } + /** + * @return void + */ public function text(string|array $message) { $this->autoPrependText(); @@ -113,27 +125,41 @@ class SymfonyStyle extends OutputStyle /** * Formats a command comment. + * + * @return void */ public function comment(string|array $message) { $this->block($message, null, null, ' // ', false, false); } + /** + * @return void + */ public function success(string|array $message) { $this->block($message, 'OK', 'fg=black;bg=green', ' ', true); } + /** + * @return void + */ public function error(string|array $message) { $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', true); } + /** + * @return void + */ public function warning(string|array $message) { $this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', true); } + /** + * @return void + */ public function note(string|array $message) { $this->block($message, 'NOTE', 'fg=yellow', ' ! '); @@ -141,17 +167,25 @@ class SymfonyStyle extends OutputStyle /** * Formats an info message. + * + * @return void */ public function info(string|array $message) { $this->block($message, 'INFO', 'fg=green', ' ', true); } + /** + * @return void + */ public function caution(string|array $message) { $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', true); } + /** + * @return void + */ public function table(array $headers, array $rows) { $this->createTable() @@ -165,6 +199,8 @@ class SymfonyStyle extends OutputStyle /** * Formats a horizontal table. + * + * @return void */ public function horizontalTable(array $headers, array $rows) { @@ -185,6 +221,8 @@ class SymfonyStyle extends OutputStyle * * 'A title' * * ['key' => 'value'] * * new TableSeparator() + * + * @return void */ public function definitionList(string|array|TableSeparator ...$list) { @@ -247,17 +285,26 @@ class SymfonyStyle extends OutputStyle return $this->askQuestion($questionChoice); } + /** + * @return void + */ public function progressStart(int $max = 0) { $this->progressBar = $this->createProgressBar($max); $this->progressBar->start(); } + /** + * @return void + */ public function progressAdvance(int $step = 1) { $this->getProgressBar()->advance($step); } + /** + * @return void + */ public function progressFinish() { $this->getProgressBar()->finish(); @@ -311,6 +358,9 @@ class SymfonyStyle extends OutputStyle return $answer; } + /** + * @return void + */ public function writeln(string|iterable $messages, int $type = self::OUTPUT_NORMAL) { if (!is_iterable($messages)) { @@ -323,6 +373,9 @@ class SymfonyStyle extends OutputStyle } } + /** + * @return void + */ public function write(string|iterable $messages, bool $newline = false, int $type = self::OUTPUT_NORMAL) { if (!is_iterable($messages)) { @@ -335,6 +388,9 @@ class SymfonyStyle extends OutputStyle } } + /** + * @return void + */ public function newLine(int $count = 1) { parent::newLine($count); @@ -381,7 +437,7 @@ class SymfonyStyle extends OutputStyle { $fetched = $this->bufferedOutput->fetch(); // Prepend new line if last char isn't EOL: - if (!str_ends_with($fetched, "\n")) { + if ($fetched && !str_ends_with($fetched, "\n")) { $this->newLine(); } } diff --git a/vendor/symfony/console/Terminal.php b/vendor/symfony/console/Terminal.php index 855f4114..3eda0376 100644 --- a/vendor/symfony/console/Terminal.php +++ b/vendor/symfony/console/Terminal.php @@ -131,7 +131,7 @@ class Terminal return self::$stty = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null')); } - private static function initDimensions() + private static function initDimensions(): void { if ('\\' === \DIRECTORY_SEPARATOR) { $ansicon = getenv('ANSICON'); @@ -165,7 +165,7 @@ class Terminal /** * Initializes dimensions using the output of an stty columns line. */ - private static function initDimensionsUsingStty() + private static function initDimensionsUsingStty(): void { if ($sttyString = self::getSttyColumns()) { if (preg_match('/rows.(\d+);.columns.(\d+);/is', $sttyString, $matches)) { diff --git a/vendor/symfony/console/Tester/TesterTrait.php b/vendor/symfony/console/Tester/TesterTrait.php index 9670a496..497b8c8c 100644 --- a/vendor/symfony/console/Tester/TesterTrait.php +++ b/vendor/symfony/console/Tester/TesterTrait.php @@ -128,7 +128,7 @@ trait TesterTrait * * verbosity: Sets the output verbosity flag * * capture_stderr_separately: Make output of stdOut and stdErr separately available */ - private function initOutput(array $options) + private function initOutput(array $options): void { $this->captureStreamsIndependently = \array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately']; if (!$this->captureStreamsIndependently) { diff --git a/vendor/symfony/console/composer.json b/vendor/symfony/console/composer.json index 6cc6166d..c3442129 100644 --- a/vendor/symfony/console/composer.json +++ b/vendor/symfony/console/composer.json @@ -17,9 +17,9 @@ ], "require": { "php": ">=8.1", - "symfony/deprecation-contracts": "^2.1|^3", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/service-contracts": "^1.1|^2|^3", + "symfony/service-contracts": "^2.5|^3", "symfony/string": "^5.4|^6.0" }, "require-dev": { @@ -34,12 +34,6 @@ "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, - "suggest": { - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "", - "psr/log": "For using the console logger" - }, "conflict": { "symfony/dependency-injection": "<5.4", "symfony/dotenv": "<5.4", diff --git a/vendor/symfony/deprecation-contracts/composer.json b/vendor/symfony/deprecation-contracts/composer.json index 774200fd..c6d02d87 100644 --- a/vendor/symfony/deprecation-contracts/composer.json +++ b/vendor/symfony/deprecation-contracts/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/vendor/symfony/filesystem/Filesystem.php b/vendor/symfony/filesystem/Filesystem.php index 3b3cf7a1..a379ce18 100644 --- a/vendor/symfony/filesystem/Filesystem.php +++ b/vendor/symfony/filesystem/Filesystem.php @@ -31,6 +31,8 @@ class Filesystem * If the target file is newer, it is overwritten only when the * $overwriteNewerFiles option is set to true. * + * @return void + * * @throws FileNotFoundException When originFile doesn't exist * @throws IOException When copy fails */ @@ -82,6 +84,8 @@ class Filesystem /** * Creates a directory recursively. * + * @return void + * * @throws IOException On any directory creation failure */ public function mkdir(string|iterable $dirs, int $mode = 0777) @@ -123,6 +127,8 @@ class Filesystem * @param int|null $time The touch time as a Unix timestamp, if not supplied the current system time is used * @param int|null $atime The access time as a Unix timestamp, if not supplied the current system time is used * + * @return void + * * @throws IOException When touch fails */ public function touch(string|iterable $files, int $time = null, int $atime = null) @@ -137,6 +143,8 @@ class Filesystem /** * Removes files or directories. * + * @return void + * * @throws IOException When removal fails */ public function remove(string|iterable $files) @@ -203,12 +211,14 @@ class Filesystem * @param int $umask The mode mask (octal) * @param bool $recursive Whether change the mod recursively or not * + * @return void + * * @throws IOException When the change fails */ public function chmod(string|iterable $files, int $mode, int $umask = 0000, bool $recursive = false) { foreach ($this->toIterable($files) as $file) { - if (\is_int($mode) && !self::box('chmod', $file, $mode & ~$umask)) { + if (!self::box('chmod', $file, $mode & ~$umask)) { throw new IOException(sprintf('Failed to chmod file "%s": ', $file).self::$lastError, 0, null, $file); } if ($recursive && is_dir($file) && !is_link($file)) { @@ -223,6 +233,8 @@ class Filesystem * @param string|int $user A user name or number * @param bool $recursive Whether change the owner recursively or not * + * @return void + * * @throws IOException When the change fails */ public function chown(string|iterable $files, string|int $user, bool $recursive = false) @@ -249,6 +261,8 @@ class Filesystem * @param string|int $group A group name or number * @param bool $recursive Whether change the group recursively or not * + * @return void + * * @throws IOException When the change fails */ public function chgrp(string|iterable $files, string|int $group, bool $recursive = false) @@ -272,6 +286,8 @@ class Filesystem /** * Renames a file or a directory. * + * @return void + * * @throws IOException When target file or directory already exists * @throws IOException When origin cannot be renamed */ @@ -313,6 +329,8 @@ class Filesystem /** * Creates a symbolic link or copy a directory. * + * @return void + * * @throws IOException When symlink fails */ public function symlink(string $originDir, string $targetDir, bool $copyOnWindows = false) @@ -349,6 +367,8 @@ class Filesystem * * @param string|string[] $targetFiles The target file(s) * + * @return void + * * @throws FileNotFoundException When original file is missing or not a file * @throws IOException When link fails, including if link already exists */ @@ -381,7 +401,7 @@ class Filesystem /** * @param string $linkType Name of the link type, typically 'symbolic' or 'hard' */ - private function linkException(string $origin, string $target, string $linkType) + private function linkException(string $origin, string $target, string $linkType): never { if (self::$lastError) { if ('\\' === \DIRECTORY_SEPARATOR && str_contains(self::$lastError, 'error code(1314)')) { @@ -438,11 +458,9 @@ class Filesystem $startPath = str_replace('\\', '/', $startPath); } - $splitDriveLetter = function ($path) { - return (\strlen($path) > 2 && ':' === $path[1] && '/' === $path[2] && ctype_alpha($path[0])) - ? [substr($path, 2), strtoupper($path[0])] - : [$path, null]; - }; + $splitDriveLetter = fn ($path) => (\strlen($path) > 2 && ':' === $path[1] && '/' === $path[2] && ctype_alpha($path[0])) + ? [substr($path, 2), strtoupper($path[0])] + : [$path, null]; $splitPath = function ($path) { $result = []; @@ -508,6 +526,8 @@ class Filesystem * - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink(), defaults to false) * - $options['delete'] Whether to delete files that are not in the source directory (defaults to false) * + * @return void + * * @throws IOException When file type is unknown */ public function mirror(string $originDir, string $targetDir, \Traversable $iterator = null, array $options = []) @@ -632,6 +652,8 @@ class Filesystem * * @param string|resource $content The data to write into the file * + * @return void + * * @throws IOException if the file cannot be written to */ public function dumpFile(string $filename, $content) @@ -642,6 +664,12 @@ class Filesystem $dir = \dirname($filename); + if (is_link($filename) && $linkTarget = $this->readlink($filename)) { + $this->dumpFile(Path::makeAbsolute($linkTarget, $dir), $content); + + return; + } + if (!is_dir($dir)) { $this->mkdir($dir); } @@ -671,6 +699,8 @@ class Filesystem * @param string|resource $content The content to append * @param bool $lock Whether the file should be locked when writing to it * + * @return void + * * @throws IOException If the file is not writable */ public function appendToFile(string $filename, $content/* , bool $lock = false */) @@ -730,7 +760,7 @@ class Filesystem /** * @internal */ - public static function handleError(int $type, string $msg) + public static function handleError(int $type, string $msg): void { self::$lastError = $msg; } diff --git a/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php b/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php index 88f6a068..07d12b4a 100644 --- a/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php +++ b/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php @@ -11,82 +11,13 @@ namespace Symfony\Contracts\Service\Test; -use PHPUnit\Framework\TestCase; -use Psr\Container\ContainerInterface; -use Symfony\Contracts\Service\ServiceLocatorTrait; +class_alias(ServiceLocatorTestCase::class, ServiceLocatorTest::class); -abstract class ServiceLocatorTest extends TestCase -{ - protected function getServiceLocator(array $factories): ContainerInterface +if (false) { + /** + * @deprecated since PHPUnit 9.6 + */ + class ServiceLocatorTest { - return new class($factories) implements ContainerInterface { - use ServiceLocatorTrait; - }; - } - - public function testHas() - { - $locator = $this->getServiceLocator([ - 'foo' => function () { return 'bar'; }, - 'bar' => function () { return 'baz'; }, - function () { return 'dummy'; }, - ]); - - $this->assertTrue($locator->has('foo')); - $this->assertTrue($locator->has('bar')); - $this->assertFalse($locator->has('dummy')); - } - - public function testGet() - { - $locator = $this->getServiceLocator([ - 'foo' => function () { return 'bar'; }, - 'bar' => function () { return 'baz'; }, - ]); - - $this->assertSame('bar', $locator->get('foo')); - $this->assertSame('baz', $locator->get('bar')); - } - - public function testGetDoesNotMemoize() - { - $i = 0; - $locator = $this->getServiceLocator([ - 'foo' => function () use (&$i) { - ++$i; - - return 'bar'; - }, - ]); - - $this->assertSame('bar', $locator->get('foo')); - $this->assertSame('bar', $locator->get('foo')); - $this->assertSame(2, $i); - } - - public function testThrowsOnUndefinedInternalService() - { - if (!$this->getExpectedException()) { - $this->expectException(\Psr\Container\NotFoundExceptionInterface::class); - $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); - } - $locator = $this->getServiceLocator([ - 'foo' => function () use (&$locator) { return $locator->get('bar'); }, - ]); - - $locator->get('foo'); - } - - public function testThrowsOnCircularReference() - { - $this->expectException(\Psr\Container\ContainerExceptionInterface::class); - $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); - $locator = $this->getServiceLocator([ - 'foo' => function () use (&$locator) { return $locator->get('bar'); }, - 'bar' => function () use (&$locator) { return $locator->get('baz'); }, - 'baz' => function () use (&$locator) { return $locator->get('bar'); }, - ]); - - $locator->get('foo'); } } diff --git a/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php b/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php new file mode 100644 index 00000000..a0f20a6a --- /dev/null +++ b/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service\Test; + +use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\ServiceLocatorTrait; + +abstract class ServiceLocatorTestCase extends TestCase +{ + protected function getServiceLocator(array $factories): ContainerInterface + { + return new class($factories) implements ContainerInterface { + use ServiceLocatorTrait; + }; + } + + public function testHas() + { + $locator = $this->getServiceLocator([ + 'foo' => function () { return 'bar'; }, + 'bar' => function () { return 'baz'; }, + function () { return 'dummy'; }, + ]); + + $this->assertTrue($locator->has('foo')); + $this->assertTrue($locator->has('bar')); + $this->assertFalse($locator->has('dummy')); + } + + public function testGet() + { + $locator = $this->getServiceLocator([ + 'foo' => function () { return 'bar'; }, + 'bar' => function () { return 'baz'; }, + ]); + + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('baz', $locator->get('bar')); + } + + public function testGetDoesNotMemoize() + { + $i = 0; + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$i) { + ++$i; + + return 'bar'; + }, + ]); + + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame(2, $i); + } + + public function testThrowsOnUndefinedInternalService() + { + if (!$this->getExpectedException()) { + $this->expectException(\Psr\Container\NotFoundExceptionInterface::class); + $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); + } + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$locator) { return $locator->get('bar'); }, + ]); + + $locator->get('foo'); + } + + public function testThrowsOnCircularReference() + { + $this->expectException(\Psr\Container\ContainerExceptionInterface::class); + $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$locator) { return $locator->get('bar'); }, + 'bar' => function () use (&$locator) { return $locator->get('baz'); }, + 'baz' => function () use (&$locator) { return $locator->get('bar'); }, + ]); + + $locator->get('foo'); + } +} diff --git a/vendor/symfony/service-contracts/composer.json b/vendor/symfony/service-contracts/composer.json index 36b0d95e..a64188b5 100644 --- a/vendor/symfony/service-contracts/composer.json +++ b/vendor/symfony/service-contracts/composer.json @@ -22,9 +22,6 @@ "conflict": { "ext-psr": "<1.1|>=2" }, - "suggest": { - "symfony/service-implementation": "" - }, "autoload": { "psr-4": { "Symfony\\Contracts\\Service\\": "" }, "exclude-from-classmap": [ @@ -34,7 +31,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/vendor/symfony/string/AbstractUnicodeString.php b/vendor/symfony/string/AbstractUnicodeString.php index 2a2bed71..d19a61a9 100644 --- a/vendor/symfony/string/AbstractUnicodeString.php +++ b/vendor/symfony/string/AbstractUnicodeString.php @@ -40,10 +40,6 @@ abstract class AbstractUnicodeString extends AbstractString private const FOLD_FROM = ['İ', 'µ', 'ſ', "\xCD\x85", 'ς', 'ϐ', 'ϑ', 'ϕ', 'ϖ', 'ϰ', 'ϱ', 'ϵ', 'ẛ', "\xE1\xBE\xBE", 'ß', 'ʼn', 'ǰ', 'ΐ', 'ΰ', 'և', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'ẚ', 'ẞ', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'ᾐ', 'ᾑ', 'ᾒ', 'ᾓ', 'ᾔ', 'ᾕ', 'ᾖ', 'ᾗ', 'ᾘ', 'ᾙ', 'ᾚ', 'ᾛ', 'ᾜ', 'ᾝ', 'ᾞ', 'ᾟ', 'ᾠ', 'ᾡ', 'ᾢ', 'ᾣ', 'ᾤ', 'ᾥ', 'ᾦ', 'ᾧ', 'ᾨ', 'ᾩ', 'ᾪ', 'ᾫ', 'ᾬ', 'ᾭ', 'ᾮ', 'ᾯ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'ᾼ', 'ῂ', 'ῃ', 'ῄ', 'ῆ', 'ῇ', 'ῌ', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ῲ', 'ῳ', 'ῴ', 'ῶ', 'ῷ', 'ῼ', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'ſt', 'st', 'ﬓ', 'ﬔ', 'ﬕ', 'ﬖ', 'ﬗ']; private const FOLD_TO = ['i̇', 'μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', 'ṡ', 'ι', 'ss', 'ʼn', 'ǰ', 'ΐ', 'ΰ', 'եւ', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'aʾ', 'ss', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὰι', 'αι', 'άι', 'ᾶ', 'ᾶι', 'αι', 'ὴι', 'ηι', 'ήι', 'ῆ', 'ῆι', 'ηι', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ὼι', 'ωι', 'ώι', 'ῶ', 'ῶι', 'ωι', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'st', 'st', 'մն', 'մե', 'մի', 'վն', 'մխ']; - // the subset of upper case mappings that map one code point to many code points - private const UPPER_FROM = ['ß', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'ſt', 'st', 'և', 'ﬓ', 'ﬔ', 'ﬕ', 'ﬖ', 'ﬗ', 'ʼn', 'ΐ', 'ΰ', 'ǰ', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'ẚ', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ᾶ', 'ῆ', 'ῒ', 'ΐ', 'ῖ', 'ῗ', 'ῢ', 'ΰ', 'ῤ', 'ῦ', 'ῧ', 'ῶ']; - private const UPPER_TO = ['SS', 'FF', 'FI', 'FL', 'FFI', 'FFL', 'ST', 'ST', 'ԵՒ', 'ՄՆ', 'ՄԵ', 'ՄԻ', 'ՎՆ', 'ՄԽ', 'ʼN', 'Ϊ́', 'Ϋ́', 'J̌', 'H̱', 'T̈', 'W̊', 'Y̊', 'Aʾ', 'Υ̓', 'Υ̓̀', 'Υ̓́', 'Υ̓͂', 'Α͂', 'Η͂', 'Ϊ̀', 'Ϊ́', 'Ι͂', 'Ϊ͂', 'Ϋ̀', 'Ϋ́', 'Ρ̓', 'Υ͂', 'Ϋ͂', 'Ω͂']; - // the subset of https://github.com/unicode-org/cldr/blob/master/common/transforms/Latin-ASCII.xml that is not in NFKD private const TRANSLIT_FROM = ['Æ', 'Ð', 'Ø', 'Þ', 'ß', 'æ', 'ð', 'ø', 'þ', 'Đ', 'đ', 'Ħ', 'ħ', 'ı', 'ĸ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'ʼn', 'Ŋ', 'ŋ', 'Œ', 'œ', 'Ŧ', 'ŧ', 'ƀ', 'Ɓ', 'Ƃ', 'ƃ', 'Ƈ', 'ƈ', 'Ɖ', 'Ɗ', 'Ƌ', 'ƌ', 'Ɛ', 'Ƒ', 'ƒ', 'Ɠ', 'ƕ', 'Ɩ', 'Ɨ', 'Ƙ', 'ƙ', 'ƚ', 'Ɲ', 'ƞ', 'Ƣ', 'ƣ', 'Ƥ', 'ƥ', 'ƫ', 'Ƭ', 'ƭ', 'Ʈ', 'Ʋ', 'Ƴ', 'ƴ', 'Ƶ', 'ƶ', 'DŽ', 'Dž', 'dž', 'Ǥ', 'ǥ', 'ȡ', 'Ȥ', 'ȥ', 'ȴ', 'ȵ', 'ȶ', 'ȷ', 'ȸ', 'ȹ', 'Ⱥ', 'Ȼ', 'ȼ', 'Ƚ', 'Ⱦ', 'ȿ', 'ɀ', 'Ƀ', 'Ʉ', 'Ɇ', 'ɇ', 'Ɉ', 'ɉ', 'Ɍ', 'ɍ', 'Ɏ', 'ɏ', 'ɓ', 'ɕ', 'ɖ', 'ɗ', 'ɛ', 'ɟ', 'ɠ', 'ɡ', 'ɢ', 'ɦ', 'ɧ', 'ɨ', 'ɪ', 'ɫ', 'ɬ', 'ɭ', 'ɱ', 'ɲ', 'ɳ', 'ɴ', 'ɶ', 'ɼ', 'ɽ', 'ɾ', 'ʀ', 'ʂ', 'ʈ', 'ʉ', 'ʋ', 'ʏ', 'ʐ', 'ʑ', 'ʙ', 'ʛ', 'ʜ', 'ʝ', 'ʟ', 'ʠ', 'ʣ', 'ʥ', 'ʦ', 'ʪ', 'ʫ', 'ᴀ', 'ᴁ', 'ᴃ', 'ᴄ', 'ᴅ', 'ᴆ', 'ᴇ', 'ᴊ', 'ᴋ', 'ᴌ', 'ᴍ', 'ᴏ', 'ᴘ', 'ᴛ', 'ᴜ', 'ᴠ', 'ᴡ', 'ᴢ', 'ᵫ', 'ᵬ', 'ᵭ', 'ᵮ', 'ᵯ', 'ᵰ', 'ᵱ', 'ᵲ', 'ᵳ', 'ᵴ', 'ᵵ', 'ᵶ', 'ᵺ', 'ᵻ', 'ᵽ', 'ᵾ', 'ᶀ', 'ᶁ', 'ᶂ', 'ᶃ', 'ᶄ', 'ᶅ', 'ᶆ', 'ᶇ', 'ᶈ', 'ᶉ', 'ᶊ', 'ᶌ', 'ᶍ', 'ᶎ', 'ᶏ', 'ᶑ', 'ᶒ', 'ᶓ', 'ᶖ', 'ᶙ', 'ẚ', 'ẜ', 'ẝ', 'ẞ', 'Ỻ', 'ỻ', 'Ỽ', 'ỽ', 'Ỿ', 'ỿ', '©', '®', '₠', '₢', '₣', '₤', '₧', '₺', '₹', 'ℌ', '℞', '㎧', '㎮', '㏆', '㏗', '㏞', '㏟', '¼', '½', '¾', '⅓', '⅔', '⅕', '⅖', '⅗', '⅘', '⅙', '⅚', '⅛', '⅜', '⅝', '⅞', '⅟', '〇', '‘', '’', '‚', '‛', '“', '”', '„', '‟', '′', '″', '〝', '〞', '«', '»', '‹', '›', '‐', '‑', '‒', '–', '—', '―', '︱', '︲', '﹘', '‖', '⁄', '⁅', '⁆', '⁎', '、', '。', '〈', '〉', '《', '》', '〔', '〕', '〘', '〙', '〚', '〛', '︑', '︒', '︹', '︺', '︽', '︾', '︿', '﹀', '﹑', '﹝', '﹞', '⦅', '⦆', '。', '、', '×', '÷', '−', '∕', '∖', '∣', '∥', '≪', '≫', '⦅', '⦆']; private const TRANSLIT_TO = ['AE', 'D', 'O', 'TH', 'ss', 'ae', 'd', 'o', 'th', 'D', 'd', 'H', 'h', 'i', 'q', 'L', 'l', 'L', 'l', '\'n', 'N', 'n', 'OE', 'oe', 'T', 't', 'b', 'B', 'B', 'b', 'C', 'c', 'D', 'D', 'D', 'd', 'E', 'F', 'f', 'G', 'hv', 'I', 'I', 'K', 'k', 'l', 'N', 'n', 'OI', 'oi', 'P', 'p', 't', 'T', 't', 'T', 'V', 'Y', 'y', 'Z', 'z', 'DZ', 'Dz', 'dz', 'G', 'g', 'd', 'Z', 'z', 'l', 'n', 't', 'j', 'db', 'qp', 'A', 'C', 'c', 'L', 'T', 's', 'z', 'B', 'U', 'E', 'e', 'J', 'j', 'R', 'r', 'Y', 'y', 'b', 'c', 'd', 'd', 'e', 'j', 'g', 'g', 'G', 'h', 'h', 'i', 'I', 'l', 'l', 'l', 'm', 'n', 'n', 'N', 'OE', 'r', 'r', 'r', 'R', 's', 't', 'u', 'v', 'Y', 'z', 'z', 'B', 'G', 'H', 'j', 'L', 'q', 'dz', 'dz', 'ts', 'ls', 'lz', 'A', 'AE', 'B', 'C', 'D', 'D', 'E', 'J', 'K', 'L', 'M', 'O', 'P', 'T', 'U', 'V', 'W', 'Z', 'ue', 'b', 'd', 'f', 'm', 'n', 'p', 'r', 'r', 's', 't', 'z', 'th', 'I', 'p', 'U', 'b', 'd', 'f', 'g', 'k', 'l', 'm', 'n', 'p', 'r', 's', 'v', 'x', 'z', 'a', 'd', 'e', 'e', 'i', 'u', 'a', 's', 's', 'SS', 'LL', 'll', 'V', 'v', 'Y', 'y', '(C)', '(R)', 'CE', 'Cr', 'Fr.', 'L.', 'Pts', 'TL', 'Rs', 'x', 'Rx', 'm/s', 'rad/s', 'C/kg', 'pH', 'V/m', 'A/m', ' 1/4', ' 1/2', ' 3/4', ' 1/3', ' 2/3', ' 1/5', ' 2/5', ' 3/5', ' 4/5', ' 1/6', ' 5/6', ' 1/8', ' 3/8', ' 5/8', ' 7/8', ' 1/', '0', '\'', '\'', ',', '\'', '"', '"', ',,', '"', '\'', '"', '"', '"', '<<', '>>', '<', '>', '-', '-', '-', '-', '-', '-', '-', '-', '-', '||', '/', '[', ']', '*', ',', '.', '<', '>', '<<', '>>', '[', ']', '[', ']', '[', ']', ',', '.', '[', ']', '<<', '>>', '<', '>', ',', '[', ']', '((', '))', '.', ',', '*', '/', '-', '/', '\\', '|', '||', '<<', '>>', '((', '))']; @@ -159,7 +155,9 @@ abstract class AbstractUnicodeString extends AbstractString public function camel(): static { $str = clone $this; - $str->string = str_replace(' ', '', preg_replace_callback('/\b.(?![A-Z]{2,})/u', static function ($m) use (&$i) { + $str->string = str_replace(' ', '', preg_replace_callback('/\b.(?![A-Z]{2,})/u', static function ($m) { + static $i = 0; + return 1 === ++$i ? ('İ' === $m[0] ? 'i̇' : mb_strtolower($m[0], 'UTF-8')) : mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'); }, preg_replace('/[^\pL0-9]++/u', ' ', $this->string))); @@ -360,9 +358,7 @@ abstract class AbstractUnicodeString extends AbstractString $limit = $allWords ? -1 : 1; - $str->string = preg_replace_callback('/\b./u', static function (array $m): string { - return mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'); - }, $str->string, $limit); + $str->string = preg_replace_callback('/\b./u', static fn (array $m): string => mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'), $str->string, $limit); return $str; } diff --git a/vendor/symfony/string/Inflector/EnglishInflector.php b/vendor/symfony/string/Inflector/EnglishInflector.php index 2871e4e5..2cd6bb87 100644 --- a/vendor/symfony/string/Inflector/EnglishInflector.php +++ b/vendor/symfony/string/Inflector/EnglishInflector.php @@ -94,6 +94,9 @@ final class EnglishInflector implements InflectorInterface // accesses (access), addresses (address), kisses (kiss) ['sess', 4, true, false, 'ss'], + // statuses (status) + ['sesutats', 8, true, true, 'status'], + // analyses (analysis), ellipses (ellipsis), fungi (fungus), // neuroses (neurosis), theses (thesis), emphases (emphasis), // oases (oasis), crises (crisis), houses (house), bases (base), @@ -138,6 +141,9 @@ final class EnglishInflector implements InflectorInterface // shoes (shoe) ['se', 2, true, true, ['', 'e']], + // status (status) + ['sutats', 6, true, true, 'status'], + // tags (tag) ['s', 1, true, true, ''], @@ -279,6 +285,9 @@ final class EnglishInflector implements InflectorInterface // circuses (circus) ['suc', 3, true, true, 'cuses'], + // status (status) + ['sutats', 6, true, true, ['status', 'statuses']], + // conspectuses (conspectus), prospectuses (prospectus) ['sutcep', 6, true, true, 'pectuses'], diff --git a/vendor/symfony/string/LazyString.php b/vendor/symfony/string/LazyString.php index 9523b8cd..3128ebb3 100644 --- a/vendor/symfony/string/LazyString.php +++ b/vendor/symfony/string/LazyString.php @@ -30,7 +30,9 @@ class LazyString implements \Stringable, \JsonSerializable } $lazyString = new static(); - $lazyString->value = static function () use (&$callback, &$arguments, &$value): string { + $lazyString->value = static function () use (&$callback, &$arguments): string { + static $value; + if (null !== $arguments) { if (!\is_callable($callback)) { $callback[0] = $callback[0](); diff --git a/vendor/symfony/string/Slugger/AsciiSlugger.php b/vendor/symfony/string/Slugger/AsciiSlugger.php index 826d07ca..6e550c61 100644 --- a/vendor/symfony/string/Slugger/AsciiSlugger.php +++ b/vendor/symfony/string/Slugger/AsciiSlugger.php @@ -74,6 +74,9 @@ class AsciiSlugger implements SluggerInterface, LocaleAwareInterface $this->symbolsMap = $symbolsMap ?? $this->symbolsMap; } + /** + * @return void + */ public function setLocale(string $locale) { $this->defaultLocale = $locale; @@ -121,9 +124,7 @@ class AsciiSlugger implements SluggerInterface, LocaleAwareInterface // If the symbols map is passed as a closure, there is no need to fallback to the parent locale // as the closure can just provide substitutions for all locales of interest. $symbolsMap = $this->symbolsMap; - array_unshift($transliterator, static function ($s) use ($symbolsMap, $locale) { - return $symbolsMap($s, $locale); - }); + array_unshift($transliterator, static fn ($s) => $symbolsMap($s, $locale)); } $unicodeString = (new UnicodeString($string))->ascii($transliterator); diff --git a/vendor/symfony/string/composer.json b/vendor/symfony/string/composer.json index 44a809d5..3545c853 100644 --- a/vendor/symfony/string/composer.json +++ b/vendor/symfony/string/composer.json @@ -26,11 +26,11 @@ "symfony/error-handler": "^5.4|^6.0", "symfony/intl": "^6.2", "symfony/http-client": "^5.4|^6.0", - "symfony/translation-contracts": "^2.0|^3.0", + "symfony/translation-contracts": "^2.5|^3.0", "symfony/var-exporter": "^5.4|^6.0" }, "conflict": { - "symfony/translation-contracts": "<2.0" + "symfony/translation-contracts": "<2.5" }, "autoload": { "psr-4": { "Symfony\\Component\\String\\": "" }, diff --git a/vendor/vimeo/psalm/composer.json b/vendor/vimeo/psalm/composer.json index cfca1191..7df7c97a 100644 --- a/vendor/vimeo/psalm/composer.json +++ b/vendor/vimeo/psalm/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0", + "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", "ext-SimpleXML": "*", "ext-ctype": "*", "ext-dom": "*", @@ -23,9 +23,9 @@ "ext-libxml": "*", "ext-mbstring": "*", "ext-tokenizer": "*", + "composer-runtime-api": "^2", "amphp/amp": "^2.4.2", "amphp/byte-stream": "^1.5", - "composer-runtime-api": "^2", "composer/semver": "^1.4 || ^2.0 || ^3.0", "composer/xdebug-handler": "^2.0 || ^3.0", "dnoegel/php-xdg-base-dir": "^0.1.1", @@ -33,7 +33,7 @@ "felixfbecker/language-server-protocol": "^1.5.2", "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1", "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", - "nikic/php-parser": "^4.14", + "nikic/php-parser": "^4.16", "sebastian/diff": "^4.0 || ^5.0", "spatie/array-to-xml": "^2.17.0 || ^3.0", "symfony/console": "^4.1.6 || ^5.0 || ^6.0", diff --git a/vendor/vimeo/psalm/config.xsd b/vendor/vimeo/psalm/config.xsd index 4d4f377f..4cf075b6 100644 --- a/vendor/vimeo/psalm/config.xsd +++ b/vendor/vimeo/psalm/config.xsd @@ -33,6 +33,7 @@ + diff --git a/vendor/vimeo/psalm/dictionaries/CallMap.php b/vendor/vimeo/psalm/dictionaries/CallMap.php index bb61ce41..7d8c477b 100644 --- a/vendor/vimeo/psalm/dictionaries/CallMap.php +++ b/vendor/vimeo/psalm/dictionaries/CallMap.php @@ -337,7 +337,6 @@ return [ 'AppendIterator::next' => ['void'], 'AppendIterator::rewind' => ['void'], 'AppendIterator::valid' => ['bool'], -'ArgumentCountError::__clone' => ['void'], 'ArgumentCountError::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'ArgumentCountError::__toString' => ['string'], 'ArgumentCountError::__wakeup' => ['void'], @@ -348,7 +347,6 @@ return [ 'ArgumentCountError::getPrevious' => ['?Throwable'], 'ArgumentCountError::getTrace' => ['list\',args?:array}>'], 'ArgumentCountError::getTraceAsString' => ['string'], -'ArithmeticError::__clone' => ['void'], 'ArithmeticError::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'ArithmeticError::__toString' => ['string'], 'ArithmeticError::__wakeup' => ['void'], @@ -425,10 +423,10 @@ return [ 'array_walk\'1' => ['bool', '&rw_array'=>'object', 'callback'=>'callable', 'arg='=>'mixed'], 'array_walk_recursive' => ['bool', '&rw_array'=>'array', 'callback'=>'callable', 'arg='=>'mixed'], 'array_walk_recursive\'1' => ['bool', '&rw_array'=>'object', 'callback'=>'callable', 'arg='=>'mixed'], -'ArrayAccess::offsetExists' => ['bool', 'offset'=>'mixed'], -'ArrayAccess::offsetGet' => ['mixed', 'offset'=>'mixed'], -'ArrayAccess::offsetSet' => ['void', 'offset'=>'mixed', 'value'=>'mixed'], -'ArrayAccess::offsetUnset' => ['void', 'offset'=>'mixed'], +'ArrayAccess::offsetExists' => ['bool', 'offset'=>'int|string'], +'ArrayAccess::offsetGet' => ['mixed', 'offset'=>'int|string'], +'ArrayAccess::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], +'ArrayAccess::offsetUnset' => ['void', 'offset'=>'int|string'], 'ArrayIterator::__construct' => ['void', 'array='=>'array|object', 'flags='=>'int'], 'ArrayIterator::append' => ['void', 'value'=>'mixed'], 'ArrayIterator::asort' => ['true', 'flags='=>'int'], @@ -443,7 +441,7 @@ return [ 'ArrayIterator::next' => ['void'], 'ArrayIterator::offsetExists' => ['bool', 'key'=>'string|int'], 'ArrayIterator::offsetGet' => ['mixed', 'key'=>'string|int'], -'ArrayIterator::offsetSet' => ['void', 'key'=>'string|int', 'value'=>'mixed'], +'ArrayIterator::offsetSet' => ['void', 'key'=>'string|int|null', 'value'=>'mixed'], 'ArrayIterator::offsetUnset' => ['void', 'key'=>'string|int'], 'ArrayIterator::rewind' => ['void'], 'ArrayIterator::seek' => ['void', 'offset'=>'int'], @@ -467,7 +465,7 @@ return [ 'ArrayObject::natsort' => ['true'], 'ArrayObject::offsetExists' => ['bool', 'key'=>'int|string'], 'ArrayObject::offsetGet' => ['mixed|null', 'key'=>'int|string'], -'ArrayObject::offsetSet' => ['void', 'key'=>'int|string', 'value'=>'mixed'], +'ArrayObject::offsetSet' => ['void', 'key'=>'int|string|null', 'value'=>'mixed'], 'ArrayObject::offsetUnset' => ['void', 'key'=>'int|string'], 'ArrayObject::serialize' => ['string'], 'ArrayObject::setFlags' => ['void', 'flags'=>'int'], @@ -491,7 +489,6 @@ return [ 'atan' => ['float', 'num'=>'float'], 'atan2' => ['float', 'y'=>'float', 'x'=>'float'], 'atanh' => ['float', 'num'=>'float'], -'BadFunctionCallException::__clone' => ['void'], 'BadFunctionCallException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'BadFunctionCallException::__toString' => ['string'], 'BadFunctionCallException::getCode' => ['int'], @@ -501,7 +498,6 @@ return [ 'BadFunctionCallException::getPrevious' => ['?Throwable'], 'BadFunctionCallException::getTrace' => ['list\',args?:array}>'], 'BadFunctionCallException::getTraceAsString' => ['string'], -'BadMethodCallException::__clone' => ['void'], 'BadMethodCallException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'BadMethodCallException::__toString' => ['string'], 'BadMethodCallException::getCode' => ['int'], @@ -511,7 +507,8 @@ return [ 'BadMethodCallException::getPrevious' => ['?Throwable'], 'BadMethodCallException::getTrace' => ['list\',args?:array}>'], 'BadMethodCallException::getTraceAsString' => ['string'], -'base64_decode' => ['string|false', 'string'=>'string', 'strict='=>'bool'], +'base64_decode' => ['string', 'string'=>'string', 'strict='=>'false'], +'base64_decode\'1' => ['string|false', 'string'=>'string', 'strict='=>'true'], 'base64_encode' => ['string', 'string'=>'string'], 'base_convert' => ['string', 'num'=>'string', 'from_base'=>'int', 'to_base'=>'int'], 'basename' => ['string', 'path'=>'string', 'suffix='=>'string'], @@ -660,7 +657,6 @@ return [ 'clearstatcache' => ['void', 'clear_realpath_cache='=>'bool', 'filename='=>'string'], 'cli_get_process_title' => ['?string'], 'cli_set_process_title' => ['bool', 'title'=>'string'], -'ClosedGeneratorException::__clone' => ['void'], 'ClosedGeneratorException::__toString' => ['string'], 'ClosedGeneratorException::getCode' => ['int'], 'ClosedGeneratorException::getFile' => ['string'], @@ -1351,7 +1347,7 @@ return [ 'datefmt_set_calendar' => ['bool', 'formatter'=>'IntlDateFormatter', 'calendar'=>'IntlCalendar|int|null'], 'datefmt_set_lenient' => ['void', 'formatter'=>'IntlDateFormatter', 'lenient'=>'bool'], 'datefmt_set_pattern' => ['bool', 'formatter'=>'IntlDateFormatter', 'pattern'=>'string'], -'datefmt_set_timezone' => ['false|null', 'formatter'=>'IntlDateFormatter', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], +'datefmt_set_timezone' => ['bool', 'formatter'=>'IntlDateFormatter', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], 'DateInterval::__construct' => ['void', 'duration'=>'string'], 'DateInterval::__set_state' => ['DateInterval', 'array'=>'array'], 'DateInterval::__wakeup' => ['void'], @@ -1545,7 +1541,7 @@ return [ 'dcgettext' => ['string', 'domain'=>'string', 'message'=>'string', 'category'=>'int'], 'dcngettext' => ['string', 'domain'=>'string', 'singular'=>'string', 'plural'=>'string', 'count'=>'int', 'category'=>'int'], 'deaggregate' => ['', 'object'=>'object', 'class_name='=>'string'], -'debug_backtrace' => ['list', 'options='=>'int', 'limit='=>'int'], +'debug_backtrace' => ['list', 'options='=>'int', 'limit='=>'int'], 'debug_print_backtrace' => ['void', 'options='=>'int', 'limit='=>'int'], 'debug_zval_dump' => ['void', 'value'=>'mixed', '...values='=>'mixed'], 'debugger_connect' => [''], @@ -1612,7 +1608,7 @@ return [ 'DirectoryIterator::setFileClass' => ['void', 'class='=>'class-string'], 'DirectoryIterator::setInfoClass' => ['void', 'class='=>'class-string'], 'DirectoryIterator::valid' => ['bool'], -'dirname' => ['string', 'path'=>'string', 'levels='=>'int'], +'dirname' => ['string', 'path'=>'string', 'levels='=>'int<1, max>'], 'disk_free_space' => ['float|false', 'directory'=>'string'], 'disk_total_space' => ['float|false', 'directory'=>'string'], 'diskfreespace' => ['float|false', 'directory'=>'string'], @@ -1632,7 +1628,6 @@ return [ 'dom_xpath_query' => ['DOMNodeList', 'expr'=>'string', 'context'=>'DOMNode', 'registernodens'=>'bool'], 'dom_xpath_register_ns' => ['bool', 'prefix'=>'string', 'uri'=>'string'], 'dom_xpath_register_php_functions' => [''], -'DomainException::__clone' => ['void'], 'DomainException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'DomainException::__toString' => ['string'], 'DomainException::__wakeup' => ['void'], @@ -2092,7 +2087,6 @@ return [ 'error_get_last' => ['?array{type:int,message:string,file:string,line:int}'], 'error_log' => ['bool', 'message'=>'string', 'message_type='=>'int', 'destination='=>'?string', 'additional_headers='=>'?string'], 'error_reporting' => ['int', 'error_level='=>'?int'], -'ErrorException::__clone' => ['void'], 'ErrorException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'severity='=>'int', 'filename='=>'?string', 'line='=>'?int', 'previous='=>'?Throwable'], 'ErrorException::__toString' => ['string'], 'ErrorException::getCode' => ['int'], @@ -3310,8 +3304,8 @@ return [ 'gethostbyname' => ['string', 'hostname'=>'string'], 'gethostbynamel' => ['list|false', 'hostname'=>'string'], 'gethostname' => ['string|false'], -'getimagesize' => ['array|false', 'filename'=>'string', '&w_image_info='=>'array'], -'getimagesizefromstring' => ['array|false', 'string'=>'string', '&w_image_info='=>'array'], +'getimagesize' => ['array{0:int, 1: int, 2: int, 3: string, mime: string, channels?: 3|4, bits?: int}|false', 'filename'=>'string', '&w_image_info='=>'array'], +'getimagesizefromstring' => ['array{0:int, 1: int, 2: int, 3: string, mime: string, channels?: 3|4, bits?: int}|false', 'string'=>'string', '&w_image_info='=>'array'], 'getlastmod' => ['int|false'], 'getmxrr' => ['bool', 'hostname'=>'string', '&w_hosts'=>'array', '&w_weights='=>'array'], 'getmygid' => ['int|false'], @@ -3329,7 +3323,7 @@ return [ 'gettimeofday' => ['array'], 'gettimeofday\'1' => ['float', 'as_float='=>'true'], 'gettype' => ['string', 'value'=>'mixed'], -'glob' => ['list|false', 'pattern'=>'non-empty-string', 'flags='=>'int<1, max>'], +'glob' => ['false|list{0?:string, ...}', 'pattern'=>'string', 'flags='=>'int<0, max>'], 'GlobIterator::__construct' => ['void', 'pattern'=>'string', 'flags='=>'int'], 'GlobIterator::count' => ['int'], 'GlobIterator::current' => ['FilesystemIterator|SplFileInfo|string'], @@ -3924,7 +3918,7 @@ return [ 'hash_hmac_algos' => ['list'], 'hash_hmac_file' => ['non-empty-string', 'algo'=>'string', 'filename'=>'string', 'key'=>'string', 'binary='=>'bool'], 'hash_init' => ['HashContext', 'algo'=>'string', 'flags='=>'int', 'key='=>'string', 'options='=>'array{seed:scalar}'], -'hash_pbkdf2' => ['non-empty-string', 'algo'=>'string', 'password'=>'string', 'salt'=>'string', 'iterations'=>'int', 'length='=>'int', 'binary='=>'bool'], +'hash_pbkdf2' => ['non-empty-string', 'algo'=>'string', 'password'=>'string', 'salt'=>'string', 'iterations'=>'int', 'length='=>'int', 'binary='=>'bool', 'options=' => 'array'], 'hash_update' => ['bool', 'context'=>'HashContext', 'data'=>'string'], 'hash_update_file' => ['bool', 'context'=>'HashContext', 'filename'=>'string', 'stream_context='=>'?resource'], 'hash_update_stream' => ['int', 'context'=>'HashContext', 'stream'=>'resource', 'length='=>'int'], @@ -4347,10 +4341,10 @@ return [ 'http\Message\Parser::stream' => ['int', 'stream'=>'resource', 'flags'=>'int', '&message'=>'http\Message'], 'http\Params::__construct' => ['void', 'params='=>'mixed', 'param_sep='=>'mixed', 'arg_sep='=>'mixed', 'val_sep='=>'mixed', 'flags='=>'mixed'], 'http\Params::__toString' => ['string'], -'http\Params::offsetExists' => ['bool', 'name'=>'mixed'], -'http\Params::offsetGet' => ['mixed', 'name'=>'mixed'], -'http\Params::offsetSet' => ['void', 'name'=>'mixed', 'value'=>'mixed'], -'http\Params::offsetUnset' => ['void', 'name'=>'mixed'], +'http\Params::offsetExists' => ['bool', 'name'=>'int|string'], +'http\Params::offsetGet' => ['mixed', 'name'=>'int|string'], +'http\Params::offsetSet' => ['void', 'name'=>'int|string|null', 'value'=>'mixed'], +'http\Params::offsetUnset' => ['void', 'name'=>'int|string'], 'http\Params::toArray' => ['array'], 'http\Params::toString' => ['string'], 'http\QueryString::__construct' => ['void', 'querystring'=>'string'], @@ -4365,10 +4359,10 @@ return [ 'http\QueryString::getObject' => ['object|mixed', 'name'=>'string', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::getString' => ['string|mixed', 'name'=>'string', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::mod' => ['http\QueryString', 'params='=>'mixed'], -'http\QueryString::offsetExists' => ['bool', 'offset'=>'mixed'], -'http\QueryString::offsetGet' => ['mixed|null', 'offset'=>'mixed'], -'http\QueryString::offsetSet' => ['void', 'offset'=>'mixed', 'value'=>'mixed'], -'http\QueryString::offsetUnset' => ['void', 'offset'=>'mixed'], +'http\QueryString::offsetExists' => ['bool', 'offset'=>'int|string'], +'http\QueryString::offsetGet' => ['mixed|null', 'offset'=>'int|string'], +'http\QueryString::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], +'http\QueryString::offsetUnset' => ['void', 'offset'=>'int|string'], 'http\QueryString::serialize' => ['string'], 'http\QueryString::set' => ['http\QueryString', 'params'=>'mixed'], 'http\QueryString::toArray' => ['array'], @@ -4492,10 +4486,10 @@ return [ 'HttpQueryString::getObject' => ['', 'name'=>'', 'defval'=>'', 'delete'=>''], 'HttpQueryString::getString' => ['', 'name'=>'', 'defval'=>'', 'delete'=>''], 'HttpQueryString::mod' => ['HttpQueryString', 'params'=>'mixed'], -'HttpQueryString::offsetExists' => ['bool', 'offset'=>'mixed'], -'HttpQueryString::offsetGet' => ['mixed', 'offset'=>'mixed'], -'HttpQueryString::offsetSet' => ['void', 'offset'=>'mixed', 'value'=>'mixed'], -'HttpQueryString::offsetUnset' => ['void', 'offset'=>'mixed'], +'HttpQueryString::offsetExists' => ['bool', 'offset'=>'int|string'], +'HttpQueryString::offsetGet' => ['mixed', 'offset'=>'int|string'], +'HttpQueryString::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], +'HttpQueryString::offsetUnset' => ['void', 'offset'=>'int|string'], 'HttpQueryString::serialize' => ['string'], 'HttpQueryString::set' => ['string', 'params'=>'mixed'], 'HttpQueryString::singleton' => ['HttpQueryString', 'global='=>'bool'], @@ -5580,21 +5574,21 @@ return [ 'imap_body' => ['string|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'flags='=>'int'], 'imap_bodystruct' => ['stdClass|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'section'=>'string'], 'imap_check' => ['stdClass|false', 'imap'=>'IMAP\Connection'], -'imap_clearflag_full' => ['bool', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], -'imap_close' => ['bool', 'imap'=>'IMAP\Connection', 'flags='=>'int'], +'imap_clearflag_full' => ['true', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], +'imap_close' => ['true', 'imap'=>'IMAP\Connection', 'flags='=>'int'], 'imap_create' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], 'imap_createmailbox' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], -'imap_delete' => ['bool', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'flags='=>'int'], +'imap_delete' => ['true', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'flags='=>'int'], 'imap_deletemailbox' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], 'imap_errors' => ['array|false'], -'imap_expunge' => ['bool', 'imap'=>'IMAP\Connection'], +'imap_expunge' => ['true', 'imap'=>'IMAP\Connection'], 'imap_fetch_overview' => ['array|false', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flags='=>'int'], 'imap_fetchbody' => ['string|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'section'=>'string', 'flags='=>'int'], 'imap_fetchheader' => ['string|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'flags='=>'int'], 'imap_fetchmime' => ['string|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'section'=>'string', 'flags='=>'int'], 'imap_fetchstructure' => ['stdClass|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'flags='=>'int'], 'imap_fetchtext' => ['string|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'flags='=>'int'], -'imap_gc' => ['bool', 'imap'=>'IMAP\Connection', 'flags'=>'int'], +'imap_gc' => ['true', 'imap'=>'IMAP\Connection', 'flags'=>'int'], 'imap_get_quota' => ['array|false', 'imap'=>'IMAP\Connection', 'quota_root'=>'string'], 'imap_get_quotaroot' => ['array|false', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], 'imap_getacl' => ['array|false', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], @@ -5635,14 +5629,14 @@ return [ 'imap_search' => ['array|false', 'imap'=>'IMAP\Connection', 'criteria'=>'string', 'flags='=>'int', 'charset='=>'string'], 'imap_set_quota' => ['bool', 'imap'=>'IMAP\Connection', 'quota_root'=>'string', 'mailbox_size'=>'int'], 'imap_setacl' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string', 'user_id'=>'string', 'rights'=>'string'], -'imap_setflag_full' => ['bool', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], +'imap_setflag_full' => ['true', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], 'imap_sort' => ['array|false', 'imap'=>'IMAP\Connection', 'criteria'=>'int', 'reverse'=>'bool', 'flags='=>'int', 'search_criteria='=>'?string', 'charset='=>'?string'], 'imap_status' => ['stdClass|false', 'imap'=>'IMAP\Connection', 'mailbox'=>'string', 'flags'=>'int'], 'imap_subscribe' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], 'imap_thread' => ['array|false', 'imap'=>'IMAP\Connection', 'flags='=>'int'], 'imap_timeout' => ['int|bool', 'timeout_type'=>'int', 'timeout='=>'int'], 'imap_uid' => ['int|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int'], -'imap_undelete' => ['bool', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'flags='=>'int'], +'imap_undelete' => ['true', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'flags='=>'int'], 'imap_unsubscribe' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], 'imap_utf7_decode' => ['string|false', 'string'=>'string'], 'imap_utf7_encode' => ['string', 'string'=>'string'], @@ -5737,11 +5731,11 @@ return [ 'IntlBreakIterator::next' => ['int', 'offset='=>'?int'], 'IntlBreakIterator::preceding' => ['int', 'offset'=>'int'], 'IntlBreakIterator::previous' => ['int'], -'IntlBreakIterator::setText' => ['?bool', 'text'=>'string'], +'IntlBreakIterator::setText' => ['bool', 'text'=>'string'], 'intlcal_add' => ['bool', 'calendar'=>'IntlCalendar', 'field'=>'int', 'value'=>'int'], 'intlcal_after' => ['bool', 'calendar'=>'IntlCalendar', 'other'=>'IntlCalendar'], 'intlcal_before' => ['bool', 'calendar'=>'IntlCalendar', 'other'=>'IntlCalendar'], -'intlcal_clear' => ['bool', 'calendar'=>'IntlCalendar', 'field='=>'?int'], +'intlcal_clear' => ['true', 'calendar'=>'IntlCalendar', 'field='=>'?int'], 'intlcal_create_instance' => ['?IntlCalendar', 'timezone='=>'mixed', 'locale='=>'?string'], 'intlcal_equals' => ['bool', 'calendar'=>'IntlCalendar', 'other'=>'IntlCalendar'], 'intlcal_field_difference' => ['int|false', 'calendar'=>'IntlCalendar', 'timestamp'=>'float', 'field'=>'int'], @@ -5774,8 +5768,8 @@ return [ 'intlcal_roll' => ['bool', 'calendar'=>'IntlCalendar', 'field'=>'int', 'value'=>'mixed'], 'intlcal_set' => ['bool', 'calendar'=>'IntlCalendar', 'year'=>'int', 'month'=>'int'], 'intlcal_set\'1' => ['bool', 'calendar'=>'IntlCalendar', 'year'=>'int', 'month'=>'int', 'dayOfMonth='=>'int', 'hour='=>'int', 'minute='=>'int', 'second='=>'int'], -'intlcal_set_first_day_of_week' => ['bool', 'calendar'=>'IntlCalendar', 'dayOfWeek'=>'int'], -'intlcal_set_lenient' => ['bool', 'calendar'=>'IntlCalendar', 'lenient'=>'bool'], +'intlcal_set_first_day_of_week' => ['true', 'calendar'=>'IntlCalendar', 'dayOfWeek'=>'int'], +'intlcal_set_lenient' => ['true', 'calendar'=>'IntlCalendar', 'lenient'=>'bool'], 'intlcal_set_repeated_wall_time_option' => ['true', 'calendar'=>'IntlCalendar', 'option'=>'int'], 'intlcal_set_skipped_wall_time_option' => ['true', 'calendar'=>'IntlCalendar', 'option'=>'int'], 'intlcal_set_time' => ['bool', 'calendar'=>'IntlCalendar', 'timestamp'=>'float'], @@ -5837,7 +5831,7 @@ return [ 'IntlChar::charType' => ['?int', 'codepoint'=>'int|string'], 'IntlChar::chr' => ['?string', 'codepoint'=>'int|string'], 'IntlChar::digit' => ['int|false|null', 'codepoint'=>'int|string', 'base='=>'int'], -'IntlChar::enumCharNames' => ['?bool', 'start'=>'string|int', 'end'=>'string|int', 'callback'=>'callable(int,int,int):void', 'type='=>'int'], +'IntlChar::enumCharNames' => ['bool', 'start'=>'string|int', 'end'=>'string|int', 'callback'=>'callable(int,int,int):void', 'type='=>'int'], 'IntlChar::enumCharTypes' => ['void', 'callback'=>'callable(int,int,int):void'], 'IntlChar::foldCase' => ['int|string|null', 'codepoint'=>'int|string', 'options='=>'int'], 'IntlChar::forDigit' => ['int', 'digit'=>'int', 'base='=>'int'], @@ -5887,7 +5881,6 @@ return [ 'IntlChar::tolower' => ['int|string|null', 'codepoint'=>'int|string'], 'IntlChar::totitle' => ['int|string|null', 'codepoint'=>'int|string'], 'IntlChar::toupper' => ['int|string|null', 'codepoint'=>'int|string'], -'IntlCodePointBreakIterator::__construct' => ['void'], 'IntlCodePointBreakIterator::createCharacterInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlCodePointBreakIterator::createCodePointInstance' => ['IntlCodePointBreakIterator'], 'IntlCodePointBreakIterator::createLineInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], @@ -5908,7 +5901,7 @@ return [ 'IntlCodePointBreakIterator::next' => ['int', 'offset='=>'?int'], 'IntlCodePointBreakIterator::preceding' => ['int', 'offset'=>'int'], 'IntlCodePointBreakIterator::previous' => ['int'], -'IntlCodePointBreakIterator::setText' => ['?bool', 'text'=>'string'], +'IntlCodePointBreakIterator::setText' => ['bool', 'text'=>'string'], 'IntlDateFormatter::__construct' => ['void', 'locale'=>'?string', 'dateType='=>'int', 'timeType='=>'int', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'?string'], 'IntlDateFormatter::create' => ['?IntlDateFormatter', 'locale'=>'?string', 'dateType='=>'int', 'timeType='=>'int', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'?string'], 'IntlDateFormatter::format' => ['string|false', 'datetime'=>'IntlCalendar|DateTimeInterface|array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int}|array{tm_sec: int, tm_min: int, tm_hour: int, tm_mday: int, tm_mon: int, tm_year: int, tm_wday: int, tm_yday: int, tm_isdst: int}|string|int|float'], @@ -5929,8 +5922,7 @@ return [ 'IntlDateFormatter::setCalendar' => ['bool', 'calendar'=>'IntlCalendar|int|null'], 'IntlDateFormatter::setLenient' => ['void', 'lenient'=>'bool'], 'IntlDateFormatter::setPattern' => ['bool', 'pattern'=>'string'], -'IntlDateFormatter::setTimeZone' => ['null|false', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], -'IntlException::__clone' => ['void'], +'IntlDateFormatter::setTimeZone' => ['bool', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], 'IntlException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'IntlException::__toString' => ['string'], 'IntlException::__wakeup' => ['void'], @@ -6026,7 +6018,7 @@ return [ 'IntlRuleBasedBreakIterator::next' => ['int', 'offset='=>'?int'], 'IntlRuleBasedBreakIterator::preceding' => ['int', 'offset'=>'int'], 'IntlRuleBasedBreakIterator::previous' => ['int'], -'IntlRuleBasedBreakIterator::setText' => ['?bool', 'text'=>'string'], +'IntlRuleBasedBreakIterator::setText' => ['bool', 'text'=>'string'], 'IntlTimeZone::countEquivalentIDs' => ['int|false', 'timezoneId'=>'string'], 'IntlTimeZone::createDefault' => ['IntlTimeZone'], 'IntlTimeZone::createEnumeration' => ['IntlIterator|false', 'countryOrRawOffset='=>'IntlTimeZone|string|int|float|null'], @@ -6071,7 +6063,6 @@ return [ 'intltz_use_daylight_time' => ['bool', 'timezone'=>'IntlTimeZone'], 'intlz_create_default' => ['IntlTimeZone'], 'intval' => ['int', 'value'=>'mixed', 'base='=>'int'], -'InvalidArgumentException::__clone' => ['void'], 'InvalidArgumentException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'InvalidArgumentException::__toString' => ['string'], 'InvalidArgumentException::getCode' => ['int'], @@ -6157,7 +6148,6 @@ return [ 'json_last_error' => ['int'], 'json_last_error_msg' => ['string'], 'json_validate' => ['bool', 'json'=>'string', 'depth='=>'positive-int', 'flags='=>'int'], -'JsonException::__clone' => ['void'], 'JsonException::__construct' => ['void', "message="=>"string", 'code='=>'int', 'previous='=>'?Throwable'], 'JsonException::__toString' => ['string'], 'JsonException::__wakeup' => ['void'], @@ -6188,10 +6178,10 @@ return [ 'Judy::memoryUsage' => ['int'], 'Judy::next' => ['mixed', 'index'=>'mixed'], 'Judy::nextEmpty' => ['mixed', 'index'=>'mixed'], -'Judy::offsetExists' => ['bool', 'offset'=>'mixed'], -'Judy::offsetGet' => ['mixed', 'offset'=>'mixed'], -'Judy::offsetSet' => ['bool', 'offset'=>'mixed', 'value'=>'mixed'], -'Judy::offsetUnset' => ['bool', 'offset'=>'mixed'], +'Judy::offsetExists' => ['bool', 'offset'=>'int|string'], +'Judy::offsetGet' => ['mixed', 'offset'=>'int|string'], +'Judy::offsetSet' => ['bool', 'offset'=>'int|string|null', 'value'=>'mixed'], +'Judy::offsetUnset' => ['bool', 'offset'=>'int|string'], 'Judy::prev' => ['mixed', 'index'=>'mixed'], 'Judy::prevEmpty' => ['mixed', 'index'=>'mixed'], 'Judy::size' => ['int'], @@ -6384,7 +6374,6 @@ return [ 'legendObj::free' => ['void'], 'legendObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'legendObj::updateFromString' => ['int', 'snippet'=>'string'], -'LengthException::__clone' => ['void'], 'LengthException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'LengthException::__toString' => ['string'], 'LengthException::getCode' => ['int'], @@ -6497,7 +6486,6 @@ return [ 'log' => ['float', 'num'=>'float', 'base='=>'float'], 'log10' => ['float', 'num'=>'float'], 'log1p' => ['float', 'num'=>'float'], -'LogicException::__clone' => ['void'], 'LogicException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'LogicException::__toString' => ['string'], 'LogicException::getCode' => ['int'], @@ -7059,6 +7047,14 @@ return [ 'MongoDB::setReadPreference' => ['bool', 'read_preference'=>'string', 'tags='=>'array'], 'MongoDB::setSlaveOkay' => ['bool', 'ok='=>'bool'], 'MongoDB::setWriteConcern' => ['bool', 'w'=>'mixed', 'wtimeout='=>'int'], +'MongoDB\BSON\fromJSON' => ['string', 'json' => 'string'], +'MongoDB\BSON\fromPHP' => ['string', 'value' => 'object|array'], +'MongoDB\BSON\toCanonicalExtendedJSON' => ['string', 'bson' => 'string'], +'MongoDB\BSON\toJSON' => ['string', 'bson' => 'string'], +'MongoDB\BSON\toPHP' => ['object|array', 'bson' => 'string', 'typemap=' => '?array'], +'MongoDB\BSON\toRelaxedExtendedJSON' => ['string', 'bson' => 'string'], +'MongoDB\Driver\Monitoring\addSubscriber' => ['void', 'subscriber' => 'MongoDB\Driver\Monitoring\Subscriber'], +'MongoDB\Driver\Monitoring\removeSubscriber' => ['void', 'subscriber' => 'MongoDB\Driver\Monitoring\Subscriber'], 'MongoDB\BSON\Binary::__construct' => ['void', 'data' => 'string', 'type=' => 'int'], 'MongoDB\BSON\Binary::getData' => ['string'], 'MongoDB\BSON\Binary::getType' => ['int'], @@ -7079,10 +7075,28 @@ return [ 'MongoDB\BSON\Decimal128::unserialize' => ['void', 'serialized' => 'string'], 'MongoDB\BSON\Decimal128::jsonSerialize' => ['mixed'], 'MongoDB\BSON\Decimal128Interface::__toString' => ['string'], +'MongoDB\BSON\Document::fromBSON' => ['MongoDB\BSON\Document', 'bson' => 'string'], +'MongoDB\BSON\Document::fromJSON' => ['MongoDB\BSON\Document', 'json' => 'string'], +'MongoDB\BSON\Document::fromPHP' => ['MongoDB\BSON\Document', 'value' => 'object|array'], +'MongoDB\BSON\Document::get' => ['mixed', 'key' => 'string'], +'MongoDB\BSON\Document::getIterator' => ['MongoDB\BSON\Iterator'], +'MongoDB\BSON\Document::has' => ['bool', 'key' => 'string'], +'MongoDB\BSON\Document::toPHP' => ['object|array', 'typeMap=' => '?array'], +'MongoDB\BSON\Document::toCanonicalExtendedJSON' => ['string'], +'MongoDB\BSON\Document::toRelaxedExtendedJSON' => ['string'], +'MongoDB\BSON\Document::__toString' => ['string'], +'MongoDB\BSON\Document::serialize' => ['string'], +'MongoDB\BSON\Document::unserialize' => ['void', 'serialized' => 'string'], +'MongoDB\BSON\Int64::__construct' => ['void', 'value' => 'string|int'], 'MongoDB\BSON\Int64::__toString' => ['string'], 'MongoDB\BSON\Int64::serialize' => ['string'], 'MongoDB\BSON\Int64::unserialize' => ['void', 'serialized' => 'string'], 'MongoDB\BSON\Int64::jsonSerialize' => ['mixed'], +'MongoDB\BSON\Iterator::current' => ['mixed'], +'MongoDB\BSON\Iterator::key' => ['string|int'], +'MongoDB\BSON\Iterator::next' => ['void'], +'MongoDB\BSON\Iterator::rewind' => ['void'], +'MongoDB\BSON\Iterator::valid' => ['bool'], 'MongoDB\BSON\Javascript::__construct' => ['void', 'code' => 'string', 'scope=' => 'object|array|null'], 'MongoDB\BSON\Javascript::getCode' => ['string'], 'MongoDB\BSON\Javascript::getScope' => ['?object'], @@ -7107,6 +7121,14 @@ return [ 'MongoDB\BSON\ObjectId::jsonSerialize' => ['mixed'], 'MongoDB\BSON\ObjectIdInterface::getTimestamp' => ['int'], 'MongoDB\BSON\ObjectIdInterface::__toString' => ['string'], +'MongoDB\BSON\PackedArray::fromPHP' => ['MongoDB\BSON\PackedArray', 'value' => 'array'], +'MongoDB\BSON\PackedArray::get' => ['mixed', 'index' => 'int'], +'MongoDB\BSON\PackedArray::getIterator' => ['MongoDB\BSON\Iterator'], +'MongoDB\BSON\PackedArray::has' => ['bool', 'index' => 'int'], +'MongoDB\BSON\PackedArray::toPHP' => ['object|array', 'typeMap=' => '?array'], +'MongoDB\BSON\PackedArray::__toString' => ['string'], +'MongoDB\BSON\PackedArray::serialize' => ['string'], +'MongoDB\BSON\PackedArray::unserialize' => ['void', 'serialized' => 'string'], 'MongoDB\BSON\Regex::__construct' => ['void', 'pattern' => 'string', 'flags=' => 'string'], 'MongoDB\BSON\Regex::getPattern' => ['string'], 'MongoDB\BSON\Regex::getFlags' => ['string'], @@ -7156,6 +7178,7 @@ return [ 'MongoDB\Driver\ClientEncryption::decrypt' => ['mixed', 'value' => 'MongoDB\BSON\Binary'], 'MongoDB\Driver\ClientEncryption::deleteKey' => ['object', 'keyId' => 'MongoDB\BSON\Binary'], 'MongoDB\Driver\ClientEncryption::encrypt' => ['MongoDB\BSON\Binary', 'value' => 'mixed', 'options=' => '?array'], +'MongoDB\Driver\ClientEncryption::encryptExpression' => ['object', 'expr' => 'object|array', 'options=' => '?array'], 'MongoDB\Driver\ClientEncryption::getKey' => ['?object', 'keyId' => 'MongoDB\BSON\Binary'], 'MongoDB\Driver\ClientEncryption::getKeyByAltName' => ['?object', 'keyAltName' => 'string'], 'MongoDB\Driver\ClientEncryption::getKeys' => ['MongoDB\Driver\Cursor'], @@ -7367,6 +7390,7 @@ return [ 'MongoDB\Driver\WriteResult::getUpsertedIds' => ['array'], 'MongoDB\Driver\WriteResult::getWriteConcernError' => ['?MongoDB\Driver\WriteConcernError'], 'MongoDB\Driver\WriteResult::getWriteErrors' => ['array'], +'MongoDB\Driver\WriteResult::getErrorReplies' => ['array'], 'MongoDB\Driver\WriteResult::isAcknowledged' => ['bool'], 'MongoDBRef::create' => ['array', 'collection'=>'string', 'id'=>'mixed', 'database='=>'string'], 'MongoDBRef::get' => ['?array', 'db'=>'MongoDB', 'ref'=>'array'], @@ -7615,7 +7639,7 @@ return [ 'mt_getrandmax' => ['int'], 'mt_rand' => ['int', 'min'=>'int', 'max'=>'int'], 'mt_rand\'1' => ['int'], -'mt_srand' => ['void', 'seed='=>'int', 'mode='=>'int'], +'mt_srand' => ['void', 'seed='=>'?int', 'mode='=>'int'], 'MultipleIterator::__construct' => ['void', 'flags='=>'int'], 'MultipleIterator::attachIterator' => ['void', 'iterator'=>'Iterator', 'info='=>'string|int|null'], 'MultipleIterator::containsIterator' => ['bool', 'iterator'=>'Iterator'], @@ -8092,8 +8116,8 @@ return [ 'MysqlndUhPreparedStatement::__construct' => ['void'], 'MysqlndUhPreparedStatement::execute' => ['bool', 'statement'=>'mysqlnd_prepared_statement'], 'MysqlndUhPreparedStatement::prepare' => ['bool', 'statement'=>'mysqlnd_prepared_statement', 'query'=>'string'], -'natcasesort' => ['bool', '&rw_array'=>'array'], -'natsort' => ['bool', '&rw_array'=>'array'], +'natcasesort' => ['true', '&rw_array'=>'array'], +'natsort' => ['true', '&rw_array'=>'array'], 'net_get_interfaces' => ['array>|false'], 'newrelic_add_custom_parameter' => ['bool', 'key'=>'string', 'value'=>'bool|float|int|string'], 'newrelic_add_custom_tracer' => ['bool', 'function_name'=>'string'], @@ -8502,7 +8526,6 @@ return [ 'OuterIterator::next' => ['void'], 'OuterIterator::rewind' => ['void'], 'OuterIterator::valid' => ['bool'], -'OutOfBoundsException::__clone' => ['void'], 'OutOfBoundsException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'OutOfBoundsException::__toString' => ['string'], 'OutOfBoundsException::getCode' => ['int'], @@ -8512,7 +8535,6 @@ return [ 'OutOfBoundsException::getPrevious' => ['?Throwable'], 'OutOfBoundsException::getTrace' => ['list\',args?:array}>'], 'OutOfBoundsException::getTraceAsString' => ['string'], -'OutOfRangeException::__clone' => ['void'], 'OutOfRangeException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'OutOfRangeException::__toString' => ['string'], 'OutOfRangeException::getCode' => ['int'], @@ -8539,7 +8561,6 @@ return [ 'outputformatObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'outputformatObj::setOption' => ['void', 'property_name'=>'string', 'new_value'=>'string'], 'outputformatObj::validate' => ['int'], -'OverflowException::__clone' => ['void'], 'OverflowException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'OverflowException::__toString' => ['string'], 'OverflowException::getCode' => ['int'], @@ -8631,7 +8652,6 @@ return [ 'parse_ini_string' => ['array|false', 'ini_string'=>'string', 'process_sections='=>'bool', 'scanner_mode='=>'int'], 'parse_str' => ['void', 'string'=>'string', '&w_result'=>'array'], 'parse_url' => ['int|string|array|null|false', 'url'=>'string', 'component='=>'int'], -'ParseError::__clone' => ['void'], 'ParseError::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'ParseError::__toString' => ['string'], 'ParseError::getCode' => ['int'], @@ -9363,7 +9383,7 @@ return [ 'posix_getppid' => ['int'], 'posix_getpwnam' => ['array{name: string, passwd: string, uid: int, gid: int, gecos: string, dir: string, shell: string}|false', 'username'=>'string'], 'posix_getpwuid' => ['array{name: string, passwd: string, uid: int, gid: int, gecos: string, dir: string, shell: string}|false', 'user_id'=>'int'], -'posix_getrlimit' => ['array{"soft core": string, "hard core": string, "soft data": string, "hard data": string, "soft stack": integer, "hard stack": string, "soft totalmem": string, "hard totalmem": string, "soft rss": string, "hard rss": string, "soft maxproc": integer, "hard maxproc": integer, "soft memlock": integer, "hard memlock": integer, "soft cpu": string, "hard cpu": string, "soft filesize": string, "hard filesize": string, "soft openfiles": integer, "hard openfiles": integer}|false'], +'posix_getrlimit' => ['array{"soft core": string, "hard core": string, "soft data": string, "hard data": string, "soft stack": integer, "hard stack": string, "soft totalmem": string, "hard totalmem": string, "soft rss": string, "hard rss": string, "soft maxproc": integer, "hard maxproc": integer, "soft memlock": integer, "hard memlock": integer, "soft cpu": string, "hard cpu": string, "soft filesize": string, "hard filesize": string, "soft openfiles": integer, "hard openfiles": integer}|false', 'resource=' => '?int'], 'posix_getsid' => ['int|false', 'process_id'=>'int'], 'posix_getuid' => ['int'], 'posix_initgroups' => ['bool', 'username'=>'string', 'group_id'=>'int'], @@ -9403,7 +9423,7 @@ return [ 'print' => ['int', 'arg'=>'string'], 'print_r' => ['string', 'value'=>'mixed'], 'print_r\'1' => ['true', 'value'=>'mixed', 'return='=>'bool'], -'printf' => ['int', 'format'=>'string', '...values='=>'string|int|float'], +'printf' => ['int<0, max>', 'format'=>'string', '...values='=>'string|int|float'], 'proc_close' => ['int', 'process'=>'resource'], 'proc_get_status' => ['array{command: string, pid: int, running: bool, signaled: bool, stopped: bool, exitcode: int, termsig: int, stopsig: int}', 'process'=>'resource'], 'proc_nice' => ['bool', 'priority'=>'int'], @@ -9624,7 +9644,6 @@ return [ 'random_bytes' => ['non-empty-string', 'length'=>'positive-int'], 'random_int' => ['int', 'min'=>'int', 'max'=>'int'], 'range' => ['non-empty-array', 'start'=>'string|int|float', 'end'=>'string|int|float', 'step='=>'int<1, max>|float'], -'RangeException::__clone' => ['void'], 'RangeException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'RangeException::__toString' => ['string'], 'RangeException::getCode' => ['int'], @@ -9814,7 +9833,7 @@ return [ 'RecursiveArrayIterator::next' => ['void'], 'RecursiveArrayIterator::offsetExists' => ['bool', 'key'=>'string|int'], 'RecursiveArrayIterator::offsetGet' => ['mixed', 'key'=>'string|int'], -'RecursiveArrayIterator::offsetSet' => ['void', 'key'=>'string|int', 'value'=>'string'], +'RecursiveArrayIterator::offsetSet' => ['void', 'key'=>'string|int|null', 'value'=>'string'], 'RecursiveArrayIterator::offsetUnset' => ['void', 'key'=>'string|int'], 'RecursiveArrayIterator::rewind' => ['void'], 'RecursiveArrayIterator::seek' => ['void', 'offset'=>'int'], @@ -10624,12 +10643,10 @@ return [ 'ReflectionMethod::isVariadic' => ['bool'], 'ReflectionMethod::returnsReference' => ['bool'], 'ReflectionMethod::setAccessible' => ['void', 'accessible'=>'bool'], -'ReflectionNamedType::__clone' => ['void'], 'ReflectionNamedType::__toString' => ['string'], 'ReflectionNamedType::allowsNull' => ['bool'], 'ReflectionNamedType::getName' => ['string'], 'ReflectionNamedType::isBuiltin' => ['bool'], -'ReflectionObject::__clone' => ['void'], 'ReflectionObject::__construct' => ['void', 'object'=>'object'], 'ReflectionObject::__toString' => ['string'], 'ReflectionObject::getConstant' => ['mixed', 'name'=>'string'], @@ -10814,7 +10831,7 @@ return [ 'RRDGraph::setOptions' => ['void', 'options'=>'array'], 'RRDUpdater::__construct' => ['void', 'path'=>'string'], 'RRDUpdater::update' => ['bool', 'values'=>'array', 'time='=>'string'], -'rsort' => ['bool', '&rw_array'=>'array', 'flags='=>'int'], +'rsort' => ['true', '&rw_array'=>'array', 'flags='=>'int'], 'rtrim' => ['string', 'string'=>'string', 'characters='=>'string'], 'runkit7_constant_add' => ['bool', 'constant_name'=>'string', 'value'=>'mixed', 'new_visibility='=>'int'], 'runkit7_constant_redefine' => ['bool', 'constant_name'=>'string', 'value'=>'mixed', 'new_visibility='=>'?int'], @@ -10861,7 +10878,6 @@ return [ 'Runkit_Sandbox_Parent::__construct' => ['void'], 'runkit_superglobals' => ['array'], 'runkit_zval_inspect' => ['array', 'value'=>'mixed'], -'RuntimeException::__clone' => ['void'], 'RuntimeException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'RuntimeException::__toString' => ['string'], 'RuntimeException::getCode' => ['int'], @@ -11303,7 +11319,7 @@ return [ 'SimpleXMLElement::getNamespaces' => ['array', 'recursive='=>'bool'], 'SimpleXMLElement::offsetExists' => ['bool', 'offset'=>'int|string'], 'SimpleXMLElement::offsetGet' => ['SimpleXMLElement', 'offset'=>'int|string'], -'SimpleXMLElement::offsetSet' => ['void', 'offset'=>'int|string', 'value'=>'mixed'], +'SimpleXMLElement::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], 'SimpleXMLElement::offsetUnset' => ['void', 'offset'=>'int|string'], 'SimpleXMLElement::registerXPathNamespace' => ['bool', 'prefix'=>'string', 'namespace'=>'string'], 'SimpleXMLElement::saveXML' => ['string|bool', 'filename='=>'?string'], @@ -12721,7 +12737,7 @@ return [ 'sqlsrv_send_stream_data' => ['bool', 'stmt'=>'resource'], 'sqlsrv_server_info' => ['array', 'conn'=>'resource'], 'sqrt' => ['float', 'num'=>'float'], -'srand' => ['void', 'seed='=>'int', 'mode='=>'int'], +'srand' => ['void', 'seed='=>'?int', 'mode='=>'int'], 'sscanf' => ['list|int|null', 'string'=>'string', 'format'=>'string', '&...w_vars='=>'string|int|float|null'], 'ssdeep_fuzzy_compare' => ['int', 'signature1'=>'string', 'signature2'=>'string'], 'ssdeep_fuzzy_hash' => ['string', 'to_hash'=>'string'], @@ -13616,10 +13632,10 @@ return [ 'Thread::merge' => ['bool', 'from'=>'', 'overwrite='=>'mixed'], 'Thread::notify' => ['bool'], 'Thread::notifyOne' => ['bool'], -'Thread::offsetExists' => ['bool', 'offset'=>'mixed'], -'Thread::offsetGet' => ['mixed', 'offset'=>'mixed'], -'Thread::offsetSet' => ['void', 'offset'=>'mixed', 'value'=>'mixed'], -'Thread::offsetUnset' => ['void', 'offset'=>'mixed'], +'Thread::offsetExists' => ['bool', 'offset'=>'int|string'], +'Thread::offsetGet' => ['mixed', 'offset'=>'int|string'], +'Thread::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], +'Thread::offsetUnset' => ['void', 'offset'=>'int|string'], 'Thread::pop' => ['bool'], 'Thread::run' => ['void'], 'Thread::setGarbage' => ['void'], @@ -13645,10 +13661,10 @@ return [ 'Threaded::merge' => ['bool', 'from'=>'mixed', 'overwrite='=>'bool'], 'Threaded::notify' => ['bool'], 'Threaded::notifyOne' => ['bool'], -'Threaded::offsetExists' => ['bool', 'offset'=>'mixed'], -'Threaded::offsetGet' => ['mixed', 'offset'=>'mixed'], -'Threaded::offsetSet' => ['void', 'offset'=>'mixed', 'value'=>'mixed'], -'Threaded::offsetUnset' => ['void', 'offset'=>'mixed'], +'Threaded::offsetExists' => ['bool', 'offset'=>'int|string'], +'Threaded::offsetGet' => ['mixed', 'offset'=>'int|string'], +'Threaded::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], +'Threaded::offsetUnset' => ['void', 'offset'=>'int|string'], 'Threaded::pop' => ['bool'], 'Threaded::run' => ['void'], 'Threaded::setGarbage' => ['void'], @@ -13973,7 +13989,6 @@ return [ 'transliterator_transliterate' => ['string|false', 'transliterator'=>'Transliterator|string', 'string'=>'string', 'start='=>'int', 'end='=>'int'], 'trigger_error' => ['bool', 'message'=>'string', 'error_level='=>'256|512|1024|16384'], 'trim' => ['string', 'string'=>'string', 'characters='=>'string'], -'TypeError::__clone' => ['void'], 'TypeError::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'TypeError::__toString' => ['string'], 'TypeError::getCode' => ['int'], @@ -14196,7 +14211,6 @@ return [ 'ui\window::setTitle' => ['', 'title'=>'string'], 'uksort' => ['true', '&rw_array'=>'array', 'callback'=>'callable(mixed,mixed):int'], 'umask' => ['int', 'mask='=>'?int'], -'UnderflowException::__clone' => ['void'], 'UnderflowException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'UnderflowException::__toString' => ['string'], 'UnderflowException::getCode' => ['int'], @@ -14206,7 +14220,6 @@ return [ 'UnderflowException::getPrevious' => ['?Throwable'], 'UnderflowException::getTrace' => ['list\',args?:array}>'], 'UnderflowException::getTraceAsString' => ['string'], -'UnexpectedValueException::__clone' => ['void'], 'UnexpectedValueException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'UnexpectedValueException::__toString' => ['string'], 'UnexpectedValueException::getCode' => ['int'], @@ -14364,7 +14377,7 @@ return [ 'VarnishStat::getSnapshot' => ['array'], 'version_compare' => ['bool', 'version1'=>'string', 'version2'=>'string', 'operator'=>'\'<\'|\'lt\'|\'<=\'|\'le\'|\'>\'|\'gt\'|\'>=\'|\'ge\'|\'==\'|\'=\'|\'eq\'|\'!=\'|\'<>\'|\'ne\''], 'version_compare\'1' => ['int', 'version1'=>'string', 'version2'=>'string'], -'vfprintf' => ['int', 'stream'=>'resource', 'format'=>'string', 'values'=>'array'], +'vfprintf' => ['int<0, max>', 'stream'=>'resource', 'format'=>'string', 'values'=>'array'], 'virtual' => ['bool', 'uri'=>'string'], 'vpopmail_add_alias_domain' => ['bool', 'domain'=>'string', 'aliasdomain'=>'string'], 'vpopmail_add_alias_domain_ex' => ['bool', 'olddomain'=>'string', 'newdomain'=>'string'], @@ -14383,8 +14396,8 @@ return [ 'vpopmail_error' => ['string'], 'vpopmail_passwd' => ['bool', 'user'=>'string', 'domain'=>'string', 'password'=>'string', 'apop='=>'bool'], 'vpopmail_set_user_quota' => ['bool', 'user'=>'string', 'domain'=>'string', 'quota'=>'string'], -'vprintf' => ['int', 'format'=>'string', 'values'=>'array'], -'vsprintf' => ['string', 'format'=>'string', 'values'=>'array'], +'vprintf' => ['int<0, max>', 'format'=>'string', 'values'=>'array'], +'vsprintf' => ['string', 'format'=>'string', 'values'=>'array'], 'Vtiful\Kernel\Chart::__construct' => ['void', 'handle'=>'resource', 'type'=>'int'], 'Vtiful\Kernel\Chart::axisNameX' => ['Vtiful\Kernel\Chart', 'name'=>'string'], 'Vtiful\Kernel\Chart::axisNameY' => ['Vtiful\Kernel\Chart', 'name'=>'string'], @@ -14570,10 +14583,10 @@ return [ 'Worker::merge' => ['bool', 'from'=>'', 'overwrite='=>'mixed'], 'Worker::notify' => ['bool'], 'Worker::notifyOne' => ['bool'], -'Worker::offsetExists' => ['bool', 'offset'=>'mixed'], -'Worker::offsetGet' => ['mixed', 'offset'=>'mixed'], -'Worker::offsetSet' => ['void', 'offset'=>'mixed', 'value'=>'mixed'], -'Worker::offsetUnset' => ['void', 'offset'=>'mixed'], +'Worker::offsetExists' => ['bool', 'offset'=>'int|string'], +'Worker::offsetGet' => ['mixed', 'offset'=>'int|string'], +'Worker::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], +'Worker::offsetUnset' => ['void', 'offset'=>'int|string'], 'Worker::pop' => ['bool'], 'Worker::run' => ['void'], 'Worker::setGarbage' => ['void'], @@ -14903,10 +14916,10 @@ return [ 'Yaf\Config\Ini::get' => ['mixed', 'name='=>'mixed'], 'Yaf\Config\Ini::key' => ['int|string'], 'Yaf\Config\Ini::next' => ['void'], -'Yaf\Config\Ini::offsetExists' => ['bool', 'name'=>'mixed'], -'Yaf\Config\Ini::offsetGet' => ['mixed', 'name'=>'mixed'], -'Yaf\Config\Ini::offsetSet' => ['void', 'name'=>'mixed', 'value'=>'mixed'], -'Yaf\Config\Ini::offsetUnset' => ['void', 'name'=>'mixed'], +'Yaf\Config\Ini::offsetExists' => ['bool', 'name'=>'int|string'], +'Yaf\Config\Ini::offsetGet' => ['mixed', 'name'=>'int|string'], +'Yaf\Config\Ini::offsetSet' => ['void', 'name'=>'int|string|null', 'value'=>'mixed'], +'Yaf\Config\Ini::offsetUnset' => ['void', 'name'=>'int|string'], 'Yaf\Config\Ini::readonly' => ['bool'], 'Yaf\Config\Ini::rewind' => ['void'], 'Yaf\Config\Ini::set' => ['Yaf\Config_Abstract', 'name'=>'string', 'value'=>'mixed'], @@ -14921,10 +14934,10 @@ return [ 'Yaf\Config\Simple::get' => ['mixed', 'name='=>'mixed'], 'Yaf\Config\Simple::key' => ['int|string'], 'Yaf\Config\Simple::next' => ['void'], -'Yaf\Config\Simple::offsetExists' => ['bool', 'name'=>'mixed'], -'Yaf\Config\Simple::offsetGet' => ['mixed', 'name'=>'mixed'], -'Yaf\Config\Simple::offsetSet' => ['void', 'name'=>'mixed', 'value'=>'mixed'], -'Yaf\Config\Simple::offsetUnset' => ['void', 'name'=>'mixed'], +'Yaf\Config\Simple::offsetExists' => ['bool', 'name'=>'int|string'], +'Yaf\Config\Simple::offsetGet' => ['mixed', 'name'=>'int|string'], +'Yaf\Config\Simple::offsetSet' => ['void', 'name'=>'int|string|null', 'value'=>'mixed'], +'Yaf\Config\Simple::offsetUnset' => ['void', 'name'=>'int|string'], 'Yaf\Config\Simple::readonly' => ['bool'], 'Yaf\Config\Simple::rewind' => ['void'], 'Yaf\Config\Simple::set' => ['Yaf\Config_Abstract', 'name'=>'string', 'value'=>'mixed'], @@ -15191,10 +15204,10 @@ return [ 'Yaf\Session::has' => ['bool', 'name'=>'string'], 'Yaf\Session::key' => ['int|string'], 'Yaf\Session::next' => ['void'], -'Yaf\Session::offsetExists' => ['bool', 'name'=>'mixed'], -'Yaf\Session::offsetGet' => ['mixed', 'name'=>'mixed'], -'Yaf\Session::offsetSet' => ['void', 'name'=>'mixed', 'value'=>'mixed'], -'Yaf\Session::offsetUnset' => ['void', 'name'=>'mixed'], +'Yaf\Session::offsetExists' => ['bool', 'name'=>'int|string'], +'Yaf\Session::offsetGet' => ['mixed', 'name'=>'int|string'], +'Yaf\Session::offsetSet' => ['void', 'name'=>'int|string|null', 'value'=>'mixed'], +'Yaf\Session::offsetUnset' => ['void', 'name'=>'int|string'], 'Yaf\Session::rewind' => ['void'], 'Yaf\Session::set' => ['Yaf\Session|false', 'name'=>'string', 'value'=>'mixed'], 'Yaf\Session::start' => ['Yaf\Session'], diff --git a/vendor/vimeo/psalm/dictionaries/CallMap_83_delta.php b/vendor/vimeo/psalm/dictionaries/CallMap_83_delta.php index 2d27020d..9bcf76de 100644 --- a/vendor/vimeo/psalm/dictionaries/CallMap_83_delta.php +++ b/vendor/vimeo/psalm/dictionaries/CallMap_83_delta.php @@ -25,8 +25,124 @@ return [ 'old' => ['array{runs:int,collected:int,threshold:int,roots:int}'], 'new' => ['array{runs:int,collected:int,threshold:int,roots:int,running:bool,protected:bool,full:bool,buffer_size:int}'], ], + 'srand' => [ + 'old' => ['void', 'seed='=>'int', 'mode='=>'int'], + 'new' => ['void', 'seed='=>'?int', 'mode='=>'int'], + ], + 'mt_srand' => [ + 'old' => ['void', 'seed='=>'int', 'mode='=>'int'], + 'new' =>['void', 'seed='=>'?int', 'mode='=>'int'], + ], + 'posix_getrlimit' => [ + 'old' => ['array{"soft core": string, "hard core": string, "soft data": string, "hard data": string, "soft stack": integer, "hard stack": string, "soft totalmem": string, "hard totalmem": string, "soft rss": string, "hard rss": string, "soft maxproc": integer, "hard maxproc": integer, "soft memlock": integer, "hard memlock": integer, "soft cpu": string, "hard cpu": string, "soft filesize": string, "hard filesize": string, "soft openfiles": integer, "hard openfiles": integer}|false'], + 'new' => ['array{"soft core": string, "hard core": string, "soft data": string, "hard data": string, "soft stack": integer, "hard stack": string, "soft totalmem": string, "hard totalmem": string, "soft rss": string, "hard rss": string, "soft maxproc": integer, "hard maxproc": integer, "soft memlock": integer, "hard memlock": integer, "soft cpu": string, "hard cpu": string, "soft filesize": string, "hard filesize": string, "soft openfiles": integer, "hard openfiles": integer}|false', 'resource=' => '?int'], + ], + 'natcasesort' => [ + 'old' => ['bool', '&rw_array'=>'array'], + 'new' => ['true', '&rw_array'=>'array'], + ], + 'natsort' => [ + 'old' => ['bool', '&rw_array'=>'array'], + 'new' => ['true', '&rw_array'=>'array'], + ], + 'rsort' => [ + 'old' => ['bool', '&rw_array'=>'array', 'flags='=>'int'], + 'new' => ['true', '&rw_array'=>'array', 'flags='=>'int'], + ], + 'hash_pbkdf2' => [ + 'old' => ['non-empty-string', 'algo'=>'string', 'password'=>'string', 'salt'=>'string', 'iterations'=>'int', 'length='=>'int', 'binary='=>'bool'], + 'new' => ['non-empty-string', 'algo'=>'string', 'password'=>'string', 'salt'=>'string', 'iterations'=>'int', 'length='=>'int', 'binary='=>'bool', 'options=' => 'array'], + ], + 'imap_setflag_full' => [ + 'old' => ['bool', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], + 'new' => ['true', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], + ], + 'imap_expunge' => [ + 'old' => ['bool', 'imap'=>'IMAP\Connection'], + 'new' => ['true', 'imap'=>'IMAP\Connection'], + ], + 'imap_gc' => [ + 'old' => ['bool', 'imap'=>'IMAP\Connection', 'flags'=>'int'], + 'new' => ['true', 'imap'=>'IMAP\Connection', 'flags'=>'int'], + ], + 'imap_undelete' => [ + 'old' => ['bool', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'flags='=>'int'], + 'new' => ['true', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'flags='=>'int'], + ], + 'imap_delete' => [ + 'old' => ['bool', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'flags='=>'int'], + 'new' => ['true', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'flags='=>'int'], + ], + 'imap_clearflag_full' => [ + 'old' => ['bool', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], + 'new' => ['true', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], + ], + 'imap_close' => [ + 'old' => ['bool', 'imap'=>'IMAP\Connection', 'flags='=>'int'], + 'new' => ['true', 'imap'=>'IMAP\Connection', 'flags='=>'int'], + ], + 'intlcal_clear' => [ + 'old' => ['bool', 'calendar'=>'IntlCalendar', 'field='=>'?int'], + 'new' => ['true', 'calendar'=>'IntlCalendar', 'field='=>'?int'], + ], + 'intlcal_set_lenient' => [ + 'old' => ['bool', 'calendar'=>'IntlCalendar', 'lenient'=>'bool'], + 'new' => ['true', 'calendar'=>'IntlCalendar', 'lenient'=>'bool'], + ], + 'intlcal_set_first_day_of_week' => [ + 'old' => ['bool', 'calendar'=>'IntlCalendar', 'dayOfWeek'=>'int'], + 'new' => ['true', 'calendar'=>'IntlCalendar', 'dayOfWeek'=>'int'], + ], + 'datefmt_set_timezone' => [ + 'old' => ['false|null', 'formatter'=>'IntlDateFormatter', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], + 'new' => ['bool', 'formatter'=>'IntlDateFormatter', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], + ], + 'IntlRuleBasedBreakIterator::setText' => [ + 'old' => ['?bool', 'text'=>'string'], + 'new' => ['bool', 'text'=>'string'], + ], + 'IntlCodePointBreakIterator::setText' => [ + 'old' => ['?bool', 'text'=>'string'], + 'new' => ['bool', 'text'=>'string'], + ], + 'IntlDateFormatter::setTimeZone' => [ + 'old' => ['null|false', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], + 'new' => ['bool', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], + ], + 'IntlChar::enumCharNames' => [ + 'old' => ['?bool', 'start'=>'string|int', 'end'=>'string|int', 'callback'=>'callable(int,int,int):void', 'type='=>'int'], + 'new' => ['bool', 'start'=>'string|int', 'end'=>'string|int', 'callback'=>'callable(int,int,int):void', 'type='=>'int'], + ], + 'IntlBreakIterator::setText' => [ + 'old' => ['?bool', 'text'=>'string'], + 'new' => ['bool', 'text'=>'string'], + ], ], 'removed' => [ + 'OutOfBoundsException::__clone' => ['void'], + 'ArgumentCountError::__clone' => ['void'], + 'ArithmeticError::__clone' => ['void'], + 'BadFunctionCallException::__clone' => ['void'], + 'BadMethodCallException::__clone' => ['void'], + 'ClosedGeneratorException::__clone' => ['void'], + 'DomainException::__clone' => ['void'], + 'ErrorException::__clone' => ['void'], + 'IntlException::__clone' => ['void'], + 'InvalidArgumentException::__clone' => ['void'], + 'JsonException::__clone' => ['void'], + 'LengthException::__clone' => ['void'], + 'LogicException::__clone' => ['void'], + 'OutOfRangeException::__clone' => ['void'], + 'OverflowException::__clone' => ['void'], + 'ParseError::__clone' => ['void'], + 'RangeException::__clone' => ['void'], + 'ReflectionNamedType::__clone' => ['void'], + 'ReflectionObject::__clone' => ['void'], + 'RuntimeException::__clone' => ['void'], + 'TypeError::__clone' => ['void'], + 'UnderflowException::__clone' => ['void'], + 'UnexpectedValueException::__clone' => ['void'], + 'IntlCodePointBreakIterator::__construct' => ['void'], ], ]; diff --git a/vendor/vimeo/psalm/dictionaries/CallMap_historical.php b/vendor/vimeo/psalm/dictionaries/CallMap_historical.php index a88bab36..d20efff9 100644 --- a/vendor/vimeo/psalm/dictionaries/CallMap_historical.php +++ b/vendor/vimeo/psalm/dictionaries/CallMap_historical.php @@ -209,10 +209,10 @@ return [ 'ArithmeticError::getPrevious' => ['?Throwable'], 'ArithmeticError::getTrace' => ['list\',args?:array}>'], 'ArithmeticError::getTraceAsString' => ['string'], - 'ArrayAccess::offsetExists' => ['bool', 'offset'=>'mixed'], - 'ArrayAccess::offsetGet' => ['mixed', 'offset'=>'mixed'], - 'ArrayAccess::offsetSet' => ['void', 'offset'=>'mixed', 'value'=>'mixed'], - 'ArrayAccess::offsetUnset' => ['void', 'offset'=>'mixed'], + 'ArrayAccess::offsetExists' => ['bool', 'offset'=>'int|string'], + 'ArrayAccess::offsetGet' => ['mixed', 'offset'=>'int|string'], + 'ArrayAccess::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], + 'ArrayAccess::offsetUnset' => ['void', 'offset'=>'int|string'], 'ArrayIterator::__construct' => ['void', 'array='=>'array|object', 'flags='=>'int'], 'ArrayIterator::append' => ['void', 'value'=>'mixed'], 'ArrayIterator::asort' => ['true', 'flags='=>'int'], @@ -227,7 +227,7 @@ return [ 'ArrayIterator::next' => ['void'], 'ArrayIterator::offsetExists' => ['bool', 'key'=>'string|int'], 'ArrayIterator::offsetGet' => ['mixed', 'key'=>'string|int'], - 'ArrayIterator::offsetSet' => ['void', 'key'=>'string|int', 'value'=>'mixed'], + 'ArrayIterator::offsetSet' => ['void', 'key'=>'string|int|null', 'value'=>'mixed'], 'ArrayIterator::offsetUnset' => ['void', 'key'=>'string|int'], 'ArrayIterator::rewind' => ['void'], 'ArrayIterator::seek' => ['void', 'offset'=>'int'], @@ -251,7 +251,7 @@ return [ 'ArrayObject::natsort' => ['true'], 'ArrayObject::offsetExists' => ['bool', 'key'=>'int|string'], 'ArrayObject::offsetGet' => ['mixed|null', 'key'=>'int|string'], - 'ArrayObject::offsetSet' => ['void', 'key'=>'int|string', 'value'=>'mixed'], + 'ArrayObject::offsetSet' => ['void', 'key'=>'int|string|null', 'value'=>'mixed'], 'ArrayObject::offsetUnset' => ['void', 'key'=>'int|string'], 'ArrayObject::serialize' => ['string'], 'ArrayObject::setFlags' => ['void', 'flags'=>'int'], @@ -2236,10 +2236,10 @@ return [ 'HttpQueryString::getObject' => ['', 'name'=>'', 'defval'=>'', 'delete'=>''], 'HttpQueryString::getString' => ['', 'name'=>'', 'defval'=>'', 'delete'=>''], 'HttpQueryString::mod' => ['HttpQueryString', 'params'=>'mixed'], - 'HttpQueryString::offsetExists' => ['bool', 'offset'=>'mixed'], - 'HttpQueryString::offsetGet' => ['mixed', 'offset'=>'mixed'], - 'HttpQueryString::offsetSet' => ['void', 'offset'=>'mixed', 'value'=>'mixed'], - 'HttpQueryString::offsetUnset' => ['void', 'offset'=>'mixed'], + 'HttpQueryString::offsetExists' => ['bool', 'offset'=>'int|string'], + 'HttpQueryString::offsetGet' => ['mixed', 'offset'=>'int|string'], + 'HttpQueryString::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], + 'HttpQueryString::offsetUnset' => ['void', 'offset'=>'int|string'], 'HttpQueryString::serialize' => ['string'], 'HttpQueryString::set' => ['string', 'params'=>'mixed'], 'HttpQueryString::singleton' => ['HttpQueryString', 'global='=>'bool'], @@ -3289,10 +3289,10 @@ return [ 'Judy::memoryUsage' => ['int'], 'Judy::next' => ['mixed', 'index'=>'mixed'], 'Judy::nextEmpty' => ['mixed', 'index'=>'mixed'], - 'Judy::offsetExists' => ['bool', 'offset'=>'mixed'], - 'Judy::offsetGet' => ['mixed', 'offset'=>'mixed'], - 'Judy::offsetSet' => ['bool', 'offset'=>'mixed', 'value'=>'mixed'], - 'Judy::offsetUnset' => ['bool', 'offset'=>'mixed'], + 'Judy::offsetExists' => ['bool', 'offset'=>'int|string'], + 'Judy::offsetGet' => ['mixed', 'offset'=>'int|string'], + 'Judy::offsetSet' => ['bool', 'offset'=>'int|string|null', 'value'=>'mixed'], + 'Judy::offsetUnset' => ['bool', 'offset'=>'int|string'], 'Judy::prev' => ['mixed', 'index'=>'mixed'], 'Judy::prevEmpty' => ['mixed', 'index'=>'mixed'], 'Judy::size' => ['int'], @@ -3731,6 +3731,14 @@ return [ 'MongoDBRef::create' => ['array', 'collection'=>'string', 'id'=>'mixed', 'database='=>'string'], 'MongoDBRef::get' => ['?array', 'db'=>'MongoDB', 'ref'=>'array'], 'MongoDBRef::isRef' => ['bool', 'ref'=>'mixed'], + 'MongoDB\BSON\fromJSON' => ['string', 'json' => 'string'], + 'MongoDB\BSON\fromPHP' => ['string', 'value' => 'object|array'], + 'MongoDB\BSON\toCanonicalExtendedJSON' => ['string', 'bson' => 'string'], + 'MongoDB\BSON\toJSON' => ['string', 'bson' => 'string'], + 'MongoDB\BSON\toPHP' => ['object|array', 'bson' => 'string', 'typemap=' => '?array'], + 'MongoDB\BSON\toRelaxedExtendedJSON' => ['string', 'bson' => 'string'], + 'MongoDB\Driver\Monitoring\addSubscriber' => ['void', 'subscriber' => 'MongoDB\Driver\Monitoring\Subscriber'], + 'MongoDB\Driver\Monitoring\removeSubscriber' => ['void', 'subscriber' => 'MongoDB\Driver\Monitoring\Subscriber'], 'MongoDB\BSON\Binary::__construct' => ['void', 'data' => 'string', 'type=' => 'int'], 'MongoDB\BSON\Binary::getData' => ['string'], 'MongoDB\BSON\Binary::getType' => ['int'], @@ -3751,10 +3759,28 @@ return [ 'MongoDB\BSON\Decimal128::unserialize' => ['void', 'serialized' => 'string'], 'MongoDB\BSON\Decimal128::jsonSerialize' => ['mixed'], 'MongoDB\BSON\Decimal128Interface::__toString' => ['string'], + 'MongoDB\BSON\Document::fromBSON' => ['MongoDB\BSON\Document', 'bson' => 'string'], + 'MongoDB\BSON\Document::fromJSON' => ['MongoDB\BSON\Document', 'json' => 'string'], + 'MongoDB\BSON\Document::fromPHP' => ['MongoDB\BSON\Document', 'value' => 'object|array'], + 'MongoDB\BSON\Document::get' => ['mixed', 'key' => 'string'], + 'MongoDB\BSON\Document::getIterator' => ['MongoDB\BSON\Iterator'], + 'MongoDB\BSON\Document::has' => ['bool', 'key' => 'string'], + 'MongoDB\BSON\Document::toPHP' => ['object|array', 'typeMap=' => '?array'], + 'MongoDB\BSON\Document::toCanonicalExtendedJSON' => ['string'], + 'MongoDB\BSON\Document::toRelaxedExtendedJSON' => ['string'], + 'MongoDB\BSON\Document::__toString' => ['string'], + 'MongoDB\BSON\Document::serialize' => ['string'], + 'MongoDB\BSON\Document::unserialize' => ['void', 'serialized' => 'string'], + 'MongoDB\BSON\Int64::__construct' => ['void', 'value' => 'string|int'], 'MongoDB\BSON\Int64::__toString' => ['string'], 'MongoDB\BSON\Int64::serialize' => ['string'], 'MongoDB\BSON\Int64::unserialize' => ['void', 'serialized' => 'string'], 'MongoDB\BSON\Int64::jsonSerialize' => ['mixed'], + 'MongoDB\BSON\Iterator::current' => ['mixed'], + 'MongoDB\BSON\Iterator::key' => ['string|int'], + 'MongoDB\BSON\Iterator::next' => ['void'], + 'MongoDB\BSON\Iterator::rewind' => ['void'], + 'MongoDB\BSON\Iterator::valid' => ['bool'], 'MongoDB\BSON\Javascript::__construct' => ['void', 'code' => 'string', 'scope=' => 'object|array|null'], 'MongoDB\BSON\Javascript::getCode' => ['string'], 'MongoDB\BSON\Javascript::getScope' => ['?object'], @@ -3779,6 +3805,14 @@ return [ 'MongoDB\BSON\ObjectId::jsonSerialize' => ['mixed'], 'MongoDB\BSON\ObjectIdInterface::getTimestamp' => ['int'], 'MongoDB\BSON\ObjectIdInterface::__toString' => ['string'], + 'MongoDB\BSON\PackedArray::fromPHP' => ['MongoDB\BSON\PackedArray', 'value' => 'array'], + 'MongoDB\BSON\PackedArray::get' => ['mixed', 'index' => 'int'], + 'MongoDB\BSON\PackedArray::getIterator' => ['MongoDB\BSON\Iterator'], + 'MongoDB\BSON\PackedArray::has' => ['bool', 'index' => 'int'], + 'MongoDB\BSON\PackedArray::toPHP' => ['object|array', 'typeMap=' => '?array'], + 'MongoDB\BSON\PackedArray::__toString' => ['string'], + 'MongoDB\BSON\PackedArray::serialize' => ['string'], + 'MongoDB\BSON\PackedArray::unserialize' => ['void', 'serialized' => 'string'], 'MongoDB\BSON\Regex::__construct' => ['void', 'pattern' => 'string', 'flags=' => 'string'], 'MongoDB\BSON\Regex::getPattern' => ['string'], 'MongoDB\BSON\Regex::getFlags' => ['string'], @@ -3828,6 +3862,7 @@ return [ 'MongoDB\Driver\ClientEncryption::decrypt' => ['mixed', 'value' => 'MongoDB\BSON\Binary'], 'MongoDB\Driver\ClientEncryption::deleteKey' => ['object', 'keyId' => 'MongoDB\BSON\Binary'], 'MongoDB\Driver\ClientEncryption::encrypt' => ['MongoDB\BSON\Binary', 'value' => 'mixed', 'options=' => '?array'], + 'MongoDB\Driver\ClientEncryption::encryptExpression' => ['object', 'expr' => 'object|array', 'options=' => '?array'], 'MongoDB\Driver\ClientEncryption::getKey' => ['?object', 'keyId' => 'MongoDB\BSON\Binary'], 'MongoDB\Driver\ClientEncryption::getKeyByAltName' => ['?object', 'keyAltName' => 'string'], 'MongoDB\Driver\ClientEncryption::getKeys' => ['MongoDB\Driver\Cursor'], @@ -4039,6 +4074,7 @@ return [ 'MongoDB\Driver\WriteResult::getUpsertedIds' => ['array'], 'MongoDB\Driver\WriteResult::getWriteConcernError' => ['?MongoDB\Driver\WriteConcernError'], 'MongoDB\Driver\WriteResult::getWriteErrors' => ['array'], + 'MongoDB\Driver\WriteResult::getErrorReplies' => ['array'], 'MongoDB\Driver\WriteResult::isAcknowledged' => ['bool'], 'MongoDate::__construct' => ['void', 'second='=>'int', 'usecond='=>'int'], 'MongoDate::__toString' => ['string'], @@ -5137,7 +5173,7 @@ return [ 'RecursiveArrayIterator::next' => ['void'], 'RecursiveArrayIterator::offsetExists' => ['bool', 'key'=>'string|int'], 'RecursiveArrayIterator::offsetGet' => ['mixed', 'key'=>'string|int'], - 'RecursiveArrayIterator::offsetSet' => ['void', 'key'=>'string|int', 'value'=>'string'], + 'RecursiveArrayIterator::offsetSet' => ['void', 'key'=>'string|int|null', 'value'=>'string'], 'RecursiveArrayIterator::offsetUnset' => ['void', 'key'=>'string|int'], 'RecursiveArrayIterator::rewind' => ['void'], 'RecursiveArrayIterator::seek' => ['void', 'offset'=>'int'], @@ -6641,7 +6677,7 @@ return [ 'SimpleXMLElement::getNamespaces' => ['array', 'recursive='=>'bool'], 'SimpleXMLElement::offsetExists' => ['bool', 'offset'=>'int|string'], 'SimpleXMLElement::offsetGet' => ['SimpleXMLElement', 'offset'=>'int|string'], - 'SimpleXMLElement::offsetSet' => ['void', 'offset'=>'int|string', 'value'=>'mixed'], + 'SimpleXMLElement::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], 'SimpleXMLElement::offsetUnset' => ['void', 'offset'=>'int|string'], 'SimpleXMLElement::registerXPathNamespace' => ['bool', 'prefix'=>'string', 'namespace'=>'string'], 'SimpleXMLElement::saveXML' => ['string|bool', 'filename='=>'string'], @@ -7871,10 +7907,10 @@ return [ 'Thread::merge' => ['bool', 'from'=>'', 'overwrite='=>'mixed'], 'Thread::notify' => ['bool'], 'Thread::notifyOne' => ['bool'], - 'Thread::offsetExists' => ['bool', 'offset'=>'mixed'], - 'Thread::offsetGet' => ['mixed', 'offset'=>'mixed'], - 'Thread::offsetSet' => ['void', 'offset'=>'mixed', 'value'=>'mixed'], - 'Thread::offsetUnset' => ['void', 'offset'=>'mixed'], + 'Thread::offsetExists' => ['bool', 'offset'=>'int|string'], + 'Thread::offsetGet' => ['mixed', 'offset'=>'int|string'], + 'Thread::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], + 'Thread::offsetUnset' => ['void', 'offset'=>'int|string'], 'Thread::pop' => ['bool'], 'Thread::run' => ['void'], 'Thread::setGarbage' => ['void'], @@ -7900,10 +7936,10 @@ return [ 'Threaded::merge' => ['bool', 'from'=>'mixed', 'overwrite='=>'bool'], 'Threaded::notify' => ['bool'], 'Threaded::notifyOne' => ['bool'], - 'Threaded::offsetExists' => ['bool', 'offset'=>'mixed'], - 'Threaded::offsetGet' => ['mixed', 'offset'=>'mixed'], - 'Threaded::offsetSet' => ['void', 'offset'=>'mixed', 'value'=>'mixed'], - 'Threaded::offsetUnset' => ['void', 'offset'=>'mixed'], + 'Threaded::offsetExists' => ['bool', 'offset'=>'int|string'], + 'Threaded::offsetGet' => ['mixed', 'offset'=>'int|string'], + 'Threaded::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], + 'Threaded::offsetUnset' => ['void', 'offset'=>'int|string'], 'Threaded::pop' => ['bool'], 'Threaded::run' => ['void'], 'Threaded::setGarbage' => ['void'], @@ -8208,10 +8244,10 @@ return [ 'Worker::merge' => ['bool', 'from'=>'', 'overwrite='=>'mixed'], 'Worker::notify' => ['bool'], 'Worker::notifyOne' => ['bool'], - 'Worker::offsetExists' => ['bool', 'offset'=>'mixed'], - 'Worker::offsetGet' => ['mixed', 'offset'=>'mixed'], - 'Worker::offsetSet' => ['void', 'offset'=>'mixed', 'value'=>'mixed'], - 'Worker::offsetUnset' => ['void', 'offset'=>'mixed'], + 'Worker::offsetExists' => ['bool', 'offset'=>'int|string'], + 'Worker::offsetGet' => ['mixed', 'offset'=>'int|string'], + 'Worker::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], + 'Worker::offsetUnset' => ['void', 'offset'=>'int|string'], 'Worker::pop' => ['bool'], 'Worker::run' => ['void'], 'Worker::setGarbage' => ['void'], @@ -8368,10 +8404,10 @@ return [ 'Yaf\Config\Ini::get' => ['mixed', 'name='=>'mixed'], 'Yaf\Config\Ini::key' => ['int|string'], 'Yaf\Config\Ini::next' => ['void'], - 'Yaf\Config\Ini::offsetExists' => ['bool', 'name'=>'mixed'], - 'Yaf\Config\Ini::offsetGet' => ['mixed', 'name'=>'mixed'], - 'Yaf\Config\Ini::offsetSet' => ['void', 'name'=>'mixed', 'value'=>'mixed'], - 'Yaf\Config\Ini::offsetUnset' => ['void', 'name'=>'mixed'], + 'Yaf\Config\Ini::offsetExists' => ['bool', 'name'=>'int|string'], + 'Yaf\Config\Ini::offsetGet' => ['mixed', 'name'=>'int|string'], + 'Yaf\Config\Ini::offsetSet' => ['void', 'name'=>'int|string|null', 'value'=>'mixed'], + 'Yaf\Config\Ini::offsetUnset' => ['void', 'name'=>'int|string'], 'Yaf\Config\Ini::readonly' => ['bool'], 'Yaf\Config\Ini::rewind' => ['void'], 'Yaf\Config\Ini::set' => ['Yaf\Config_Abstract', 'name'=>'string', 'value'=>'mixed'], @@ -8386,10 +8422,10 @@ return [ 'Yaf\Config\Simple::get' => ['mixed', 'name='=>'mixed'], 'Yaf\Config\Simple::key' => ['int|string'], 'Yaf\Config\Simple::next' => ['void'], - 'Yaf\Config\Simple::offsetExists' => ['bool', 'name'=>'mixed'], - 'Yaf\Config\Simple::offsetGet' => ['mixed', 'name'=>'mixed'], - 'Yaf\Config\Simple::offsetSet' => ['void', 'name'=>'mixed', 'value'=>'mixed'], - 'Yaf\Config\Simple::offsetUnset' => ['void', 'name'=>'mixed'], + 'Yaf\Config\Simple::offsetExists' => ['bool', 'name'=>'int|string'], + 'Yaf\Config\Simple::offsetGet' => ['mixed', 'name'=>'int|string'], + 'Yaf\Config\Simple::offsetSet' => ['void', 'name'=>'int|string|null', 'value'=>'mixed'], + 'Yaf\Config\Simple::offsetUnset' => ['void', 'name'=>'int|string'], 'Yaf\Config\Simple::readonly' => ['bool'], 'Yaf\Config\Simple::rewind' => ['void'], 'Yaf\Config\Simple::set' => ['Yaf\Config_Abstract', 'name'=>'string', 'value'=>'mixed'], @@ -8656,10 +8692,10 @@ return [ 'Yaf\Session::has' => ['bool', 'name'=>'string'], 'Yaf\Session::key' => ['int|string'], 'Yaf\Session::next' => ['void'], - 'Yaf\Session::offsetExists' => ['bool', 'name'=>'mixed'], - 'Yaf\Session::offsetGet' => ['mixed', 'name'=>'mixed'], - 'Yaf\Session::offsetSet' => ['void', 'name'=>'mixed', 'value'=>'mixed'], - 'Yaf\Session::offsetUnset' => ['void', 'name'=>'mixed'], + 'Yaf\Session::offsetExists' => ['bool', 'name'=>'int|string'], + 'Yaf\Session::offsetGet' => ['mixed', 'name'=>'int|string'], + 'Yaf\Session::offsetSet' => ['void', 'name'=>'int|string|null', 'value'=>'mixed'], + 'Yaf\Session::offsetUnset' => ['void', 'name'=>'int|string'], 'Yaf\Session::rewind' => ['void'], 'Yaf\Session::set' => ['Yaf\Session|false', 'name'=>'string', 'value'=>'mixed'], 'Yaf\Session::start' => ['Yaf\Session'], @@ -9404,7 +9440,8 @@ return [ 'atan' => ['float', 'num'=>'float'], 'atan2' => ['float', 'y'=>'float', 'x'=>'float'], 'atanh' => ['float', 'num'=>'float'], - 'base64_decode' => ['string|false', 'string'=>'string', 'strict='=>'bool'], + 'base64_decode' => ['string', 'string'=>'string', 'strict='=>'false'], + 'base64_decode\'1' => ['string|false', 'string'=>'string', 'strict='=>'true'], 'base64_encode' => ['string', 'string'=>'string'], 'base_convert' => ['string', 'num'=>'string', 'from_base'=>'int', 'to_base'=>'int'], 'basename' => ['string', 'path'=>'string', 'suffix='=>'string'], @@ -9966,7 +10003,7 @@ return [ 'dcgettext' => ['string', 'domain'=>'string', 'message'=>'string', 'category'=>'int'], 'dcngettext' => ['string', 'domain'=>'string', 'singular'=>'string', 'plural'=>'string', 'count'=>'int', 'category'=>'int'], 'deaggregate' => ['', 'object'=>'object', 'class_name='=>'string'], - 'debug_backtrace' => ['list', 'options='=>'int', 'limit='=>'int'], + 'debug_backtrace' => ['list', 'options='=>'int', 'limit='=>'int'], 'debug_print_backtrace' => ['void', 'options='=>'int', 'limit='=>'int'], 'debug_zval_dump' => ['void', 'value'=>'mixed', '...values='=>'mixed'], 'debugger_connect' => [''], @@ -9994,7 +10031,7 @@ return [ 'dio_truncate' => ['bool', 'fd'=>'resource', 'offset'=>'int'], 'dio_write' => ['int', 'fd'=>'resource', 'data'=>'string', 'length='=>'int'], 'dir' => ['Directory|false', 'directory'=>'string', 'context='=>'resource'], - 'dirname' => ['string', 'path'=>'string', 'levels='=>'int'], + 'dirname' => ['string', 'path'=>'string', 'levels='=>'int<1, max>'], 'disk_free_space' => ['float|false', 'directory'=>'string'], 'disk_total_space' => ['float|false', 'directory'=>'string'], 'diskfreespace' => ['float|false', 'directory'=>'string'], @@ -10708,8 +10745,8 @@ return [ 'gethostbyname' => ['string', 'hostname'=>'string'], 'gethostbynamel' => ['list|false', 'hostname'=>'string'], 'gethostname' => ['string|false'], - 'getimagesize' => ['array|false', 'filename'=>'string', '&w_image_info='=>'array'], - 'getimagesizefromstring' => ['array|false', 'string'=>'string', '&w_image_info='=>'array'], + 'getimagesize' => ['array{0:int, 1: int, 2: int, 3: string, mime: string, channels?: 3|4, bits?: int}|false', 'filename'=>'string', '&w_image_info='=>'array'], + 'getimagesizefromstring' => ['array{0:int, 1: int, 2: int, 3: string, mime: string, channels?: 3|4, bits?: int}|false', 'string'=>'string', '&w_image_info='=>'array'], 'getlastmod' => ['int|false'], 'getmxrr' => ['bool', 'hostname'=>'string', '&w_hosts'=>'array', '&w_weights='=>'array'], 'getmygid' => ['int|false'], @@ -10727,7 +10764,7 @@ return [ 'gettimeofday' => ['array'], 'gettimeofday\'1' => ['float', 'as_float='=>'true'], 'gettype' => ['string', 'value'=>'mixed'], - 'glob' => ['list|false', 'pattern'=>'non-empty-string', 'flags='=>'int<1, max>'], + 'glob' => ['false|list{0?:string, ...}', 'pattern'=>'string', 'flags='=>'int<0, max>'], 'gmdate' => ['string', 'format'=>'string', 'timestamp='=>'int'], 'gmmktime' => ['int|false', 'hour='=>'int', 'minute='=>'int', 'second='=>'int', 'month='=>'int', 'day='=>'int', 'year='=>'int'], 'gmp_abs' => ['GMP', 'num'=>'GMP|string|int'], @@ -11306,10 +11343,10 @@ return [ 'http\Message\Parser::stream' => ['int', 'stream'=>'resource', 'flags'=>'int', '&message'=>'http\Message'], 'http\Params::__construct' => ['void', 'params='=>'mixed', 'param_sep='=>'mixed', 'arg_sep='=>'mixed', 'val_sep='=>'mixed', 'flags='=>'mixed'], 'http\Params::__toString' => ['string'], - 'http\Params::offsetExists' => ['bool', 'name'=>'mixed'], - 'http\Params::offsetGet' => ['mixed', 'name'=>'mixed'], - 'http\Params::offsetSet' => ['void', 'name'=>'mixed', 'value'=>'mixed'], - 'http\Params::offsetUnset' => ['void', 'name'=>'mixed'], + 'http\Params::offsetExists' => ['bool', 'name'=>'int|string'], + 'http\Params::offsetGet' => ['mixed', 'name'=>'int|string'], + 'http\Params::offsetSet' => ['void', 'name'=>'int|string|null', 'value'=>'mixed'], + 'http\Params::offsetUnset' => ['void', 'name'=>'int|string'], 'http\Params::toArray' => ['array'], 'http\Params::toString' => ['string'], 'http\QueryString::__construct' => ['void', 'querystring'=>'string'], @@ -11324,10 +11361,10 @@ return [ 'http\QueryString::getObject' => ['object|mixed', 'name'=>'string', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::getString' => ['string|mixed', 'name'=>'string', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::mod' => ['http\QueryString', 'params='=>'mixed'], - 'http\QueryString::offsetExists' => ['bool', 'offset'=>'mixed'], - 'http\QueryString::offsetGet' => ['mixed|null', 'offset'=>'mixed'], - 'http\QueryString::offsetSet' => ['void', 'offset'=>'mixed', 'value'=>'mixed'], - 'http\QueryString::offsetUnset' => ['void', 'offset'=>'mixed'], + 'http\QueryString::offsetExists' => ['bool', 'offset'=>'int|string'], + 'http\QueryString::offsetGet' => ['mixed|null', 'offset'=>'int|string'], + 'http\QueryString::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], + 'http\QueryString::offsetUnset' => ['void', 'offset'=>'int|string'], 'http\QueryString::serialize' => ['string'], 'http\QueryString::set' => ['http\QueryString', 'params'=>'mixed'], 'http\QueryString::toArray' => ['array'], @@ -13554,7 +13591,7 @@ return [ 'print' => ['int', 'arg'=>'string'], 'print_r' => ['string', 'value'=>'mixed'], 'print_r\'1' => ['true', 'value'=>'mixed', 'return='=>'bool'], - 'printf' => ['int', 'format'=>'string', '...values='=>'string|int|float'], + 'printf' => ['int<0, max>', 'format'=>'string', '...values='=>'string|int|float'], 'proc_close' => ['int', 'process'=>'resource'], 'proc_get_status' => ['array{command: string, pid: int, running: bool, signaled: bool, stopped: bool, exitcode: int, termsig: int, stopsig: int}|false', 'process'=>'resource'], 'proc_nice' => ['bool', 'priority'=>'int'], @@ -15317,7 +15354,7 @@ return [ 'variant_xor' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'version_compare' => ['bool', 'version1'=>'string', 'version2'=>'string', 'operator'=>'\'<\'|\'lt\'|\'<=\'|\'le\'|\'>\'|\'gt\'|\'>=\'|\'ge\'|\'==\'|\'=\'|\'eq\'|\'!=\'|\'<>\'|\'ne\''], 'version_compare\'1' => ['int', 'version1'=>'string', 'version2'=>'string'], - 'vfprintf' => ['int', 'stream'=>'resource', 'format'=>'string', 'values'=>'array'], + 'vfprintf' => ['int<0, max>', 'stream'=>'resource', 'format'=>'string', 'values'=>'array'], 'virtual' => ['bool', 'uri'=>'string'], 'vpopmail_add_alias_domain' => ['bool', 'domain'=>'string', 'aliasdomain'=>'string'], 'vpopmail_add_alias_domain_ex' => ['bool', 'olddomain'=>'string', 'newdomain'=>'string'], @@ -15336,8 +15373,8 @@ return [ 'vpopmail_error' => ['string'], 'vpopmail_passwd' => ['bool', 'user'=>'string', 'domain'=>'string', 'password'=>'string', 'apop='=>'bool'], 'vpopmail_set_user_quota' => ['bool', 'user'=>'string', 'domain'=>'string', 'quota'=>'string'], - 'vprintf' => ['int', 'format'=>'string', 'values'=>'array'], - 'vsprintf' => ['string', 'format'=>'string', 'values'=>'array'], + 'vprintf' => ['int<0, max>', 'format'=>'string', 'values'=>'array'], + 'vsprintf' => ['string', 'format'=>'string', 'values'=>'array'], 'w32api_deftype' => ['bool', 'typename'=>'string', 'member1_type'=>'string', 'member1_name'=>'string', '...args='=>'string'], 'w32api_init_dtype' => ['resource', 'typename'=>'string', 'value'=>'', '...args='=>''], 'w32api_invoke_function' => ['', 'funcname'=>'string', 'argument'=>'', '...args='=>''], diff --git a/vendor/vimeo/psalm/docs/annotating_code/type_syntax/array_types.md b/vendor/vimeo/psalm/docs/annotating_code/type_syntax/array_types.md index 7a3c00f9..2846a9a2 100644 --- a/vendor/vimeo/psalm/docs/annotating_code/type_syntax/array_types.md +++ b/vendor/vimeo/psalm/docs/annotating_code/type_syntax/array_types.md @@ -126,6 +126,19 @@ Optional keys can be denoted by a trailing `?`, e.g.: /** @return array{optional?: string, bar: int} */ ``` +You can use "one-line" comments (similar to PHP), e.g: + +```php +/** @return array { // Array with comments. + * // Comments can be placed on their own line. + * foo: string, // An array key description. + * bar: array {, // Another array key description. + * 'foo//bar': string, // Array key with "//" in it's name. + * }, + * } + */ +``` + Tip: if you find yourself copying the same complex array shape over and over again to avoid `InvalidArgument` issues, try using [type aliases](utility_types.md#type-aliases), instead. ### Validating array shapes diff --git a/vendor/vimeo/psalm/docs/annotating_code/type_syntax/atomic_types.md b/vendor/vimeo/psalm/docs/annotating_code/type_syntax/atomic_types.md index 612cf9f7..6a710588 100644 --- a/vendor/vimeo/psalm/docs/annotating_code/type_syntax/atomic_types.md +++ b/vendor/vimeo/psalm/docs/annotating_code/type_syntax/atomic_types.md @@ -46,7 +46,7 @@ Atomic types are the basic building block of all type information used in Psalm. * [`key-of`](utility_types.md#key-oft) * [`value-of`](utility_types.md#value-oft) * [`properties-of`](utility_types.md#properties-oft) - * [`class-string-map`](utility_types.md#class-string-mapt-as-foo-t) + * [`class-string-map`](utility_types.md#class-string-mapt-of-foo-t) * [`T[K]`](utility_types.md#tk) * [Type aliases](utility_types.md#type-aliases) * [Variable templates](utility_types.md#variable-templates) diff --git a/vendor/vimeo/psalm/docs/running_psalm/configuration.md b/vendor/vimeo/psalm/docs/running_psalm/configuration.md index 43f42c3b..f4976aaa 100644 --- a/vendor/vimeo/psalm/docs/running_psalm/configuration.md +++ b/vendor/vimeo/psalm/docs/running_psalm/configuration.md @@ -414,6 +414,14 @@ Whether or not to allow `require`/`include` calls in your PHP. Defaults to `true ``` Allows you to hard-code a serializer for Psalm to use when caching data. By default, Psalm uses `ext-igbinary` *if* the version is greater than or equal to 2.0.5, otherwise it defaults to PHP's built-in serializer. +#### compressor +```xml + +``` +Allows you to hard-code a compressor for Psalm's cache. By default, Psalm uses `ext-zlib` deflate, if it's enabled. + #### threads ```xml + ``` diff --git a/vendor/vimeo/psalm/docs/running_psalm/language_server.md b/vendor/vimeo/psalm/docs/running_psalm/language_server.md index 47504068..3d80a91c 100644 --- a/vendor/vimeo/psalm/docs/running_psalm/language_server.md +++ b/vendor/vimeo/psalm/docs/running_psalm/language_server.md @@ -6,7 +6,9 @@ It currently supports diagnostics (i.e. finding errors and warnings), go-to-defi It works well in a variety of editors (listed alphabetically): -## Emacs +## Client configuration + +### Emacs I got it working with [eglot](https://github.com/joaotavora/eglot) @@ -27,13 +29,13 @@ This is the config I used: ) ``` -## PhpStorm +### PhpStorm -### Native Support +#### Native Support As of PhpStorm 2020.3 support for psalm is supported and on by default, you can read more about that [here](https://www.jetbrains.com/help/phpstorm/using-psalm.html) -### With LSP +#### With LSP Alternatively, psalm works with `gtache/intellij-lsp` plugin ([Jetbrains-approved version](https://plugins.jetbrains.com/plugin/10209-lsp-support), [latest version](https://github.com/gtache/intellij-lsp/releases/tag/v1.6.0)). @@ -51,7 +53,7 @@ In the "Server definitions" tab you should add a definition for Psalm: In the "Timeouts" tab you can adjust the initialization timeout. This is important if you have a large project. You should set the "Init" value to the number of milliseconds you allow Psalm to scan your entire project and your project's dependencies. For opening a couple of projects that use large PHP frameworks, on a high-end business laptop, try `240000` milliseconds for Init. -## Sublime Text +### Sublime Text I use the excellent Sublime [LSP plugin](https://github.com/tomv564/LSP) with the following config(Package Settings > LSP > Settings): ```json @@ -64,7 +66,7 @@ I use the excellent Sublime [LSP plugin](https://github.com/tomv564/LSP) with th } ``` -## Vim & Neovim +### Vim & Neovim **ALE** @@ -105,6 +107,15 @@ Add settings to `coc-settings.json`: } ``` -## VS Code +### VS Code [Get the Psalm plugin here](https://marketplace.visualstudio.com/items?itemName=getpsalm.psalm-vscode-plugin) (Requires VS Code 1.26+): + +## Running the server in a docker container + +Make sure you use `--map-folder` option. Using it without argument will map the server's CWD to the host's project root folder. You can also specify a custom mapping. For example: +```bash +docker-compose exec php /usr/share/php/psalm/psalm-language-server \ + -r=/var/www/html \ + --map-folder=/var/www/html:$PWD +``` diff --git a/vendor/vimeo/psalm/src/Psalm/Codebase.php b/vendor/vimeo/psalm/src/Psalm/Codebase.php index d6caa46d..56a9aab5 100644 --- a/vendor/vimeo/psalm/src/Psalm/Codebase.php +++ b/vendor/vimeo/psalm/src/Psalm/Codebase.php @@ -533,11 +533,12 @@ final class Codebase public function cacheClassLikeStorage(ClassLikeStorage $classlike_storage, string $file_path): void { - $file_contents = $this->file_provider->getContents($file_path); - - if ($this->classlike_storage_provider->cache) { - $this->classlike_storage_provider->cache->writeToCache($classlike_storage, $file_path, $file_contents); + if (!$this->classlike_storage_provider->cache) { + return; } + + $file_contents = $this->file_provider->getContents($file_path); + $this->classlike_storage_provider->cache->writeToCache($classlike_storage, $file_path, $file_contents); } public function exhumeClassLikeStorage(string $fq_classlike_name, string $file_path): void @@ -553,6 +554,8 @@ final class Codebase $this->classlikes->addFullyQualifiedTraitName($storage->name, $file_path); } elseif ($storage->is_interface) { $this->classlikes->addFullyQualifiedInterfaceName($storage->name, $file_path); + } elseif ($storage->is_enum) { + $this->classlikes->addFullyQualifiedEnumName($storage->name, $file_path); } else { $this->classlikes->addFullyQualifiedClassName($storage->name, $file_path); } diff --git a/vendor/vimeo/psalm/src/Psalm/Config.php b/vendor/vimeo/psalm/src/Psalm/Config.php index fcc1fbea..e84a134f 100644 --- a/vendor/vimeo/psalm/src/Psalm/Config.php +++ b/vendor/vimeo/psalm/src/Psalm/Config.php @@ -68,6 +68,7 @@ use function file_exists; use function file_get_contents; use function flock; use function fopen; +use function function_exists; use function get_class; use function get_defined_constants; use function get_defined_functions; @@ -331,6 +332,9 @@ class Config /** @var bool */ public $use_igbinary = false; + /** @var 'lz4'|'deflate'|'off' */ + public $compressor = 'off'; + /** * @var bool */ @@ -1188,12 +1192,43 @@ class Config if (isset($config_xml['serializer'])) { $attribute_text = (string) $config_xml['serializer']; $config->use_igbinary = $attribute_text === 'igbinary'; + if ($config->use_igbinary + && ( + !function_exists('igbinary_serialize') + || !function_exists('igbinary_unserialize') + ) + ) { + $config->use_igbinary = false; + $config->config_warnings[] = '"serializer" set to "igbinary" but ext-igbinary seems to be missing on ' . + 'the system. Using php\'s build-in serializer.'; + } } elseif ($igbinary_version = phpversion('igbinary')) { $config->use_igbinary = version_compare($igbinary_version, '2.0.5') >= 0; } + if (isset($config_xml['compressor'])) { + $compressor = (string) $config_xml['compressor']; + if ($compressor === 'lz4') { + if (function_exists('lz4_compress') && function_exists('lz4_uncompress')) { + $config->compressor = 'lz4'; + } else { + $config->config_warnings[] = '"compressor" set to "lz4" but ext-lz4 seems to be missing on the ' . + 'system. Disabling cache compressor.'; + } + } elseif ($compressor === 'deflate') { + if (function_exists('gzinflate') && function_exists('gzdeflate')) { + $config->compressor = 'deflate'; + } else { + $config->config_warnings[] = '"compressor" set to "deflate" but zlib seems to be missing on the ' . + 'system. Disabling cache compressor.'; + } + } + } elseif (function_exists('gzinflate') && function_exists('gzdeflate')) { + $config->compressor = 'deflate'; + } + if (!isset($config_xml['findUnusedBaselineEntry'])) { - $config->config_warnings[] = '"findUnusedBaselineEntry" will be defaulted to "true" in Psalm 6.' + $config->config_warnings[] = '"findUnusedBaselineEntry" will default to "true" in Psalm 6.' . ' You should explicitly enable or disable this setting.'; } @@ -1202,7 +1237,7 @@ class Config $config->find_unused_code = $attribute_text === 'true' || $attribute_text === '1'; $config->find_unused_variables = $config->find_unused_code; } else { - $config->config_warnings[] = '"findUnusedCode" will be defaulted to "true" in Psalm 6.' + $config->config_warnings[] = '"findUnusedCode" will default to "true" in Psalm 6.' . ' You should explicitly enable or disable this setting.'; } @@ -2218,28 +2253,27 @@ class Config $codebase->register_stub_files = true; $dir_lvl_2 = dirname(__DIR__, 2); + $stubsDir = $dir_lvl_2 . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR; $this->internal_stubs = [ - $dir_lvl_2 . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'CoreGenericFunctions.phpstub', - $dir_lvl_2 . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'CoreGenericClasses.phpstub', - $dir_lvl_2 . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'CoreGenericIterators.phpstub', - $dir_lvl_2 . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'CoreImmutableClasses.phpstub', - $dir_lvl_2 . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'Reflection.phpstub', - $dir_lvl_2 . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'SPL.phpstub', + $stubsDir . 'CoreGenericFunctions.phpstub', + $stubsDir . 'CoreGenericClasses.phpstub', + $stubsDir . 'CoreGenericIterators.phpstub', + $stubsDir . 'CoreImmutableClasses.phpstub', + $stubsDir . 'Reflection.phpstub', + $stubsDir . 'SPL.phpstub', ]; if ($codebase->analysis_php_version_id >= 8_00_00) { - $stringable_path = $dir_lvl_2 . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'Php80.phpstub'; - $this->internal_stubs[] = $stringable_path; + $this->internal_stubs[] = $stubsDir . 'CoreGenericAttributes.phpstub'; + $this->internal_stubs[] = $stubsDir . 'Php80.phpstub'; } if ($codebase->analysis_php_version_id >= 8_01_00) { - $stringable_path = $dir_lvl_2 . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'Php81.phpstub'; - $this->internal_stubs[] = $stringable_path; + $this->internal_stubs[] = $stubsDir . 'Php81.phpstub'; } if ($codebase->analysis_php_version_id >= 8_02_00) { - $stringable_path = $dir_lvl_2 . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'Php82.phpstub'; - $this->internal_stubs[] = $stringable_path; + $this->internal_stubs[] = $stubsDir . 'Php82.phpstub'; $this->php_extensions['random'] = true; // random is a part of the PHP core starting from PHP 8.2 } diff --git a/vendor/vimeo/psalm/src/Psalm/Config/Creator.php b/vendor/vimeo/psalm/src/Psalm/Config/Creator.php index 2ce9f3c5..a2fe9646 100644 --- a/vendor/vimeo/psalm/src/Psalm/Config/Creator.php +++ b/vendor/vimeo/psalm/src/Psalm/Config/Creator.php @@ -23,6 +23,7 @@ use function glob; use function implode; use function is_array; use function is_dir; +use function is_string; use function json_decode; use function ksort; use function max; @@ -46,6 +47,7 @@ final class Creator xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" findUnusedBaselineEntry="true" + findUnusedCode="true" > @@ -249,6 +251,10 @@ final class Creator } foreach ($paths as $path) { + if (!is_string($path)) { + continue; + } + if ($path === '') { $nodes = [...$nodes, ...self::guessPhpFileDirs($current_dir)]; diff --git a/vendor/vimeo/psalm/src/Psalm/Config/FileFilter.php b/vendor/vimeo/psalm/src/Psalm/Config/FileFilter.php index cefa55b0..6e51d088 100644 --- a/vendor/vimeo/psalm/src/Psalm/Config/FileFilter.php +++ b/vendor/vimeo/psalm/src/Psalm/Config/FileFilter.php @@ -10,12 +10,18 @@ use SimpleXMLElement; use function array_filter; use function array_map; +use function array_merge; +use function array_shift; +use function count; use function explode; use function glob; use function in_array; use function is_dir; use function is_iterable; +use function is_string; use function preg_match; +use function preg_replace; +use function preg_split; use function readlink; use function realpath; use function restore_error_handler; @@ -52,12 +58,12 @@ class FileFilter protected $fq_classlike_names = []; /** - * @var array + * @var array */ protected $fq_classlike_patterns = []; /** - * @var array + * @var array */ protected $method_ids = []; @@ -129,10 +135,12 @@ class FileFilter } if (strpos($prospective_directory_path, '*') !== false) { - $globs = array_map( - 'realpath', - glob($prospective_directory_path, GLOB_ONLYDIR), - ); + // Strip meaningless trailing recursive wildcard like "path/**/" or "path/**" + $prospective_directory_path = preg_replace('#(\/\*\*)+\/?$#', '/', $prospective_directory_path); + // Split by /**/, allow duplicated wildcards like "path/**/**/path" and any leading dir separator. + /** @var non-empty-list $path_parts */ + $path_parts = preg_split('#(\/|\\\)(\*\*\/)+#', $prospective_directory_path); + $globs = self::recursiveGlob($path_parts, true); if (empty($globs)) { if ($allow_missing_files) { @@ -145,8 +153,8 @@ class FileFilter ); } - foreach ($globs as $glob_index => $directory_path) { - if (!$directory_path) { + foreach ($globs as $glob_index => $glob_directory_path) { + if (!$glob_directory_path) { if ($allow_missing_files) { continue; } @@ -158,14 +166,14 @@ class FileFilter } if ($ignore_type_stats && $filter instanceof ProjectFileFilter) { - $filter->ignore_type_stats[$directory_path] = true; + $filter->ignore_type_stats[$glob_directory_path] = true; } if ($declare_strict_types && $filter instanceof ProjectFileFilter) { - $filter->declare_strict_types[$directory_path] = true; + $filter->declare_strict_types[$glob_directory_path] = true; } - $filter->addDirectory($directory_path); + $filter->addDirectory($glob_directory_path); } continue; } @@ -246,13 +254,10 @@ class FileFilter } if (strpos($prospective_file_path, '*') !== false) { - $globs = array_map( - 'realpath', - array_filter( - glob($prospective_file_path, GLOB_NOSORT), - 'file_exists', - ), - ); + // Split by /**/, allow duplicated wildcards like "path/**/**/path" and any leading dir separator. + /** @var non-empty-list $path_parts */ + $path_parts = preg_split('#(\/|\\\)(\*\*\/)+#', $prospective_file_path); + $globs = self::recursiveGlob($path_parts, false); if (empty($globs)) { if ($allow_missing_files) { @@ -265,14 +270,18 @@ class FileFilter ); } - foreach ($globs as $glob_index => $file_path) { - if (!$file_path && !$allow_missing_files) { + foreach ($globs as $glob_index => $glob_file_path) { + if (!$glob_file_path) { + if ($allow_missing_files) { + continue; + } + throw new ConfigException( 'Could not resolve config path to ' . $base_dir . DIRECTORY_SEPARATOR . $file_path . ':' . $glob_index, ); } - $filter->addFile($file_path); + $filter->addFile($glob_file_path); } continue; } @@ -306,14 +315,18 @@ class FileFilter if (isset($config['referencedMethod']) && is_iterable($config['referencedMethod'])) { /** @var array $referenced_method */ foreach ($config['referencedMethod'] as $referenced_method) { - $method_id = (string) ($referenced_method['name'] ?? ''); - - if (!preg_match('/^[^:]+::[^:]+$/', $method_id) && !static::isRegularExpression($method_id)) { + $method_id = $referenced_method['name'] ?? ''; + if (!is_string($method_id) + || (!preg_match('/^[^:]+::[^:]+$/', $method_id) && !static::isRegularExpression($method_id))) { throw new ConfigException( - 'Invalid referencedMethod ' . $method_id, + 'Invalid referencedMethod ' . ((string) $method_id), ); } + if ($method_id === '') { + continue; + } + $filter->method_ids[] = strtolower($method_id); } } @@ -321,7 +334,21 @@ class FileFilter if (isset($config['referencedFunction']) && is_iterable($config['referencedFunction'])) { /** @var array $referenced_function */ foreach ($config['referencedFunction'] as $referenced_function) { - $filter->method_ids[] = strtolower((string) ($referenced_function['name'] ?? '')); + $function_id = $referenced_function['name'] ?? ''; + if (!is_string($function_id) + || (!preg_match('/^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$/', $function_id) + && !preg_match('/^[^:]+::[^:]+$/', $function_id) // methods are also allowed + && !static::isRegularExpression($function_id))) { + throw new ConfigException( + 'Invalid referencedFunction ' . ((string) $function_id), + ); + } + + if ($function_id === '') { + continue; + } + + $filter->method_ids[] = strtolower($function_id); } } @@ -433,8 +460,15 @@ class FileFilter return self::loadFromArray($config, $base_dir, $inclusive); } + /** + * @psalm-assert-if-true non-empty-string $string + */ private static function isRegularExpression(string $string): bool { + if ($string === '') { + return false; + } + set_error_handler( static fn(): bool => true, E_WARNING, @@ -445,6 +479,39 @@ class FileFilter return $is_regexp; } + /** + * @mutation-free + * @param non-empty-list $parts + * @return array + */ + private static function recursiveGlob(array $parts, bool $only_dir): array + { + if (count($parts) < 2) { + if ($only_dir) { + $list = glob($parts[0], GLOB_ONLYDIR | GLOB_NOSORT) ?: []; + } else { + $list = array_filter( + glob($parts[0], GLOB_NOSORT) ?: [], + 'file_exists', + ); + } + + return array_map('realpath', $list); + } + + $first_dir = self::slashify($parts[0]); + $paths = glob($first_dir . '*', GLOB_ONLYDIR | GLOB_NOSORT); + $result = []; + foreach ($paths as $path) { + $parts[0] = $path; + $result = array_merge($result, self::recursiveGlob($parts, $only_dir)); + } + array_shift($parts); + $parts[0] = $first_dir . $parts[0]; + + return array_merge($result, self::recursiveGlob($parts, $only_dir)); + } + /** * @psalm-pure */ diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Algebra.php b/vendor/vimeo/psalm/src/Psalm/Internal/Algebra.php index 0f581fc8..d2b16a26 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Algebra.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Algebra.php @@ -4,6 +4,9 @@ namespace Psalm\Internal; use Psalm\Exception\ComplicatedExpressionException; use Psalm\Storage\Assertion; +use Psalm\Type\Atomic\TArray; +use Psalm\Type\Atomic\TKeyedArray; +use Psalm\Type\Atomic\TList; use UnexpectedValueException; use function array_filter; @@ -322,6 +325,9 @@ class Algebra /** * Look for clauses with only one possible value * + * doesn't infer the "unset" correctly + * + * @psalm-suppress MoreSpecificReturnType * @param list $clauses * @param array $cond_referenced_var_ids * @param array>> $active_truths @@ -388,6 +394,72 @@ class Algebra } } + foreach ($truths as $var => $anded_types) { + $has_list_or_array = false; + foreach ($anded_types as $orred_types) { + foreach ($orred_types as $assertion) { + if ($assertion->isNegation()) { + continue; + } + + if (!isset($assertion->type)) { + continue; + } + + if ($assertion->type instanceof TList + || $assertion->type instanceof TArray + || $assertion->type instanceof TKeyedArray) { + $has_list_or_array = true; + // list/array are collapsed, therefore there can only be 1 and we can abort + // otherwise we would have to remove them all individually + // e.g. array cannot be array + break 2; + } + } + } + + if ($has_list_or_array === false) { + continue; + } + + foreach ($anded_types as $key => $orred_types) { + foreach ($orred_types as $index => $assertion) { + // we only need to check negations + // due to type collapsing, any negations for arrays are irrelevant + if (!$assertion->isNegation()) { + continue; + } + + if (!isset($assertion->type)) { + continue; + } + + if ($assertion->type instanceof TList + || $assertion->type instanceof TArray + || $assertion->type instanceof TKeyedArray) { + unset($truths[$var][$key][$index]); + } + } + + /** + * doesn't infer the "unset" correctly + * + * @psalm-suppress DocblockTypeContradiction + */ + if ($truths[$var][$key] === []) { + unset($truths[$var][$key]); + } else { + /** + * doesn't infer the "unset" correctly + * + * @psalm-suppress RedundantFunctionCallGivenDocblockType + */ + $truths[$var][$key] = array_values($truths[$var][$key]); + } + } + } + + /** @psalm-suppress LessSpecificReturnStatement */ return $truths; } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/CanAlias.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/CanAlias.php index 1e23e08b..3be3d60d 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/CanAlias.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/CanAlias.php @@ -8,7 +8,6 @@ use Psalm\CodeLocation; use Psalm\FileManipulation; use Psalm\Internal\FileManipulation\FileManipulationBuffer; -use function implode; use function strtolower; /** @@ -51,7 +50,7 @@ trait CanAlias $codebase = $this->getCodebase(); foreach ($stmt->uses as $use) { - $use_path = implode('\\', $use->name->parts); + $use_path = $use->name->toString(); $use_path_lc = strtolower($use_path); $use_alias = $use->alias->name ?? $use->name->getLast(); $use_alias_lc = strtolower($use_alias); @@ -106,12 +105,12 @@ trait CanAlias public function visitGroupUse(PhpParser\Node\Stmt\GroupUse $stmt): void { - $use_prefix = implode('\\', $stmt->prefix->parts); + $use_prefix = $stmt->prefix->toString(); $codebase = $this->getCodebase(); foreach ($stmt->uses as $use) { - $use_path = $use_prefix . '\\' . implode('\\', $use->name->parts); + $use_path = $use_prefix . '\\' . $use->name->toString(); $use_alias = $use->alias->name ?? $use->name->getLast(); switch ($use->type !== PhpParser\Node\Stmt\Use_::TYPE_UNKNOWN ? $use->type : $stmt->type) { diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php index 3d120c89..bdb35732 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php @@ -802,7 +802,20 @@ class ClassAnalyzer extends ClassLikeAnalyzer $codebase, ); - if ($property_storage->location + if ($guide_property_storage->readonly + && UnionTypeComparator::isContainedBy( + $codebase, + $property_type, + $guide_property_type, + false, + false, + null, + false, + false, + )) { + // if the original property is readonly, it cannot be written + // therefore invariance is not a problem, if the parent type contains the child type + } elseif ($property_storage->location && !$property_type->equals($guide_property_type, false) && $guide_class_storage->user_defined ) { @@ -999,6 +1012,11 @@ class ClassAnalyzer extends ClassLikeAnalyzer return; } + // abstract constructors do not have any code, therefore cannot set any properties either + if (isset($storage->methods['__construct']) && $storage->methods['__construct']->abstract) { + return; + } + $fq_class_name = $class_context->self ?: $this->fq_class_name; $fq_class_name_lc = strtolower($fq_class_name); @@ -2003,7 +2021,7 @@ class ClassAnalyzer extends ClassLikeAnalyzer . ($interface_name instanceof PhpParser\Node\Name\FullyQualified ? '\\' : $this->getNamespace() . '-') - . implode('\\', $interface_name->parts), + . $interface_name->toString(), ); $interface_location = new CodeLocation($this, $interface_name); @@ -2419,7 +2437,7 @@ class ClassAnalyzer extends ClassLikeAnalyzer . ($extended_class instanceof PhpParser\Node\Name\FullyQualified ? '\\' : $this->getNamespace() . '-') - . implode('\\', $extended_class->parts), + . $extended_class->toString(), ); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php index 92e86998..a6c90919 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php @@ -40,7 +40,6 @@ use function array_search; use function count; use function explode; use function gettype; -use function implode; use function in_array; use function preg_match; use function preg_replace; @@ -421,15 +420,15 @@ abstract class ClassLikeAnalyzer extends SourceAnalyzer } if ($class_name instanceof PhpParser\Node\Name\FullyQualified) { - return implode('\\', $class_name->parts); + return $class_name->toString(); } - if (in_array($class_name->parts[0], ['self', 'static', 'parent'], true)) { - return $class_name->parts[0]; + if (in_array($class_name->getFirst(), ['self', 'static', 'parent'], true)) { + return $class_name->getFirst(); } return Type::getFQCLNFromString( - implode('\\', $class_name->parts), + $class_name->toString(), $aliases, ); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/CommentAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/CommentAnalyzer.php index 00a3f8a2..9668f292 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/CommentAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/CommentAnalyzer.php @@ -34,6 +34,7 @@ use function preg_split; use function rtrim; use function str_replace; use function strlen; +use function strpos; use function substr; use function substr_count; use function trim; @@ -259,7 +260,8 @@ class CommentAnalyzer public static function sanitizeDocblockType(string $docblock_type): string { $docblock_type = preg_replace('@^[ \t]*\*@m', '', $docblock_type); - $docblock_type = preg_replace('/,\n\s+\}/', '}', $docblock_type); + $docblock_type = preg_replace('/,\n\s+}/', '}', $docblock_type); + return str_replace("\n", '', $docblock_type); } @@ -326,6 +328,22 @@ class CommentAnalyzer continue; } + if ($char === '/' && $next_char === '/') { + // Ignore the rest of the current line + $i = strpos($return_block, "\n", $i); + if ($i === false) { + throw new IncorrectDocblockException( + 'Comment lines must be terminated with a new line character (\\n).', + ); + } + + // Remove trailing whitespaces (needed for `sanitizeDocblockType`) + $type = rtrim($type); + $type .= "\n"; + + continue; + } + if ($char === '[' || $char === '{' || $char === '(' || $char === '<') { $brackets .= $char; } elseif ($char === ']' || $char === '}' || $char === ')' || $char === '>') { @@ -346,6 +364,11 @@ class CommentAnalyzer continue; } + if ($next_char === '{') { + $type .= ' '; + continue; + } + if ($next_char === '|' || $next_char === '&') { $nexter_char = $i < $l - 2 ? $return_block[$i + 2] : null; @@ -377,7 +400,7 @@ class CommentAnalyzer $remaining = trim(preg_replace('@^[ \t]*\* *@m', ' ', substr($return_block, $i + 1))); if ($remaining) { - return array_merge([rtrim($type)], preg_split('/[ \s]+/', $remaining) ?: []); + return array_merge([rtrim($type)], preg_split('/\s+/', $remaining) ?: []); } return [$type]; diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php index 7f6ce4ce..d9879558 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php @@ -32,7 +32,6 @@ use function array_combine; use function array_diff_key; use function array_keys; use function count; -use function implode; use function strpos; use function strtolower; @@ -283,7 +282,7 @@ class FileAnalyzer extends SourceAnalyzer } elseif ($stmt instanceof PhpParser\Node\Stmt\ClassLike) { $this->populateClassLikeAnalyzers($stmt); } elseif ($stmt instanceof PhpParser\Node\Stmt\Namespace_) { - $namespace_name = $stmt->name ? implode('\\', $stmt->name->parts) : ''; + $namespace_name = $stmt->name ? $stmt->name->toString() : ''; $namespace_analyzer = new NamespaceAnalyzer($stmt, $this); $namespace_analyzer->collectAnalyzableInformation(); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/IssueData.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/IssueData.php index 6b273c0b..72e72b21 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/IssueData.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/IssueData.php @@ -11,6 +11,12 @@ use const STR_PAD_LEFT; */ class IssueData { + public const SEVERITY_INFO = 'info'; + public const SEVERITY_ERROR = 'error'; + + /** + * @var self::SEVERITY_* + */ public string $severity; public int $line_from; @@ -93,6 +99,7 @@ class IssueData public ?string $dupe_key = null; /** + * @param self::SEVERITY_* $severity * @param ?list $taint_trace * @param ?list $other_references */ diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php index 6b5d2809..a01318a3 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php @@ -14,7 +14,6 @@ use UnexpectedValueException; use function assert; use function count; -use function implode; use function is_string; use function preg_replace; use function strpos; @@ -49,7 +48,7 @@ class NamespaceAnalyzer extends SourceAnalyzer { $this->source = $source; $this->namespace = $namespace; - $this->namespace_name = $this->namespace->name ? implode('\\', $this->namespace->name->parts) : ''; + $this->namespace_name = $this->namespace->name ? $this->namespace->name->toString() : ''; } public function collectAnalyzableInformation(): void diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php index 6104e067..a418a52b 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php @@ -1098,6 +1098,15 @@ class ProjectAnalyzer } } + public function finish(float $start_time, string $psalm_version): void + { + $this->codebase->file_reference_provider->removeDeletedFilesFromReferences(); + + if ($this->project_cache_provider) { + $this->project_cache_provider->processSuccessfulRun($start_time, $psalm_version); + } + } + public function getConfig(): Config { return $this->config; diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfConditionalAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfConditionalAnalyzer.php index ea9e450f..e1c5e5e4 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfConditionalAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfConditionalAnalyzer.php @@ -238,13 +238,13 @@ class IfConditionalAnalyzer || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Identical ) { if ($stmt->left instanceof PhpParser\Node\Expr\ConstFetch - && $stmt->left->name->parts === ['true'] + && $stmt->left->name->getParts() === ['true'] ) { return self::getDefinitelyEvaluatedExpressionAfterIf($stmt->right); } if ($stmt->right instanceof PhpParser\Node\Expr\ConstFetch - && $stmt->right->name->parts === ['true'] + && $stmt->right->name->getParts() === ['true'] ) { return self::getDefinitelyEvaluatedExpressionAfterIf($stmt->left); } @@ -282,13 +282,13 @@ class IfConditionalAnalyzer || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Identical ) { if ($stmt->left instanceof PhpParser\Node\Expr\ConstFetch - && $stmt->left->name->parts === ['true'] + && $stmt->left->name->getParts() === ['true'] ) { return self::getDefinitelyEvaluatedExpressionInsideIf($stmt->right); } if ($stmt->right instanceof PhpParser\Node\Expr\ConstFetch - && $stmt->right->name->parts === ['true'] + && $stmt->right->name->getParts() === ['true'] ) { return self::getDefinitelyEvaluatedExpressionInsideIf($stmt->left); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfElse/ElseIfAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfElse/ElseIfAnalyzer.php index 4ff32acc..f55d1d0a 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfElse/ElseIfAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfElse/ElseIfAnalyzer.php @@ -358,16 +358,6 @@ class ElseIfAnalyzer $elseif_context->inside_loop, new CodeLocation($statements_analyzer->getSource(), $elseif, $outer_context->include_location), ); - - $updated_vars = []; - - $outer_context->update( - $elseif_context, - $implied_outer_context, - false, - array_keys($negated_elseif_types), - $updated_vars, - ); } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/SwitchCaseAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/SwitchCaseAnalyzer.php index 5fd9b4b1..e116f117 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/SwitchCaseAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/SwitchCaseAnalyzer.php @@ -209,7 +209,7 @@ class SwitchCaseAnalyzer } if ($switch_condition instanceof PhpParser\Node\Expr\ConstFetch - && $switch_condition->name->parts === ['true'] + && $switch_condition->name->getParts() === ['true'] ) { $case_equality_expr = $case->cond; } elseif (($switch_condition_type = $statements_analyzer->node_data->getType($switch_condition)) diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/WhileAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/WhileAnalyzer.php index a1fd1707..bb486123 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/WhileAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/WhileAnalyzer.php @@ -26,7 +26,8 @@ class WhileAnalyzer PhpParser\Node\Stmt\While_ $stmt, Context $context ): ?bool { - $while_true = ($stmt->cond instanceof PhpParser\Node\Expr\ConstFetch && $stmt->cond->name->parts === ['true']) + $while_true = ($stmt->cond instanceof PhpParser\Node\Expr\ConstFetch + && $stmt->cond->name->getParts() === ['true']) || (($t = $statements_analyzer->node_data->getType($stmt->cond)) && $t->isAlwaysTruthy()); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php index 3396deae..fc57f217 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php @@ -830,7 +830,7 @@ class AssertionFinder $if_types[$first_var_name] = [[new IsType(new TCallableString())]]; } } elseif ($expr->name instanceof PhpParser\Node\Name - && strtolower($expr->name->parts[0]) === 'method_exists' + && strtolower($expr->name->getFirst()) === 'method_exists' && isset($expr->getArgs()[1]) && $expr->getArgs()[1]->value instanceof PhpParser\Node\Scalar\String_ ) { @@ -1233,7 +1233,7 @@ class AssertionFinder FileSource $source ): array { if ($stmt->class instanceof PhpParser\Node\Name) { - if (!in_array(strtolower($stmt->class->parts[0]), ['self', 'static', 'parent'], true)) { + if (!in_array(strtolower($stmt->class->getFirst()), ['self', 'static', 'parent'], true)) { $instanceof_class = ClassLikeAnalyzer::getFQCLNFromNameObject( $stmt->class, $source->getAliases(), @@ -1248,8 +1248,8 @@ class AssertionFinder } if ($this_class_name - && (in_array(strtolower($stmt->class->parts[0]), ['self', 'static'], true))) { - $is_static = $stmt->class->parts[0] === 'static'; + && (in_array(strtolower($stmt->class->getFirst()), ['self', 'static'], true))) { + $is_static = $stmt->class->getFirst() === 'static'; $named_object = new TNamedObject($this_class_name, $is_static); if ($is_static) { @@ -1297,13 +1297,13 @@ class AssertionFinder FileSource $source ): ?int { if ($conditional->right instanceof PhpParser\Node\Expr\ConstFetch - && strtolower($conditional->right->name->parts[0]) === 'null' + && strtolower($conditional->right->name->getFirst()) === 'null' ) { return self::ASSIGNMENT_TO_RIGHT; } if ($conditional->left instanceof PhpParser\Node\Expr\ConstFetch - && strtolower($conditional->left->name->parts[0]) === 'null' + && strtolower($conditional->left->name->getFirst()) === 'null' ) { return self::ASSIGNMENT_TO_LEFT; } @@ -1325,13 +1325,13 @@ class AssertionFinder PhpParser\Node\Expr\BinaryOp $conditional ): ?int { if ($conditional->right instanceof PhpParser\Node\Expr\ConstFetch - && strtolower($conditional->right->name->parts[0]) === 'false' + && strtolower($conditional->right->name->getFirst()) === 'false' ) { return self::ASSIGNMENT_TO_RIGHT; } if ($conditional->left instanceof PhpParser\Node\Expr\ConstFetch - && strtolower($conditional->left->name->parts[0]) === 'false' + && strtolower($conditional->left->name->getFirst()) === 'false' ) { return self::ASSIGNMENT_TO_LEFT; } @@ -1346,13 +1346,13 @@ class AssertionFinder PhpParser\Node\Expr\BinaryOp $conditional ): ?int { if ($conditional->right instanceof PhpParser\Node\Expr\ConstFetch - && strtolower($conditional->right->name->parts[0]) === 'true' + && strtolower($conditional->right->name->getFirst()) === 'true' ) { return self::ASSIGNMENT_TO_RIGHT; } if ($conditional->left instanceof PhpParser\Node\Expr\ConstFetch - && strtolower($conditional->left->name->parts[0]) === 'true' + && strtolower($conditional->left->name->getFirst()) === 'true' ) { return self::ASSIGNMENT_TO_LEFT; } @@ -1390,7 +1390,7 @@ class AssertionFinder ) { if ($conditional->right instanceof PhpParser\Node\Expr\FuncCall && $conditional->right->name instanceof PhpParser\Node\Name - && strtolower($conditional->right->name->parts[0]) === 'gettype' + && strtolower($conditional->right->name->getFirst()) === 'gettype' && $conditional->right->getArgs() && $conditional->left instanceof PhpParser\Node\Scalar\String_ ) { @@ -1399,7 +1399,7 @@ class AssertionFinder if ($conditional->left instanceof PhpParser\Node\Expr\FuncCall && $conditional->left->name instanceof PhpParser\Node\Name - && strtolower($conditional->left->name->parts[0]) === 'gettype' + && strtolower($conditional->left->name->getFirst()) === 'gettype' && $conditional->left->getArgs() && $conditional->right instanceof PhpParser\Node\Scalar\String_ ) { @@ -1418,7 +1418,7 @@ class AssertionFinder ) { if ($conditional->right instanceof PhpParser\Node\Expr\FuncCall && $conditional->right->name instanceof PhpParser\Node\Name - && strtolower($conditional->right->name->parts[0]) === 'get_debug_type' + && strtolower($conditional->right->name->getFirst()) === 'get_debug_type' && $conditional->right->getArgs() && ($conditional->left instanceof PhpParser\Node\Scalar\String_ || $conditional->left instanceof PhpParser\Node\Expr\ClassConstFetch) @@ -1428,7 +1428,7 @@ class AssertionFinder if ($conditional->left instanceof PhpParser\Node\Expr\FuncCall && $conditional->left->name instanceof PhpParser\Node\Name - && strtolower($conditional->left->name->parts[0]) === 'get_debug_type' + && strtolower($conditional->left->name->getFirst()) === 'get_debug_type' && $conditional->left->getArgs() && ($conditional->right instanceof PhpParser\Node\Scalar\String_ || $conditional->right instanceof PhpParser\Node\Expr\ClassConstFetch) @@ -1453,11 +1453,11 @@ class AssertionFinder $right_get_class = $conditional->right instanceof PhpParser\Node\Expr\FuncCall && $conditional->right->name instanceof PhpParser\Node\Name - && strtolower($conditional->right->name->parts[0]) === 'get_class'; + && strtolower($conditional->right->name->getFirst()) === 'get_class'; $right_static_class = $conditional->right instanceof PhpParser\Node\Expr\ClassConstFetch && $conditional->right->class instanceof PhpParser\Node\Name - && $conditional->right->class->parts === ['static'] + && $conditional->right->class->getParts() === ['static'] && $conditional->right->name instanceof PhpParser\Node\Identifier && strtolower($conditional->right->name->name) === 'class'; @@ -1492,11 +1492,11 @@ class AssertionFinder $left_get_class = $conditional->left instanceof PhpParser\Node\Expr\FuncCall && $conditional->left->name instanceof PhpParser\Node\Name - && strtolower($conditional->left->name->parts[0]) === 'get_class'; + && strtolower($conditional->left->name->getFirst()) === 'get_class'; $left_static_class = $conditional->left instanceof PhpParser\Node\Expr\ClassConstFetch && $conditional->left->class instanceof PhpParser\Node\Name - && $conditional->left->class->parts === ['static'] + && $conditional->left->class->getParts() === ['static'] && $conditional->left->name instanceof PhpParser\Node\Identifier && strtolower($conditional->left->name->name) === 'class'; @@ -1542,7 +1542,7 @@ class AssertionFinder ) { if ($conditional->left instanceof PhpParser\Node\Expr\FuncCall && $conditional->left->name instanceof PhpParser\Node\Name - && in_array(strtolower($conditional->left->name->parts[0]), ['count', 'sizeof']) + && in_array(strtolower($conditional->left->name->getFirst()), ['count', 'sizeof']) && $conditional->left->getArgs() && ($conditional instanceof BinaryOp\Greater || $conditional instanceof BinaryOp\GreaterOrEqual) ) { @@ -1551,7 +1551,7 @@ class AssertionFinder $comparison_adjustment = $conditional instanceof BinaryOp\Greater ? 1 : 0; } elseif ($conditional->right instanceof PhpParser\Node\Expr\FuncCall && $conditional->right->name instanceof PhpParser\Node\Name - && in_array(strtolower($conditional->right->name->parts[0]), ['count', 'sizeof']) + && in_array(strtolower($conditional->right->name->getFirst()), ['count', 'sizeof']) && $conditional->right->getArgs() && ($conditional instanceof BinaryOp\Smaller || $conditional instanceof BinaryOp\SmallerOrEqual) ) { @@ -1584,7 +1584,7 @@ class AssertionFinder ) { $left_count = $conditional->left instanceof PhpParser\Node\Expr\FuncCall && $conditional->left->name instanceof PhpParser\Node\Name - && in_array(strtolower($conditional->left->name->parts[0]), ['count', 'sizeof']) + && in_array(strtolower($conditional->left->name->getFirst()), ['count', 'sizeof']) && $conditional->left->getArgs(); $operator_less_than_or_equal = @@ -1603,7 +1603,7 @@ class AssertionFinder $right_count = $conditional->right instanceof PhpParser\Node\Expr\FuncCall && $conditional->right->name instanceof PhpParser\Node\Name - && in_array(strtolower($conditional->right->name->parts[0]), ['count', 'sizeof']) + && in_array(strtolower($conditional->right->name->getFirst()), ['count', 'sizeof']) && $conditional->right->getArgs(); $operator_greater_than_or_equal = @@ -1633,7 +1633,7 @@ class AssertionFinder ) { $left_count = $conditional->left instanceof PhpParser\Node\Expr\FuncCall && $conditional->left->name instanceof PhpParser\Node\Name - && in_array(strtolower($conditional->left->name->parts[0]), ['count', 'sizeof']) + && in_array(strtolower($conditional->left->name->getFirst()), ['count', 'sizeof']) && $conditional->left->getArgs(); if ($left_count && $conditional->right instanceof PhpParser\Node\Scalar\LNumber) { @@ -1644,7 +1644,7 @@ class AssertionFinder $right_count = $conditional->right instanceof PhpParser\Node\Expr\FuncCall && $conditional->right->name instanceof PhpParser\Node\Name - && in_array(strtolower($conditional->right->name->parts[0]), ['count', 'sizeof']) + && in_array(strtolower($conditional->right->name->getFirst()), ['count', 'sizeof']) && $conditional->right->getArgs(); if ($right_count && $conditional->left instanceof PhpParser\Node\Scalar\LNumber) { @@ -1785,7 +1785,7 @@ class AssertionFinder ) { $left_count = $conditional->left instanceof PhpParser\Node\Expr\FuncCall && $conditional->left->name instanceof PhpParser\Node\Name - && in_array(strtolower($conditional->left->name->parts[0]), ['count', 'sizeof']); + && in_array(strtolower($conditional->left->name->getFirst()), ['count', 'sizeof']); $right_number = $conditional->right instanceof PhpParser\Node\Scalar\LNumber && $conditional->right->value === ( @@ -1841,8 +1841,8 @@ class AssertionFinder StatementsAnalyzer $source ): bool { if ($stmt->name instanceof PhpParser\Node\Name - && (strtolower($stmt->name->parts[0]) === 'is_a' - || strtolower($stmt->name->parts[0]) === 'is_subclass_of') + && (strtolower($stmt->name->getFirst()) === 'is_a' + || strtolower($stmt->name->getFirst()) === 'is_subclass_of') && isset($stmt->getArgs()[1]) ) { $second_arg = $stmt->getArgs()[1]->value; @@ -1920,7 +1920,7 @@ class AssertionFinder ): array { $if_types = []; if ($stmt->name instanceof PhpParser\Node\Name - && ($function_name = strtolower($stmt->name->parts[0])) + && ($function_name = strtolower($stmt->name->getFirst())) && ($assertion_type = self::getIsAssertion($function_name)) && $source instanceof StatementsAnalyzer && ($source->getNamespace() === null //either the namespace is null @@ -1954,7 +1954,7 @@ class AssertionFinder protected static function hasCallableCheck(PhpParser\Node\Expr\FuncCall $stmt): bool { - return $stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->parts[0]) === 'is_callable'; + return $stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->getFirst()) === 'is_callable'; } /** @@ -1963,7 +1963,7 @@ class AssertionFinder protected static function hasClassExistsCheck(PhpParser\Node\Expr\FuncCall $stmt): int { if ($stmt->name instanceof PhpParser\Node\Name - && strtolower($stmt->name->parts[0]) === 'class_exists' + && strtolower($stmt->name->getFirst()) === 'class_exists' ) { if (!isset($stmt->getArgs()[1])) { return 2; @@ -1972,7 +1972,7 @@ class AssertionFinder $second_arg = $stmt->getArgs()[1]->value; if ($second_arg instanceof PhpParser\Node\Expr\ConstFetch - && strtolower($second_arg->name->parts[0]) === 'true' + && strtolower($second_arg->name->getFirst()) === 'true' ) { return 2; } @@ -1989,7 +1989,7 @@ class AssertionFinder protected static function hasTraitExistsCheck(PhpParser\Node\Expr\FuncCall $stmt): int { if ($stmt->name instanceof PhpParser\Node\Name - && strtolower($stmt->name->parts[0]) === 'trait_exists' + && strtolower($stmt->name->getFirst()) === 'trait_exists' ) { if (!isset($stmt->getArgs()[1])) { return 2; @@ -1998,7 +1998,7 @@ class AssertionFinder $second_arg = $stmt->getArgs()[1]->value; if ($second_arg instanceof PhpParser\Node\Expr\ConstFetch - && strtolower($second_arg->name->parts[0]) === 'true' + && strtolower($second_arg->name->getFirst()) === 'true' ) { return 2; } @@ -2011,29 +2011,29 @@ class AssertionFinder protected static function hasEnumExistsCheck(PhpParser\Node\Expr\FuncCall $stmt): bool { - return $stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->parts[0]) === 'enum_exists'; + return $stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->getFirst()) === 'enum_exists'; } protected static function hasInterfaceExistsCheck(PhpParser\Node\Expr\FuncCall $stmt): bool { - return $stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->parts[0]) === 'interface_exists'; + return $stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->getFirst()) === 'interface_exists'; } protected static function hasFunctionExistsCheck(PhpParser\Node\Expr\FuncCall $stmt): bool { - return $stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->parts[0]) === 'function_exists'; + return $stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->getFirst()) === 'function_exists'; } protected static function hasInArrayCheck(PhpParser\Node\Expr\FuncCall $stmt): bool { if ($stmt->name instanceof PhpParser\Node\Name - && strtolower($stmt->name->parts[0]) === 'in_array' + && strtolower($stmt->name->getFirst()) === 'in_array' && isset($stmt->getArgs()[2]) ) { $second_arg = $stmt->getArgs()[2]->value; if ($second_arg instanceof PhpParser\Node\Expr\ConstFetch - && strtolower($second_arg->name->parts[0]) === 'true' + && strtolower($second_arg->name->getFirst()) === 'true' ) { return true; } @@ -2045,12 +2045,12 @@ class AssertionFinder protected static function hasNonEmptyCountCheck(PhpParser\Node\Expr\FuncCall $stmt): bool { return $stmt->name instanceof PhpParser\Node\Name && - in_array(strtolower($stmt->name->parts[0]), ['count', 'sizeof']); + in_array(strtolower($stmt->name->getFirst()), ['count', 'sizeof']); } protected static function hasArrayKeyExistsCheck(PhpParser\Node\Expr\FuncCall $stmt): bool { - return $stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->parts[0]) === 'array_key_exists'; + return $stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->getFirst()) === 'array_key_exists'; } /** @@ -2254,6 +2254,7 @@ class AssertionFinder } /** + * @psalm-suppress MoreSpecificReturnType * @param PhpParser\Node\Expr\BinaryOp\NotIdentical|PhpParser\Node\Expr\BinaryOp\NotEqual $conditional * @return list>>> */ @@ -2325,15 +2326,45 @@ class AssertionFinder } if (count($notif_types) === 1) { - $notif_types = $notif_types[0]; + $notif_type = $notif_types[0]; - if (count($notif_types) === 1) { - $if_types = Algebra::negateTypes($notif_types); + if (count($notif_type) === 1) { + $if_types = Algebra::negateTypes($notif_type); } } $if_types = $if_types ? [$if_types] : []; + if ($if_types === [] && count($notif_types) === 2) { + $check_var_assertion = null; + $check_var = null; + foreach ($notif_types as $notif_type) { + foreach ($notif_type as $var => $assertions) { + if (count($assertions) !== 1 || count($assertions[0]) !== 1) { + $if_types = []; + break 2; + } + + $is_not_assertion = $assertions[0][0] instanceof IsNotType ? true : false; + if (!isset($check_var)) { + $check_var_assertion = $is_not_assertion; + $check_var = $var; + continue; + } + + // only if we have 1 IsType and 1 IsNotType assertion for same variable + if ($check_var !== $var + || !isset($check_var_assertion) + || $check_var_assertion === $is_not_assertion) { + $if_types = []; + break 2; + } + } + + $if_types[] = Algebra::negateTypes($notif_type); + } + } + if ($codebase && $source instanceof StatementsAnalyzer && ($var_type = $source->node_data->getType($base_conditional)) @@ -2373,6 +2404,7 @@ class AssertionFinder } } + /** @psalm-suppress LessSpecificReturnStatement */ return $if_types; } @@ -2951,6 +2983,7 @@ class AssertionFinder } /** + * @psalm-suppress MoreSpecificReturnType * @param PhpParser\Node\Expr\BinaryOp\Identical|PhpParser\Node\Expr\BinaryOp\Equal $conditional * @return list>>> */ @@ -3022,15 +3055,48 @@ class AssertionFinder } if (count($notif_types) === 1) { - $notif_types = $notif_types[0]; + $notif_type = $notif_types[0]; - if (count($notif_types) === 1) { - $if_types = Algebra::negateTypes($notif_types); + if (count($notif_type) === 1) { + $if_types = Algebra::negateTypes($notif_type); } } $if_types = $if_types ? [$if_types] : []; + // @psalm-assert-if-true and @psalm-assert-if-false for same variable in same function, e.g. array/list cases + // @todo optionally extend this to arbitrary number of assert-if cases of multiple variables in the function + // same code above too + if ($if_types === [] && count($notif_types) === 2) { + $check_var_assertion = null; + $check_var = null; + foreach ($notif_types as $notif_type) { + foreach ($notif_type as $var => $assertions) { + if (count($assertions) !== 1 || count($assertions[0]) !== 1) { + $if_types = []; + break 2; + } + + $is_not_assertion = $assertions[0][0] instanceof IsNotType ? true : false; + if (!isset($check_var)) { + $check_var_assertion = $is_not_assertion; + $check_var = $var; + continue; + } + + // only if we have 1 IsType and 1 IsNotType assertion for same variable + if ($check_var !== $var + || !isset($check_var_assertion) + || $check_var_assertion === $is_not_assertion) { + $if_types = []; + break 2; + } + } + + $if_types[] = Algebra::negateTypes($notif_type); + } + } + if ($codebase && $source instanceof StatementsAnalyzer && ($var_type = $source->node_data->getType($base_conditional)) @@ -3066,6 +3132,7 @@ class AssertionFinder } } + /** @psalm-suppress LessSpecificReturnStatement */ return $if_types; } @@ -3408,56 +3475,53 @@ class AssertionFinder throw new UnexpectedValueException('$typed_value_position value'); } - if ($var_name && $var_type) { - $identical = $conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical - || ($other_type - && (($var_type->isString(true) && $other_type->isString(true)) - || ($var_type->isInt(true) && $other_type->isInt(true)) - || ($var_type->isFloat() && $other_type->isFloat()) - ) - ); + //soit on a un === explicite, soit on compare des types strictement égaux + $identical = $conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical + || ($other_type && $var_type + && (($var_type->isString(true) && $other_type->isString(true)) + || ($var_type->isInt(true) && $other_type->isInt(true)) + || ($var_type->isFloat() && $other_type->isFloat()) + ) + ); - if (count($var_type->getAtomicTypes()) === 1) { - $orred_types = []; + if ($var_name + && $var_type + && !$var_type->isMixed() + && count($var_type->getAtomicTypes()) === 1 + ) { + $orred_types = []; - foreach ($var_type->getAtomicTypes() as $atomic_var_type) { - if ($identical) { - $orred_types[] = new IsIdentical($atomic_var_type); - } else { - $orred_types[] = new IsLooselyEqual($atomic_var_type); - } + foreach ($var_type->getAtomicTypes() as $atomic_var_type) { + if ($identical) { + $orred_types[] = new IsIdentical($atomic_var_type); + } else { + $orred_types[] = new IsLooselyEqual($atomic_var_type); } - - $if_types[$var_name] = [$orred_types]; } - if ($other_var_name - && $other_type - && !$other_type->isMixed() - && count($other_type->getAtomicTypes()) === 1 - ) { - $orred_types = []; - - foreach ($other_type->getAtomicTypes() as $atomic_other_type) { - if ($identical) { - $orred_types[] = new IsIdentical($atomic_other_type); - } else { - $orred_types[] = new IsLooselyEqual($atomic_other_type); - } - } - - $if_types[$other_var_name] = [$orred_types]; - } + $if_types[$var_name] = [$orred_types]; } - if ($codebase + if ($other_var_name && $other_type - && $var_type - && ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical - || ($other_type->isString() - && $var_type->isString()) - ) + && !$other_type->isMixed() + && count($other_type->getAtomicTypes()) === 1 + && $other_var_name[0] === '$' //don't try to assert on constant or other, it's too perf consuming ) { + $orred_types = []; + + foreach ($other_type->getAtomicTypes() as $atomic_other_type) { + if ($identical) { + $orred_types[] = new IsIdentical($atomic_other_type); + } else { + $orred_types[] = new IsLooselyEqual($atomic_other_type); + } + } + + $if_types[$other_var_name] = [$orred_types]; + } + + if ($codebase && $other_type && $var_type && $identical) { self::handleParadoxicalAssertions( $source, $var_type, @@ -3486,8 +3550,8 @@ class AssertionFinder && $expr->getArgs()[0]->value->name instanceof PhpParser\Node\Identifier && strtolower($expr->getArgs()[0]->value->name->name) === 'class' && $expr->getArgs()[0]->value->class instanceof PhpParser\Node\Name - && count($expr->getArgs()[0]->value->class->parts) === 1 - && strtolower($expr->getArgs()[0]->value->class->parts[0]) === 'static' + && count($expr->getArgs()[0]->value->class->getParts()) === 1 + && strtolower($expr->getArgs()[0]->value->class->getFirst()) === 'static' ) { $first_var_name = '$this'; } @@ -3498,14 +3562,14 @@ class AssertionFinder $third_arg = $expr->getArgs()[2]->value ?? null; if ($third_arg instanceof PhpParser\Node\Expr\ConstFetch) { - if (!in_array(strtolower($third_arg->name->parts[0]), ['true', 'false'])) { + if (!in_array(strtolower($third_arg->name->getFirst()), ['true', 'false'])) { return []; } - $third_arg_value = strtolower($third_arg->name->parts[0]); + $third_arg_value = strtolower($third_arg->name->getFirst()); } else { $third_arg_value = $expr->name instanceof PhpParser\Node\Name - && strtolower($expr->name->parts[0]) === 'is_subclass_of' + && strtolower($expr->name->getFirst()) === 'is_subclass_of' ? 'true' : 'false'; } @@ -3532,18 +3596,18 @@ class AssertionFinder ) { $class_node = $second_arg->class; - if ($class_node->parts === ['static']) { + if ($class_node->getParts() === ['static']) { if ($this_class_name) { $object = new TNamedObject($this_class_name, true); $if_types[$first_var_name] = [[new IsAClass($object, $third_arg_value === 'true')]]; } - } elseif ($class_node->parts === ['self']) { + } elseif ($class_node->getParts() === ['self']) { if ($this_class_name) { $object = new TNamedObject($this_class_name); $if_types[$first_var_name] = [[new IsAClass($object, $third_arg_value === 'true')]]; } - } elseif ($class_node->parts === ['parent']) { + } elseif ($class_node->getParts() === ['parent']) { // do nothing } else { $object = new TNamedObject( diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php index 509acb41..76c7073c 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php @@ -981,17 +981,23 @@ class AssignmentAnalyzer $context->references_to_external_scope[$lhs_var_id] = true; } if (strpos($rhs_var_id, '->') !== false) { - IssueBuffer::maybeAdd(new UnsupportedPropertyReferenceUsage( - new CodeLocation($statements_analyzer->getSource(), $stmt), - )); + IssueBuffer::maybeAdd( + new UnsupportedPropertyReferenceUsage( + new CodeLocation($statements_analyzer->getSource(), $stmt), + ), + $statements_analyzer->getSuppressedIssues(), + ); // Reference to object property, we always consider object properties to be an external scope for references // TODO handle differently so it's detected as unused if the object is unused? $context->references_to_external_scope[$lhs_var_id] = true; } if (strpos($rhs_var_id, '::') !== false) { - IssueBuffer::maybeAdd(new UnsupportedPropertyReferenceUsage( - new CodeLocation($statements_analyzer->getSource(), $stmt), - )); + IssueBuffer::maybeAdd( + new UnsupportedPropertyReferenceUsage( + new CodeLocation($statements_analyzer->getSource(), $stmt), + ), + $statements_analyzer->getSuppressedIssues(), + ); } $lhs_location = new CodeLocation($statements_analyzer->getSource(), $stmt->var); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ArithmeticOpAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ArithmeticOpAnalyzer.php index 9be82c7c..36ae21d6 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ArithmeticOpAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ArithmeticOpAnalyzer.php @@ -815,11 +815,9 @@ class ArithmeticOpAnalyzer if ($right_type_part instanceof TLiteralInt) { $literal_value_max = $right_type_part->value - 1; if ($always_positive) { - $result_type = new Union([new TIntRange(0, $literal_value_max)]); + $result_type = Type::getIntRange(0, $literal_value_max); } else { - $result_type = new Union( - [new TIntRange(-$literal_value_max, $literal_value_max)], - ); + $result_type = Type::getIntRange(-$literal_value_max, $literal_value_max); } } else { if ($always_positive) { @@ -830,7 +828,7 @@ class ArithmeticOpAnalyzer } } else { $result_type = Type::combineUnionTypes( - $always_positive ? new Union([new TIntRange(1, null)]) : Type::getInt(true), + $always_positive ? Type::getIntRange(1, null) : Type::getInt(true), $result_type, ); } @@ -1072,7 +1070,7 @@ class ArithmeticOpAnalyzer $min_value = $calculated_min_type !== null ? $calculated_min_type->getSingleIntLiteral()->value : null; $max_value = $calculated_max_type !== null ? $calculated_max_type->getSingleIntLiteral()->value : null; - $new_result_type = new Union([new TIntRange($min_value, $max_value)]); + $new_result_type = Type::getIntRange($min_value, $max_value); $result_type = Type::combineUnionTypes($new_result_type, $result_type); } @@ -1122,7 +1120,7 @@ class ArithmeticOpAnalyzer $min_value = min($x_1 * $y_1, $x_1 * $y_2, $x_2 * $y_1, $x_2 * $y_2); $max_value = max($x_1 * $y_1, $x_1 * $y_2, $x_2 * $y_1, $x_2 * $y_2); - $new_result_type = new Union([new TIntRange($min_value, $max_value)]); + $new_result_type = Type::getIntRange($min_value, $max_value); } elseif ($right_type_part->isPositiveOrZero() && $left_type_part->isPositiveOrZero()) { // both operands are positive, result will be only positive $min_operand1 = $left_type_part->min_bound; @@ -1156,7 +1154,7 @@ class ArithmeticOpAnalyzer $min_value = $calculated_min_type !== null ? $calculated_min_type->getSingleIntLiteral()->value : null; $max_value = $calculated_max_type !== null ? $calculated_max_type->getSingleIntLiteral()->value : null; - $new_result_type = new Union([new TIntRange($min_value, $max_value)]); + $new_result_type = Type::getIntRange($min_value, $max_value); } elseif ($right_type_part->isPositiveOrZero() && $left_type_part->isNegativeOrZero()) { // one operand is negative, result will be negative and we have to check min vs max $min_operand1 = $left_type_part->max_bound; @@ -1194,7 +1192,7 @@ class ArithmeticOpAnalyzer [$min_value, $max_value] = [$max_value, $min_value]; } - $new_result_type = new Union([new TIntRange($min_value, $max_value)]); + $new_result_type = Type::getIntRange($min_value, $max_value); } elseif ($right_type_part->isNegativeOrZero() && $left_type_part->isPositiveOrZero()) { // one operand is negative, result will be negative and we have to check min vs max $min_operand1 = $left_type_part->min_bound; @@ -1232,7 +1230,7 @@ class ArithmeticOpAnalyzer [$min_value, $max_value] = [$max_value, $min_value]; } - $new_result_type = new Union([new TIntRange($min_value, $max_value)]); + $new_result_type = Type::getIntRange($min_value, $max_value); } elseif ($right_type_part->isNegativeOrZero() && $left_type_part->isNegativeOrZero()) { // both operand are negative, result will be positive $min_operand1 = $left_type_part->max_bound; @@ -1266,7 +1264,7 @@ class ArithmeticOpAnalyzer $min_value = $calculated_min_type !== null ? $calculated_min_type->getSingleIntLiteral()->value : null; $max_value = $calculated_max_type !== null ? $calculated_max_type->getSingleIntLiteral()->value : null; - $new_result_type = new Union([new TIntRange($min_value, $max_value)]); + $new_result_type = Type::getIntRange($min_value, $max_value); } else { $new_result_type = Type::getInt(true); } @@ -1283,7 +1281,7 @@ class ArithmeticOpAnalyzer //If Pow second operand is negative, the result will be float, if it's 0, it will be 1/-1, else positive if ($left_type_part->isPositive()) { if ($right_type_part->isPositive()) { - $new_result_type = new Union([new TIntRange(1, null)]); + $new_result_type = Type::getIntRange(1, null); } elseif ($right_type_part->isNegative()) { $new_result_type = Type::getFloat(); } elseif ($right_type_part->min_bound === 0 && $right_type_part->max_bound === 0) { @@ -1296,9 +1294,9 @@ class ArithmeticOpAnalyzer if ($right_type_part->isPositive()) { if ($right_type_part->min_bound === $right_type_part->max_bound) { if ($right_type_part->max_bound % 2 === 0) { - $new_result_type = new Union([new TIntRange(1, null)]); + $new_result_type = Type::getIntRange(1, null); } else { - $new_result_type = new Union([new TIntRange(null, -1)]); + $new_result_type = Type::getIntRange(null, -1); } } else { $new_result_type = Type::getInt(true); @@ -1330,7 +1328,7 @@ class ArithmeticOpAnalyzer if ($right_type_part->min_bound === $right_type_part->max_bound && $right_type_part->max_bound % 2 === 0 ) { - $new_result_type = new Union([new TIntRange(1, null)]); + $new_result_type = Type::getIntRange(1, null); } else { $new_result_type = Type::getInt(true); } @@ -1361,18 +1359,18 @@ class ArithmeticOpAnalyzer if ($left_type_part->isPositiveOrZero()) { if ($right_type_part->isPositive()) { $max = $right_type_part->min_bound - 1; - $new_result_type = new Union([new TIntRange(0, $max)]); + $new_result_type = Type::getIntRange(0, $max); } else { $max = $right_type_part->min_bound + 1; - $new_result_type = new Union([new TIntRange($max, 0)]); + $new_result_type = Type::getIntRange($max, 0); } } elseif ($left_type_part->isNegativeOrZero()) { if ($right_type_part->isPositive()) { $max = $right_type_part->min_bound - 1; - $new_result_type = new Union([new TIntRange(-$max, 0)]); + $new_result_type = Type::getIntRange(-$max, 0); } else { $max = $right_type_part->min_bound + 1; - $new_result_type = new Union([new TIntRange(-$max, 0)]); + $new_result_type = Type::getIntRange(-$max, 0); } } else { if ($right_type_part->isPositive()) { @@ -1380,7 +1378,7 @@ class ArithmeticOpAnalyzer } else { $max = -$right_type_part->min_bound - 1; } - $new_result_type = new Union([new TIntRange(-$max, $max)]); + $new_result_type = Type::getIntRange(-$max, $max); } } } elseif ($right_type_part->isPositive()) { @@ -1394,15 +1392,15 @@ class ArithmeticOpAnalyzer $new_result_type = Type::getListKey(); } } elseif ($left_type_part->isNegativeOrZero()) { - $new_result_type = new Union([new TIntRange(null, 0)]); + $new_result_type = Type::getIntRange(null, 0); } else { $new_result_type = Type::getInt(true); } } elseif ($right_type_part->isNegative()) { if ($left_type_part->isPositiveOrZero()) { - $new_result_type = new Union([new TIntRange(null, 0)]); + $new_result_type = Type::getIntRange(null, 0); } elseif ($left_type_part->isNegativeOrZero()) { - $new_result_type = new Union([new TIntRange(null, 0)]); + $new_result_type = Type::getIntRange(null, 0); } else { $new_result_type = Type::getInt(true); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOpAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOpAnalyzer.php index 58e8ad5a..da8e3794 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOpAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOpAnalyzer.php @@ -261,7 +261,7 @@ class BinaryOpAnalyzer || $stmt instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical) && $stmt->left instanceof PhpParser\Node\Expr\FuncCall && $stmt->left->name instanceof PhpParser\Node\Name - && $stmt->left->name->parts === ['substr'] + && $stmt->left->name->getParts() === ['substr'] && isset($stmt->left->getArgs()[1]) && $stmt_right_type && $stmt_right_type->hasLiteralString() diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentsAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentsAnalyzer.php index c9fdc523..653ffedc 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentsAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentsAnalyzer.php @@ -268,7 +268,12 @@ class ArgumentsAnalyzer $inferred_arg_type = $statements_analyzer->node_data->getType($arg->value); - if (null !== $inferred_arg_type && null !== $template_result && null !== $param && null !== $param->type) { + if (null !== $inferred_arg_type + && null !== $template_result + && null !== $param + && null !== $param->type + && !$arg->unpack + ) { $codebase = $statements_analyzer->getCodebase(); TemplateStandinTypeReplacer::fillTemplateResult( diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php index 7ecfff03..21bdf3f9 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php @@ -102,7 +102,7 @@ class FunctionCallAnalyzer extends CallAnalyzer && isset($stmt->getArgs()[0]) && !$stmt->getArgs()[0]->unpack ) { - $original_function_id = implode('\\', $function_name->parts); + $original_function_id = implode('\\', $function_name->getParts()); if ($original_function_id === 'call_user_func') { $other_args = array_slice($stmt->getArgs(), 1); @@ -160,7 +160,7 @@ class FunctionCallAnalyzer extends CallAnalyzer $set_inside_conditional = false; if ($function_name instanceof PhpParser\Node\Name - && $function_name->parts === ['assert'] + && $function_name->getParts() === ['assert'] && !$context->inside_conditional ) { $context->inside_conditional = true; @@ -235,7 +235,10 @@ class FunctionCallAnalyzer extends CallAnalyzer $function_call_info->function_id, ); - $template_result->lower_bounds += $already_inferred_lower_bounds; + $template_result->lower_bounds = array_merge( + $template_result->lower_bounds, + $already_inferred_lower_bounds, + ); if ($function_name instanceof PhpParser\Node\Name && $function_call_info->function_id) { $stmt_type = FunctionCallReturnTypeFetcher::fetch( @@ -319,7 +322,7 @@ class FunctionCallAnalyzer extends CallAnalyzer } if ($function_name instanceof PhpParser\Node\Name - && $function_name->parts === ['assert'] + && $function_name->getParts() === ['assert'] && isset($stmt->getArgs()[0]) ) { self::processAssertFunctionEffects( @@ -437,7 +440,7 @@ class FunctionCallAnalyzer extends CallAnalyzer $codebase = $statements_analyzer->getCodebase(); $codebase_functions = $codebase->functions; - $original_function_id = implode('\\', $function_name->parts); + $original_function_id = $function_name->toString(); if (!$function_name instanceof PhpParser\Node\Name\FullyQualified) { $function_call_info->function_id = $codebase_functions->getFullyQualifiedFunctionNameFromString( @@ -487,7 +490,7 @@ class FunctionCallAnalyzer extends CallAnalyzer $is_predefined = true; $is_maybe_root_function = !$function_name instanceof PhpParser\Node\Name\FullyQualified - && count($function_name->parts) === 1; + && count($function_name->getParts()) === 1; $args = $stmt->isFirstClassCallable() ? [] : $stmt->getArgs(); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallReturnTypeFetcher.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallReturnTypeFetcher.php index 7941941c..34dae01f 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallReturnTypeFetcher.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallReturnTypeFetcher.php @@ -383,7 +383,7 @@ class FunctionCallReturnTypeFetcher if ($min === $max) { return new Union([new TLiteralInt($max)]); } - return new Union([new TIntRange($min, $max)]); + return Type::getIntRange($min, $max); } if ($atomic_types['array'] instanceof TArray diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php index b521f8bc..45476ca2 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php @@ -58,7 +58,6 @@ use Psalm\Type\Union; use function array_map; use function array_values; -use function implode; use function in_array; use function md5; use function preg_match; @@ -94,7 +93,7 @@ class NewAnalyzer extends CallAnalyzer } if ($stmt->class instanceof PhpParser\Node\Name) { - if (!in_array(strtolower($stmt->class->parts[0]), ['self', 'static', 'parent'], true)) { + if (!in_array(strtolower($stmt->class->getFirst()), ['self', 'static', 'parent'], true)) { $aliases = $statements_analyzer->getAliases(); if ($context->calling_method_id @@ -102,7 +101,7 @@ class NewAnalyzer extends CallAnalyzer ) { $codebase->file_reference_provider->addMethodReferenceToClassMember( $context->calling_method_id, - 'use:' . $stmt->class->parts[0] . ':' . md5($statements_analyzer->getFilePath()), + 'use:' . $stmt->class->getFirst() . ':' . md5($statements_analyzer->getFilePath()), false, ); } @@ -114,7 +113,7 @@ class NewAnalyzer extends CallAnalyzer $fq_class_name = $codebase->classlikes->getUnAliasedName($fq_class_name); } elseif ($context->self !== null) { - switch ($stmt->class->parts[0]) { + switch ($stmt->class->getFirst()) { case 'self': $class_storage = $codebase->classlike_storage_provider->get($context->self); $fq_class_name = $class_storage->name; @@ -152,7 +151,7 @@ class NewAnalyzer extends CallAnalyzer . ($stmt->class instanceof PhpParser\Node\Name\FullyQualified ? '\\' : $statements_analyzer->getNamespace() . '-') - . implode('\\', $stmt->class->parts), + . $stmt->class->toString(), ); } } elseif ($stmt->class instanceof PhpParser\Node\Stmt\Class_) { @@ -174,7 +173,7 @@ class NewAnalyzer extends CallAnalyzer if ($fq_class_name) { if ($codebase->alter_code && $stmt->class instanceof PhpParser\Node\Name - && !in_array($stmt->class->parts[0], ['parent', 'static']) + && !in_array($stmt->class->getFirst(), ['parent', 'static']) ) { $codebase->classlikes->handleClassLikeReferenceInMigration( $codebase, diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticCallAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticCallAnalyzer.php index a79f2760..fa7cc498 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticCallAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticCallAnalyzer.php @@ -56,10 +56,10 @@ class StaticCallAnalyzer extends CallAnalyzer if ($stmt->class instanceof PhpParser\Node\Name) { $fq_class_name = null; - if (count($stmt->class->parts) === 1 - && in_array(strtolower($stmt->class->parts[0]), ['self', 'static', 'parent'], true) + if (count($stmt->class->getParts()) === 1 + && in_array(strtolower($stmt->class->getFirst()), ['self', 'static', 'parent'], true) ) { - if ($stmt->class->parts[0] === 'parent') { + if ($stmt->class->getFirst() === 'parent') { $child_fq_class_name = $context->self; $class_storage = $child_fq_class_name @@ -84,7 +84,7 @@ class StaticCallAnalyzer extends CallAnalyzer $fq_class_name = $class_storage->name; } elseif ($context->self) { - if ($stmt->class->parts[0] === 'static' && isset($context->vars_in_scope['$this'])) { + if ($stmt->class->getFirst() === 'static' && isset($context->vars_in_scope['$this'])) { $fq_class_name = (string) $context->vars_in_scope['$this']; $lhs_type = $context->vars_in_scope['$this']; } else { @@ -93,7 +93,7 @@ class StaticCallAnalyzer extends CallAnalyzer } else { return !IssueBuffer::accepts( new NonStaticSelfCall( - 'Cannot use ' . $stmt->class->parts[0] . ' outside class context', + 'Cannot use ' . $stmt->class->getFirst() . ' outside class context', new CodeLocation($statements_analyzer->getSource(), $stmt), ), $statements_analyzer->getSuppressedIssues(), @@ -111,7 +111,7 @@ class StaticCallAnalyzer extends CallAnalyzer ) { $codebase->file_reference_provider->addMethodReferenceToClassMember( $context->calling_method_id, - 'use:' . $stmt->class->parts[0] . ':' . md5($statements_analyzer->getFilePath()), + 'use:' . $stmt->class->getFirst() . ':' . md5($statements_analyzer->getFilePath()), false, ); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/AtomicStaticCallAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/AtomicStaticCallAnalyzer.php index 52a87e9a..b0839345 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/AtomicStaticCallAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/AtomicStaticCallAnalyzer.php @@ -99,8 +99,8 @@ class AtomicStaticCallAnalyzer $statements_analyzer->getSuppressedIssues(), new ClassLikeNameOptions( $stmt->class instanceof PhpParser\Node\Name - && count($stmt->class->parts) === 1 - && in_array(strtolower($stmt->class->parts[0]), ['self', 'static'], true), + && count($stmt->class->getParts()) === 1 + && in_array(strtolower($stmt->class->getFirst()), ['self', 'static'], true), ), )) { return; @@ -284,7 +284,7 @@ class AtomicStaticCallAnalyzer && $fq_class_name && !$moved_call && $stmt->class instanceof PhpParser\Node\Name - && !in_array($stmt->class->parts[0], ['parent', 'static']) + && !in_array($stmt->class->getFirst(), ['parent', 'static']) ) { $codebase->classlikes->handleClassLikeReferenceInMigration( $codebase, @@ -293,7 +293,7 @@ class AtomicStaticCallAnalyzer $fq_class_name, $context->calling_method_id, false, - $stmt->class->parts[0] === 'self', + $stmt->class->getFirst() === 'self', ); } } @@ -718,7 +718,7 @@ class AtomicStaticCallAnalyzer if ($pseudo_method_storage->return_type) { return true; } - } elseif ($stmt->class instanceof PhpParser\Node\Name && $stmt->class->parts[0] === 'parent' + } elseif ($stmt->class instanceof PhpParser\Node\Name && $stmt->class->getFirst() === 'parent' && !$codebase->methodExists($method_id) && !$statements_analyzer->isStatic() ) { @@ -846,7 +846,7 @@ class AtomicStaticCallAnalyzer } if ((!$stmt->class instanceof PhpParser\Node\Name - || $stmt->class->parts[0] !== 'parent' + || $stmt->class->getFirst() !== 'parent' || $statements_analyzer->isStatic()) && ( !$context->self @@ -857,7 +857,7 @@ class AtomicStaticCallAnalyzer MethodAnalyzer::checkStatic( $method_id, ($stmt->class instanceof PhpParser\Node\Name - && strtolower($stmt->class->parts[0]) === 'self') + && strtolower($stmt->class->getFirst()) === 'self') || $context->self === $fq_class_name, !$statements_analyzer->isStatic(), $codebase, diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php index 0a604e08..607f5218 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php @@ -156,7 +156,7 @@ class ExistingAtomicStaticCallAnalyzer if ($found_generic_params && $stmt->class instanceof PhpParser\Node\Name - && $stmt->class->parts === ['parent'] + && $stmt->class->getParts() === ['parent'] && $context->self && ($self_class_storage = $codebase->classlike_storage_provider->get($context->self)) && $self_class_storage->template_extended_params @@ -201,7 +201,7 @@ class ExistingAtomicStaticCallAnalyzer return; } - $fq_class_name = $stmt->class instanceof PhpParser\Node\Name && $stmt->class->parts === ['parent'] + $fq_class_name = $stmt->class instanceof PhpParser\Node\Name && $stmt->class->getParts() === ['parent'] ? (string) $statements_analyzer->getFQCLN() : $fq_class_name; @@ -371,7 +371,7 @@ class ExistingAtomicStaticCallAnalyzer $new_fq_class_name, $context->calling_method_id, strtolower($old_declaring_fq_class_name) !== strtolower($new_fq_class_name), - $stmt->class->parts[0] === 'self', + $stmt->class->getFirst() === 'self', )) { $moved_call = true; } @@ -519,8 +519,8 @@ class ExistingAtomicStaticCallAnalyzer $lhs_type_part->defining_class, ); } elseif ($stmt->class instanceof PhpParser\Node\Name - && count($stmt->class->parts) === 1 - && in_array(strtolower($stmt->class->parts[0]), ['self', 'static', 'parent'], true) + && count($stmt->class->getParts()) === 1 + && in_array(strtolower($stmt->class->getFirst()), ['self', 'static', 'parent'], true) && $lhs_type_part instanceof TNamedObject && $context->self ) { diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php index 348f528c..a547b291 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php @@ -505,7 +505,7 @@ class CallAnalyzer && $callable_arg->left->class instanceof Name && $callable_arg->left->name instanceof Identifier && strtolower($callable_arg->left->name->name) === 'class' - && !in_array(strtolower($callable_arg->left->class->parts[0]), ['self', 'static', 'parent']) + && !in_array(strtolower($callable_arg->left->class->getFirst()), ['self', 'static', 'parent']) && $callable_arg->right instanceof PhpParser\Node\Scalar\String_ && preg_match('/^::[A-Za-z0-9]+$/', $callable_arg->right->value) ) { diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ClassConstAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ClassConstAnalyzer.php index 0af910bd..2dec200f 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ClassConstAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ClassConstAnalyzer.php @@ -72,7 +72,7 @@ class ClassConstAnalyzer $statements_analyzer->node_data->setType($stmt, Type::getMixed()); if ($stmt->class instanceof PhpParser\Node\Name) { - $first_part_lc = strtolower($stmt->class->parts[0]); + $first_part_lc = strtolower($stmt->class->getFirst()); if ($first_part_lc === 'self' || $first_part_lc === 'static') { if (!$context->self) { @@ -128,7 +128,7 @@ class ClassConstAnalyzer $moved_class = false; if ($codebase->alter_code - && !in_array($stmt->class->parts[0], ['parent', 'static']) + && !in_array($stmt->class->getFirst(), ['parent', 'static']) ) { $moved_class = $codebase->classlikes->handleClassLikeReferenceInMigration( $codebase, @@ -137,7 +137,7 @@ class ClassConstAnalyzer $fq_class_name, $context->calling_method_id, false, - $stmt->class->parts[0] === 'self', + $stmt->class->getFirst() === 'self', ); } @@ -259,7 +259,7 @@ class ClassConstAnalyzer $class_visibility, $statements_analyzer, [], - $stmt->class->parts[0] === "static", + $stmt->class->getFirst() === "static", ); } catch (InvalidArgumentException $_) { return true; diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ExpressionIdentifier.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ExpressionIdentifier.php index 04b808c3..53794faa 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ExpressionIdentifier.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ExpressionIdentifier.php @@ -33,11 +33,11 @@ class ExpressionIdentifier && $stmt->name instanceof PhpParser\Node\Identifier && $stmt->class instanceof PhpParser\Node\Name ) { - if (count($stmt->class->parts) === 1 - && in_array(strtolower($stmt->class->parts[0]), ['self', 'static', 'parent'], true) + if (count($stmt->class->getParts()) === 1 + && in_array(strtolower($stmt->class->getFirst()), ['self', 'static', 'parent'], true) ) { if (!$this_class_name) { - $fq_class_name = $stmt->class->parts[0]; + $fq_class_name = $stmt->class->getFirst(); } else { $fq_class_name = $this_class_name; } @@ -47,7 +47,7 @@ class ExpressionIdentifier $stmt->class, $source->getAliases(), ) - : implode('\\', $stmt->class->parts); + : implode('\\', $stmt->class->getParts()); } return $fq_class_name . '::$' . $stmt->name->name; @@ -124,7 +124,7 @@ class ExpressionIdentifier ) { $offset = '$' . $stmt->dim->name; } elseif ($stmt->dim instanceof PhpParser\Node\Expr\ConstFetch) { - $offset = implode('\\', $stmt->dim->name->parts); + $offset = implode('\\', $stmt->dim->name->getParts()); } elseif ($stmt->dim instanceof PhpParser\Node\Expr\PropertyFetch) { $object_id = self::getExtendedVarId($stmt->dim->var, $this_class_name, $source); @@ -134,7 +134,7 @@ class ExpressionIdentifier } elseif ($stmt->dim instanceof PhpParser\Node\Expr\ClassConstFetch && $stmt->dim->name instanceof PhpParser\Node\Identifier && $stmt->dim->class instanceof PhpParser\Node\Name - && $stmt->dim->class->parts[0] === 'static' + && $stmt->dim->class->getFirst() === 'static' ) { $offset = 'static::' . $stmt->dim->name; } elseif ($stmt->dim diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ConstFetchAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ConstFetchAnalyzer.php index 3ae0ead2..8b30a60f 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ConstFetchAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ConstFetchAnalyzer.php @@ -16,7 +16,6 @@ use Psalm\Internal\Provider\NodeDataProvider; use Psalm\Issue\UndefinedConstant; use Psalm\IssueBuffer; use Psalm\Type; -use Psalm\Type\Atomic\TIntRange; use Psalm\Type\Union; use ReflectionProperty; @@ -36,7 +35,7 @@ class ConstFetchAnalyzer PhpParser\Node\Expr\ConstFetch $stmt, Context $context ): void { - $const_name = implode('\\', $stmt->name->parts); + $const_name = $stmt->name->toString(); switch (strtolower($const_name)) { case 'null': @@ -175,7 +174,7 @@ class ConstFetchAnalyzer case 'PHP_INT_SIZE': case 'PHP_MAXPATHLEN': case 'PHP_VERSION_ID': - return new Union([new TIntRange(1, null)]); + return Type::getIntRange(1, null); case 'PHP_FLOAT_EPSILON': case 'PHP_FLOAT_MAX': diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/StaticPropertyFetchAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/StaticPropertyFetchAnalyzer.php index 84ab1558..46a4cf0f 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/StaticPropertyFetchAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/StaticPropertyFetchAnalyzer.php @@ -51,10 +51,10 @@ class StaticPropertyFetchAnalyzer $codebase = $statements_analyzer->getCodebase(); - if (count($stmt->class->parts) === 1 - && in_array(strtolower($stmt->class->parts[0]), ['self', 'static', 'parent'], true) + if (count($stmt->class->getParts()) === 1 + && in_array(strtolower($stmt->class->getFirst()), ['self', 'static', 'parent'], true) ) { - if ($stmt->class->parts[0] === 'parent') { + if ($stmt->class->getFirst() === 'parent') { $fq_class_name = $statements_analyzer->getParentFQCLN(); if ($fq_class_name === null) { @@ -81,7 +81,7 @@ class StaticPropertyFetchAnalyzer ) { $codebase->file_reference_provider->addMethodReferenceToClassMember( $context->calling_method_id, - 'use:' . $stmt->class->parts[0] . ':' . md5($statements_analyzer->getFilePath()), + 'use:' . $stmt->class->getFirst() . ':' . md5($statements_analyzer->getFilePath()), false, ); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/VariableFetchAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/VariableFetchAnalyzer.php index 98e911a0..80ad5e0e 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/VariableFetchAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/VariableFetchAnalyzer.php @@ -783,7 +783,7 @@ class VariableFetchAnalyzer 'type' => $str, 'tmp_name' => $str, 'size' => Type::getListKey(), - 'error' => new Union([new TIntRange(0, 8)]), + 'error' => Type::getIntRange(0, 8), ]; if ($files_full_path) { diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/IncludeAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/IncludeAnalyzer.php index cfa4326c..e293afab 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/IncludeAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/IncludeAnalyzer.php @@ -335,7 +335,7 @@ class IncludeAnalyzer } } elseif ($stmt instanceof PhpParser\Node\Expr\FuncCall && $stmt->name instanceof PhpParser\Node\Name && - $stmt->name->parts === ['dirname'] + $stmt->name->getParts() === ['dirname'] ) { if ($stmt->getArgs()) { $dir_level = 1; @@ -369,10 +369,14 @@ class IncludeAnalyzer return null; } + if ($dir_level < 1) { + return null; + } + return dirname($evaled_path, $dir_level); } } elseif ($stmt instanceof PhpParser\Node\Expr\ConstFetch) { - $const_name = implode('', $stmt->name->parts); + $const_name = implode('', $stmt->name->getParts()); if (defined($const_name)) { $constant_value = constant($const_name); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/InstanceofAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/InstanceofAnalyzer.php index 380279b7..83b04cd9 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/InstanceofAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/InstanceofAnalyzer.php @@ -39,7 +39,7 @@ class InstanceofAnalyzer if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->class, $context) === false) { return false; } - } elseif (!in_array(strtolower($stmt->class->parts[0]), ['self', 'static', 'parent'], true)) { + } elseif (!in_array(strtolower($stmt->class->getFirst()), ['self', 'static', 'parent'], true)) { if ($context->check_classes) { $codebase = $statements_analyzer->getCodebase(); @@ -62,7 +62,7 @@ class InstanceofAnalyzer . ($stmt->class instanceof PhpParser\Node\Name\FullyQualified ? '\\' : $statements_analyzer->getNamespace() . '-') - . implode('\\', $stmt->class->parts), + . implode('\\', $stmt->class->getParts()), ); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/MagicConstAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/MagicConstAnalyzer.php index f439a59b..129266f9 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/MagicConstAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/MagicConstAnalyzer.php @@ -29,7 +29,7 @@ class MagicConstAnalyzer Context $context ): void { if ($stmt instanceof PhpParser\Node\Scalar\MagicConst\Line) { - $statements_analyzer->node_data->setType($stmt, Type::getInt()); + $statements_analyzer->node_data->setType($stmt, Type::getIntRange(1, null)); } elseif ($stmt instanceof PhpParser\Node\Scalar\MagicConst\Class_) { $codebase = $statements_analyzer->getCodebase(); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/MatchAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/MatchAnalyzer.php index 91ec38b4..a76a1990 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/MatchAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/MatchAnalyzer.php @@ -78,11 +78,11 @@ class MatchAnalyzer if (!$switch_var_id) { if ($stmt->cond instanceof PhpParser\Node\Expr\FuncCall && $stmt->cond->name instanceof PhpParser\Node\Name - && ($stmt->cond->name->parts === ['get_class'] - || $stmt->cond->name->parts === ['gettype'] - || $stmt->cond->name->parts === ['get_debug_type'] - || $stmt->cond->name->parts === ['count'] - || $stmt->cond->name->parts === ['sizeof']) + && ($stmt->cond->name->getParts() === ['get_class'] + || $stmt->cond->name->getParts() === ['gettype'] + || $stmt->cond->name->getParts() === ['get_debug_type'] + || $stmt->cond->name->getParts() === ['count'] + || $stmt->cond->name->getParts() === ['sizeof']) && $stmt->cond->getArgs() ) { $first_arg = $stmt->cond->getArgs()[0]; diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/SimpleTypeInferer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/SimpleTypeInferer.php index 3ba14ca6..ab144621 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/SimpleTypeInferer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/SimpleTypeInferer.php @@ -260,7 +260,7 @@ class SimpleTypeInferer } if ($stmt instanceof PhpParser\Node\Expr\ConstFetch) { - $name = strtolower($stmt->name->parts[0]); + $name = strtolower($stmt->name->getFirst()); if ($name === 'false') { return Type::getFalse(); } @@ -273,7 +273,7 @@ class SimpleTypeInferer return Type::getNull(); } - if ($stmt->name->parts[0] === '__NAMESPACE__') { + if ($stmt->name->getFirst() === '__NAMESPACE__') { return Type::getString($aliases->namespace); } @@ -287,7 +287,7 @@ class SimpleTypeInferer } if ($stmt instanceof PhpParser\Node\Scalar\MagicConst\Line) { - return Type::getInt(); + return Type::getIntRange(1, null); } if ($stmt instanceof PhpParser\Node\Scalar\MagicConst\Class_ @@ -306,18 +306,18 @@ class SimpleTypeInferer if ($stmt->class instanceof PhpParser\Node\Name && $stmt->name instanceof PhpParser\Node\Identifier && $fq_classlike_name - && $stmt->class->parts !== ['static'] - && $stmt->class->parts !== ['parent'] + && $stmt->class->getParts() !== ['static'] + && $stmt->class->getParts() !== ['parent'] ) { if (isset($existing_class_constants[$stmt->name->name]) && $existing_class_constants[$stmt->name->name]->type ) { - if ($stmt->class->parts === ['self']) { + if ($stmt->class->getParts() === ['self']) { return $existing_class_constants[$stmt->name->name]->type; } } - if ($stmt->class->parts === ['self']) { + if ($stmt->class->getParts() === ['self']) { $const_fq_class_name = $fq_classlike_name; } else { $const_fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject( diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/UnsetAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/UnsetAnalyzer.php index 5299d8d6..b1c12d12 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/UnsetAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/UnsetAnalyzer.php @@ -6,6 +6,7 @@ use PhpParser; use Psalm\Context; use Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier; use Psalm\Internal\Analyzer\StatementsAnalyzer; +use Psalm\Type; use Psalm\Type\Atomic\TArray; use Psalm\Type\Atomic\TIntRange; use Psalm\Type\Atomic\TKeyedArray; @@ -90,7 +91,7 @@ class UnsetAnalyzer if ($atomic_root_type->is_list && !$is_list && is_int($key_value)) { if ($key_value === 0) { - $list_key = new Union([new TIntRange(1, null)]); + $list_key = Type::getIntRange(1, null); } elseif ($key_value === 1) { $list_key = new Union([ new TLiteralInt(0), diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php index 2b43d085..f1d4044b 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php @@ -304,7 +304,7 @@ class StatementsAnalyzer extends SourceAnalyzer } elseif ($stmt instanceof PhpParser\Node\Stmt\Expression && $stmt->expr instanceof PhpParser\Node\Expr\FuncCall && $stmt->expr->name instanceof PhpParser\Node\Name - && $stmt->expr->name->parts === ['define'] + && $stmt->expr->name->getParts() === ['define'] && isset($stmt->expr->getArgs()[1]) ) { $const_name = ConstFetchAnalyzer::getConstName( diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Cache.php b/vendor/vimeo/psalm/src/Psalm/Internal/Cache.php new file mode 100644 index 00000000..88e2f570 --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Cache.php @@ -0,0 +1,128 @@ +config = $config; + $this->use_igbinary = $config->use_igbinary; + } + + /** + * @return array|object|string|null + */ + public function getItem(string $path) + { + if (!file_exists($path)) { + return null; + } + + $cache = Providers::safeFileGetContents($path); + if ($cache === '') { + return null; + } + + if ($this->config->compressor === 'deflate') { + $inflated = @gzinflate($cache); + } elseif ($this->config->compressor === 'lz4') { + /** + * @psalm-suppress UndefinedFunction + * @var string|false $inflated + */ + $inflated = lz4_uncompress($cache); + } else { + $inflated = $cache; + } + + // invalid cache data + if ($inflated === false) { + $this->deleteItem($path); + + return null; + } + + if ($this->use_igbinary) { + /** @var object|false $unserialized */ + $unserialized = @igbinary_unserialize($inflated); + } else { + /** @var object|false $unserialized */ + $unserialized = @unserialize($inflated); + } + + if ($unserialized === false) { + $this->deleteItem($path); + + return null; + } + + return $unserialized; + } + + public function deleteItem(string $path): void + { + if (@is_writable($path)) { + @unlink($path); + } + } + + /** + * @param array|object|string $item + */ + public function saveItem(string $path, $item): void + { + if ($this->use_igbinary) { + $serialized = igbinary_serialize($item); + } else { + $serialized = serialize($item); + } + + if ($this->config->compressor === 'deflate') { + $compressed = gzdeflate($serialized); + } elseif ($this->config->compressor === 'lz4') { + /** + * @psalm-suppress UndefinedFunction + * @var string|false $compressed + */ + $compressed = lz4_compress($serialized, 4); + } else { + $compressed = $serialized; + } + + if ($compressed !== false) { + file_put_contents($path, $compressed, LOCK_EX); + } + // TODO: Error handling + } + + public function getCacheDirectory(): ?string + { + return $this->config->getCacheDirectory(); + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Cli/LanguageServer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Cli/LanguageServer.php index 429144b6..07d5e6f9 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Cli/LanguageServer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Cli/LanguageServer.php @@ -10,6 +10,7 @@ use Psalm\Internal\Fork\PsalmRestarter; use Psalm\Internal\IncludeCollector; use Psalm\Internal\LanguageServer\ClientConfiguration; use Psalm\Internal\LanguageServer\LanguageServer as LanguageServerLanguageServer; +use Psalm\Internal\LanguageServer\PathMapper; use Psalm\Report; use function array_key_exists; @@ -18,6 +19,7 @@ use function array_search; use function array_slice; use function chdir; use function error_log; +use function explode; use function fwrite; use function gc_disable; use function getcwd; @@ -31,6 +33,7 @@ use function is_string; use function preg_replace; use function realpath; use function setlocale; +use function strlen; use function strpos; use function strtolower; use function substr; @@ -75,6 +78,7 @@ final class LanguageServer 'find-dead-code', 'help', 'root:', + 'map-folder::', 'use-ini-defaults', 'version', 'tcp:', @@ -127,6 +131,14 @@ final class LanguageServer // get options from command line $options = getopt(implode('', $valid_short_options), $valid_long_options); + if ($options === false) { + // shouldn't really happen, but just in case + fwrite( + STDERR, + 'Failed to get CLI args' . PHP_EOL, + ); + exit(1); + } if (!array_key_exists('use-ini-defaults', $options)) { ini_set('display_errors', '1'); @@ -169,6 +181,14 @@ final class LanguageServer -r, --root If running Psalm globally you'll need to specify a project root. Defaults to cwd + --map-folder[=SERVER_FOLDER:CLIENT_FOLDER] + Specify folder to map between the client and the server. Use this when the client + and server have different views of the filesystem (e.g. in a docker container). + Defaults to mapping the rootUri provided by the client to the server's cwd, + or `-r` if provided. + + No mapping is done when this option is not specified. + --find-dead-code Look for dead code @@ -291,6 +311,8 @@ final class LanguageServer setlocale(LC_CTYPE, 'C'); + $path_mapper = self::createPathMapper($options, $current_dir); + $path_to_config = CliUtils::getPathToConfig($options); if (isset($options['tcp'])) { @@ -394,6 +416,49 @@ final class LanguageServer $clientConfiguration->TCPServerAddress = $options['tcp'] ?? null; $clientConfiguration->TCPServerMode = isset($options['tcp-server']); - LanguageServerLanguageServer::run($config, $clientConfiguration, $current_dir, $inMemory); + LanguageServerLanguageServer::run($config, $clientConfiguration, $current_dir, $path_mapper, $inMemory); + } + + /** @param array> $options */ + private static function createPathMapper(array $options, string $server_start_dir): PathMapper + { + if (!isset($options['map-folder'])) { + // dummy no-op mapper + return new PathMapper('/', '/'); + } + + $map_folder = $options['map-folder']; + + if ($map_folder === false) { + // autoconfigured mapper + return new PathMapper($server_start_dir, null); + } + + if (is_string($map_folder)) { + if (strpos($map_folder, ':') === false) { + fwrite( + STDERR, + 'invalid format for --map-folder option' . PHP_EOL, + ); + exit(1); + } + /** @psalm-suppress PossiblyUndefinedArrayOffset we just checked that we have the separator*/ + [$server_dir, $client_dir] = explode(':', $map_folder, 2); + if (!strlen($server_dir) || !strlen($client_dir)) { + fwrite( + STDERR, + 'invalid format for --map-folder option, ' + . 'neither SERVER_FOLDER nor CLIENT_FOLDER can be empty' . PHP_EOL, + ); + exit(1); + } + return new PathMapper($server_dir, $client_dir); + } + + fwrite( + STDERR, + '--map-folder option can only be specified once' . PHP_EOL, + ); + exit(1); } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Cli/Psalm.php b/vendor/vimeo/psalm/src/Psalm/Internal/Cli/Psalm.php index 7401cd1e..4df6a9dd 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Cli/Psalm.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Cli/Psalm.php @@ -166,6 +166,7 @@ final class Psalm /** * @param array $argv + * @psalm-suppress ComplexMethod Maybe some of the option handling could be moved to its own function... */ public static function run(array $argv): void { @@ -183,6 +184,14 @@ final class Psalm throw new RuntimeException('Failed to parse CLI options'); } + // debug CI environment + if (!array_key_exists('debug', $options) + && 'true' === getenv('GITHUB_ACTIONS') + && '1' === getenv('RUNNER_DEBUG') + ) { + $options['debug'] = false; + } + self::forwardCliCall($options, $argv); self::validateCliArguments($args); @@ -403,7 +412,24 @@ final class Psalm { return isset($options['output-format']) && is_string($options['output-format']) ? $options['output-format'] - : Report::TYPE_CONSOLE; + : self::findDefaultOutputFormat(); + } + + /** + * @return Report::TYPE_* + */ + private static function findDefaultOutputFormat(): string + { + $emulator = getenv('TERMINAL_EMULATOR'); + if (is_string($emulator) && substr($emulator, 0, 9) === 'JetBrains') { + return Report::TYPE_PHP_STORM; + } + + if ('true' === getenv('GITHUB_ACTIONS')) { + return Report::TYPE_GITHUB_ACTIONS; + } + + return Report::TYPE_CONSOLE; } private static function initShowInfo(array $options): bool diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php index 7b2a8b97..ba0209ea 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php @@ -687,6 +687,16 @@ class Analyzer } } + // This could be optimized by storing method references to files + foreach ($file_reference_provider->getDeletedReferencedFiles() as $deleted_file) { + foreach ($file_reference_provider->getFilesReferencingFile($deleted_file) as $file_referencing_deleted) { + $methods_referencing_deleted = $this->analyzed_methods[$file_referencing_deleted] ?? []; + foreach ($methods_referencing_deleted as $method_referencing_deleted => $_) { + $newly_invalidated_methods[$method_referencing_deleted] = true; + } + } + } + foreach ($newly_invalidated_methods as $method_id => $_) { foreach ($method_references_to_class_members as $i => $_) { unset($method_references_to_class_members[$i][$method_id]); @@ -1552,13 +1562,13 @@ class Analyzer $has_info = false; foreach ($issues as $issue) { - if ($issue->severity === 'error') { - $has_error = true; - break; - } - - if ($issue->severity === 'info') { - $has_info = true; + switch ($issue->severity) { + case IssueData::SEVERITY_INFO: + $has_info = true; + break; + default: + $has_error = true; + break; } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/ClassLikes.php b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/ClassLikes.php index 696b0413..15953d98 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/ClassLikes.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/ClassLikes.php @@ -2347,15 +2347,31 @@ class ClassLikes $existing_classes, ] = $thread_data; - $this->existing_classlikes_lc = array_merge($existing_classlikes_lc, $this->existing_classlikes_lc); - $this->existing_classes_lc = array_merge($existing_classes_lc, $this->existing_classes_lc); - $this->existing_traits_lc = array_merge($existing_traits_lc, $this->existing_traits_lc); - $this->existing_traits = array_merge($existing_traits, $this->existing_traits); - $this->existing_enums_lc = array_merge($existing_enums_lc, $this->existing_enums_lc); - $this->existing_enums = array_merge($existing_enums, $this->existing_enums); - $this->existing_interfaces_lc = array_merge($existing_interfaces_lc, $this->existing_interfaces_lc); - $this->existing_interfaces = array_merge($existing_interfaces, $this->existing_interfaces); - $this->existing_classes = array_merge($existing_classes, $this->existing_classes); + $this->existing_classlikes_lc = self::mergeThreadData($existing_classlikes_lc, $this->existing_classlikes_lc); + $this->existing_classes_lc = self::mergeThreadData($existing_classes_lc, $this->existing_classes_lc); + $this->existing_traits_lc = self::mergeThreadData($existing_traits_lc, $this->existing_traits_lc); + $this->existing_traits = self::mergeThreadData($existing_traits, $this->existing_traits); + $this->existing_enums_lc = self::mergeThreadData($existing_enums_lc, $this->existing_enums_lc); + $this->existing_enums = self::mergeThreadData($existing_enums, $this->existing_enums); + $this->existing_interfaces_lc = self::mergeThreadData($existing_interfaces_lc, $this->existing_interfaces_lc); + $this->existing_interfaces = self::mergeThreadData($existing_interfaces, $this->existing_interfaces); + $this->existing_classes = self::mergeThreadData($existing_classes, $this->existing_classes); + } + + /** + * @template T as string|lowercase-string + * @param array $old + * @param array $new + * @return array + */ + private static function mergeThreadData(array $old, array $new): array + { + foreach ($new as $name => $value) { + if (!isset($old[$name]) || (!$old[$name] && $value)) { + $old[$name] = $value; + } + } + return $old; } public function getStorageFor(string $fq_class_name): ?ClassLikeStorage diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Methods.php b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Methods.php index a67a1d38..ff78e684 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Methods.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Methods.php @@ -8,6 +8,7 @@ use Psalm\CodeLocation; use Psalm\Codebase; use Psalm\Context; use Psalm\Internal\Analyzer\SourceAnalyzer; +use Psalm\Internal\Analyzer\Statements\Expression\Call\ClassTemplateParamCollector; use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer; use Psalm\Internal\Analyzer\StatementsAnalyzer; use Psalm\Internal\MethodIdentifier; @@ -18,6 +19,8 @@ use Psalm\Internal\Provider\MethodParamsProvider; use Psalm\Internal\Provider\MethodReturnTypeProvider; use Psalm\Internal\Provider\MethodVisibilityProvider; use Psalm\Internal\Type\Comparator\UnionTypeComparator; +use Psalm\Internal\Type\TemplateInferredTypeReplacer; +use Psalm\Internal\Type\TemplateResult; use Psalm\Internal\Type\TypeExpander; use Psalm\Internal\TypeVisitor\TypeLocalizer; use Psalm\StatementsSource; @@ -768,11 +771,26 @@ class Methods $candidate_type, ); - if (((!$old_contained_by_new && !$new_contained_by_old) - || ($old_contained_by_new && $new_contained_by_old)) - && !$candidate_type->hasTemplate() - && !$overridden_storage_return_type->hasTemplate() + if ((!$old_contained_by_new && !$new_contained_by_old) + || ($old_contained_by_new && $new_contained_by_old) ) { + $found_generic_params = ClassTemplateParamCollector::collect( + $source_analyzer->getCodebase(), + $appearing_fq_class_storage, + $appearing_fq_class_storage, + $appearing_method_name, + null, + true, + ); + + if ($found_generic_params) { + $overridden_storage_return_type = TemplateInferredTypeReplacer::replace( + $overridden_storage_return_type, + new TemplateResult([], $found_generic_params), + $source_analyzer->getCodebase(), + ); + } + $attempted_intersection = null; if ($old_contained_by_new) { //implicitly $new_contained_by_old as well try { diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Diff/ClassStatementsDiffer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Diff/ClassStatementsDiffer.php index 686aeb92..5bc637b4 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Diff/ClassStatementsDiffer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Diff/ClassStatementsDiffer.php @@ -158,6 +158,22 @@ class ClassStatementsDiffer extends AstDiffer return false; } + if ($a->type xor $b->type) { + return false; + } + + if ($a->type && $b->type) { + $a_type_start = (int) $a->type->getAttribute('startFilePos'); + $a_type_end = (int) $a->type->getAttribute('endFilePos'); + $b_type_start = (int) $b->type->getAttribute('startFilePos'); + $b_type_end = (int) $b->type->getAttribute('endFilePos'); + if (substr($a_code, $a_type_start, $a_type_end - $a_type_start + 1) + !== substr($b_code, $b_type_start, $b_type_end - $b_type_start + 1) + ) { + return false; + } + } + $body_change = substr($a_code, $a_comments_end, $a_end - $a_comments_end) !== substr($b_code, $b_comments_end, $b_end - $b_comments_end); } else { diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Diff/FileStatementsDiffer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Diff/FileStatementsDiffer.php index d1864043..797b6f73 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Diff/FileStatementsDiffer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Diff/FileStatementsDiffer.php @@ -129,7 +129,7 @@ class FileStatementsDiffer extends AstDiffer if ($use->alias) { $add_or_delete[] = 'use:' . (string) $use->alias; } else { - $name_parts = $use->name->parts; + $name_parts = $use->name->getParts(); $add_or_delete[] = 'use:' . end($name_parts); } @@ -156,7 +156,7 @@ class FileStatementsDiffer extends AstDiffer if ($use->alias) { $add_or_delete[] = 'use:' . (string) $use->alias; } else { - $name_parts = $use->name->parts; + $name_parts = $use->name->getParts(); $add_or_delete[] = 'use:' . end($name_parts); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Diff/NamespaceStatementsDiffer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Diff/NamespaceStatementsDiffer.php index 4232a405..cfeab612 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Diff/NamespaceStatementsDiffer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Diff/NamespaceStatementsDiffer.php @@ -114,7 +114,7 @@ class NamespaceStatementsDiffer extends AstDiffer if ($use->alias) { $add_or_delete[] = 'use:' . (string) $use->alias; } else { - $name_parts = $use->name->parts; + $name_parts = $use->name->getParts(); $add_or_delete[] = 'use:' . end($name_parts); } @@ -128,7 +128,7 @@ class NamespaceStatementsDiffer extends AstDiffer if ($use->alias) { $add_or_delete[] = 'use:' . (string) $use->alias; } else { - $name_parts = $use->name->parts; + $name_parts = $use->name->getParts(); $add_or_delete[] = 'use:' . end($name_parts); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Fork/Pool.php b/vendor/vimeo/psalm/src/Psalm/Internal/Fork/Pool.php index 1d097b19..09e525dd 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Fork/Pool.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Fork/Pool.php @@ -98,6 +98,7 @@ class Pool * @param array> $process_task_data_iterator * An array of task data items to be divided up among the * workers. The size of this is the number of forked processes. + * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint * @param Closure $startup_closure * A closure to execute upon starting a child * @param Closure(int, mixed):mixed $task_closure diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Client/Progress/LegacyProgress.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Client/Progress/LegacyProgress.php new file mode 100644 index 00000000..13eba280 --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Client/Progress/LegacyProgress.php @@ -0,0 +1,83 @@ +handler = $handler; + } + + public function begin(string $title, ?string $message = null, ?int $percentage = null): void + { + + if ($this->status === self::STATUS_ACTIVE) { + throw new LogicException('Progress has already been started'); + } + + if ($this->status === self::STATUS_FINISHED) { + throw new LogicException('Progress has already been finished'); + } + + $this->title = $title; + + $this->notify($message); + + $this->status = self::STATUS_ACTIVE; + } + + public function update(?string $message = null, ?int $percentage = null): void + { + if ($this->status === self::STATUS_FINISHED) { + throw new LogicException('Progress has already been finished'); + } + + if ($this->status === self::STATUS_INACTIVE) { + throw new LogicException('Progress has not been started yet'); + } + + $this->notify($message); + } + + public function end(?string $message = null): void + { + if ($this->status === self::STATUS_FINISHED) { + throw new LogicException('Progress has already been finished'); + } + + if ($this->status === self::STATUS_INACTIVE) { + throw new LogicException('Progress has not been started yet'); + } + + $this->notify($message); + + $this->status = self::STATUS_FINISHED; + } + + private function notify(?string $message): void + { + $this->handler->notify( + 'telemetry/event', + new LogMessage( + MessageType::INFO, + $this->title . (empty($message) ? '' : (': ' . $message)), + ), + ); + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Client/Progress/Progress.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Client/Progress/Progress.php new file mode 100644 index 00000000..8a1ca5da --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Client/Progress/Progress.php @@ -0,0 +1,121 @@ +handler = $handler; + $this->token = $token; + } + + public function begin( + string $title, + ?string $message = null, + ?int $percentage = null + ): void { + if ($this->status === self::STATUS_ACTIVE) { + throw new LogicException('Progress has already been started'); + } + + if ($this->status === self::STATUS_FINISHED) { + throw new LogicException('Progress has already been finished'); + } + + $notification = [ + 'token' => $this->token, + 'value' => [ + 'kind' => 'begin', + 'title' => $title, + ], + ]; + + if ($message !== null) { + $notification['value']['message'] = $message; + } + + if ($percentage !== null) { + $notification['value']['percentage'] = $percentage; + $this->withPercentage = true; + } + + $this->handler->notify('$/progress', $notification); + + $this->status = self::STATUS_ACTIVE; + } + + public function end(?string $message = null): void + { + if ($this->status === self::STATUS_FINISHED) { + throw new LogicException('Progress has already been finished'); + } + + if ($this->status === self::STATUS_INACTIVE) { + throw new LogicException('Progress has not been started yet'); + } + + $notification = [ + 'token' => $this->token, + 'value' => [ + 'kind' => 'end', + ], + ]; + + if ($message !== null) { + $notification['value']['message'] = $message; + } + + $this->handler->notify('$/progress', $notification); + + $this->status = self::STATUS_FINISHED; + } + + public function update(?string $message = null, ?int $percentage = null): void + { + if ($this->status === self::STATUS_FINISHED) { + throw new LogicException('Progress has already been finished'); + } + + if ($this->status === self::STATUS_INACTIVE) { + throw new LogicException('Progress has not been started yet'); + } + + $notification = [ + 'token' => $this->token, + 'value' => [ + 'kind' => 'report', + ], + ]; + + if ($message !== null) { + $notification['value']['message'] = $message; + } + + if ($percentage !== null) { + if (!$this->withPercentage) { + throw new LogicException( + 'Cannot update percentage for progress ' + . 'that was started without percentage', + ); + } + $notification['value']['percentage'] = $percentage; + } + + $this->handler->notify('$/progress', $notification); + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Client/Progress/ProgressInterface.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Client/Progress/ProgressInterface.php new file mode 100644 index 00000000..78f045c2 --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Client/Progress/ProgressInterface.php @@ -0,0 +1,16 @@ +server->clientCapabilities; - if ($capabilities && $capabilities->workspace && $capabilities->workspace->configuration) { + if ($capabilities->workspace->configuration ?? false) { $this->workspace->requestConfiguration('psalm')->onResolve(function ($error, $value): void { if ($error) { $this->server->logError('There was an error getting configuration'); @@ -131,6 +134,15 @@ class LanguageClient ); } + public function makeProgress(string $token): ProgressInterface + { + if ($this->server->clientCapabilities->window->workDoneProgress ?? false) { + return new Progress($this->handler, $token); + } else { + return new LegacyProgress($this->handler); + } + } + /** * Configuration Refreshed from Client * diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/LanguageServer.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/LanguageServer.php index daec34e8..cc358753 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/LanguageServer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/LanguageServer.php @@ -88,6 +88,7 @@ use function stream_socket_server; use function strpos; use function substr; use function trim; +use function uniqid; use function urldecode; use const JSON_PRETTY_PRINT; @@ -142,13 +143,16 @@ class LanguageServer extends Dispatcher */ protected JsonMapper $mapper; + protected PathMapper $path_mapper; + public function __construct( ProtocolReader $reader, ProtocolWriter $writer, ProjectAnalyzer $project_analyzer, Codebase $codebase, ClientConfiguration $clientConfiguration, - Progress $progress + Progress $progress, + PathMapper $path_mapper ) { parent::__construct($this, '/'); @@ -158,6 +162,8 @@ class LanguageServer extends Dispatcher $this->codebase = $codebase; + $this->path_mapper = $path_mapper; + $this->protocolWriter = $writer; $this->protocolReader = $reader; @@ -240,6 +246,7 @@ class LanguageServer extends Dispatcher $this->client = new LanguageClient($reader, $writer, $this, $clientConfiguration); + $this->logInfo("Psalm Language Server ".PSALM_VERSION." has started."); } @@ -250,6 +257,7 @@ class LanguageServer extends Dispatcher Config $config, ClientConfiguration $clientConfiguration, string $base_dir, + PathMapper $path_mapper, bool $inMemory = false ): void { $progress = new Progress(); @@ -322,6 +330,7 @@ class LanguageServer extends Dispatcher $codebase, $clientConfiguration, $progress, + $path_mapper, ); Loop::run(); } elseif ($clientConfiguration->TCPServerMode && $clientConfiguration->TCPServerAddress) { @@ -345,6 +354,7 @@ class LanguageServer extends Dispatcher $codebase, $clientConfiguration, $progress, + $path_mapper, ); Loop::run(); } @@ -358,6 +368,7 @@ class LanguageServer extends Dispatcher $codebase, $clientConfiguration, $progress, + $path_mapper, ); Loop::run(); } @@ -367,38 +378,36 @@ class LanguageServer extends Dispatcher * The initialize request is sent as the first request from the client to the server. * * @param ClientCapabilities $capabilities The capabilities provided by the client (editor) - * @param int|null $processId The process Id of the parent process that started the server. * Is null if the process has not been started by another process. If the parent process is * not alive then the server should exit (see exit notification) its process. * @param ClientInfo|null $clientInfo Information about the client - * @param string|null $locale The locale the client is currently showing the user interface - * in. This must not necessarily be the locale of the operating - * system. - * @param string|null $rootPath The rootPath of the workspace. Is null if no folder is open. - * @param mixed $initializationOptions * @param string|null $trace The initial trace setting. If omitted trace is disabled ('off'). + * @param string|null $workDoneToken The token to be used to report progress during init. * @psalm-return Promise - * @psalm-suppress PossiblyUnusedParam */ public function initialize( ClientCapabilities $capabilities, - ?int $processId = null, ?ClientInfo $clientInfo = null, - ?string $locale = null, - ?string $rootPath = null, ?string $rootUri = null, - $initializationOptions = null, - ?string $trace = null - //?array $workspaceFolders = null //error in json-dispatcher + ?string $trace = null, + ?string $workDoneToken = null ): Promise { $this->clientInfo = $clientInfo; $this->clientCapabilities = $capabilities; $this->trace = $trace; + + + if ($rootUri !== null) { + $this->path_mapper->configureClientRoot($this->getPathPart($rootUri)); + } + return call( /** @return Generator */ - function () { + function () use ($workDoneToken) { + $progress = $this->client->makeProgress($workDoneToken ?? uniqid('tkn', true)); + $this->logInfo("Initializing..."); - $this->clientStatus('initializing'); + $progress->begin('Psalm', 'initializing'); // Eventually, this might block on something. Leave it as a generator. /** @psalm-suppress TypeDoesNotContainType */ @@ -409,14 +418,14 @@ class LanguageServer extends Dispatcher $this->project_analyzer->serverMode($this); $this->logInfo("Initializing: Getting code base..."); - $this->clientStatus('initializing', 'getting code base'); + $progress->update('getting code base'); $this->logInfo("Initializing: Scanning files ({$this->project_analyzer->threads} Threads)..."); - $this->clientStatus('initializing', 'scanning files'); + $progress->update('scanning files'); $this->codebase->scanFiles($this->project_analyzer->threads); $this->logInfo("Initializing: Registering stub files..."); - $this->clientStatus('initializing', 'registering stub files'); + $progress->update('registering stub files'); $this->codebase->config->visitStubFiles($this->codebase, $this->project_analyzer->progress); if ($this->textDocument === null) { @@ -538,11 +547,7 @@ class LanguageServer extends Dispatcher * * @since LSP 3.16.0 */ - if ($this->clientCapabilities && - $this->clientCapabilities->textDocument && - $this->clientCapabilities->textDocument->publishDiagnostics && - $this->clientCapabilities->textDocument->publishDiagnostics->dataSupport - ) { + if ($this->clientCapabilities->textDocument->publishDiagnostics->dataSupport ?? false) { $serverCapabilities->codeActionProvider = true; } @@ -560,7 +565,7 @@ class LanguageServer extends Dispatcher } $this->logInfo("Initializing: Complete."); - $this->clientStatus('initialized'); + $progress->end('initialized'); /** * Information about the server. @@ -728,10 +733,9 @@ class LanguageServer extends Dispatcher new Position($end_line - 1, $end_column - 1), ); switch ($severity) { - case Config::REPORT_INFO: + case IssueData::SEVERITY_INFO: $diagnostic_severity = DiagnosticSeverity::WARNING; break; - case Config::REPORT_ERROR: default: $diagnostic_severity = DiagnosticSeverity::ERROR; break; @@ -758,11 +762,7 @@ class LanguageServer extends Dispatcher * * @since LSP 3.16.0 */ - if ($this->clientCapabilities !== null && - $this->clientCapabilities->textDocument && - $this->clientCapabilities->textDocument->publishDiagnostics && - $this->clientCapabilities->textDocument->publishDiagnostics->codeDescriptionSupport - ) { + if ($this->clientCapabilities->textDocument->publishDiagnostics->codeDescriptionSupport ?? false) { $diagnostic->codeDescription = new CodeDescription($issue_data->link); } @@ -788,7 +788,7 @@ class LanguageServer extends Dispatcher ); if ($position !== false) { - $issue_data->severity = Config::REPORT_INFO; + $issue_data->severity = IssueData::SEVERITY_INFO; /** @psalm-suppress MixedArgument */ array_splice($issue_baseline[$file][$type]['s'], $position, 1); /** @psalm-suppress MixedArrayAssignment, MixedOperand, MixedAssignment */ @@ -797,7 +797,7 @@ class LanguageServer extends Dispatcher } else { /** @psalm-suppress MixedArrayAssignment */ $issue_baseline[$file][$type]['s'] = []; - $issue_data->severity = Config::REPORT_INFO; + $issue_data->severity = IssueData::SEVERITY_INFO; /** @psalm-suppress MixedArrayAssignment, MixedOperand, MixedAssignment */ $issue_baseline[$file][$type]['o']--; } @@ -806,7 +806,7 @@ class LanguageServer extends Dispatcher }, $data[$file_path] ?? []), function (IssueData $issue_data) { //Hide Warnings - if ($issue_data->severity === Config::REPORT_INFO && + if ($issue_data->severity === IssueData::SEVERITY_INFO && $this->client->clientConfiguration->hideWarnings ) { return false; @@ -957,12 +957,15 @@ class LanguageServer extends Dispatcher /** * Transforms an absolute file path into a URI as used by the language server protocol. - * - * @psalm-pure */ - public static function pathToUri(string $filepath): string + public function pathToUri(string $filepath): string { - $filepath = trim(str_replace('\\', '/', $filepath), '/'); + $filepath = str_replace('\\', '/', $filepath); + + $filepath = $this->path_mapper->mapServerToClient($oldpath = $filepath); + $this->logDebug('Translated path to URI', ['from' => $oldpath, 'to' => $filepath]); + + $filepath = trim($filepath, '/'); $parts = explode('/', $filepath); // Don't %-encode the colon after a Windows drive letter $first = array_shift($parts); @@ -979,7 +982,29 @@ class LanguageServer extends Dispatcher /** * Transforms URI into file path */ - public static function uriToPath(string $uri): string + public function uriToPath(string $uri): string + { + $filepath = urldecode($this->getPathPart($uri)); + + if (strpos($filepath, ':') !== false) { + if ($filepath[0] === '/') { + $filepath = substr($filepath, 1); + } + $filepath = str_replace('/', '\\', $filepath); + } + + $filepath = $this->path_mapper->mapClientToServer($oldpath = $filepath); + $this->logDebug('Translated URI to path', ['from' => $oldpath, 'to' => $filepath]); + + $realpath = realpath($filepath); + if ($realpath !== false) { + return $realpath; + } + + return $filepath; + } + + private function getPathPart(string $uri): string { $fragments = parse_url($uri); if ($fragments === false @@ -989,21 +1014,21 @@ class LanguageServer extends Dispatcher ) { throw new InvalidArgumentException("Not a valid file URI: $uri"); } + return $fragments['path']; + } - $filepath = urldecode($fragments['path']); + // the methods below forward special paths + // like `$/cancelRequest` to `$this->cancelRequest()` + // and `$/a/b/c` to `$this->a->b->c()` - if (strpos($filepath, ':') !== false) { - if ($filepath[0] === '/') { - $filepath = substr($filepath, 1); - } - $filepath = str_replace('/', '\\', $filepath); - } + public function __isset(string $prop_name): bool + { + return $prop_name === '$'; + } - $realpath = realpath($filepath); - if ($realpath !== false) { - return $realpath; - } - - return $filepath; + /** @return static */ + public function __get(string $_prop_name): self + { + return $this; } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/PathMapper.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/PathMapper.php new file mode 100644 index 00000000..bd4b815b --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/PathMapper.php @@ -0,0 +1,61 @@ +server_root = $this->sanitizeFolderPath($server_root); + $this->client_root = $this->sanitizeFolderPath($client_root); + } + + public function configureClientRoot(string $client_root): void + { + // ignore if preconfigured + if ($this->client_root === null) { + $this->client_root = $this->sanitizeFolderPath($client_root); + } + } + + public function mapClientToServer(string $client_path): string + { + if ($this->client_root === null) { + return $client_path; + } + + if (substr($client_path, 0, strlen($this->client_root)) === $this->client_root) { + return $this->server_root . substr($client_path, strlen($this->client_root)); + } + + return $client_path; + } + + public function mapServerToClient(string $server_path): string + { + if ($this->client_root === null) { + return $server_path; + } + if (substr($server_path, 0, strlen($this->server_root)) === $this->server_root) { + return $this->client_root . substr($server_path, strlen($this->server_root)); + } + return $server_path; + } + + /** @return ($path is null ? null : string) */ + private function sanitizeFolderPath(?string $path): ?string + { + if ($path === null) { + return $path; + } + return rtrim($path, '/'); + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/FileReferenceCacheProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/FileReferenceCacheProvider.php index 79d54534..ca12912e 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/FileReferenceCacheProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/FileReferenceCacheProvider.php @@ -62,7 +62,7 @@ class FileReferenceCacheProvider extends InternalFileReferenceCacheProvider public function __construct(Config $config) { - $this->config = $config; + parent::__construct($config); } public function getCachedFileReferences(): ?array diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/FileStorageCacheProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/FileStorageCacheProvider.php index c91ffcc1..8841cf40 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/FileStorageCacheProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/FileStorageCacheProvider.php @@ -19,30 +19,24 @@ class FileStorageCacheProvider extends InternalFileStorageCacheProvider { } - public function writeToCache(FileStorage $storage, string $file_contents): void + /** + * @param lowercase-string $file_path + */ + protected function storeInCache(string $file_path, FileStorage $storage): void { - $file_path = strtolower($storage->file_path); $this->cache[$file_path] = $storage; } - public function getLatestFromCache(string $file_path, string $file_contents): ?FileStorage - { - $cached_value = $this->loadFromCache(strtolower($file_path)); - - if (!$cached_value) { - return null; - } - - return $cached_value; - } - public function removeCacheForFile(string $file_path): void { unset($this->cache[strtolower($file_path)]); } - private function loadFromCache(string $file_path): ?FileStorage + /** + * @param lowercase-string $file_path + */ + protected function loadFromCache(string $file_path): ?FileStorage { - return $this->cache[strtolower($file_path)] ?? null; + return $this->cache[$file_path] ?? null; } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Server/TextDocument.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Server/TextDocument.php index b9c4bcca..508af5ae 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Server/TextDocument.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Server/TextDocument.php @@ -74,7 +74,7 @@ class TextDocument ['version' => $textDocument->version, 'uri' => $textDocument->uri], ); - $file_path = LanguageServer::uriToPath($textDocument->uri); + $file_path = $this->server->uriToPath($textDocument->uri); $this->codebase->removeTemporaryFileChanges($file_path); $this->codebase->file_provider->openFile($file_path); @@ -97,7 +97,7 @@ class TextDocument ['uri' => (array) $textDocument], ); - $file_path = LanguageServer::uriToPath($textDocument->uri); + $file_path = $this->server->uriToPath($textDocument->uri); // reopen file $this->codebase->removeTemporaryFileChanges($file_path); @@ -119,7 +119,7 @@ class TextDocument ['version' => $textDocument->version, 'uri' => $textDocument->uri], ); - $file_path = LanguageServer::uriToPath($textDocument->uri); + $file_path = $this->server->uriToPath($textDocument->uri); if (count($contentChanges) === 1 && isset($contentChanges[0]) && $contentChanges[0]->range === null) { $new_content = $contentChanges[0]->text; @@ -154,7 +154,7 @@ class TextDocument ['uri' => $textDocument->uri], ); - $file_path = LanguageServer::uriToPath($textDocument->uri); + $file_path = $this->server->uriToPath($textDocument->uri); $this->codebase->file_provider->closeFile($file_path); $this->server->client->textDocument->publishDiagnostics($textDocument->uri, []); @@ -178,7 +178,7 @@ class TextDocument 'textDocument/definition', ); - $file_path = LanguageServer::uriToPath($textDocument->uri); + $file_path = $this->server->uriToPath($textDocument->uri); //This currently doesnt work right with out of project files if (!$this->codebase->config->isInProjectDirs($file_path)) { @@ -205,7 +205,7 @@ class TextDocument return new Success( new Location( - LanguageServer::pathToUri($code_location->file_path), + $this->server->pathToUri($code_location->file_path), new Range( new Position($code_location->getLineNumber() - 1, $code_location->getColumn() - 1), new Position($code_location->getEndLineNumber() - 1, $code_location->getEndColumn() - 1), @@ -232,7 +232,7 @@ class TextDocument 'textDocument/hover', ); - $file_path = LanguageServer::uriToPath($textDocument->uri); + $file_path = $this->server->uriToPath($textDocument->uri); //This currently doesnt work right with out of project files if (!$this->codebase->config->isInProjectDirs($file_path)) { @@ -288,7 +288,7 @@ class TextDocument 'textDocument/completion', ); - $file_path = LanguageServer::uriToPath($textDocument->uri); + $file_path = $this->server->uriToPath($textDocument->uri); //This currently doesnt work right with out of project files if (!$this->codebase->config->isInProjectDirs($file_path)) { @@ -301,12 +301,8 @@ class TextDocument [$recent_type, $gap, $offset] = $completion_data; if ($gap === '->' || $gap === '::') { - $snippetSupport = ($this->server->clientCapabilities && - $this->server->clientCapabilities->textDocument && - $this->server->clientCapabilities->textDocument->completion && - $this->server->clientCapabilities->textDocument->completion->completionItem && - $this->server->clientCapabilities->textDocument->completion->completionItem->snippetSupport) - ? true : false; + $snippetSupport = $this->server->clientCapabilities + ->textDocument->completion->completionItem->snippetSupport ?? false; $completion_items = $this->codebase->getCompletionItemsForClassishThing($recent_type, $gap, $snippetSupport); } elseif ($gap === '[') { @@ -360,7 +356,7 @@ class TextDocument 'textDocument/signatureHelp', ); - $file_path = LanguageServer::uriToPath($textDocument->uri); + $file_path = $this->server->uriToPath($textDocument->uri); //This currently doesnt work right with out of project files if (!$this->codebase->config->isInProjectDirs($file_path)) { @@ -402,10 +398,8 @@ class TextDocument * The code action request is sent from the client to the server to compute commands * for a given text document and range. These commands are typically code fixes to * either fix problems or to beautify/refactor code. - * - * @psalm-suppress PossiblyUnusedParam */ - public function codeAction(TextDocumentIdentifier $textDocument, Range $range, CodeActionContext $context): Promise + public function codeAction(TextDocumentIdentifier $textDocument, CodeActionContext $context): Promise { if (!$this->server->client->clientConfiguration->provideCodeActions) { return new Success(null); @@ -415,7 +409,7 @@ class TextDocument 'textDocument/codeAction', ); - $file_path = LanguageServer::uriToPath($textDocument->uri); + $file_path = $this->server->uriToPath($textDocument->uri); //Don't report code actions for files we arent watching if (!$this->codebase->config->isInProjectDirs($file_path)) { @@ -431,12 +425,12 @@ class TextDocument /** @var array{type: string, snippet: string, line_from: int, line_to: int} */ $data = (array)$diagnostic->data; - //$file_path = LanguageServer::uriToPath($textDocument->uri); + //$file_path = $this->server->uriToPath($textDocument->uri); //$contents = $this->codebase->file_provider->getContents($file_path); $snippetRange = new Range( - new Position($data['line_from']-1), - new Position($data['line_to']), + new Position($data['line_from'] - 1, 0), + new Position($data['line_to'], 0), ); $indentation = ''; diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Server/Workspace.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Server/Workspace.php index af49619c..6d2e1622 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Server/Workspace.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Server/Workspace.php @@ -63,7 +63,7 @@ class Workspace $realFiles = array_filter( array_map(function (FileEvent $change) { try { - return LanguageServer::uriToPath($change->uri); + return $this->server->uriToPath($change->uri); } catch (InvalidArgumentException $e) { return null; } @@ -79,7 +79,7 @@ class Workspace } foreach ($changes as $change) { - $file_path = LanguageServer::uriToPath($change->uri); + $file_path = $this->server->uriToPath($change->uri); if ($composerLockFile === $file_path) { continue; @@ -108,10 +108,9 @@ class Workspace /** * A notification sent from the client to the server to signal the change of configuration settings. * - * @param mixed $settings - * @psalm-suppress PossiblyUnusedMethod, PossiblyUnusedParam + * @psalm-suppress PossiblyUnusedMethod */ - public function didChangeConfiguration($settings): void + public function didChangeConfiguration(): void { $this->server->logDebug( 'workspace/didChangeConfiguration', @@ -140,7 +139,7 @@ class Workspace case 'psalm.analyze.uri': /** @var array{uri: string} */ $arguments = (array) $arguments; - $file = LanguageServer::uriToPath($arguments['uri']); + $file = $this->server->uriToPath($arguments['uri']); $this->codebase->reloadFiles( $this->project_analyzer, [$file], diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php index 2bc9d718..fae0c8da 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php @@ -839,10 +839,15 @@ class ClassLikeNodeScanner $classlike_storage->properties[$property_name] = new PropertyStorage(); } - $classlike_storage->properties[$property_name]->type = $property_type; - $property_id = $fq_classlike_name . '::$' . $property_name; + if ($property_id === 'DateInterval::$days') { + /** @psalm-suppress InaccessibleProperty We just parsed this type */ + $property_type->ignore_falsable_issues = true; + } + + $classlike_storage->properties[$property_name]->type = $property_type; + $classlike_storage->declaring_property_ids[$property_name] = $fq_classlike_name; $classlike_storage->appearing_property_ids[$property_name] = $property_id; } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionResolver.php b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionResolver.php index 20c75007..ac05615b 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionResolver.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionResolver.php @@ -32,10 +32,12 @@ use Psalm\Internal\Scanner\UnresolvedConstantComponent; use ReflectionClass; use ReflectionFunction; +use function array_merge; +use function array_values; use function assert; use function class_exists; use function function_exists; -use function implode; +use function get_defined_constants; use function in_array; use function interface_exists; use function strtolower; @@ -139,7 +141,7 @@ class ExpressionResolver } if ($stmt instanceof PhpParser\Node\Expr\ConstFetch) { - $part0_lc = strtolower($stmt->name->parts[0]); + $part0_lc = strtolower($stmt->name->getFirst()); if ($part0_lc === 'false') { return new ScalarValue(false); } @@ -157,7 +159,7 @@ class ExpressionResolver } return new Constant( - implode('\\', $stmt->name->parts), + $stmt->name->toString(), $stmt->name instanceof PhpParser\Node\Name\FullyQualified, ); } @@ -190,13 +192,13 @@ class ExpressionResolver if ($stmt->class instanceof PhpParser\Node\Name && $stmt->name instanceof PhpParser\Node\Identifier && $fq_classlike_name - && $stmt->class->parts !== ['static'] - && ($stmt->class->parts !== ['parent'] || $parent_fq_class_name !== null) + && $stmt->class->getParts() !== ['static'] + && ($stmt->class->getParts() !== ['parent'] || $parent_fq_class_name !== null) ) { - if ($stmt->class->parts === ['self']) { + if ($stmt->class->getParts() === ['self']) { $const_fq_class_name = $fq_classlike_name; } else { - if ($stmt->class->parts === ['parent']) { + if ($stmt->class->getParts() === ['parent']) { assert($parent_fq_class_name !== null); $const_fq_class_name = $parent_fq_class_name; } else { @@ -305,15 +307,28 @@ class ExpressionResolver && $stmt->var->class instanceof PhpParser\Node\Name && $stmt->var->name instanceof PhpParser\Node\Identifier && $stmt->name instanceof PhpParser\Node\Identifier - && in_array($stmt->name->name, ['name', 'value', true]) + && in_array($stmt->name->name, ['name', 'value'], true) + && ($stmt->var->class->getParts() !== ['self'] || $fq_classlike_name !== null) + && $stmt->var->class->getParts() !== ['static'] + && ($stmt->var->class->getParts() !== ['parent'] || $parent_fq_class_name !== null) ) { - $enum_fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject( - $stmt->var->class, - $aliases, - ); + if ($stmt->var->class->getParts() === ['self']) { + assert($fq_classlike_name !== null); + $enum_fq_class_name = $fq_classlike_name; + } else { + if ($stmt->var->class->getParts() === ['parent']) { + assert($parent_fq_class_name !== null); + $enum_fq_class_name = $parent_fq_class_name; + } else { + $enum_fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject( + $stmt->var->class, + $aliases, + ); + } + } if ($stmt->name->name === 'value') { return new EnumValueFetch($enum_fq_class_name, $stmt->var->name->name); - } elseif ($stmt->name->name === 'name') { + } else /*if ($stmt->name->name === 'name')*/ { return new EnumNameFetch($enum_fq_class_name, $stmt->var->name->name); } } @@ -355,18 +370,18 @@ class ExpressionResolver ) && ( ( $expr->left instanceof PhpParser\Node\Expr\ConstFetch - && $expr->left->name->parts === ['PHP_VERSION_ID'] + && $expr->left->name->getParts() === ['PHP_VERSION_ID'] && $expr->right instanceof PhpParser\Node\Scalar\LNumber ) || ( $expr->right instanceof PhpParser\Node\Expr\ConstFetch - && $expr->right->name->parts === ['PHP_VERSION_ID'] + && $expr->right->name->getParts() === ['PHP_VERSION_ID'] && $expr->left instanceof PhpParser\Node\Scalar\LNumber ) ) ) { $php_version_id = $codebase->analysis_php_version_id; $evaluator = new ConstExprEvaluator(static function (Expr $expr) use ($php_version_id) { - if ($expr instanceof ConstFetch && $expr->name->parts === ['PHP_VERSION_ID']) { + if ($expr instanceof ConstFetch && $expr->name->getParts() === ['PHP_VERSION_ID']) { return $php_version_id; } throw new ConstExprEvaluationException('unexpected'); @@ -395,7 +410,7 @@ class ExpressionResolver return null; } - if ($function->name->parts === ['function_exists'] + if ($function->name->getParts() === ['function_exists'] && isset($function->getArgs()[0]) && $function->getArgs()[0]->value instanceof PhpParser\Node\Scalar\String_ && function_exists($function->getArgs()[0]->value->value) @@ -409,7 +424,7 @@ class ExpressionResolver return false; } - if ($function->name->parts === ['class_exists'] + if ($function->name->getParts() === ['class_exists'] && isset($function->getArgs()[0]) ) { $string_value = null; @@ -439,7 +454,7 @@ class ExpressionResolver return false; } - if ($function->name->parts === ['interface_exists'] + if ($function->name->getParts() === ['interface_exists'] && isset($function->getArgs()[0]) ) { $string_value = null; @@ -469,7 +484,7 @@ class ExpressionResolver return false; } - if ($function->name->parts === ['enum_exists'] + if ($function->name->getParts() === ['enum_exists'] && isset($function->getArgs()[0]) ) { $string_value = null; @@ -501,6 +516,19 @@ class ExpressionResolver return false; } + if ($function->name->getParts() === ['defined'] + && isset($function->getArgs()[0]) + && $function->getArgs()[0]->value instanceof PhpParser\Node\Scalar\String_ + ) { + $predefined_constants = get_defined_constants(true); + if (isset($predefined_constants['user'])) { + unset($predefined_constants['user']); + } + $predefined_constants = array_merge(...array_values($predefined_constants)); + + return isset($predefined_constants[$function->getArgs()[0]->value->value]); + } + return null; } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionScanner.php b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionScanner.php index d37bd9a9..696b7497 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionScanner.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionScanner.php @@ -6,8 +6,10 @@ use PhpParser; use Psalm\Aliases; use Psalm\Codebase; use Psalm\Config; +use Psalm\Exception\DocblockParseException; use Psalm\Exception\FileIncludeException; use Psalm\Internal\Analyzer\ClassLikeAnalyzer; +use Psalm\Internal\Analyzer\CommentAnalyzer; use Psalm\Internal\Analyzer\Statements\Expression\CallAnalyzer; use Psalm\Internal\Analyzer\Statements\Expression\Fetch\ConstFetchAnalyzer; use Psalm\Internal\Analyzer\Statements\Expression\IncludeAnalyzer; @@ -23,7 +25,6 @@ use function assert; use function defined; use function dirname; use function explode; -use function implode; use function in_array; use function preg_match; use function strpos; @@ -80,7 +81,7 @@ class ExpressionScanner $file_storage->referenced_classlikes[strtolower($fq_classlike_name)] = $fq_classlike_name; } } elseif ($node instanceof PhpParser\Node\Expr\FuncCall && $node->name instanceof PhpParser\Node\Name) { - $function_id = implode('\\', $node->name->parts); + $function_id = $node->name->toString(); if (InternalCallMapHandler::inCallMap($function_id)) { self::registerClassMapFunctionCall( @@ -152,7 +153,29 @@ class ExpressionScanner $type_provider, $second_arg_value, $aliases, - ) ?? Type::getMixed(); + ); + + // allow docblocks to override the declared value to make constants in stubs configurable + $doc_comment = $second_arg_value->getDocComment(); + if ($doc_comment) { + try { + $var_comments = CommentAnalyzer::getTypeFromComment($doc_comment, $file_scanner, $aliases); + foreach ($var_comments as $var_comment) { + if ($var_comment->type) { + $const_type = $var_comment->type; + } + + // only check the first @var comment + break; + } + } catch (DocblockParseException $e) { + // do nothing + } + } + + if ($const_type === null) { + $const_type = Type::getMixed(); + } $config = Config::getInstance(); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeNodeScanner.php b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeNodeScanner.php index ed3463b9..e0ba4e34 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeNodeScanner.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeNodeScanner.php @@ -57,7 +57,6 @@ use function array_search; use function count; use function end; use function explode; -use function implode; use function in_array; use function is_string; use function spl_object_id; @@ -371,7 +370,7 @@ class FunctionLikeNodeScanner && $function_stmt->expr->expr instanceof PhpParser\Node\Expr\FuncCall && $function_stmt->expr->expr->name instanceof PhpParser\Node\Name ) { - $inner_function_id = implode('\\', $function_stmt->expr->expr->name->parts); + $inner_function_id = $function_stmt->expr->expr->name->toString(); if ($inner_function_id === 'func_get_arg' || $inner_function_id === 'func_get_args' @@ -385,7 +384,7 @@ class FunctionLikeNodeScanner && $function_stmt->cond->left->left instanceof PhpParser\Node\Expr\FuncCall && $function_stmt->cond->left->left->name instanceof PhpParser\Node\Name ) { - $inner_function_id = implode('\\', $function_stmt->cond->left->left->name->parts); + $inner_function_id = $function_stmt->cond->left->left->name->toString(); if ($inner_function_id === 'func_get_arg' || $inner_function_id === 'func_get_args' @@ -806,7 +805,7 @@ class FunctionLikeNodeScanner $param_type = null; $is_nullable = $param->default instanceof PhpParser\Node\Expr\ConstFetch && - strtolower($param->default->name->parts[0]) === 'null'; + strtolower($param->default->name->getFirst()) === 'null'; $param_typehint = $param->type; diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/TypeHintResolver.php b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/TypeHintResolver.php index 7ae1e78e..3e5fcef5 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/TypeHintResolver.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/TypeHintResolver.php @@ -21,7 +21,6 @@ use Psalm\Type\Atomic\TNull; use Psalm\Type\Union; use UnexpectedValueException; -use function implode; use function strtolower; /** @@ -137,7 +136,7 @@ class TypeHintResolver $codebase->scanner->queueClassLikeForScanning($fq_type_string); $file_storage->referenced_classlikes[strtolower($fq_type_string)] = $fq_type_string; } else { - $lower_hint = strtolower($hint->parts[0]); + $lower_hint = strtolower($hint->getFirst()); if ($classlike_storage && ($lower_hint === 'self' || $lower_hint === 'static') @@ -149,7 +148,7 @@ class TypeHintResolver $fq_type_string .= '&static'; } } else { - $type_string = implode('\\', $hint->parts); + $type_string = $hint->toString(); $fq_type_string = ClassLikeAnalyzer::getFQCLNFromNameObject($hint, $aliases); $codebase->scanner->queueClassLikeForScanning($fq_type_string); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php index 989bae6e..734c14d8 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php @@ -39,7 +39,6 @@ use function array_pop; use function end; use function explode; use function get_class; -use function implode; use function in_array; use function is_string; use function reset; @@ -395,7 +394,7 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements FileSour $this->namespace_name = $node->name; $this->aliases = new Aliases( - $node->name ? implode('\\', $node->name->parts) : '', + $node->name ? $node->name->toString() : '', $this->aliases->uses, $this->aliases->functions, $this->aliases->constants, @@ -414,7 +413,7 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements FileSour private function handleUse(PhpParser\Node\Stmt\Use_ $node): void { foreach ($node->uses as $use) { - $use_path = implode('\\', $use->name->parts); + $use_path = $use->name->toString(); $use_alias = $use->alias->name ?? $use->name->getLast(); @@ -445,10 +444,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements FileSour private function handleGroupUse(PhpParser\Node\Stmt\GroupUse $node): void { - $use_prefix = implode('\\', $node->prefix->parts); + $use_prefix = $node->prefix->toString(); foreach ($node->uses as $use) { - $use_path = $use_prefix . '\\' . implode('\\', $use->name->parts); + $use_path = $use_prefix . '\\' . $use->name->toString(); $use_alias = $use->alias->name ?? $use->name->getLast(); switch ($use->type !== PhpParser\Node\Stmt\Use_::TYPE_UNKNOWN ? $use->type : $node->type) { @@ -490,13 +489,13 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements FileSour if ($this->codebase->register_stub_files && $node->name - && $node->name->parts === ['PHPSTORM_META'] + && $node->name->getParts() === ['PHPSTORM_META'] ) { foreach ($node->stmts as $meta_stmt) { if ($meta_stmt instanceof PhpParser\Node\Stmt\Expression && $meta_stmt->expr instanceof PhpParser\Node\Expr\FuncCall && $meta_stmt->expr->name instanceof Name - && $meta_stmt->expr->name->parts === ['override'] + && $meta_stmt->expr->name->getParts() === ['override'] ) { PhpStormMetaScanner::handleOverride($meta_stmt->expr->getArgs(), $this->codebase); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/AddRemoveTaints/HtmlFunctionTainter.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/AddRemoveTaints/HtmlFunctionTainter.php index c96a50f1..1f862278 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/AddRemoveTaints/HtmlFunctionTainter.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/AddRemoveTaints/HtmlFunctionTainter.php @@ -32,13 +32,13 @@ class HtmlFunctionTainter implements AddTaintsInterface, RemoveTaintsInterface || !$item instanceof PhpParser\Node\Expr\FuncCall || $item->isFirstClassCallable() || !$item->name instanceof PhpParser\Node\Name - || count($item->name->parts) !== 1 + || count($item->name->getParts()) !== 1 || count($item->getArgs()) === 0 ) { return []; } - $function_id = strtolower($item->name->parts[0]); + $function_id = strtolower($item->name->getFirst()); if ($function_id === 'html_entity_decode' || $function_id === 'htmlspecialchars_decode' @@ -84,13 +84,13 @@ class HtmlFunctionTainter implements AddTaintsInterface, RemoveTaintsInterface || !$item instanceof PhpParser\Node\Expr\FuncCall || $item->isFirstClassCallable() || !$item->name instanceof PhpParser\Node\Name - || count($item->name->parts) !== 1 + || count($item->name->getParts()) !== 1 || count($item->getArgs()) === 0 ) { return []; } - $function_id = strtolower($item->name->parts[0]); + $function_id = strtolower($item->name->getFirst()); if ($function_id === 'htmlentities' || $function_id === 'htmlspecialchars' diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php index 7b03bb3e..82eb578f 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php @@ -3,6 +3,7 @@ namespace Psalm\Internal\Provider; use Psalm\Config; +use Psalm\Internal\Cache; use Psalm\Storage\ClassLikeStorage; use RuntimeException; use UnexpectedValueException; @@ -10,22 +11,15 @@ use UnexpectedValueException; use function array_merge; use function dirname; use function file_exists; -use function file_put_contents; use function filemtime; use function get_class; use function hash; -use function igbinary_serialize; -use function igbinary_unserialize; use function is_dir; use function is_null; use function mkdir; -use function serialize; use function strtolower; -use function unlink; -use function unserialize; use const DIRECTORY_SEPARATOR; -use const LOCK_EX; use const PHP_VERSION_ID; /** @@ -33,7 +27,7 @@ use const PHP_VERSION_ID; */ class ClassLikeStorageCacheProvider { - private Config $config; + private Cache $cache; private string $modified_timestamps = ''; @@ -41,7 +35,7 @@ class ClassLikeStorageCacheProvider public function __construct(Config $config) { - $this->config = $config; + $this->cache = new Cache($config); $storage_dir = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'Storage' . DIRECTORY_SEPARATOR; @@ -64,7 +58,7 @@ class ClassLikeStorageCacheProvider $this->modified_timestamps .= ' ' . filemtime($dependent_file_path); } - $this->modified_timestamps .= $this->config->computeHash(); + $this->modified_timestamps .= $config->computeHash(); } public function writeToCache(ClassLikeStorage $storage, string $file_path, string $file_contents): void @@ -80,11 +74,7 @@ class ClassLikeStorageCacheProvider } $cache_location = $this->getCacheLocationForClass($fq_classlike_name_lc, $file_path, true); - if ($this->config->use_igbinary) { - file_put_contents($cache_location, igbinary_serialize($storage), LOCK_EX); - } else { - file_put_contents($cache_location, serialize($storage), LOCK_EX); - } + $this->cache->saveItem($cache_location, $storage); } public function getLatestFromCache( @@ -104,7 +94,7 @@ class ClassLikeStorageCacheProvider if (@get_class($cached_value) === '__PHP_Incomplete_Class' || $cache_hash !== $cached_value->hash ) { - unlink($this->getCacheLocationForClass($fq_classlike_name_lc, $file_path)); + $this->cache->deleteItem($this->getCacheLocationForClass($fq_classlike_name_lc, $file_path)); throw new UnexpectedValueException($fq_classlike_name_lc . ' should not be outdated'); } @@ -118,31 +108,11 @@ class ClassLikeStorageCacheProvider return PHP_VERSION_ID >= 8_01_00 ? hash('xxh128', $data) : hash('md4', $data); } - /** - * @psalm-suppress MixedAssignment - */ private function loadFromCache(string $fq_classlike_name_lc, ?string $file_path): ?ClassLikeStorage { - $cache_location = $this->getCacheLocationForClass($fq_classlike_name_lc, $file_path); - - if (file_exists($cache_location)) { - if ($this->config->use_igbinary) { - $storage = igbinary_unserialize(Providers::safeFileGetContents($cache_location)); - - if ($storage instanceof ClassLikeStorage) { - return $storage; - } - - return null; - } - - $storage = unserialize(Providers::safeFileGetContents($cache_location)); - - if ($storage instanceof ClassLikeStorage) { - return $storage; - } - - return null; + $storage = $this->cache->getItem($this->getCacheLocationForClass($fq_classlike_name_lc, $file_path)); + if ($storage instanceof ClassLikeStorage) { + return $storage; } return null; @@ -153,7 +123,7 @@ class ClassLikeStorageCacheProvider ?string $file_path, bool $create_directory = false ): string { - $root_cache_directory = $this->config->getCacheDirectory(); + $root_cache_directory = $this->cache->getCacheDirectory(); if (!$root_cache_directory) { throw new UnexpectedValueException('No cache directory defined'); @@ -186,6 +156,6 @@ class ClassLikeStorageCacheProvider return $parser_cache_directory . DIRECTORY_SEPARATOR . $file_path_sha - . ($this->config->use_igbinary ? '-igbinary' : ''); + . ($this->cache->use_igbinary ? '-igbinary' : ''); } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FakeFileProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FakeFileProvider.php index 64251084..756e0d72 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FakeFileProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FakeFileProvider.php @@ -68,6 +68,12 @@ class FakeFileProvider extends FileProvider $this->fake_file_times[$file_path] = (int)microtime(true); } + public function deleteFile(string $file_path): void + { + unset($this->fake_files[$file_path]); + unset($this->fake_file_times[$file_path]); + } + /** * @param array $file_extensions * @param null|callable(string):bool $filter diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FileReferenceCacheProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FileReferenceCacheProvider.php index 9f469a08..cb302971 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FileReferenceCacheProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FileReferenceCacheProvider.php @@ -3,6 +3,7 @@ namespace Psalm\Internal\Provider; use Psalm\Config; +use Psalm\Internal\Cache; use Psalm\Internal\Codebase\Analyzer; use Psalm\Internal\Provider\Providers; use RuntimeException; @@ -10,23 +11,19 @@ use UnexpectedValueException; use function file_exists; use function file_put_contents; -use function igbinary_serialize; -use function igbinary_unserialize; use function is_array; use function is_dir; use function is_readable; use function mkdir; -use function serialize; -use function unserialize; use const DIRECTORY_SEPARATOR; use const LOCK_EX; /** - * @psalm-import-type FileMapType from Analyzer - * * Used to determine which files reference other files, necessary for using the --diff * option from the command line. + * + * @psalm-import-type FileMapType from Analyzer * @internal */ class FileReferenceCacheProvider @@ -53,10 +50,12 @@ class FileReferenceCacheProvider private const METHOD_PARAM_USE_CACHE_NAME = 'method_param_uses'; protected Config $config; + protected Cache $cache; public function __construct(Config $config) { $this->config = $config; + $this->cache = new Cache($config); } public function hasConfigChanged(): bool @@ -65,771 +64,164 @@ class FileReferenceCacheProvider return $new_hash !== $this->getConfigHashCache(); } - /** - * @psalm-suppress MixedAssignment - */ public function getCachedFileReferences(): ?array { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return null; - } - - $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::REFERENCE_CACHE_NAME; - - if (!is_readable($reference_cache_location)) { - return null; - } - - if ($this->config->use_igbinary) { - $reference_cache = igbinary_unserialize(Providers::safeFileGetContents($reference_cache_location)); - } else { - $reference_cache = unserialize(Providers::safeFileGetContents($reference_cache_location)); - } - - if (!is_array($reference_cache)) { - throw new UnexpectedValueException('The reference cache must be an array'); - } - - return $reference_cache; + return $this->getCacheItem(self::REFERENCE_CACHE_NAME); } - /** - * @psalm-suppress MixedAssignment - */ public function getCachedClassLikeFiles(): ?array { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return null; - } - - $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASSLIKE_FILE_CACHE_NAME; - - if (!is_readable($reference_cache_location)) { - return null; - } - - if ($this->config->use_igbinary) { - $reference_cache = igbinary_unserialize(Providers::safeFileGetContents($reference_cache_location)); - } else { - $reference_cache = unserialize(Providers::safeFileGetContents($reference_cache_location)); - } - - if (!is_array($reference_cache)) { - throw new UnexpectedValueException('The reference cache must be an array'); - } - - return $reference_cache; + return $this->getCacheItem(self::CLASSLIKE_FILE_CACHE_NAME); } - /** - * @psalm-suppress MixedAssignment - */ public function getCachedNonMethodClassReferences(): ?array { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return null; - } - - $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::NONMETHOD_CLASS_REFERENCE_CACHE_NAME; - - if (!is_readable($reference_cache_location)) { - return null; - } - - if ($this->config->use_igbinary) { - $reference_cache = igbinary_unserialize(Providers::safeFileGetContents($reference_cache_location)); - } else { - $reference_cache = unserialize(Providers::safeFileGetContents($reference_cache_location)); - } - - if (!is_array($reference_cache)) { - throw new UnexpectedValueException('The reference cache must be an array'); - } - - return $reference_cache; + return $this->getCacheItem(self::NONMETHOD_CLASS_REFERENCE_CACHE_NAME); } - /** - * @psalm-suppress MixedAssignment - */ public function getCachedMethodClassReferences(): ?array { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return null; - } - - $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_CLASS_REFERENCE_CACHE_NAME; - - if (!is_readable($reference_cache_location)) { - return null; - } - - if ($this->config->use_igbinary) { - $reference_cache = igbinary_unserialize(Providers::safeFileGetContents($reference_cache_location)); - } else { - $reference_cache = unserialize(Providers::safeFileGetContents($reference_cache_location)); - } - - if (!is_array($reference_cache)) { - throw new UnexpectedValueException('The reference cache must be an array'); - } - - return $reference_cache; + return $this->getCacheItem(self::METHOD_CLASS_REFERENCE_CACHE_NAME); } - /** - * @psalm-suppress MixedAssignment - */ public function getCachedMethodMemberReferences(): ?array { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return null; - } - - $class_member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASS_METHOD_CACHE_NAME; - - if (!is_readable($class_member_cache_location)) { - return null; - } - - $class_member_reference_cache = Providers::safeFileGetContents($class_member_cache_location); - if ($this->config->use_igbinary) { - $class_member_reference_cache = igbinary_unserialize($class_member_reference_cache); - } else { - $class_member_reference_cache = unserialize($class_member_reference_cache); - } - - if (!is_array($class_member_reference_cache)) { - throw new UnexpectedValueException('The reference cache must be an array'); - } - - return $class_member_reference_cache; + return $this->getCacheItem(self::CLASS_METHOD_CACHE_NAME); } - /** - * @psalm-suppress MixedAssignment - */ public function getCachedMethodDependencies(): ?array { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return null; - } - - $method_dependencies_cache_location - = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_DEPENDENCIES_CACHE_NAME; - - if (!is_readable($method_dependencies_cache_location)) { - return null; - } - - $method_dependencies_cache = Providers::safeFileGetContents($method_dependencies_cache_location); - if ($this->config->use_igbinary) { - $method_dependencies_cache = igbinary_unserialize($method_dependencies_cache); - } else { - $method_dependencies_cache = unserialize($method_dependencies_cache); - } - - if (!is_array($method_dependencies_cache)) { - throw new UnexpectedValueException('The reference cache must be an array'); - } - - return $method_dependencies_cache; + return $this->getCacheItem(self::METHOD_DEPENDENCIES_CACHE_NAME); } - /** - * @psalm-suppress MixedAssignment - */ public function getCachedMethodPropertyReferences(): ?array { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return null; - } - - $class_member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASS_PROPERTY_CACHE_NAME; - - if (!is_readable($class_member_cache_location)) { - return null; - } - - $class_member_reference_cache = Providers::safeFileGetContents($class_member_cache_location); - if ($this->config->use_igbinary) { - $class_member_reference_cache = igbinary_unserialize($class_member_reference_cache); - } else { - $class_member_reference_cache = unserialize($class_member_reference_cache); - } - - if (!is_array($class_member_reference_cache)) { - throw new UnexpectedValueException('The reference cache must be an array'); - } - - return $class_member_reference_cache; + return $this->getCacheItem(self::CLASS_PROPERTY_CACHE_NAME); } - /** - * @psalm-suppress MixedAssignment - */ public function getCachedMethodMethodReturnReferences(): ?array { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return null; - } - - $class_member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASS_METHOD_RETURN_CACHE_NAME; - - if (!is_readable($class_member_cache_location)) { - return null; - } - - $class_member_reference_cache = Providers::safeFileGetContents($class_member_cache_location); - if ($this->config->use_igbinary) { - $class_member_reference_cache = igbinary_unserialize($class_member_reference_cache); - } else { - $class_member_reference_cache = unserialize($class_member_reference_cache); - } - - if (!is_array($class_member_reference_cache)) { - throw new UnexpectedValueException('The reference cache must be an array'); - } - - return $class_member_reference_cache; + return $this->getCacheItem(self::CLASS_METHOD_RETURN_CACHE_NAME); } - /** - * @psalm-suppress MixedAssignment - */ public function getCachedMethodMissingMemberReferences(): ?array { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return null; - } - - $class_member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_MISSING_MEMBER_CACHE_NAME; - - if (!is_readable($class_member_cache_location)) { - return null; - } - - $class_member_reference_cache = Providers::safeFileGetContents($class_member_cache_location); - if ($this->config->use_igbinary) { - $class_member_reference_cache = igbinary_unserialize($class_member_reference_cache); - } else { - $class_member_reference_cache = unserialize($class_member_reference_cache); - } - - if (!is_array($class_member_reference_cache)) { - throw new UnexpectedValueException('The reference cache must be an array'); - } - - return $class_member_reference_cache; + return $this->getCacheItem(self::METHOD_MISSING_MEMBER_CACHE_NAME); } - /** - * @psalm-suppress MixedAssignment - */ public function getCachedFileMemberReferences(): ?array { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return null; - } - - $file_class_member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_CLASS_MEMBER_CACHE_NAME; - - if (!is_readable($file_class_member_cache_location)) { - return null; - } - - $file_class_member_reference_cache = Providers::safeFileGetContents($file_class_member_cache_location); - if ($this->config->use_igbinary) { - $file_class_member_reference_cache = igbinary_unserialize($file_class_member_reference_cache); - } else { - $file_class_member_reference_cache = unserialize($file_class_member_reference_cache); - } - - if (!is_array($file_class_member_reference_cache)) { - throw new UnexpectedValueException('The reference cache must be an array'); - } - - return $file_class_member_reference_cache; + return $this->getCacheItem(self::FILE_CLASS_MEMBER_CACHE_NAME); } - /** - * @psalm-suppress MixedAssignment - */ public function getCachedFilePropertyReferences(): ?array { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return null; - } - - $file_class_member_cache_location = $cache_directory - . DIRECTORY_SEPARATOR - . self::FILE_CLASS_PROPERTY_CACHE_NAME; - - if (!is_readable($file_class_member_cache_location)) { - return null; - } - - $file_class_member_reference_cache = Providers::safeFileGetContents($file_class_member_cache_location); - if ($this->config->use_igbinary) { - $file_class_member_reference_cache = igbinary_unserialize($file_class_member_reference_cache); - } else { - $file_class_member_reference_cache = unserialize($file_class_member_reference_cache); - } - - if (!is_array($file_class_member_reference_cache)) { - throw new UnexpectedValueException('The reference cache must be an array'); - } - - return $file_class_member_reference_cache; + return $this->getCacheItem(self::FILE_CLASS_PROPERTY_CACHE_NAME); } - /** - * @psalm-suppress MixedAssignment - */ public function getCachedFileMethodReturnReferences(): ?array { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return null; - } - - $file_class_member_cache_location = $cache_directory - . DIRECTORY_SEPARATOR - . self::FILE_METHOD_RETURN_CACHE_NAME; - - if (!is_readable($file_class_member_cache_location)) { - return null; - } - - $file_class_member_reference_cache = Providers::safeFileGetContents($file_class_member_cache_location); - if ($this->config->use_igbinary) { - $file_class_member_reference_cache = igbinary_unserialize($file_class_member_reference_cache); - } else { - $file_class_member_reference_cache = unserialize($file_class_member_reference_cache); - } - - if (!is_array($file_class_member_reference_cache)) { - throw new UnexpectedValueException('The reference cache must be an array'); - } - - return $file_class_member_reference_cache; + return $this->getCacheItem(self::FILE_METHOD_RETURN_CACHE_NAME); } - /** - * @psalm-suppress MixedAssignment - */ public function getCachedFileMissingMemberReferences(): ?array { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return null; - } - - $file_class_member_cache_location - = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_MISSING_MEMBER_CACHE_NAME; - - if (!is_readable($file_class_member_cache_location)) { - return null; - } - - $file_class_member_reference_cache = Providers::safeFileGetContents($file_class_member_cache_location); - if ($this->config->use_igbinary) { - $file_class_member_reference_cache = igbinary_unserialize($file_class_member_reference_cache); - } else { - $file_class_member_reference_cache = unserialize($file_class_member_reference_cache); - } - - if (!is_array($file_class_member_reference_cache)) { - throw new UnexpectedValueException('The reference cache must be an array'); - } - - return $file_class_member_reference_cache; + return $this->getCacheItem(self::FILE_MISSING_MEMBER_CACHE_NAME); } - /** - * @psalm-suppress MixedAssignment - */ public function getCachedMixedMemberNameReferences(): ?array { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return null; - } - - $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::UNKNOWN_MEMBER_CACHE_NAME; - - if (!is_readable($reference_cache_location)) { - return null; - } - - if ($this->config->use_igbinary) { - $reference_cache = igbinary_unserialize(Providers::safeFileGetContents($reference_cache_location)); - } else { - $reference_cache = unserialize(Providers::safeFileGetContents($reference_cache_location)); - } - - if (!is_array($reference_cache)) { - throw new UnexpectedValueException('The reference cache must be an array'); - } - - return $reference_cache; + return $this->getCacheItem(self::UNKNOWN_MEMBER_CACHE_NAME); } - /** - * @psalm-suppress MixedAssignment - */ public function getCachedMethodParamUses(): ?array { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return null; - } - - $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_PARAM_USE_CACHE_NAME; - - if (!is_readable($reference_cache_location)) { - return null; - } - - if ($this->config->use_igbinary) { - $reference_cache = igbinary_unserialize(Providers::safeFileGetContents($reference_cache_location)); - } else { - $reference_cache = unserialize(Providers::safeFileGetContents($reference_cache_location)); - } - - if (!is_array($reference_cache)) { - throw new UnexpectedValueException('The method param use cache must be an array'); - } - - return $reference_cache; + return $this->getCacheItem(self::METHOD_PARAM_USE_CACHE_NAME); } - /** - * @psalm-suppress MixedAssignment - */ public function getCachedIssues(): ?array { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return null; - } - - $issues_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::ISSUES_CACHE_NAME; - - if (!is_readable($issues_cache_location)) { - return null; - } - - if ($this->config->use_igbinary) { - $issues_cache = igbinary_unserialize(Providers::safeFileGetContents($issues_cache_location)); - } else { - $issues_cache = unserialize(Providers::safeFileGetContents($issues_cache_location)); - } - - if (!is_array($issues_cache)) { - throw new UnexpectedValueException('The reference cache must be an array'); - } - - return $issues_cache; + return $this->getCacheItem(self::ISSUES_CACHE_NAME); } public function setCachedFileReferences(array $file_references): void { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return; - } - - $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::REFERENCE_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($reference_cache_location, igbinary_serialize($file_references), LOCK_EX); - } else { - file_put_contents($reference_cache_location, serialize($file_references), LOCK_EX); - } + $this->saveCacheItem(self::REFERENCE_CACHE_NAME, $file_references); } public function setCachedClassLikeFiles(array $file_references): void { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return; - } - - $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASSLIKE_FILE_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($reference_cache_location, igbinary_serialize($file_references), LOCK_EX); - } else { - file_put_contents($reference_cache_location, serialize($file_references), LOCK_EX); - } + $this->saveCacheItem(self::CLASSLIKE_FILE_CACHE_NAME, $file_references); } public function setCachedNonMethodClassReferences(array $file_class_references): void { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return; - } - - $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::NONMETHOD_CLASS_REFERENCE_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($reference_cache_location, igbinary_serialize($file_class_references), LOCK_EX); - } else { - file_put_contents($reference_cache_location, serialize($file_class_references), LOCK_EX); - } + $this->saveCacheItem(self::NONMETHOD_CLASS_REFERENCE_CACHE_NAME, $file_class_references); } public function setCachedMethodClassReferences(array $method_class_references): void { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return; - } - - $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_CLASS_REFERENCE_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($reference_cache_location, igbinary_serialize($method_class_references), LOCK_EX); - } else { - file_put_contents($reference_cache_location, serialize($method_class_references), LOCK_EX); - } + $this->saveCacheItem(self::METHOD_CLASS_REFERENCE_CACHE_NAME, $method_class_references); } public function setCachedMethodMemberReferences(array $member_references): void { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return; - } - - $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASS_METHOD_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($member_references), LOCK_EX); - } else { - file_put_contents($member_cache_location, serialize($member_references), LOCK_EX); - } + $this->saveCacheItem(self::CLASS_METHOD_CACHE_NAME, $member_references); } public function setCachedMethodDependencies(array $member_references): void { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return; - } - - $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_DEPENDENCIES_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($member_references), LOCK_EX); - } else { - file_put_contents($member_cache_location, serialize($member_references), LOCK_EX); - } + $this->saveCacheItem(self::METHOD_DEPENDENCIES_CACHE_NAME, $member_references); } public function setCachedMethodPropertyReferences(array $property_references): void { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return; - } - - $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASS_PROPERTY_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($property_references), LOCK_EX); - } else { - file_put_contents($member_cache_location, serialize($property_references), LOCK_EX); - } + $this->saveCacheItem(self::CLASS_PROPERTY_CACHE_NAME, $property_references); } public function setCachedMethodMethodReturnReferences(array $method_return_references): void { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return; - } - - $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASS_METHOD_RETURN_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($method_return_references), LOCK_EX); - } else { - file_put_contents($member_cache_location, serialize($method_return_references), LOCK_EX); - } + $this->saveCacheItem(self::CLASS_METHOD_RETURN_CACHE_NAME, $method_return_references); } public function setCachedMethodMissingMemberReferences(array $member_references): void { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return; - } - - $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_MISSING_MEMBER_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($member_references), LOCK_EX); - } else { - file_put_contents($member_cache_location, serialize($member_references), LOCK_EX); - } + $this->saveCacheItem(self::METHOD_MISSING_MEMBER_CACHE_NAME, $member_references); } public function setCachedFileMemberReferences(array $member_references): void { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return; - } - - $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_CLASS_MEMBER_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($member_references), LOCK_EX); - } else { - file_put_contents($member_cache_location, serialize($member_references), LOCK_EX); - } + $this->saveCacheItem(self::FILE_CLASS_MEMBER_CACHE_NAME, $member_references); } public function setCachedFilePropertyReferences(array $property_references): void { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return; - } - - $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_CLASS_PROPERTY_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($property_references), LOCK_EX); - } else { - file_put_contents($member_cache_location, serialize($property_references), LOCK_EX); - } + $this->saveCacheItem(self::FILE_CLASS_PROPERTY_CACHE_NAME, $property_references); } public function setCachedFileMethodReturnReferences(array $method_return_references): void { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return; - } - - $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_METHOD_RETURN_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($method_return_references), LOCK_EX); - } else { - file_put_contents($member_cache_location, serialize($method_return_references), LOCK_EX); - } + $this->saveCacheItem(self::FILE_METHOD_RETURN_CACHE_NAME, $method_return_references); } public function setCachedFileMissingMemberReferences(array $member_references): void { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return; - } - - $member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_MISSING_MEMBER_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($member_cache_location, igbinary_serialize($member_references), LOCK_EX); - } else { - file_put_contents($member_cache_location, serialize($member_references), LOCK_EX); - } + $this->saveCacheItem(self::FILE_MISSING_MEMBER_CACHE_NAME, $member_references); } public function setCachedMixedMemberNameReferences(array $references): void { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return; - } - - $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::UNKNOWN_MEMBER_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($reference_cache_location, igbinary_serialize($references), LOCK_EX); - } else { - file_put_contents($reference_cache_location, serialize($references), LOCK_EX); - } + $this->saveCacheItem(self::UNKNOWN_MEMBER_CACHE_NAME, $references); } public function setCachedMethodParamUses(array $uses): void { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return; - } - - $reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_PARAM_USE_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($reference_cache_location, igbinary_serialize($uses), LOCK_EX); - } else { - file_put_contents($reference_cache_location, serialize($uses), LOCK_EX); - } + $this->saveCacheItem(self::METHOD_PARAM_USE_CACHE_NAME, $uses); } public function setCachedIssues(array $issues): void { - $cache_directory = $this->config->getCacheDirectory(); - - if (!$cache_directory) { - return; - } - - $issues_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::ISSUES_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($issues_cache_location, igbinary_serialize($issues), LOCK_EX); - } else { - file_put_contents($issues_cache_location, serialize($issues), LOCK_EX); - } + $this->saveCacheItem(self::ISSUES_CACHE_NAME, $issues); } /** @@ -837,23 +229,10 @@ class FileReferenceCacheProvider */ public function getAnalyzedMethodCache() { - $cache_directory = $this->config->getCacheDirectory(); + /** @var null|array> $cache_item */ + $cache_item = $this->getCacheItem(self::ANALYZED_METHODS_CACHE_NAME); - $analyzed_methods_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::ANALYZED_METHODS_CACHE_NAME; - - if ($cache_directory - && file_exists($analyzed_methods_cache_location) - ) { - if ($this->config->use_igbinary) { - /** @var array> */ - return igbinary_unserialize(Providers::safeFileGetContents($analyzed_methods_cache_location)); - } else { - /** @var array> */ - return unserialize(Providers::safeFileGetContents($analyzed_methods_cache_location)); - } - } - - return false; + return $cache_item ?? false; } /** @@ -861,19 +240,7 @@ class FileReferenceCacheProvider */ public function setAnalyzedMethodCache(array $analyzed_methods): void { - $cache_directory = Config::getInstance()->getCacheDirectory(); - - if ($cache_directory) { - $analyzed_methods_cache_location = $cache_directory - . DIRECTORY_SEPARATOR - . self::ANALYZED_METHODS_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($analyzed_methods_cache_location, igbinary_serialize($analyzed_methods), LOCK_EX); - } else { - file_put_contents($analyzed_methods_cache_location, serialize($analyzed_methods), LOCK_EX); - } - } + $this->saveCacheItem(self::ANALYZED_METHODS_CACHE_NAME, $analyzed_methods); } /** @@ -881,29 +248,10 @@ class FileReferenceCacheProvider */ public function getFileMapCache() { - $cache_directory = $this->config->getCacheDirectory(); + /** @var array|null $cache_item */ + $cache_item = $this->getCacheItem(self::FILE_MAPS_CACHE_NAME); - $file_maps_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_MAPS_CACHE_NAME; - - if ($cache_directory - && file_exists($file_maps_cache_location) - ) { - if ($this->config->use_igbinary) { - /** - * @var array - */ - $file_maps_cache = igbinary_unserialize(Providers::safeFileGetContents($file_maps_cache_location)); - } else { - /** - * @var array - */ - $file_maps_cache = unserialize(Providers::safeFileGetContents($file_maps_cache_location)); - } - - return $file_maps_cache; - } - - return false; + return $cache_item ?? false; } /** @@ -911,17 +259,7 @@ class FileReferenceCacheProvider */ public function setFileMapCache(array $file_maps): void { - $cache_directory = Config::getInstance()->getCacheDirectory(); - - if ($cache_directory) { - $file_maps_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_MAPS_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($file_maps_cache_location, igbinary_serialize($file_maps), LOCK_EX); - } else { - file_put_contents($file_maps_cache_location, serialize($file_maps), LOCK_EX); - } - } + $this->saveCacheItem(self::FILE_MAPS_CACHE_NAME, $file_maps); } //phpcs:disable -- Remove this once the phpstan phpdoc parser MR is merged @@ -931,29 +269,10 @@ class FileReferenceCacheProvider public function getTypeCoverage() { //phpcs:enable -- Remove this once the phpstan phpdoc parser MR is merged - $cache_directory = Config::getInstance()->getCacheDirectory(); + /** @var array|null $cache_item */ + $cache_item = $this->getCacheItem(self::TYPE_COVERAGE_CACHE_NAME); - $type_coverage_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::TYPE_COVERAGE_CACHE_NAME; - - if ($cache_directory - && file_exists($type_coverage_cache_location) - ) { - if ($this->config->use_igbinary) { - /** @var array */ - $type_coverage_cache = igbinary_unserialize( - Providers::safeFileGetContents($type_coverage_cache_location), - ); - } else { - /** @var array */ - $type_coverage_cache = unserialize( - Providers::safeFileGetContents($type_coverage_cache_location), - ); - } - - return $type_coverage_cache; - } - - return false; + return $cache_item ?? false; } /** @@ -961,17 +280,7 @@ class FileReferenceCacheProvider */ public function setTypeCoverage(array $mixed_counts): void { - $cache_directory = Config::getInstance()->getCacheDirectory(); - - if ($cache_directory) { - $type_coverage_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::TYPE_COVERAGE_CACHE_NAME; - - if ($this->config->use_igbinary) { - file_put_contents($type_coverage_cache_location, igbinary_serialize($mixed_counts), LOCK_EX); - } else { - file_put_contents($type_coverage_cache_location, serialize($mixed_counts), LOCK_EX); - } - } + $this->saveCacheItem(self::TYPE_COVERAGE_CACHE_NAME, $mixed_counts); } /** @@ -1030,4 +339,37 @@ class FileReferenceCacheProvider LOCK_EX, ); } + + private function getCacheItem(string $type): ?array + { + $cache_directory = $this->config->getCacheDirectory(); + if (!$cache_directory) { + return null; + } + + $cache_location = $cache_directory . DIRECTORY_SEPARATOR . $type; + if (!is_readable($cache_location)) { + return null; + } + + $cache_item = $this->cache->getItem($cache_location); + if ($cache_item === null) { + return null; + } elseif (!is_array($cache_item)) { + throw new UnexpectedValueException('The reference cache must be an array'); + } + + return $cache_item; + } + + private function saveCacheItem(string $type, array $cache_item): void + { + $cache_directory = $this->config->getCacheDirectory(); + if (!$cache_directory) { + return; + } + $cache_location = $cache_directory . DIRECTORY_SEPARATOR . $type; + + $this->cache->saveItem($cache_location, $cache_item); + } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FileReferenceProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FileReferenceProvider.php index 459447bb..15950320 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FileReferenceProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FileReferenceProvider.php @@ -14,13 +14,12 @@ use function array_keys; use function array_merge; use function array_unique; use function explode; -use function file_exists; /** - * @psalm-import-type FileMapType from Analyzer - * * Used to determine which files reference other files, necessary for using the --diff * option from the command line. + * + * @psalm-import-type FileMapType from Analyzer * @internal */ class FileReferenceProvider @@ -164,10 +163,12 @@ class FileReferenceProvider */ private static array $method_param_uses = []; + private FileProvider $file_provider; public ?FileReferenceCacheProvider $cache = null; - public function __construct(?FileReferenceCacheProvider $cache = null) + public function __construct(FileProvider $file_provider, ?FileReferenceCacheProvider $cache = null) { + $this->file_provider = $file_provider; $this->cache = $cache; } @@ -179,7 +180,7 @@ class FileReferenceProvider if (self::$deleted_files === null) { self::$deleted_files = array_filter( array_keys(self::$file_references), - static fn(string $file_name): bool => !file_exists($file_name) + fn(string $file_name): bool => !$this->file_provider->fileExists($file_name) ); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FileStorageCacheProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FileStorageCacheProvider.php index 10f2ef14..9fcb7d9d 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FileStorageCacheProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FileStorageCacheProvider.php @@ -3,6 +3,7 @@ namespace Psalm\Internal\Provider; use Psalm\Config; +use Psalm\Internal\Cache; use Psalm\Storage\FileStorage; use RuntimeException; use UnexpectedValueException; @@ -10,21 +11,14 @@ use UnexpectedValueException; use function array_merge; use function dirname; use function file_exists; -use function file_put_contents; use function filemtime; use function get_class; use function hash; -use function igbinary_serialize; -use function igbinary_unserialize; use function is_dir; use function mkdir; -use function serialize; use function strtolower; -use function unlink; -use function unserialize; use const DIRECTORY_SEPARATOR; -use const LOCK_EX; use const PHP_VERSION_ID; /** @@ -34,13 +28,13 @@ class FileStorageCacheProvider { private string $modified_timestamps = ''; - private Config $config; + private Cache $cache; private const FILE_STORAGE_CACHE_DIRECTORY = 'file_cache'; public function __construct(Config $config) { - $this->config = $config; + $this->cache = new Cache($config); $storage_dir = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'Storage' . DIRECTORY_SEPARATOR; @@ -64,20 +58,24 @@ class FileStorageCacheProvider $this->modified_timestamps .= ' ' . filemtime($dependent_file_path); } - $this->modified_timestamps .= $this->config->computeHash(); + $this->modified_timestamps .= $config->computeHash(); } public function writeToCache(FileStorage $storage, string $file_contents): void { $file_path = strtolower($storage->file_path); - $cache_location = $this->getCacheLocationForPath($file_path, true); $storage->hash = $this->getCacheHash($file_path, $file_contents); - if ($this->config->use_igbinary) { - file_put_contents($cache_location, igbinary_serialize($storage), LOCK_EX); - } else { - file_put_contents($cache_location, serialize($storage), LOCK_EX); - } + $this->storeInCache($file_path, $storage); + } + + /** + * @param lowercase-string $file_path + */ + protected function storeInCache(string $file_path, FileStorage $storage): void + { + $cache_location = $this->getCacheLocationForPath($file_path, true); + $this->cache->saveItem($cache_location, $storage); } public function getLatestFromCache(string $file_path, string $file_contents): ?FileStorage @@ -105,11 +103,7 @@ class FileStorageCacheProvider public function removeCacheForFile(string $file_path): void { - $cache_path = $this->getCacheLocationForPath($file_path); - - if (file_exists($cache_path)) { - unlink($cache_path); - } + $this->cache->deleteItem($this->getCacheLocationForPath($file_path)); } private function getCacheHash(string $_unused_file_path, string $file_contents): string @@ -122,30 +116,13 @@ class FileStorageCacheProvider } /** - * @psalm-suppress MixedAssignment + * @param lowercase-string $file_path */ - private function loadFromCache(string $file_path): ?FileStorage + protected function loadFromCache(string $file_path): ?FileStorage { - $cache_location = $this->getCacheLocationForPath($file_path); - - if (file_exists($cache_location)) { - if ($this->config->use_igbinary) { - $storage = igbinary_unserialize(Providers::safeFileGetContents($cache_location)); - - if ($storage instanceof FileStorage) { - return $storage; - } - - return null; - } - - $storage = unserialize(Providers::safeFileGetContents($cache_location)); - - if ($storage instanceof FileStorage) { - return $storage; - } - - return null; + $storage = $this->cache->getItem($this->getCacheLocationForPath($file_path)); + if ($storage instanceof FileStorage) { + return $storage; } return null; @@ -153,7 +130,7 @@ class FileStorageCacheProvider private function getCacheLocationForPath(string $file_path, bool $create_directory = false): string { - $root_cache_directory = $this->config->getCacheDirectory(); + $root_cache_directory = $this->cache->getCacheDirectory(); if (!$root_cache_directory) { throw new UnexpectedValueException('No cache directory defined'); @@ -188,6 +165,6 @@ class FileStorageCacheProvider return $parser_cache_directory . DIRECTORY_SEPARATOR . $hash - . ($this->config->use_igbinary ? '-igbinary' : ''); + . ($this->cache->use_igbinary ? '-igbinary' : ''); } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FunctionReturnTypeProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FunctionReturnTypeProvider.php index de1e27d7..ab43dcf5 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FunctionReturnTypeProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FunctionReturnTypeProvider.php @@ -39,6 +39,7 @@ use Psalm\Internal\Provider\ReturnTypeProvider\ParseUrlReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\PowReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\RandReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\RoundReturnTypeProvider; +use Psalm\Internal\Provider\ReturnTypeProvider\SprintfReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\StrReplaceReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\StrTrReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\TriggerErrorReturnTypeProvider; @@ -105,6 +106,7 @@ class FunctionReturnTypeProvider $this->registerClass(MbInternalEncodingReturnTypeProvider::class); $this->registerClass(DateReturnTypeProvider::class); $this->registerClass(PowReturnTypeProvider::class); + $this->registerClass(SprintfReturnTypeProvider::class); } /** diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ParserCacheProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ParserCacheProvider.php index 17aa7e5e..55aa13e0 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ParserCacheProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ParserCacheProvider.php @@ -6,6 +6,7 @@ use JsonException; use PhpParser; use PhpParser\Node\Stmt; use Psalm\Config; +use Psalm\Internal\Cache; use RuntimeException; use UnexpectedValueException; @@ -15,20 +16,15 @@ use function file_put_contents; use function filemtime; use function gettype; use function hash; -use function igbinary_serialize; -use function igbinary_unserialize; use function is_array; use function is_dir; use function is_readable; -use function is_writable; +use function is_string; use function json_decode; use function json_encode; use function mkdir; use function scandir; -use function serialize; use function touch; -use function unlink; -use function unserialize; use const DIRECTORY_SEPARATOR; use const JSON_THROW_ON_ERROR; @@ -45,7 +41,7 @@ class ParserCacheProvider private const PARSER_CACHE_DIRECTORY = 'php-parser'; private const FILE_CONTENTS_CACHE_DIRECTORY = 'file-caches'; - private Config $config; + private Cache $cache; /** * A map of filename hashes to contents hashes @@ -65,7 +61,7 @@ class ParserCacheProvider public function __construct(Config $config, bool $use_file_cache = true) { - $this->config = $config; + $this->cache = new Cache($config); $this->use_file_cache = $use_file_cache; } @@ -92,15 +88,12 @@ class ParserCacheProvider && is_readable($cache_location) && filemtime($cache_location) > $file_modified_time ) { - if ($this->config->use_igbinary) { - /** @var list */ - $stmts = igbinary_unserialize(Providers::safeFileGetContents($cache_location)); - } else { - /** @var list */ - $stmts = unserialize(Providers::safeFileGetContents($cache_location)); - } + $stmts = $this->cache->getItem($cache_location); - return $stmts; + if (is_array($stmts)) { + /** @var list $stmts */ + return $stmts; + } } return null; @@ -118,13 +111,12 @@ class ParserCacheProvider $cache_location = $this->getCacheLocationForPath($file_path, self::PARSER_CACHE_DIRECTORY); if (is_readable($cache_location)) { - if ($this->config->use_igbinary) { - /** @var list */ - return igbinary_unserialize(Providers::safeFileGetContents($cache_location)) ?: null; - } + $stmts = $this->cache->getItem($cache_location); - /** @var list */ - return unserialize(Providers::safeFileGetContents($cache_location)) ?: null; + if (is_array($stmts)) { + /** @var list $stmts */ + return $stmts; + } } return null; @@ -138,11 +130,13 @@ class ParserCacheProvider $cache_location = $this->getCacheLocationForPath($file_path, self::FILE_CONTENTS_CACHE_DIRECTORY); - if (is_readable($cache_location)) { - return Providers::safeFileGetContents($cache_location); + $cache_item = $this->cache->getItem($cache_location); + + if (!is_string($cache_item)) { + return null; } - return null; + return $cache_item; } /** @@ -155,7 +149,7 @@ class ParserCacheProvider } if ($this->existing_file_content_hashes === null) { - $root_cache_directory = $this->config->getCacheDirectory(); + $root_cache_directory = $this->cache->getCacheDirectory(); $file_hashes_path = $root_cache_directory . DIRECTORY_SEPARATOR . self::FILE_HASHES; if (!$root_cache_directory) { @@ -234,11 +228,7 @@ class ParserCacheProvider if ($touch_only) { touch($cache_location); } else { - if ($this->config->use_igbinary) { - file_put_contents($cache_location, igbinary_serialize($stmts), LOCK_EX); - } else { - file_put_contents($cache_location, serialize($stmts), LOCK_EX); - } + $this->cache->saveItem($cache_location, $stmts); $file_cache_key = $this->getParserCacheKey($file_path); $this->new_file_content_hashes[$file_cache_key] = $file_content_hash; @@ -267,7 +257,7 @@ class ParserCacheProvider return; } - $root_cache_directory = $this->config->getCacheDirectory(); + $root_cache_directory = $this->cache->getCacheDirectory(); if (!$root_cache_directory) { return; @@ -299,13 +289,12 @@ class ParserCacheProvider } $cache_location = $this->getCacheLocationForPath($file_path, self::FILE_CONTENTS_CACHE_DIRECTORY, true); - - file_put_contents($cache_location, $file_contents, LOCK_EX); + $this->cache->saveItem($cache_location, $file_contents); } public function deleteOldParserCaches(float $time_before): int { - $cache_directory = $this->config->getCacheDirectory(); + $cache_directory = $this->cache->getCacheDirectory(); $this->existing_file_content_hashes = null; $this->new_file_content_hashes = []; @@ -328,8 +317,8 @@ class ParserCacheProvider continue; } - if (filemtime($full_path) < $time_before && is_writable($full_path)) { - unlink($full_path); + if (filemtime($full_path) < $time_before) { + $this->cache->deleteItem($full_path); ++$removed_count; } } @@ -346,7 +335,7 @@ class ParserCacheProvider $hash = hash('md4', $file_path); } - return $hash . ($this->config->use_igbinary ? '-igbinary' : '') . '-r'; + return $hash . ($this->cache->use_igbinary ? '-igbinary' : '') . '-r'; } @@ -355,7 +344,7 @@ class ParserCacheProvider string $subdirectory, bool $create_directory = false ): string { - $root_cache_directory = $this->config->getCacheDirectory(); + $root_cache_directory = $this->cache->getCacheDirectory(); if (!$root_cache_directory) { throw new UnexpectedValueException('No cache directory defined'); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ProjectCacheProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ProjectCacheProvider.php index b97b0c31..4948acc5 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ProjectCacheProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ProjectCacheProvider.php @@ -78,20 +78,19 @@ class ProjectCacheProvider public function hasLockfileChanged(): bool { - if (!file_exists($this->composer_lock_location)) { - return true; - } + if (file_exists($this->composer_lock_location)) { + $lockfile_contents = Providers::safeFileGetContents($this->composer_lock_location); + if (!$lockfile_contents) { + return true; + } - $lockfile_contents = Providers::safeFileGetContents($this->composer_lock_location); - - if (!$lockfile_contents) { - return true; - } - - if (PHP_VERSION_ID >= 8_01_00) { - $hash = hash('xxh128', $lockfile_contents); + if (PHP_VERSION_ID >= 8_01_00) { + $hash = hash('xxh128', $lockfile_contents); + } else { + $hash = hash('md4', $lockfile_contents); + } } else { - $hash = hash('md4', $lockfile_contents); + $hash = ''; } $changed = $hash !== $this->getComposerLockHash(); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/Providers.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/Providers.php index 57f5f848..b3a5a2a8 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/Providers.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/Providers.php @@ -51,7 +51,7 @@ class Providers $parser_cache_provider, $file_storage_cache_provider, ); - $this->file_reference_provider = new FileReferenceProvider($file_reference_cache_provider); + $this->file_reference_provider = new FileReferenceProvider($file_provider, $file_reference_cache_provider); } public static function safeFileGetContents(string $path): string diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayFillReturnTypeProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayFillReturnTypeProvider.php index f7f0cd24..3d0a08f2 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayFillReturnTypeProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayFillReturnTypeProvider.php @@ -7,7 +7,6 @@ use Psalm\Plugin\EventHandler\Event\FunctionReturnTypeProviderEvent; use Psalm\Plugin\EventHandler\FunctionReturnTypeProviderInterface; use Psalm\Type; use Psalm\Type\Atomic\TArray; -use Psalm\Type\Atomic\TIntRange; use Psalm\Type\Atomic\TKeyedArray; use Psalm\Type\Atomic\TNonEmptyArray; use Psalm\Type\Union; @@ -99,10 +98,10 @@ class ArrayFillReturnTypeProvider implements FunctionReturnTypeProviderInterface ) { return new Union([ new TNonEmptyArray([ - new Union([new TIntRange( + Type::getIntRange( $first_arg_type->getSingleIntLiteral()->value, $second_arg_type->getSingleIntLiteral()->value, - )]), + ), $value_type_from_third_arg, ]), ]); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/DirnameReturnTypeProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/DirnameReturnTypeProvider.php index c8867999..6d96bf81 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/DirnameReturnTypeProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/DirnameReturnTypeProvider.php @@ -9,6 +9,7 @@ use Psalm\Plugin\EventHandler\Event\FunctionReturnTypeProviderEvent; use Psalm\Plugin\EventHandler\FunctionReturnTypeProviderInterface; use Psalm\Type; use Psalm\Type\Atomic\TLiteralInt; +use Psalm\Type\Atomic\TNonEmptyString; use Psalm\Type\Union; use function array_values; @@ -61,6 +62,16 @@ class DirnameReturnTypeProvider implements FunctionReturnTypeProviderInterface $statements_source->getCodebase()->config, ); + if ($evaled_path === null) { + $type = $node_type_provider->getType($call_args[0]->value); + if ($type !== null && $type->isSingle()) { + $atomic_type = array_values($type->getAtomicTypes())[0]; + if ($atomic_type instanceof TNonEmptyString) { + return Type::getNonEmptyString(); + } + } + } + if ($evaled_path === null) { return Type::getString(); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/ImagickPixelColorReturnTypeProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/ImagickPixelColorReturnTypeProvider.php index 384f5572..b756e98a 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/ImagickPixelColorReturnTypeProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/ImagickPixelColorReturnTypeProvider.php @@ -6,7 +6,6 @@ use Psalm\Internal\Analyzer\StatementsAnalyzer; use Psalm\Plugin\EventHandler\Event\MethodReturnTypeProviderEvent; use Psalm\Plugin\EventHandler\MethodReturnTypeProviderInterface; use Psalm\Type; -use Psalm\Type\Atomic\TIntRange; use Psalm\Type\Atomic\TKeyedArray; use Psalm\Type\Atomic\TLiteralInt; use Psalm\Type\Union; @@ -57,10 +56,10 @@ class ImagickPixelColorReturnTypeProvider implements MethodReturnTypeProviderInt if (isset($formats[0])) { $types []= new Union([ new TKeyedArray([ - 'r' => new Union([new TIntRange(0, 255)]), - 'g' => new Union([new TIntRange(0, 255)]), - 'b' => new Union([new TIntRange(0, 255)]), - 'a' => new Union([new TIntRange(0, 1)]), + 'r' => Type::getIntRange(0, 255), + 'g' => Type::getIntRange(0, 255), + 'b' => Type::getIntRange(0, 255), + 'a' => Type::getIntRange(0, 1), ]), ]); } @@ -77,10 +76,10 @@ class ImagickPixelColorReturnTypeProvider implements MethodReturnTypeProviderInt if (isset($formats[2])) { $types []= new Union([ new TKeyedArray([ - 'r' => new Union([new TIntRange(0, 255)]), - 'g' => new Union([new TIntRange(0, 255)]), - 'b' => new Union([new TIntRange(0, 255)]), - 'a' => new Union([new TIntRange(0, 255)]), + 'r' => Type::getIntRange(0, 255), + 'g' => Type::getIntRange(0, 255), + 'b' => Type::getIntRange(0, 255), + 'a' => Type::getIntRange(0, 255), ]), ]); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/MinMaxReturnTypeProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/MinMaxReturnTypeProvider.php index 516b8b5f..2f4b7fff 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/MinMaxReturnTypeProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/MinMaxReturnTypeProvider.php @@ -127,7 +127,7 @@ class MinMaxReturnTypeProvider implements FunctionReturnTypeProviderInterface return Type::getInt(false, $min_potential_int); } - return new Union([new TIntRange($min_potential_int, $max_potential_int)]); + return Type::getIntRange($min_potential_int, $max_potential_int); } //if we're dealing with non-int elements, just combine them all together diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/PdoStatementReturnTypeProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/PdoStatementReturnTypeProvider.php index 0e09aa85..3edc2342 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/PdoStatementReturnTypeProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/PdoStatementReturnTypeProvider.php @@ -27,88 +27,268 @@ class PdoStatementReturnTypeProvider implements MethodReturnTypeProviderInterfac public static function getMethodReturnType(MethodReturnTypeProviderEvent $event): ?Union { $config = Config::getInstance(); + $method_name_lowercase = $event->getMethodNameLowercase(); + + if (!$config->php_extensions["pdo"]) { + return null; + } + + if ($method_name_lowercase === 'fetch') { + return self::handleFetch($event); + } + + if ($method_name_lowercase === 'fetchall') { + return self::handleFetchAll($event); + } + + return null; + } + + private static function handleFetch(MethodReturnTypeProviderEvent $event): ?Union + { $source = $event->getSource(); $call_args = $event->getCallArgs(); - $method_name_lowercase = $event->getMethodNameLowercase(); - if ($method_name_lowercase === 'fetch' - && $config->php_extensions["pdo"] - && isset($call_args[0]) + $fetch_mode = 0; + + if (isset($call_args[0]) && ($first_arg_type = $source->getNodeTypeProvider()->getType($call_args[0]->value)) && $first_arg_type->isSingleIntLiteral() ) { $fetch_mode = $first_arg_type->getSingleIntLiteral()->value; + } - switch ($fetch_mode) { - case 2: // PDO::FETCH_ASSOC - array|false - return new Union([ - new TArray([ - Type::getString(), - new Union([ - new TScalar(), - new TNull(), + switch ($fetch_mode) { + case 2: // PDO::FETCH_ASSOC - array|false + return new Union([ + new TArray([ + Type::getString(), + new Union([ + new TScalar(), + new TNull(), + ]), + ]), + new TFalse(), + ]); + + case 4: // PDO::FETCH_BOTH - array|false + return new Union([ + new TArray([ + Type::getArrayKey(), + new Union([ + new TScalar(), + new TNull(), + ]), + ]), + new TFalse(), + ]); + + case 6: // PDO::FETCH_BOUND - bool + return Type::getBool(); + + case 7: // PDO::FETCH_COLUMN - scalar|null|false + return new Union([ + new TScalar(), + new TNull(), + new TFalse(), + ]); + + case 8: // PDO::FETCH_CLASS - object|false + return new Union([ + new TObject(), + new TFalse(), + ]); + + case 1: // PDO::FETCH_LAZY - object|false + // This actually returns a PDORow object, but that class is + // undocumented, and its attributes are all dynamic anyway + return new Union([ + new TObject(), + new TFalse(), + ]); + + case 11: // PDO::FETCH_NAMED - array>|false + return new Union([ + new TArray([ + Type::getString(), + new Union([ + new TScalar(), + new TNull(), + Type::getListAtomic( + new Union([ + new TScalar(), + new TNull(), + ]), + ), + ]), + ]), + new TFalse(), + ]); + + case 12: // PDO::FETCH_KEY_PAIR - array + return new Union([ + new TArray([ + Type::getArrayKey(), + new Union([ + new TScalar(), + new TNull(), + ]), + ]), + ]); + + case 3: // PDO::FETCH_NUM - list|false + return new Union([ + Type::getListAtomic( + new Union([ + new TScalar(), + new TNull(), + ]), + ), + new TFalse(), + ]); + + case 5: // PDO::FETCH_OBJ - stdClass|false + return new Union([ + new TNamedObject('stdClass'), + new TFalse(), + ]); + } + + return null; + } + + private static function handleFetchAll(MethodReturnTypeProviderEvent $event): ?Union + { + $source = $event->getSource(); + $call_args = $event->getCallArgs(); + $fetch_mode = 0; + + if (isset($call_args[0]) + && ($first_arg_type = $source->getNodeTypeProvider()->getType($call_args[0]->value)) + && $first_arg_type->isSingleIntLiteral() + ) { + $fetch_mode = $first_arg_type->getSingleIntLiteral()->value; + } + + $fetch_class_name = null; + + if (isset($call_args[1]) + && ($second_arg_type = $source->getNodeTypeProvider()->getType($call_args[1]->value)) + && $second_arg_type->isSingleStringLiteral() + ) { + $fetch_class_name = $second_arg_type->getSingleStringLiteral()->value; + } + + switch ($fetch_mode) { + case 2: // PDO::FETCH_ASSOC - list> + return new Union([ + Type::getListAtomic( + new Union([ + new TArray([ + Type::getString(), + new Union([ + new TScalar(), + new TNull(), + ]), ]), ]), - new TFalse(), - ]); + ), + ]); - case 4: // PDO::FETCH_BOTH - array|false - return new Union([ - new TArray([ - Type::getArrayKey(), - new Union([ - new TScalar(), - new TNull(), + case 4: // PDO::FETCH_BOTH - list> + return new Union([ + Type::getListAtomic( + new Union([ + new TArray([ + Type::getArrayKey(), + new Union([ + new TScalar(), + new TNull(), + ]), ]), ]), - new TFalse(), - ]); + ), + ]); - case 6: // PDO::FETCH_BOUND - bool - return Type::getBool(); + case 6: // PDO::FETCH_BOUND - list + return new Union([ + Type::getListAtomic( + Type::getBool(), + ), + ]); - case 8: // PDO::FETCH_CLASS - object|false - return new Union([ - new TObject(), - new TFalse(), - ]); + case 7: // PDO::FETCH_COLUMN - list + return new Union([ + Type::getListAtomic( + new Union([ + new TScalar(), + new TNull(), + ]), + ), + ]); - case 1: // PDO::FETCH_LAZY - object|false - // This actually returns a PDORow object, but that class is - // undocumented, and its attributes are all dynamic anyway - return new Union([ - new TObject(), - new TFalse(), - ]); + case 8: // PDO::FETCH_CLASS - list + return new Union([ + Type::getListAtomic( + new Union([ + $fetch_class_name ? new TNamedObject($fetch_class_name) : new TObject(), + ]), + ), + ]); - case 11: // PDO::FETCH_NAMED - array>|false - return new Union([ - new TArray([ - Type::getString(), - new Union([ - new TScalar(), - Type::getListAtomic(Type::getScalar()), + case 11: // PDO::FETCH_NAMED - list>> + return new Union([ + Type::getListAtomic( + new Union([ + new TArray([ + Type::getString(), + new Union([ + new TScalar(), + new TNull(), + Type::getListAtomic( + new Union([ + new TScalar(), + new TNull(), + ]), + ), + ]), ]), ]), - new TFalse(), - ]); + ), + ]); - case 3: // PDO::FETCH_NUM - list|false - return new Union([ - Type::getListAtomic( - new Union([ - new TScalar(), - new TNull(), - ]), - ), - new TFalse(), - ]); + case 12: // PDO::FETCH_KEY_PAIR - array + return new Union([ + new TArray([ + Type::getArrayKey(), + new Union([ + new TScalar(), + new TNull(), + ]), + ]), + ]); - case 5: // PDO::FETCH_OBJ - stdClass|false - return new Union([ - new TNamedObject('stdClass'), - new TFalse(), - ]); - } + case 3: // PDO::FETCH_NUM - list> + return new Union([ + Type::getListAtomic( + new Union([ + Type::getListAtomic( + new Union([ + new TScalar(), + new TNull(), + ]), + ), + ]), + ), + ]); + + case 5: // PDO::FETCH_OBJ - list + return new Union([ + Type::getListAtomic( + new Union([ + new TNamedObject('stdClass'), + ]), + ), + ]); } return null; diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/RandReturnTypeProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/RandReturnTypeProvider.php index 7ccfce13..ea6184e7 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/RandReturnTypeProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/RandReturnTypeProvider.php @@ -63,6 +63,6 @@ class RandReturnTypeProvider implements FunctionReturnTypeProviderInterface } } - return new Union([new TIntRange($min_value, $max_value)]); + return Type::getIntRange($min_value, $max_value); } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/SprintfReturnTypeProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/SprintfReturnTypeProvider.php new file mode 100644 index 00000000..8c9af941 --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/SprintfReturnTypeProvider.php @@ -0,0 +1,329 @@ + + */ + public static function getFunctionIds(): array + { + return [ + 'printf', + 'sprintf', + ]; + } + + public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event): ?Union + { + $statements_source = $event->getStatementsSource(); + $call_args = $event->getCallArgs(); + + $has_splat_args = false; + $node_type_provider = $statements_source->getNodeTypeProvider(); + foreach ($call_args as $call_arg) { + $type = $node_type_provider->getType($call_arg->value); + if ($type === null) { + continue; + } + + // if it's an array, used with splat operator + // we cannot validate it reliably below and report false positive errors + if ($type->isArray()) { + $has_splat_args = true; + break; + } + } + + // there is only 1 array argument, fall back to the default handling + // eventually this could be refined + // to check if it's an array with literal string as first element for further checking + if (count($call_args) === 1 && $has_splat_args === true) { + return null; + } + + // it makes no sense to use sprintf when there is only 1 arg (the format) + // as it wouldn't have any placeholders + if (count($call_args) === 1 && $event->getFunctionId() === 'sprintf') { + IssueBuffer::maybeAdd( + new TooFewArguments( + 'Too few arguments for ' . $event->getFunctionId() . ', expecting at least 2 arguments', + $event->getCodeLocation(), + $event->getFunctionId(), + ), + $statements_source->getSuppressedIssues(), + ); + + return null; + } + + // PHP 7 handling for formats that do not contain anything but placeholders + $is_falsable = true; + foreach ($call_args as $index => $call_arg) { + $type = $node_type_provider->getType($call_arg->value); + if ($type === null && $index === 0 && $event->getFunctionId() === 'printf') { + break; + } + + if ($type === null) { + continue; + } + + if ($index === 0 && $type->isSingleStringLiteral()) { + if ($type->getSingleStringLiteral()->value === '') { + IssueBuffer::maybeAdd( + new InvalidArgument( + 'Argument 1 of ' . $event->getFunctionId() . ' must not be an empty string', + $event->getCodeLocation(), + $event->getFunctionId(), + ), + $statements_source->getSuppressedIssues(), + ); + + if ($event->getFunctionId() === 'printf') { + return Type::getInt(false, 0); + } + + return Type::getString(''); + } + + // there are probably additional formats that return an empty string, this is just a starting point + if (preg_match('/^%(?:\d+\$)?[-+]?0(?:\.0)?s$/', $type->getSingleStringLiteral()->value) === 1) { + IssueBuffer::maybeAdd( + new InvalidArgument( + 'The pattern of argument 1 of ' . $event->getFunctionId() + . ' will always return an empty string', + $event->getCodeLocation(), + $event->getFunctionId(), + ), + $statements_source->getSuppressedIssues(), + ); + + if ($event->getFunctionId() === 'printf') { + return Type::getInt(false, 0); + } + + return Type::getString(''); + } + + // these placeholders are too complex to handle for now + if (preg_match( + '/%(?:\d+\$)?[-+]?(?:\d+|\*)(?:\.(?:\d+|\*))?[bcdouxXeEfFgGhHs]/', + $type->getSingleStringLiteral()->value, + ) === 1) { + return null; + } + + // assume a random, high number for tests + $provided_placeholders_count = $has_splat_args === true ? 100 : count($call_args) - 1; + $dummy = array_fill(0, $provided_placeholders_count, ''); + + // check if we have enough/too many arguments and a valid format + $initial_result = null; + while (count($dummy) > -1) { + $result = null; + try { + // before PHP 8, an uncatchable Warning is thrown if too few arguments are passed + // which is ignored and handled below instead + $result = @sprintf($type->getSingleStringLiteral()->value, ...$dummy); + if ($initial_result === null) { + $initial_result = $result; + + if ($result === $type->getSingleStringLiteral()->value) { + IssueBuffer::maybeAdd( + new InvalidArgument( + 'Argument 1 of ' . $event->getFunctionId() + . ' does not contain any placeholders', + $event->getCodeLocation(), + $event->getFunctionId(), + ), + $statements_source->getSuppressedIssues(), + ); + + return null; + } + } + } catch (ValueError $value_error) { + // PHP 8 + // the format is invalid + IssueBuffer::maybeAdd( + new InvalidArgument( + 'Argument 1 of ' . $event->getFunctionId() . ' is invalid - ' + . $value_error->getMessage(), + $event->getCodeLocation(), + $event->getFunctionId(), + ), + $statements_source->getSuppressedIssues(), + ); + + break 2; + } catch (ArgumentCountError $error) { + // PHP 8 + if (count($dummy) === $provided_placeholders_count) { + IssueBuffer::maybeAdd( + new TooFewArguments( + 'Too few arguments for ' . $event->getFunctionId(), + $event->getCodeLocation(), + $event->getFunctionId(), + ), + $statements_source->getSuppressedIssues(), + ); + + break 2; + } + } + + if ($result === false && count($dummy) === $provided_placeholders_count) { + // could be invalid format or too few arguments + // we cannot distinguish this in PHP 7 without additional checks + $max_dummy = array_fill(0, 100, ''); + $result = @sprintf($type->getSingleStringLiteral()->value, ...$max_dummy); + if ($result === false) { + // the format is invalid + IssueBuffer::maybeAdd( + new InvalidArgument( + 'Argument 1 of ' . $event->getFunctionId() . ' is invalid', + $event->getCodeLocation(), + $event->getFunctionId(), + ), + $statements_source->getSuppressedIssues(), + ); + } else { + IssueBuffer::maybeAdd( + new TooFewArguments( + 'Too few arguments for ' . $event->getFunctionId(), + $event->getCodeLocation(), + $event->getFunctionId(), + ), + $statements_source->getSuppressedIssues(), + ); + } + + return Type::getFalse(); + } + + // we can only validate the format and arg 1 when using splat + if ($has_splat_args === true) { + break; + } + + if (is_string($result) && count($dummy) + 1 <= $provided_placeholders_count) { + IssueBuffer::maybeAdd( + new TooManyArguments( + 'Too many arguments for the number of placeholders in ' . $event->getFunctionId(), + $event->getCodeLocation(), + $event->getFunctionId(), + ), + $statements_source->getSuppressedIssues(), + ); + + break; + } + + if (!is_string($result)) { + break; + } + + // abort if it's empty, since we checked everything + if (array_pop($dummy) === null) { + break; + } + } + + if ($event->getFunctionId() === 'printf') { + // printf only has the format validated above + // don't change the return type + return null; + } + + if ($initial_result !== null && $initial_result !== false && $initial_result !== '') { + return Type::getNonEmptyString(); + } + + // if we didn't have any valid result + // the pattern is invalid or not yet supported by the return type provider + if ($initial_result === null || $initial_result === false) { + return null; + } + + // the initial result is an empty string + // which means the format is valid and it depends on the args, whether it is non-empty-string or not + $is_falsable = false; + } + + if ($index === 0 && $event->getFunctionId() === 'printf') { + // printf only has the format validated above + // don't change the return type + break; + } + + if ($index === 0) { + continue; + } + + // if the function has more arguments than the pattern has placeholders, this could be a false positive + // if the param is not used in the pattern + if ($type->isNonEmptyString() || $type->isInt() || $type->isFloat()) { + return Type::getNonEmptyString(); + } + + // check for unions of either + $atomic_types = $type->getAtomicTypes(); + if ($atomic_types === []) { + continue; + } + + foreach ($atomic_types as $atomic_type) { + if ($atomic_type instanceof TNonEmptyString + || $atomic_type instanceof TClassString + || ($atomic_type instanceof TLiteralString && $atomic_type->value !== '') + || $atomic_type instanceof TInt + || $atomic_type instanceof TFloat + || $atomic_type instanceof TNumeric) { + // valid non-empty types, potentially there are more though + continue; + } + + // empty or generic string + // or other unhandled type + continue 2; + } + + return Type::getNonEmptyString(); + } + + if ($is_falsable === false) { + return Type::getString(); + } + + return null; + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/StrReplaceReturnTypeProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/StrReplaceReturnTypeProvider.php index f56f8279..c7d64270 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/StrReplaceReturnTypeProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/StrReplaceReturnTypeProvider.php @@ -6,13 +6,10 @@ use Psalm\Internal\Analyzer\StatementsAnalyzer; use Psalm\Plugin\EventHandler\Event\FunctionReturnTypeProviderEvent; use Psalm\Plugin\EventHandler\FunctionReturnTypeProviderInterface; use Psalm\Type; -use Psalm\Type\Atomic\TNull; -use Psalm\Type\Atomic\TString; use Psalm\Type\Union; use function call_user_func; use function count; -use function in_array; /** * @internal @@ -27,13 +24,10 @@ class StrReplaceReturnTypeProvider implements FunctionReturnTypeProviderInterfac return [ 'str_replace', 'str_ireplace', - 'substr_replace', - 'preg_replace', - 'preg_replace_callback', ]; } - public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event): Union + public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event): ?Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); @@ -41,47 +35,34 @@ class StrReplaceReturnTypeProvider implements FunctionReturnTypeProviderInterfac if (!$statements_source instanceof StatementsAnalyzer || count($call_args) < 3 ) { - return Type::getMixed(); + // use the defaults, it will already report an error for the invalid params + return null; } if ($subject_type = $statements_source->node_data->getType($call_args[2]->value)) { - if (!$subject_type->hasString() && $subject_type->hasArray()) { - return Type::getArray(); + if (!$subject_type->isSingleStringLiteral()) { + return null; } - $return_type = Type::getString(); - - if (in_array($function_id, ['str_replace', 'str_ireplace'], true) - && $subject_type->isSingleStringLiteral() + $first_arg = $statements_source->node_data->getType($call_args[0]->value); + $second_arg = $statements_source->node_data->getType($call_args[1]->value); + if ($first_arg + && $second_arg && $first_arg->isSingleStringLiteral() + && $second_arg->isSingleStringLiteral() ) { - $first_arg = $statements_source->node_data->getType($call_args[0]->value); - $second_arg = $statements_source->node_data->getType($call_args[1]->value); - if ($first_arg - && $second_arg && $first_arg->isSingleStringLiteral() - && $second_arg->isSingleStringLiteral() - ) { - /** - * @var string $replaced_string - */ - $replaced_string = call_user_func( - $function_id, - $first_arg->getSingleStringLiteral()->value, - $second_arg->getSingleStringLiteral()->value, - $subject_type->getSingleStringLiteral()->value, - ); - $return_type = Type::getString($replaced_string); - } - } elseif (in_array($function_id, ['preg_replace', 'preg_replace_callback'], true)) { - $codebase = $statements_source->getCodebase(); - - $return_type = new Union([new TString, new TNull()], [ - 'ignore_nullable_issues' => $codebase->config->ignore_internal_nullable_issues, - ]); + /** + * @var string $replaced_string + */ + $replaced_string = call_user_func( + $function_id, + $first_arg->getSingleStringLiteral()->value, + $second_arg->getSingleStringLiteral()->value, + $subject_type->getSingleStringLiteral()->value, + ); + return Type::getString($replaced_string); } - - return $return_type; } - return Type::getMixed(); + return null; } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/StatementsProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/StatementsProvider.php index 6393cd34..21bccd1c 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/StatementsProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/StatementsProvider.php @@ -52,8 +52,6 @@ class StatementsProvider private ?FileStorageCacheProvider $file_storage_cache_provider = null; - private StatementsVolatileCache $statements_volatile_cache; - /** * @var array> */ @@ -97,7 +95,6 @@ class StatementsProvider $this->parser_cache_provider = $parser_cache_provider; $this->this_modified_time = filemtime(__FILE__); $this->file_storage_cache_provider = $file_storage_cache_provider; - $this->statements_volatile_cache = StatementsVolatileCache::getInstance(); } /** @@ -132,20 +129,11 @@ class StatementsProvider if (!$this->parser_cache_provider || (!$config->isInProjectDirs($file_path) && strpos($file_path, 'vendor')) ) { - $cache_key = "{$file_content_hash}:{$analysis_php_version_id}"; - if ($this->statements_volatile_cache->has($cache_key)) { - return $this->statements_volatile_cache->get($cache_key); - } - $progress->debug('Parsing ' . $file_path . "\n"); $has_errors = false; - $stmts = self::parseStatements($file_contents, $analysis_php_version_id, $has_errors, $file_path); - - $this->statements_volatile_cache->set($cache_key, $stmts); - - return $stmts; + return self::parseStatements($file_contents, $analysis_php_version_id, $has_errors, $file_path); } $stmts = $this->parser_cache_provider->loadStatementsFromCache( diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/StatementsVolatileCache.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/StatementsVolatileCache.php deleted file mode 100644 index e9fef387..00000000 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/StatementsVolatileCache.php +++ /dev/null @@ -1,100 +0,0 @@ -> - */ - protected array $cache = []; - - /** - * @var array - */ - protected array $access = []; - - protected int $max_size; - - protected static ?StatementsVolatileCache $instance = null; - - public function __construct(int $max_size = 4096) - { - $this->max_size = $max_size; - } - - public static function getInstance(): StatementsVolatileCache - { - if (is_null(self::$instance)) { - self::$instance = new self(); - } - - return self::$instance; - } - - public function has(string $key): bool - { - return array_key_exists($key, $this->cache); - } - - /** - * @return list - * @throws InvalidArgumentException - */ - public function get(string $key): array - { - if (! $this->has($key)) { - throw new InvalidArgumentException('Given $key does not exists'); - } - - $access_index = array_search($key, $this->access); - if (false !== $access_index) { - array_splice($this->access, $access_index, 1); - } - $this->access[] = $key; - - return $this->cache[$key]; - } - - /** - * @param list $content - */ - public function set(string $key, array $content): void - { - if (count($this->cache) > $this->max_size) { - reset($this->access); - - $oldest_key_index = key($this->access); - - if (! is_null($oldest_key_index)) { - $oldest_key = $this->access[$oldest_key_index]; - unset($this->cache[$oldest_key]); - unset($this->access[$oldest_key_index]); - } - } - - $this->cache[$key] = $content; - $this->access[] = $key; - } - - public function clearCache(): void - { - $this->cache = []; - $this->access = []; - } -} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/RuntimeCaches.php b/vendor/vimeo/psalm/src/Psalm/Internal/RuntimeCaches.php index 2d63da00..694b49e4 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/RuntimeCaches.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/RuntimeCaches.php @@ -14,7 +14,6 @@ use Psalm\Internal\Provider\ClassLikeStorageProvider; use Psalm\Internal\Provider\FileReferenceProvider; use Psalm\Internal\Provider\FileStorageProvider; use Psalm\Internal\Provider\StatementsProvider; -use Psalm\Internal\Provider\StatementsVolatileCache; use Psalm\Internal\Scanner\ParsedDocblock; use Psalm\Internal\Type\TypeTokenizer; use Psalm\IssueBuffer; @@ -42,6 +41,5 @@ abstract class RuntimeCaches StatementsProvider::clearLexer(); StatementsProvider::clearParser(); ParsedDocblock::resetNewlineBetweenAnnotations(); - StatementsVolatileCache::getInstance()->clearCache(); } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/DocblockParser.php b/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/DocblockParser.php index 2aca637e..0c052346 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/DocblockParser.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/DocblockParser.php @@ -12,6 +12,7 @@ use function count; use function explode; use function implode; use function is_string; +use function ltrim; use function min; use function preg_match; use function preg_replace; @@ -54,7 +55,8 @@ class DocblockParser } // Normalize multi-line @specials. - $lines = explode("\n", $docblock); + $lines = explode("\n", str_replace("\t", ' ', $docblock)); + $has_r = strpos($docblock, "\r") === false ? false : true; $special = []; @@ -62,9 +64,9 @@ class DocblockParser $last = false; foreach ($lines as $k => $line) { - if (preg_match('/^[ \t]*\*?\s*@\w/i', $line)) { + if (strpos($line, '@') !== false && preg_match('/^ *\*?\s*@\w/', $line)) { $last = $k; - } elseif (preg_match('/^\s*\r?$/', $line)) { + } elseif (trim($line) === '') { $last = false; } elseif ($last !== false) { $old_last_line = $lines[$last]; @@ -78,26 +80,29 @@ class DocblockParser foreach ($lines as $k => $line) { $original_line_length = strlen($line); - - $line = str_replace("\r", '', $line); + if ($has_r === true) { + $line = str_replace("\r", '', $line); + } if ($first_line_padding === null) { $asterisk_pos = strpos($line, '*'); - if ($asterisk_pos) { + if ($asterisk_pos === 0 || $asterisk_pos === 1) { + $first_line_padding = ''; + } elseif ($asterisk_pos > 1) { $first_line_padding = substr($line, 0, $asterisk_pos - 1); } } - if (preg_match('/^[ \t]*\*?\s*@([\w\-\\\:]+)[\t ]*(.*)$/sm', $line, $matches, PREG_OFFSET_CAPTURE)) { + if (preg_match('/^ *\*?\s*@([\w\-\\\:]+) *(.*)$/sm', $line, $matches, PREG_OFFSET_CAPTURE)) { /** @var array $matches */ [, $type_info, $data_info] = $matches; [$type] = $type_info; [$data, $data_offset] = $data_info; - if (strpos($data, '*')) { - $data = rtrim(preg_replace('/^[ \t]*\*\s*$/m', '', $data)); + if (strpos($data, '*') !== false) { + $data = rtrim(preg_replace('/^ *\*\s*$/m', '', $data)); } if (empty($special[$type])) { @@ -111,10 +116,9 @@ class DocblockParser unset($lines[$k]); } else { // Strip the leading *, if present. - $text = $lines[$k]; - $text = str_replace("\t", ' ', $text); - $text = preg_replace('/^ *\*/', '', $text, 1); - $lines[$k] = $text; + // technically only need to preg_replace('/^ *\*/', '', $lines[$k], 1) + // however it's slower and removing all spaces and * is fine + $lines[$k] = ltrim($lines[$k], ' *'); } $line_offset += $original_line_length + 1; @@ -122,13 +126,20 @@ class DocblockParser // Smush the whole docblock to the left edge. $min_indent = 80; + $reached_first_non_empty_line = false; foreach ($lines as $k => $line) { $indent = strspn($line, ' '); if ($indent === strlen($line)) { // This line consists of only spaces. Trim it completely. + if ($reached_first_non_empty_line === false) { + // remove any leading empty lines here, to avoid a preg_replace later + unset($lines[$k]); + continue; + } $lines[$k] = ''; continue; } + $reached_first_non_empty_line = true; $min_indent = min($indent, $min_indent); } if ($min_indent > 0) { @@ -142,10 +153,6 @@ class DocblockParser $docblock = implode("\n", $lines); $docblock = rtrim($docblock); - // Trim any empty lines off the front, but leave the indent level if there - // is one. - $docblock = preg_replace('/^\s*\n/', '', $docblock, 1); - $parsed = new ParsedDocblock($docblock, $special, $first_line_padding ?: ''); self::resolveTags($parsed); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/PhpStormMetaScanner.php b/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/PhpStormMetaScanner.php index 5058e67c..b812456d 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/PhpStormMetaScanner.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/PhpStormMetaScanner.php @@ -15,7 +15,6 @@ use Psalm\Type\Union; use ReflectionProperty; use function count; -use function implode; use function is_string; use function str_replace; use function strpos; @@ -45,7 +44,7 @@ class PhpStormMetaScanner $map = []; - if ($args[1]->value->name->parts === ['map'] + if ($args[1]->value->name->getParts() === ['map'] && $args[1]->value->getArgs() && $args[1]->value->getArgs()[0]->value instanceof PhpParser\Node\Expr\Array_ ) { @@ -59,7 +58,7 @@ class PhpStormMetaScanner && strtolower($array_item->value->name->name) ) { $map[$array_item->key->value] = new Union([ - new TNamedObject(implode('\\', $array_item->value->class->parts)), + new TNamedObject($array_item->value->class->toString()), ]); } elseif ($array_item->value instanceof PhpParser\Node\Scalar\String_) { $map[$array_item->key->value] = $array_item->value->value; @@ -93,7 +92,7 @@ class PhpStormMetaScanner && strtolower($array_item->value->name->name) ) { $map[$meta_key] = new Union([ - new TNamedObject(implode('\\', $array_item->value->class->parts)), + new TNamedObject($array_item->value->class->toString()), ]); } elseif ($array_item->value instanceof PhpParser\Node\Scalar\String_) { $map[$meta_key] = $array_item->value->value; @@ -104,7 +103,7 @@ class PhpStormMetaScanner $type_offset = null; - if ($args[1]->value->name->parts === ['type'] + if ($args[1]->value->name->getParts() === ['type'] && $args[1]->value->getArgs() && $args[1]->value->getArgs()[0]->value instanceof PhpParser\Node\Scalar\LNumber ) { @@ -113,7 +112,7 @@ class PhpStormMetaScanner $element_type_offset = null; - if ($args[1]->value->name->parts === ['elementType'] + if ($args[1]->value->name->getParts() === ['elementType'] && $args[1]->value->getArgs() && $args[1]->value->getArgs()[0]->value instanceof PhpParser\Node\Scalar\LNumber ) { @@ -128,7 +127,7 @@ class PhpStormMetaScanner || $identifier->getArgs()[0]->value instanceof PhpParser\Node\Scalar\LNumber ) ) { - $meta_fq_classlike_name = implode('\\', $identifier->class->parts); + $meta_fq_classlike_name = $identifier->class->toString(); $meta_method_name = strtolower($identifier->name->name); @@ -280,7 +279,7 @@ class PhpStormMetaScanner || $identifier->getArgs()[0]->value instanceof PhpParser\Node\Scalar\LNumber ) ) { - $function_id = strtolower(implode('\\', $identifier->name->parts)); + $function_id = strtolower($identifier->name->toString()); if ($map) { $offset = 0; diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/AssertionReconciler.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/AssertionReconciler.php index ac8419f3..85410c4c 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/AssertionReconciler.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/AssertionReconciler.php @@ -771,12 +771,25 @@ class AssertionReconciler extends Reconciler } if ($type_1_param->getId() !== $type_2_param->getId()) { - $type_1_param = $type_2_param; + $type_1_param = $type_2_param->setPossiblyUndefined($type_1_param->possibly_undefined); } } unset($type_1_param); - $matching_atomic_type = $type_1_atomic->setProperties($type_1_properties); + if ($type_1_atomic->fallback_params === null) { + $fallback_types = null; + } else { + //any fallback type is now the value of iterable + $fallback_types = [$type_1_atomic->fallback_params[0], $type_2_param]; + } + + $matching_atomic_type = new TKeyedArray( + $type_1_properties, + $type_1_atomic->class_strings, + $fallback_types, + $type_1_atomic->is_list, + $type_1_atomic->from_docblock, + ); $atomic_comparison_results->type_coerced = true; } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/ClosedInheritanceToUnion.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/ClosedInheritanceToUnion.php new file mode 100644 index 00000000..541f690f --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/ClosedInheritanceToUnion.php @@ -0,0 +1,81 @@ +getAtomicTypes() as $atomic_type) { + if ($atomic_type instanceof TNamedObject) { + $storage = $codebase->classlikes->getStorageFor($atomic_type->value); + + if (null === $storage || null === $storage->inheritors) { + $new_types[] = $atomic_type; + continue; + } + + $template_result = self::getTemplateResult($atomic_type, $codebase); + + $replaced_inheritors = TemplateInferredTypeReplacer::replace( + $storage->inheritors, + $template_result, + $codebase, + ); + + foreach ($replaced_inheritors->getAtomicTypes() as $replaced_atomic_type) { + $new_types[] = $replaced_atomic_type; + } + + $meet_inheritors = true; + } else { + $new_types[] = $atomic_type; + } + } + + if (!$meet_inheritors) { + return $input; + } + + return $new_types ? $input->setTypes($new_types) : $input; + } + + private static function getTemplateResult(TNamedObject $object, Codebase $codebase): TemplateResult + { + if (!$object instanceof TGenericObject) { + return new TemplateResult([], []); + } + + $storage = $codebase->classlikes->getStorageFor($object->value); + + if (null === $storage || null === $storage->template_types) { + return new TemplateResult([], []); + } + + $lower_bounds = []; + $offset = 0; + + foreach ($storage->template_types as $template_name => $templates) { + foreach (array_keys($templates) as $defining_class) { + $lower_bounds[$template_name][$defining_class] = $object->type_params[$offset++]; + } + } + + return new TemplateResult($storage->template_types, $lower_bounds); + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/CallableTypeComparator.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/CallableTypeComparator.php index fa3b5328..2999480d 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/CallableTypeComparator.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/CallableTypeComparator.php @@ -29,6 +29,7 @@ use Psalm\Type\Atomic\TTemplateParam; use Psalm\Type\Union; use UnexpectedValueException; +use function array_slice; use function end; use function strtolower; use function substr; @@ -65,6 +66,8 @@ class CallableTypeComparator return false; } + $input_variadic_param_idx = null; + if ($input_type_part->params !== null && $container_type_part->params !== null) { foreach ($input_type_part->params as $i => $input_param) { $container_param = null; @@ -79,7 +82,15 @@ class CallableTypeComparator } } + if ($input_param->is_variadic) { + $input_variadic_param_idx = $i; + } + if (!$container_param) { + if ($input_param->is_variadic) { + break; + } + if ($input_param->is_optional) { break; } @@ -103,6 +114,26 @@ class CallableTypeComparator } } + if ($input_variadic_param_idx && isset($input_type_part->params[$input_variadic_param_idx])) { + $input_param = $input_type_part->params[$input_variadic_param_idx]; + + foreach (array_slice($container_type_part->params ?? [], $input_variadic_param_idx) as $container_param) { + if ($container_param->type + && !$container_param->type->hasMixed() + && !UnionTypeComparator::isContainedBy( + $codebase, + $container_param->type, + $input_param->type ?: Type::getMixed(), + false, + false, + $atomic_comparison_result, + ) + ) { + return false; + } + } + } + if (isset($container_type_part->return_type)) { if (!isset($input_type_part->return_type)) { if ($atomic_comparison_result) { diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/NegatedAssertionReconciler.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/NegatedAssertionReconciler.php index 3ce8aedd..f4de672c 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/NegatedAssertionReconciler.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/NegatedAssertionReconciler.php @@ -59,6 +59,11 @@ class NegatedAssertionReconciler extends Reconciler int &$failed_reconciliation, bool $inside_loop ): Union { + $existing_var_type = ClosedInheritanceToUnion::map( + $existing_var_type, + $statements_analyzer->getCodebase(), + ); + $is_equality = $assertion->hasEquality(); $assertion_type = $assertion->getAtomicType(); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/SimpleAssertionReconciler.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/SimpleAssertionReconciler.php index 57dd5c2b..0602fff8 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/SimpleAssertionReconciler.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/SimpleAssertionReconciler.php @@ -2441,7 +2441,9 @@ class SimpleAssertionReconciler extends Reconciler $redundant = false; } elseif ($type instanceof TIterable) { - $array_types[] = Type::getListAtomic($type->type_params[1]); + $array_types[] = $is_non_empty + ? Type::getNonEmptyListAtomic($type->type_params[1]) + : Type::getListAtomic($type->type_params[1]); $redundant = false; } else { diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/TemplateStandinTypeReplacer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/TemplateStandinTypeReplacer.php index e824e76f..9fa51c42 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/TemplateStandinTypeReplacer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/TemplateStandinTypeReplacer.php @@ -36,6 +36,7 @@ use Psalm\Type\Atomic\TTemplateValueOf; use Psalm\Type\Union; use function array_fill; +use function array_filter; use function array_keys; use function array_merge; use function array_search; @@ -1253,6 +1254,7 @@ class TemplateStandinTypeReplacer Atomic $container_type_part, ?array &$container_type_params_covariant = null ): array { + $_ = null; if ($input_type_part instanceof TGenericObject || $input_type_part instanceof TIterable) { $input_type_params = $input_type_part->type_params; } elseif ($codebase->classlike_storage_provider->has($input_type_part->value)) { @@ -1316,40 +1318,43 @@ class TemplateStandinTypeReplacer foreach ($params as $extended_input_param_type) { $new_input_param = null; - foreach ($extended_input_param_type->getAtomicTypes() as $et) { - if ($et instanceof TTemplateParam) { - $ets = Methods::getExtendedTemplatedTypes( - $et, - $template_extends, - ); - } else { - $ets = []; - } - - if ($ets - && $ets[0] instanceof TTemplateParam - && isset( - $input_class_storage->template_types - [$ets[0]->param_name] - [$ets[0]->defining_class], + foreach ($extended_input_param_type->getAtomicTypes() as $extended_template) { + $extended_templates = $extended_template instanceof TTemplateParam + ? array_values( + array_filter( + Methods::getExtendedTemplatedTypes($extended_template, $template_extends), + static fn(Atomic $a) => $a instanceof TTemplateParam, + ), ) - ) { - $old_params_offset = (int) array_search( - $ets[0]->param_name, - array_keys($input_class_storage->template_types), - ); + : []; - $candidate_param_type = $input_type_params[$old_params_offset] ?? Type::getMixed(); - $candidate_param_type = $candidate_param_type->setProperties([ - 'from_template_default' => true, - ]); - } else { - $candidate_param_type = new Union([$et], ['from_template_default' => true]); + $candidate_param_types = []; + + if ($extended_templates) { + foreach ($extended_templates as $template) { + if (!isset( + $input_class_storage->template_types + [$template->param_name] + [$template->defining_class], + )) { + continue; + } + + $old_params_offset = (int) array_search( + $template->param_name, + array_keys($input_class_storage->template_types), + ); + + $candidate_param_types[] = ($input_type_params[$old_params_offset] ?? Type::getMixed()) + ->setProperties(['from_template_default' => true]); + } } $new_input_param = Type::combineUnionTypes( $new_input_param, - $candidate_param_type, + $candidate_param_types + ? Type::combineUnionTypeArray($candidate_param_types, $codebase) + : new Union([$extended_template], ['from_template_default' => true]), ); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeCombiner.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeCombiner.php index 0daa9d29..ee1dd03c 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeCombiner.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeCombiner.php @@ -130,7 +130,9 @@ class TypeCombiner if (count($combination->value_types) === 1 && !count($combination->objectlike_entries) && (!$combination->array_type_params - || $combination->array_type_params[1]->isNever() + || ( $overwrite_empty_array + && $combination->array_type_params[1]->isNever() + ) ) && !$combination->builtin_type_params && !$combination->object_type_params @@ -1031,14 +1033,12 @@ class TypeCombiner && strtolower($type->value) === $type->value ) { // do nothing - } elseif (isset($combination->value_types['string']) - && $combination->value_types['string'] instanceof TNonFalsyString - && $type->value - ) { - // do nothing } elseif (isset($combination->value_types['string']) && $combination->value_types['string'] instanceof TNonEmptyString - && $type->value !== '' + && ($combination->value_types['string'] instanceof TNonFalsyString + ? $type->value + : $type->value !== '' + ) ) { // do nothing } else { diff --git a/vendor/vimeo/psalm/src/Psalm/Issue/CodeIssue.php b/vendor/vimeo/psalm/src/Psalm/Issue/CodeIssue.php index 08645794..ce4fcbc4 100644 --- a/vendor/vimeo/psalm/src/Psalm/Issue/CodeIssue.php +++ b/vendor/vimeo/psalm/src/Psalm/Issue/CodeIssue.php @@ -68,6 +68,9 @@ abstract class CodeIssue return array_pop($fqcn_parts); } + /** + * @param IssueData::SEVERITY_* $severity + */ public function toIssueData(string $severity): IssueData { $location = $this->code_location; diff --git a/vendor/vimeo/psalm/src/Psalm/IssueBuffer.php b/vendor/vimeo/psalm/src/Psalm/IssueBuffer.php index 0c40288a..8adb31ea 100644 --- a/vendor/vimeo/psalm/src/Psalm/IssueBuffer.php +++ b/vendor/vimeo/psalm/src/Psalm/IssueBuffer.php @@ -302,7 +302,7 @@ final class IssueBuffer if ($reporting_level === Config::REPORT_INFO) { if ($is_tainted || !self::alreadyEmitted($emitted_key)) { - self::$issues_data[$e->getFilePath()][] = $e->toIssueData(Config::REPORT_INFO); + self::$issues_data[$e->getFilePath()][] = $e->toIssueData(IssueData::SEVERITY_INFO); if ($is_fixable) { self::addFixableIssue($issue_type); @@ -331,7 +331,7 @@ final class IssueBuffer if ($is_tainted || !self::alreadyEmitted($emitted_key)) { ++self::$error_count; - self::$issues_data[$e->getFilePath()][] = $e->toIssueData(Config::REPORT_ERROR); + self::$issues_data[$e->getFilePath()][] = $e->toIssueData(IssueData::SEVERITY_ERROR); if ($is_fixable) { self::addFixableIssue($issue_type); @@ -570,9 +570,8 @@ final class IssueBuffer foreach (self::$issues_data as $file_path => $file_issues) { usort( $file_issues, - static fn(IssueData $d1, IssueData $d2): int => - [$d1->file_path, $d1->line_from, $d1->column_from] - <=> + static fn(IssueData $d1, IssueData $d2): int => [$d1->file_path, $d1->line_from, $d1->column_from] + <=> [$d2->file_path, $d2->line_from, $d2->column_from] ); self::$issues_data[$file_path] = $file_issues; @@ -580,68 +579,68 @@ final class IssueBuffer // make a copy so what gets saved in cache is unaffected by baseline $issues_data = self::$issues_data; + } - if (!empty($issue_baseline)) { - // Set severity for issues in baseline to INFO - foreach ($issues_data as $file_path => $file_issues) { - foreach ($file_issues as $key => $issue_data) { - $file = $issue_data->file_name; - $file = str_replace('\\', '/', $file); - $type = $issue_data->type; + if (!empty($issue_baseline)) { + // Set severity for issues in baseline to INFO + foreach ($issues_data as $file_path => $file_issues) { + foreach ($file_issues as $key => $issue_data) { + $file = $issue_data->file_name; + $file = str_replace('\\', '/', $file); + $type = $issue_data->type; - if (isset($issue_baseline[$file][$type]) && $issue_baseline[$file][$type]['o'] > 0) { - if ($issue_baseline[$file][$type]['o'] === count($issue_baseline[$file][$type]['s'])) { - $position = array_search( - str_replace("\r\n", "\n", trim($issue_data->selected_text)), - $issue_baseline[$file][$type]['s'], - true, - ); + if (isset($issue_baseline[$file][$type]) && $issue_baseline[$file][$type]['o'] > 0) { + if ($issue_baseline[$file][$type]['o'] === count($issue_baseline[$file][$type]['s'])) { + $position = array_search( + str_replace("\r\n", "\n", trim($issue_data->selected_text)), + $issue_baseline[$file][$type]['s'], + true, + ); - if ($position !== false) { - $issue_data->severity = Config::REPORT_INFO; - array_splice($issue_baseline[$file][$type]['s'], $position, 1); - $issue_baseline[$file][$type]['o']--; - } - } else { - $issue_baseline[$file][$type]['s'] = []; - $issue_data->severity = Config::REPORT_INFO; + if ($position !== false) { + $issue_data->severity = IssueData::SEVERITY_INFO; + array_splice($issue_baseline[$file][$type]['s'], $position, 1); $issue_baseline[$file][$type]['o']--; } + } else { + $issue_baseline[$file][$type]['s'] = []; + $issue_data->severity = IssueData::SEVERITY_INFO; + $issue_baseline[$file][$type]['o']--; } - - $issues_data[$file_path][$key] = $issue_data; } - } - if ($codebase->config->find_unused_baseline_entry) { - foreach ($issue_baseline as $file_path => $issues) { - foreach ($issues as $issue_name => $issue) { - if ($issue['o'] !== 0) { - $issues_data[$file_path][] = new IssueData( - Config::REPORT_ERROR, - 0, - 0, - UnusedBaselineEntry::getIssueType(), - sprintf( - 'Baseline for issue "%s" has %d extra %s.', - $issue_name, - $issue['o'], - $issue['o'] === 1 ? 'entry' : 'entries', - ), - $file_path, - '', - '', - '', - 0, - 0, - 0, - 0, - 0, - 0, - UnusedBaselineEntry::SHORTCODE, - UnusedBaselineEntry::ERROR_LEVEL, - ); - } + $issues_data[$file_path][$key] = $issue_data; + } + } + + if ($codebase->config->find_unused_baseline_entry) { + foreach ($issue_baseline as $file_path => $issues) { + foreach ($issues as $issue_name => $issue) { + if ($issue['o'] !== 0) { + $issues_data[$file_path][] = new IssueData( + IssueData::SEVERITY_ERROR, + 0, + 0, + UnusedBaselineEntry::getIssueType(), + sprintf( + 'Baseline for issue "%s" has %d extra %s.', + $issue_name, + $issue['o'], + $issue['o'] === 1 ? 'entry' : 'entries', + ), + $file_path, + '', + '', + '', + 0, + 0, + 0, + 0, + 0, + 0, + UnusedBaselineEntry::SHORTCODE, + UnusedBaselineEntry::ERROR_LEVEL, + ); } } } @@ -792,11 +791,7 @@ final class IssueBuffer } if ($is_full && $start_time) { - $codebase->file_reference_provider->removeDeletedFilesFromReferences(); - - if ($project_analyzer->project_cache_provider) { - $project_analyzer->project_cache_provider->processSuccessfulRun($start_time, PSALM_VERSION); - } + $project_analyzer->finish($start_time, PSALM_VERSION); } if ($error_count diff --git a/vendor/vimeo/psalm/src/Psalm/Plugin/EventHandler/Event/AfterAnalysisEvent.php b/vendor/vimeo/psalm/src/Psalm/Plugin/EventHandler/Event/AfterAnalysisEvent.php index 92ac8ae9..60db9473 100644 --- a/vendor/vimeo/psalm/src/Psalm/Plugin/EventHandler/Event/AfterAnalysisEvent.php +++ b/vendor/vimeo/psalm/src/Psalm/Plugin/EventHandler/Event/AfterAnalysisEvent.php @@ -10,7 +10,7 @@ final class AfterAnalysisEvent { private Codebase $codebase; /** - * @var IssueData[][] + * @var array> where string key is a filepath */ private array $issues; private array $build_info; @@ -19,7 +19,7 @@ final class AfterAnalysisEvent /** * Called after analysis is complete * - * @param array> $issues + * @param array> $issues where string key is a filepath * @internal */ public function __construct( @@ -40,7 +40,7 @@ final class AfterAnalysisEvent } /** - * @return IssueData[][] + * @return array> where string key is a filepath */ public function getIssues(): array { diff --git a/vendor/vimeo/psalm/src/Psalm/Plugin/Shepherd.php b/vendor/vimeo/psalm/src/Psalm/Plugin/Shepherd.php index 73cbdac4..096a17bb 100644 --- a/vendor/vimeo/psalm/src/Psalm/Plugin/Shepherd.php +++ b/vendor/vimeo/psalm/src/Psalm/Plugin/Shepherd.php @@ -5,6 +5,7 @@ namespace Psalm\Plugin; use BadMethodCallException; use Psalm\Config; use Psalm\Internal\Analyzer\IssueData; +use Psalm\Internal\VersionUtils; use Psalm\Plugin\EventHandler\AfterAnalysisInterface; use Psalm\Plugin\EventHandler\Event\AfterAnalysisEvent; @@ -95,7 +96,14 @@ final class Shepherd implements AfterAnalysisInterface } /** - * @return array{build: array, git: array, issues: array, coverage: list, level: int<1,8>}|null + * @return array{ + * build: array, + * git: array, + * issues: array, + * coverage: list, + * level: int<1, 8>, + * versions: array + * }|null */ private static function collectPayloadToSend(AfterAnalysisEvent $event): ?array { @@ -120,11 +128,11 @@ final class Shepherd implements AfterAnalysisInterface return null; } - $issues = $event->getIssues(); - $normalized_data = $issues === [] ? [] : array_filter( - array_merge(...array_values($issues)), - static fn(IssueData $i): bool => $i->severity === 'error', - ); + $issues_grouped_by_filename = $event->getIssues(); + $normalized_data = $issues_grouped_by_filename === [] ? [] : array_values(array_filter( + array_merge(...array_values($issues_grouped_by_filename)), // flatten an array + static fn(IssueData $i): bool => $i->severity === IssueData::SEVERITY_ERROR, + )); $codebase = $event->getCodebase(); @@ -134,6 +142,10 @@ final class Shepherd implements AfterAnalysisInterface 'issues' => $normalized_data, 'coverage' => $codebase->analyzer->getTotalTypeCoverage($codebase), 'level' => Config::getInstance()->level, + 'versions' => [ + 'psalm' => VersionUtils::getPsalmVersion(), + 'parser' => VersionUtils::getPhpParserVersion(), + ], ]; } diff --git a/vendor/vimeo/psalm/src/Psalm/Report.php b/vendor/vimeo/psalm/src/Psalm/Report.php index a7b9268d..fddfd452 100644 --- a/vendor/vimeo/psalm/src/Psalm/Report.php +++ b/vendor/vimeo/psalm/src/Psalm/Report.php @@ -74,7 +74,7 @@ abstract class Report if (!$report_options->show_info) { $this->issues_data = array_filter( $issues_data, - static fn(IssueData $issue_data): bool => $issue_data->severity !== Config::REPORT_INFO, + static fn(IssueData $issue_data): bool => $issue_data->severity !== IssueData::SEVERITY_INFO, ); } else { $this->issues_data = $issues_data; diff --git a/vendor/vimeo/psalm/src/Psalm/Report/CompactReport.php b/vendor/vimeo/psalm/src/Psalm/Report/CompactReport.php index d351b5ba..11416eb2 100644 --- a/vendor/vimeo/psalm/src/Psalm/Report/CompactReport.php +++ b/vendor/vimeo/psalm/src/Psalm/Report/CompactReport.php @@ -3,6 +3,7 @@ namespace Psalm\Report; use Psalm\Config; +use Psalm\Internal\Analyzer\IssueData; use Psalm\Report; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Output\BufferedOutput; @@ -31,7 +32,7 @@ final class CompactReport extends Report $output = []; foreach ($this->issues_data as $i => $issue_data) { - if (!$this->show_info && $issue_data->severity === Config::REPORT_INFO) { + if (!$this->show_info && $issue_data->severity === IssueData::SEVERITY_INFO) { continue; } diff --git a/vendor/vimeo/psalm/src/Psalm/Report/EmacsReport.php b/vendor/vimeo/psalm/src/Psalm/Report/EmacsReport.php index d022fe5d..c1cb008e 100644 --- a/vendor/vimeo/psalm/src/Psalm/Report/EmacsReport.php +++ b/vendor/vimeo/psalm/src/Psalm/Report/EmacsReport.php @@ -2,7 +2,7 @@ namespace Psalm\Report; -use Psalm\Config; +use Psalm\Internal\Analyzer\IssueData; use Psalm\Report; use function sprintf; @@ -18,7 +18,7 @@ final class EmacsReport extends Report $issue_data->file_path, $issue_data->line_from, $issue_data->column_from, - ($issue_data->severity === Config::REPORT_ERROR ? 'error' : 'warning'), + ($issue_data->severity === IssueData::SEVERITY_ERROR ? 'error' : 'warning'), $issue_data->type, $issue_data->message, $issue_data->link, diff --git a/vendor/vimeo/psalm/src/Psalm/Report/GithubActionsReport.php b/vendor/vimeo/psalm/src/Psalm/Report/GithubActionsReport.php index 71a7a0f6..9d7c617f 100644 --- a/vendor/vimeo/psalm/src/Psalm/Report/GithubActionsReport.php +++ b/vendor/vimeo/psalm/src/Psalm/Report/GithubActionsReport.php @@ -2,7 +2,7 @@ namespace Psalm\Report; -use Psalm\Config; +use Psalm\Internal\Analyzer\IssueData; use Psalm\Report; use function sprintf; @@ -34,7 +34,7 @@ final class GithubActionsReport extends Report $output .= sprintf( '::%1$s %2$s::%3$s', - ($issue_data->severity === Config::REPORT_ERROR ? 'error' : 'warning'), + ($issue_data->severity === IssueData::SEVERITY_ERROR ? 'error' : 'warning'), $properties, $data, ) . "\n"; diff --git a/vendor/vimeo/psalm/src/Psalm/Report/JunitReport.php b/vendor/vimeo/psalm/src/Psalm/Report/JunitReport.php index f917aa50..dfef6208 100644 --- a/vendor/vimeo/psalm/src/Psalm/Report/JunitReport.php +++ b/vendor/vimeo/psalm/src/Psalm/Report/JunitReport.php @@ -27,8 +27,8 @@ final class JunitReport extends Report $ndata = []; foreach ($this->issues_data as $error) { - $is_error = $error->severity === Config::REPORT_ERROR; - $is_warning = $error->severity === Config::REPORT_INFO; + $is_error = $error->severity === IssueData::SEVERITY_ERROR; + $is_warning = $error->severity === IssueData::SEVERITY_INFO; if (!$is_error && !$is_warning) { continue; diff --git a/vendor/vimeo/psalm/src/Psalm/Report/TextReport.php b/vendor/vimeo/psalm/src/Psalm/Report/TextReport.php index d2fa2382..2ee578fd 100644 --- a/vendor/vimeo/psalm/src/Psalm/Report/TextReport.php +++ b/vendor/vimeo/psalm/src/Psalm/Report/TextReport.php @@ -2,7 +2,7 @@ namespace Psalm\Report; -use Psalm\Config; +use Psalm\Internal\Analyzer\IssueData; use Psalm\Report; use function sprintf; @@ -18,7 +18,7 @@ final class TextReport extends Report $issue_data->file_path, $issue_data->line_from, $issue_data->column_from, - ($issue_data->severity === Config::REPORT_ERROR ? 'error' : 'warning'), + ($issue_data->severity === IssueData::SEVERITY_ERROR ? 'error' : 'warning'), $issue_data->type, $issue_data->message, ) . "\n"; diff --git a/vendor/vimeo/psalm/src/Psalm/Type.php b/vendor/vimeo/psalm/src/Psalm/Type.php index 3b98f05c..fbc3e7e7 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type.php +++ b/vendor/vimeo/psalm/src/Psalm/Type.php @@ -190,6 +190,14 @@ abstract class Type ]); } + /** + * @psalm-pure + */ + public static function getIntRange(?int $min, ?int $max): Union + { + return new Union([new TIntRange($min, $max)]); + } + /** * @psalm-pure */ @@ -495,7 +503,7 @@ abstract class Type if ($from_docblock) { return self::$listKeyFromDocblock ??= new Union([new TIntRange(0, null, true)]); } - return self::$listKey ??= new Union([new TIntRange(0, null)]); + return self::$listKey ??= self::getIntRange(0, null); } /** diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TCallableList.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TCallableList.php index 8ff15012..764f1ca2 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TCallableList.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TCallableList.php @@ -7,9 +7,9 @@ use Psalm\Type; use function array_fill; /** - * @deprecated Will be removed in Psalm v6, please use TCallableKeyedArrays with is_list=true instead. - * * Denotes a list that is _also_ `callable`. + * + * @deprecated Will be removed in Psalm v6, please use TCallableKeyedArrays with is_list=true instead. * @psalm-immutable */ final class TCallableList extends TNonEmptyList diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentListKey.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentListKey.php index 042c95d4..338136d8 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentListKey.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentListKey.php @@ -3,9 +3,9 @@ namespace Psalm\Type\Atomic; /** - * @deprecated Will be removed in Psalm v6, use TIntRange instead - * * Represents a list key created from foreach ($list as $key => $value) + * + * @deprecated Will be removed in Psalm v6, use TIntRange instead * @psalm-immutable */ final class TDependentListKey extends TInt implements DependentType diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TKeyedArray.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TKeyedArray.php index 8510b83d..dfddbe81 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TKeyedArray.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TKeyedArray.php @@ -310,7 +310,7 @@ class TKeyedArray extends Atomic if (count($this->properties) === 1) { return new Union([new TLiteralInt(0)]); } - return new Union([new TIntRange(0, count($this->properties)-1)]); + return Type::getIntRange(0, count($this->properties)-1); } $key_types = []; diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TList.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TList.php index 9e2c611c..13c44e5b 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TList.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TList.php @@ -14,16 +14,15 @@ use Psalm\Type\Union; use function get_class; /** - * @deprecated Will be removed in Psalm v6, please use TKeyedArrays with is_list=true instead. - * * You may also use the \Psalm\Type::getListAtomic shortcut, which creates unsealed list-like shaped arrays * with all elements optional, semantically equivalent to a TList. * - * * Represents an array that has some particularities: * - its keys are integers * - they start at 0 * - they are consecutive and go upwards (no negative int) + * + * @deprecated Will be removed in Psalm v6, please use TKeyedArrays with is_list=true instead. * @psalm-immutable */ class TList extends Atomic diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TNonEmptyList.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TNonEmptyList.php index e6c02940..47c628cc 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TNonEmptyList.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TNonEmptyList.php @@ -8,13 +8,12 @@ use Psalm\Type\Union; use function array_fill; /** - * @deprecated Will be removed in Psalm v6, please use TKeyedArrays with is_list=true instead. - * * You may also use the \Psalm\Type::getNonEmptyListAtomic shortcut, which creates unsealed list-like shaped arrays * with one non-optional element, semantically equivalent to a TNonEmptyList. * - * * Represents a non-empty list + * + * @deprecated Will be removed in Psalm v6, please use TKeyedArrays with is_list=true instead. * @psalm-immutable */ class TNonEmptyList extends TList diff --git a/vendor/vimeo/psalm/stubs/CoreGenericAttributes.phpstub b/vendor/vimeo/psalm/stubs/CoreGenericAttributes.phpstub new file mode 100644 index 00000000..7aa6400d --- /dev/null +++ b/vendor/vimeo/psalm/stubs/CoreGenericAttributes.phpstub @@ -0,0 +1,13 @@ + $array + * @param non-empty-string $pattern + * @param array $array * @param 0|1 $flags 1=PREG_GREP_INVERT - * @return array + * @return array */ function preg_grep($pattern, array $array, $flags = 0) { @@ -619,7 +619,7 @@ function strtoupper(string $string) : string {} * @param int|array $offset * @param null|int|array $length * - * @return ($string is array ? array : string) + * @return ($string is array ? array : string) * * @psalm-flow ($string, $replace) -> return */ @@ -786,6 +786,8 @@ function explode(string $separator, string $string, int $limit = -1) : array {} /** * @psalm-pure * + * @param non-empty-string $pattern + * * @psalm-flow ($subject) -(array-assignment)-> return * * @template TFlags as int-mask<0, 1, 2, 4> @@ -998,11 +1000,13 @@ function strlen(string $string) : int {} /** * @psalm-pure * + * @template TKey of array-key + * * @param string|array $search * @param string|array $replace - * @param string|array $subject - * @param int $count - * @return ($subject is array ? array : string) + * @param string|array $subject + * @param int<0, max> $count + * @return ($subject is array ? array : string) * * @psalm-flow ($replace, $subject) -> return */ @@ -1011,11 +1015,13 @@ function str_replace($search, $replace, $subject, &$count = null) {} /** * @psalm-pure * + * @template TKey of array-key + * * @param string|array $search * @param string|array $replace - * @param string|array $subject - * @param int $count - * @return ($subject is array ? array : string) + * @param string|array $subject + * @param int<0, max> $count + * @return ($subject is array ? array : string) * * @psalm-flow ($replace, $subject) -> return */ @@ -1169,10 +1175,10 @@ function str_word_count(string $string, int $format = 0, string|null $characters /** * @psalm-pure * - * @param string|string[] $pattern + * @param non-empty-string|non-empty-string[] $pattern * @param string|array $replacement * @param string|array $subject - * @param int $count + * @param int<0, max> $count * @return ($subject is array ? array : string|null) * * @psalm-flow ($replacement, $subject) -> return @@ -1182,22 +1188,30 @@ function preg_filter($pattern, $replacement, $subject, int $limit = -1, &$count /** * @psalm-pure * - * @param string|string[] $pattern + * @template TKey of array-key + * + * @param non-empty-string|non-empty-string[] $pattern * @param string|array $replacement - * @param string|array $subject - * @param int $count - * @return ($subject is array ? array|null : string|null) + * @param string|array $subject + * @param int<0, max> $count + * @return ($subject is array ? array|null : string|null) + * + * @psalm-ignore-nullable-return * * @psalm-flow ($replacement, $subject) -> return */ function preg_replace($pattern, $replacement, $subject, int $limit = -1, &$count = null) {} /** - * @param string|string[] $pattern + * @template TKey of array-key + * + * @param non-empty-string|non-empty-string[] $pattern * @param callable(string[]):string $callback - * @param string|array $subject - * @param int $count - * @return ($subject is array ? array|null : string|null) + * @param string|array $subject + * @param int<0, max> $count + * @return ($subject is array ? array|null : string|null) + * + * @psalm-ignore-nullable-return * * @psalm-taint-specialize * @psalm-flow ($subject) -> return @@ -1208,7 +1222,7 @@ function preg_replace_callback($pattern, $callback, $subject, int $limit = -1, & * @psalm-pure * @template TFlags as int * - * @param string $pattern + * @param non-empty-string $pattern * @param string $subject * @param mixed $matches * @param TFlags $flags @@ -1244,7 +1258,7 @@ function preg_match_all($pattern, $subject, &$matches = [], int $flags = 1, int * @psalm-pure * @template TFlags as int-mask<0, 256, 512> * - * @param string $pattern + * @param non-empty-string $pattern * @param string $subject * @param mixed $matches * @param TFlags $flags @@ -1279,17 +1293,17 @@ function preg_quote(string $str, ?string $delimiter = null) : string {} * @psalm-pure * * @param string|int|float $values - * @return ($format is non-empty-string - * ? ($values is non-empty-string|int|float ? non-empty-string : string) - * : string) + * @return (PHP_MAJOR_VERSION is 8 ? string : string|false) + * @psalm-ignore-falsable-return * * @psalm-flow ($format, $values) -> return */ -function sprintf(string $format, ...$values) : string {} +function sprintf(string $format, ...$values) {} /** * @psalm-pure - * @return string|false + * @param array $values + * @return (PHP_MAJOR_VERSION is 8 ? string : string|false) * @psalm-ignore-falsable-return * * @psalm-flow ($format, $values) -> return @@ -1308,20 +1322,27 @@ function wordwrap(string $string, int $width = 75, string $break = "\n", bool $c * @psalm-pure * * @param string|int|float $values + * @return (PHP_MAJOR_VERSION is 8 ? int<0, max> : int<0, max>|false) + * @psalm-ignore-falsable-return * * @psalm-taint-specialize * @psalm-flow ($format, $values) -> return * @psalm-taint-sink html $format * @psalm-taint-sink html $values */ -function printf(string $format, ...$values) : string {} +function printf(string $format, ...$values) {} /** + * @param array $values + * @return (PHP_MAJOR_VERSION is 8 ? int<0, max> : int<0, max>|false) + * @psalm-ignore-falsable-return + * + * @psalm-pure * @psalm-taint-specialize * @psalm-taint-sink html $format * @psalm-taint-sink html $values */ -function vprintf(string $format, array $values) : int {} +function vprintf(string $format, array $values) {} /** * @psalm-pure @@ -1364,11 +1385,11 @@ function str_getcsv(string $string, string $separator = ',', string $enclosure = /** * @template TKey as array-key - * @template TArray as array + * @template TArray as array * * @param TArray $array * - * @return (TArray is non-empty-array ? non-empty-array : array) + * @return (TArray is non-empty-array ? non-empty-array> : array>) * * @psalm-pure */ @@ -1508,7 +1529,7 @@ function ldap_escape(string $value, string $ignore = "", int $flags = 0) : strin function json_decode(string $json, ?bool $associative = null, int $depth = 512, int $flags = 0) {} /** - * The conditional return type below relies on the fact that JSON_THROW_ON_ERROR is + * The conditional return type below relies on the fact that JSON_THROW_ON_ERROR is * the highest-valued of JSON constants * @psalm-pure * @@ -1542,6 +1563,8 @@ function sapi_windows_cp_conv($in_codepage, $out_codepage, string $subject) : ?s /** * @psalm-pure * + * @return non-empty-string + * * @psalm-flow ($prefix) -> return */ function uniqid(string $prefix = "", bool $more_entropy = false) : string {} @@ -1559,7 +1582,10 @@ function unpack(string $format, string $string, int $offset = 0) {} /** * @psalm-pure * + * @template T of bool + * @param T $strict * @return string|false + * @psalm-return (T is false ? string : string|false) * * @psalm-flow ($string) -> return * @psalm-ignore-falsable-return @@ -1704,3 +1730,58 @@ function pg_escape_literal($string1, $string2 = null) {} * @psalm-flow ($string1, $string2) -> return */ function pg_escape_string($string1, $string2 = null) {} + +if (defined('GLOB_BRACE')) { + /** + * @psalm-template P of string + * @psalm-template F of int-mask + * @psalm-param P $pattern + * @psalm-param F $flags + * @psalm-return ( + * P is '' + * ? (F is int-mask + * ? false|list + * : (F is int-mask + * ? false|list{0:''} + * : false|list + * ) + * ) + * : (F is int-mask + * ? false|list + * : (F is int-mask + * ? false|list{0:non-empty-string, ...} + * : false|list + * ) + * ) + * ) + * @psalm-ignore-falsable-return + */ + function glob (string $pattern, int $flags = 0): array|false {} +} else { + /** + * @psalm-template P of string + * @psalm-template F of int-mask + * @psalm-param P $pattern + * @psalm-param F $flags + * @psalm-return ( + * P is '' + * ? (F is int-mask + * ? false|list + * : (F is int-mask + * ? false|list{0:''} + * : false|list + * ) + * ) + * : (F is int-mask + * ? false|list + * : (F is int-mask + * ? false|list{0:non-empty-string, ...} + * : false|list + * ) + * ) + * ) + * @psalm-ignore-falsable-return + */ + function glob (string $pattern, int $flags = 0): array|false {} +} + diff --git a/vendor/vimeo/psalm/stubs/Php82.phpstub b/vendor/vimeo/psalm/stubs/Php82.phpstub index 8696bd08..81b99f91 100644 --- a/vendor/vimeo/psalm/stubs/Php82.phpstub +++ b/vendor/vimeo/psalm/stubs/Php82.phpstub @@ -34,18 +34,6 @@ namespace { public function getIterator(): Iterator {} } - #[Attribute(Attribute::TARGET_PARAMETER)] - final class SensitiveParameter - { - public function __construct() {} - } - - #[Attribute(Attribute::TARGET_CLASS)] - final class AllowDynamicProperties - { - public function __construct() {} - } - /** * @psalm-pure * @param positive-int $length diff --git a/vendor/vimeo/psalm/stubs/extensions/mongodb.phpstub b/vendor/vimeo/psalm/stubs/extensions/mongodb.phpstub index ad6f34d5..00d9f203 100644 --- a/vendor/vimeo/psalm/stubs/extensions/mongodb.phpstub +++ b/vendor/vimeo/psalm/stubs/extensions/mongodb.phpstub @@ -1,59 +1,251 @@ - */ -interface CursorInterface extends Traversable +namespace MongoDB\BSON { + use IteratorAggregate; + use Serializable; + /** - * @return array + * @template TValue + * @template-implements IteratorAggregate */ - public function toArray(); + final class Document implements IteratorAggregate, Serializable + { + private function __construct() + { + } + + final static public function fromBSON(string $bson): Document + { + } + + final static public function fromJSON(string $json): Document + { + } + + /** @param array|object $value */ + final static public function fromPHP($value): Document + { + } + + /** @return TValue */ + final public function get(string $key) + { + } + + /** @return Iterator */ + final public function getIterator(): Iterator + { + } + + final public function has(string $key): bool + { + } + + /** @return array|object */ + final public function toPHP(?array $typeMap = null) + { + } + + final public function toCanonicalExtendedJSON(): string + { + } + + final public function toRelaxedExtendedJSON(): string + { + } + + final public function __toString(): string + { + } + + final public static function __set_state(array $properties): Document + { + } + + final public function serialize(): string + { + } + + /** @param string $serialized */ + final public function unserialize($serialized): void + { + } + + final public function __unserialize(array $data): void + { + } + + final public function __serialize(): array + { + } + } + + /** + * @psalm-template TKey of int|string + * @psalm-template TValue + * $psalm-implements \Iterator + */ + final class Iterator implements \Iterator + { + final private function __construct() + { + } + + /** @return TValue */ + final public function current() + { + } + + /** @return TKey */ + final public function key() + { + } + + final public function next(): void + { + } + + final public function rewind(): void + { + } + + final public function valid(): bool + { + } + + final public function __wakeup(): void + { + } + } + + /** + * @template TValue + * @template-implements IteratorAggregate + */ + final class PackedArray implements IteratorAggregate, Serializable + { + private function __construct() + { + } + + final static public function fromPHP(array $value): PackedArray + { + } + + /** @return TValue */ + final public function get(int $index) + { + } + + /** @return Iterator */ + final public function getIterator(): Iterator + { + } + + final public function has(int $index): bool + { + } + + /** @return array|object */ + final public function toPHP(?array $typeMap = null) + { + } + + final public function __toString(): string + { + } + + final public static function __set_state(array $properties): PackedArray + { + } + + final public function serialize(): string + { + } + + /** @param string $serialized */ + final public function unserialize($serialized): void + { + } + + final public function __unserialize(array $data): void + { + } + + final public function __serialize(): array + { + } + } } -/** - * @template-covariant TValue of array|object - * - * @template-implements Iterator - * @template-implements CursorInterface - */ -final class Cursor implements CursorInterface, Iterator +namespace MongoDB\Driver { - /** - * @return TValue - */ - public function current() {} + use Iterator; + use Traversable; /** - * @return void + * @template-covariant TKey + * @template-covariant TValue + * + * @template-extends Traversable */ - public function next() {} + interface CursorInterface extends Traversable + { + /** + * @return array + */ + public function toArray(); + } /** - * @return int + * @template-covariant TValue of array|object + * + * @template-implements Iterator + * @template-implements CursorInterface */ - public function key() {} + final class Cursor implements CursorInterface, Iterator + { + /** + * @return TValue + */ + public function current() + { + } - /** - * @return bool - */ - public function valid() {} + /** + * @return void + */ + public function next() + { + } - /** - * @return void - */ - public function rewind() {} + /** + * @return int + */ + public function key() + { + } - /** - * @return array - */ - public function toArray() {} + /** + * @return bool + */ + public function valid() + { + } + + /** + * @return void + */ + public function rewind() + { + } + + /** + * @return array + */ + public function toArray() + { + } + } } diff --git a/vendor/vimeo/psalm/stubs/extensions/pdo.phpstub b/vendor/vimeo/psalm/stubs/extensions/pdo.phpstub index 039b565e..aec49654 100644 --- a/vendor/vimeo/psalm/stubs/extensions/pdo.phpstub +++ b/vendor/vimeo/psalm/stubs/extensions/pdo.phpstub @@ -150,6 +150,16 @@ class PDOStatement implements Traversable * @return false|T */ public function fetchObject($class = \stdclass::class, array $ctorArgs = array()) {} + + /** + * @psalm-taint-sink sql $value + */ + public function bindValue(string|int $param, mixed $value, int $type = PDO::PARAM_STR): bool {} + + /** + * @psalm-taint-sink sql $var + */ + public function bindParam(string|int $param, mixed &$var, int $type = PDO::PARAM_STR, int $maxLength = 0, mixed $driverOptions = null): bool {} } class PDOException extends RuntimeException { diff --git a/vendor/vimeo/psalm/stubs/phpparser.phpstub b/vendor/vimeo/psalm/stubs/phpparser.phpstub index 856cd2fe..18fd86b3 100644 --- a/vendor/vimeo/psalm/stubs/phpparser.phpstub +++ b/vendor/vimeo/psalm/stubs/phpparser.phpstub @@ -20,3 +20,21 @@ abstract class CallLike extends Expr { */ public function getArgs(): array {} } + + +namespace PhpParser\Node; + +use PhpParser\NodeAbstract; + +class Name extends NodeAbstract { + /** + * @param string|string[]|self $name + * @param array $attributes + */ + public function __construct($name, array $attributes = []) {} + + /** + * @return non-empty-string + */ + public function toString(): string {} +}