diff --git a/composer.json b/composer.json index 989352f7..aaae80ef 100644 --- a/composer.json +++ b/composer.json @@ -6,6 +6,7 @@ "ext-json": "*", "azjezz/psl": "^2.3.1", "composer/composer": "^2.5.1", + "nikic/php-parser": "^4.15.3", "nikolaposa/version": "^4.1.0", "ocramius/package-versions": "^2.7.0", "roave/better-reflection": "^6.5.0", diff --git a/composer.lock b/composer.lock index 58837adb..79732ee0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8b89828b37844c22b230ad947fdbf10c", + "content-hash": "3e7bc55a493461b07c54b86cef013320", "packages": [ { "name": "azjezz/psl", @@ -896,16 +896,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.15.2", + "version": "v4.15.3", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc" + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc", - "reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", "shasum": "" }, "require": { @@ -946,9 +946,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" }, - "time": "2022-11-12T15:38:23+00:00" + "time": "2023-01-16T22:05:37+00:00" }, { "name": "nikolaposa/version", @@ -4792,6 +4792,7 @@ "apereo/phpcas": "<1.6", "api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6", "appwrite/server-ce": "<0.11.1|>=0.12,<0.12.2", + "arc/web": "<3", "area17/twill": "<1.2.5|>=2,<2.5.3", "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", "awesome-support/awesome-support": "<=6.0.7", @@ -4802,6 +4803,7 @@ "barrelstrength/sprout-base-email": "<1.2.7", "barrelstrength/sprout-forms": "<3.9", "barryvdh/laravel-translation-manager": "<0.6.2", + "barzahlen/barzahlen-php": "<2.0.1", "baserproject/basercms": "<4.7.2", "billz/raspap-webgui": "<=2.6.6", "bk2k/bootstrap-package": ">=7.1,<7.1.2|>=8,<8.0.8|>=9,<9.0.4|>=9.1,<9.1.3|>=10,<10.0.10|>=11,<11.0.3", @@ -4817,7 +4819,8 @@ "bugsnag/bugsnag-laravel": ">=2,<2.0.2", "bytefury/crater": "<6.0.2", "cachethq/cachet": "<2.5.1", - "cakephp/cakephp": "<3.10.3|>=4,<4.0.6", + "cakephp/cakephp": "<3.10.3|>=4,<4.0.10|>=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10|= 1.3.7|>=4.1,<4.1.4", + "cakephp/database": ">=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10", "cardgate/magento2": "<2.0.33", "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", "cartalyst/sentry": "<=2.1.6", @@ -4845,6 +4848,7 @@ "darylldoyle/safe-svg": "<1.9.10", "datadog/dd-trace": ">=0.30,<0.30.2", "david-garcia/phpwhois": "<=4.3.1", + "dbrisinajumi/d2files": "<1", "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1", "directmailteam/direct-mail": "<5.2.4", "doctrine/annotations": ">=1,<1.2.7", @@ -4895,7 +4899,8 @@ "fenom/fenom": "<=2.12.1", "filegator/filegator": "<7.8", "firebase/php-jwt": "<2", - "flarum/core": ">=1,<=1.0.1|>=1.5,<1.6.2", + "flarum/core": "<1.6.3", + "flarum/mentions": "<1.6.3", "flarum/sticky": ">=0.1-beta.14,<=0.1-beta.15", "flarum/tags": "<=0.1-beta.13", "fluidtypo3/vhs": "<5.1.1", @@ -4910,7 +4915,7 @@ "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", "froala/wysiwyg-editor": "<3.2.7", - "froxlor/froxlor": "<0.10.39", + "froxlor/froxlor": "<2.0.8", "fuel/core": "<1.8.1", "gaoming13/wechat-php-sdk": "<=1.10.2", "genix/cms": "<=1.1.11", @@ -4924,11 +4929,13 @@ "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", "gree/jose": "<=2.2", "gregwar/rst": "<1.0.3", - "grumpydictator/firefly-iii": "<5.6.5", + "grumpydictator/firefly-iii": "<5.8", "guzzlehttp/guzzle": "<6.5.8|>=7,<7.4.5", "guzzlehttp/psr7": "<1.8.4|>=2,<2.1.1", + "harvesthq/chosen": "<1.8.7", "helloxz/imgurl": "= 2.31|<=2.31", "hillelcoren/invoice-ninja": "<5.3.35", + "himiklab/yii2-jqgrid-widget": "<1.0.8", "hjue/justwriting": "<=1", "hov/jobfair": "<1.0.13|>=2,<2.0.2", "hyn/multi-tenant": ">=5.6,<5.7.2", @@ -4946,6 +4953,7 @@ "impresscms/impresscms": "<=1.4.3", "in2code/femanager": "<5.5.2|>=6,<6.3.3|>=7,<7.0.1", "in2code/lux": "<17.6.1|>=18,<24.0.2", + "innologi/typo3-appointments": "<2.0.6", "intelliants/subrion": "<=4.2.1", "islandora/islandora": ">=2,<2.4.1", "ivankristianto/phpwhois": "<=4.3", @@ -4961,6 +4969,7 @@ "jsdecena/laracom": "<2.0.9", "jsmitty12/phpwhois": "<5.1", "kazist/phpwhois": "<=4.2.6", + "kelvinmo/simplexrd": "<3.1.1", "kevinpapst/kimai2": "<1.16.7", "kitodo/presentation": "<3.1.2", "klaviyo/magento2-extension": ">=1,<3", @@ -4980,6 +4989,7 @@ "league/flysystem": "<1.1.4|>=2,<2.1.1", "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", "librenms/librenms": "<22.10", + "liftkit/database": "<2.13.2", "limesurvey/limesurvey": "<3.27.19", "livehelperchat/livehelperchat": "<=3.91", "livewire/livewire": ">2.2.4,<2.2.6", @@ -4998,6 +5008,7 @@ "melisplatform/melis-cms": "<5.0.1", "melisplatform/melis-front": "<5.0.1", "mezzio/mezzio-swoole": "<3.7|>=4,<4.3", + "mgallegos/laravel-jqgrid": "<=1.3", "microweber/microweber": "<=1.3.1", "miniorange/miniorange-saml": "<1.4.3", "mittwald/typo3_forum": "<1.2.1", @@ -5032,7 +5043,7 @@ "open-web-analytics/open-web-analytics": "<1.7.4", "opencart/opencart": "<=3.0.3.7", "openid/php-openid": "<2.3", - "openmage/magento-lts": "<19.4.15|>=20,<20.0.13", + "openmage/magento-lts": "<19.4.22|>=20,<20.0.19", "orchid/platform": ">=9,<9.4.4", "oro/commerce": ">=4.1,<5.0.6", "oro/crm": ">=1.7,<1.7.4|>=3.1,<4.1.17|>=4.2,<4.2.7", @@ -5049,6 +5060,7 @@ "pegasus/google-for-jobs": "<1.5.1|>=2,<2.1.1", "personnummer/personnummer": "<3.0.2", "phanan/koel": "<5.1.4", + "php-mod/curl": "<2.3.2", "phpfastcache/phpfastcache": "<6.1.5|>=7,<7.1.2|>=8,<8.0.7", "phpmailer/phpmailer": "<6.5", "phpmussel/phpmussel": ">=1,<1.6", @@ -5061,11 +5073,11 @@ "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5,<5.6.3", "phpwhois/phpwhois": "<=4.2.5", "phpxmlrpc/extras": "<0.6.1", - "phpxmlrpc/phpxmlrpc": "<4.9", + "phpxmlrpc/phpxmlrpc": "<4.9.2", "pimcore/data-hub": "<1.2.4", - "pimcore/pimcore": "<10.5.9", + "pimcore/pimcore": "<10.5.14", "pocketmine/bedrock-protocol": "<8.0.2", - "pocketmine/pocketmine-mp": "<4.7.2|>= 4.0.0-BETA5, < 4.4.2", + "pocketmine/pocketmine-mp": "<4.12.5|>= 4.0.0-BETA5, < 4.4.2", "pressbooks/pressbooks": "<5.18", "prestashop/autoupgrade": ">=4,<4.10.1", "prestashop/blockwishlist": ">=2,<2.1.1", @@ -5100,8 +5112,8 @@ "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", "sensiolabs/connect": "<4.2.3", "serluck/phpwhois": "<=4.2.6", - "shopware/core": "<=6.4.9", - "shopware/platform": "<=6.4.9", + "shopware/core": "<=6.4.18", + "shopware/platform": "<=6.4.18", "shopware/production": "<=6.3.5.2", "shopware/shopware": "<=5.7.14", "shopware/storefront": "<=6.4.8.1", @@ -5126,10 +5138,12 @@ "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", "simplesamlphp/simplesamlphp": "<1.18.6", "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", + "simplesamlphp/simplesamlphp-module-openid": "<1", + "simplesamlphp/simplesamlphp-module-openidprovider": "<0.9", "simplito/elliptic-php": "<1.0.6", "slim/slim": "<2.6", "smarty/smarty": "<3.1.47|>=4,<4.2.1", - "snipe/snipe-it": "<6.0.11|>= 6.0.0-RC-1, <= 6.0.0-RC-5", + "snipe/snipe-it": "<=6.0.14|>= 6.0.0-RC-1, <= 6.0.0-RC-5", "socalnick/scn-social-auth": "<1.15.2", "socialiteproviders/steam": "<1.1", "spatie/browsershot": "<3.57.4", @@ -5141,7 +5155,9 @@ "stormpath/sdk": ">=0,<9.9.99", "studio-42/elfinder": "<2.1.59", "subrion/cms": "<=4.2.1", + "sukohi/surpass": "<1", "sulu/sulu": "= 2.4.0-RC1|<1.6.44|>=2,<2.2.18|>=2.3,<2.3.8", + "sumocoders/framework-user-bundle": "<1.4", "swiftmailer/swiftmailer": ">=4,<5.4.5", "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", @@ -5151,8 +5167,9 @@ "sylius/sylius": "<1.9.10|>=1.10,<1.10.11|>=1.11,<1.11.2", "symbiote/silverstripe-multivaluefield": ">=3,<3.0.99", "symbiote/silverstripe-queuedjobs": ">=3,<3.0.2|>=3.1,<3.1.4|>=4,<4.0.7|>=4.1,<4.1.2|>=4.2,<4.2.4|>=4.3,<4.3.3|>=4.4,<4.4.3|>=4.5,<4.5.1|>=4.6,<4.6.4", + "symbiote/silverstripe-seed": "<6.0.3", "symbiote/silverstripe-versionedfiles": "<=2.0.3", - "symfont/process": ">=0,<4", + "symfont/process": ">=0", "symfony/cache": ">=3.1,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8", "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/error-handler": ">=4.4,<4.4.4|>=5,<5.0.4", @@ -5190,15 +5207,16 @@ "thelia/thelia": ">=2.1-beta.1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", "thinkcmf/thinkcmf": "<=5.1.7", - "thorsten/phpmyfaq": "<3.1.9", + "thorsten/phpmyfaq": "<3.1.10", "tinymce/tinymce": "<5.10.7|>=6,<6.3.1", "titon/framework": ">=0,<9.9.99", "tobiasbg/tablepress": "<= 2.0-RC1", - "topthink/framework": "<=6.0.13", + "topthink/framework": "<6.0.14", "topthink/think": "<=6.0.9", "topthink/thinkphp": "<=3.2.3", "tribalsystems/zenario": "<=9.3.57595", "truckersmp/phpwhois": "<=4.3.1", + "ttskch/pagination-service-provider": "<1", "twig/twig": "<1.44.7|>=2,<2.15.3|>=3,<3.4.3", "typo3/cms": "<2.0.5|>=3,<3.0.3|>=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.29|>=10,<10.4.33|>=11,<11.5.20|>=12,<12.1.1", "typo3/cms-backend": ">=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", @@ -5216,11 +5234,13 @@ "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", "vanilla/safecurl": "<0.9.2", "verot/class.upload.php": "<=1.0.3|>=2,<=2.0.4", + "vova07/yii2-fileapi-widget": "<0.1.9", "vrana/adminer": "<4.8.1", "wallabag/tcpdf": "<6.2.22", "wanglelecc/laracms": "<=1.0.3", "web-auth/webauthn-framework": ">=3.3,<3.3.4", "webcoast/deferred-image-processing": "<1.0.2", + "webpa/webpa": "<3.1.2", "wikimedia/parsoid": "<0.12.2", "willdurand/js-translation-bundle": "<2.1.1", "wintercms/winter": "<1.0.475|>=1.1,<1.1.10|>=1.2,<1.2.1", @@ -5229,6 +5249,7 @@ "wp-graphql/wp-graphql": "<0.3.5", "wpanel/wpanel4-cms": "<=4.3.1", "wwbn/avideo": "<=11.6", + "xataface/xataface": "<3", "yeswiki/yeswiki": "<4.1", "yetiforce/yetiforce-crm": "<=6.4", "yidashi/yii2cmf": "<=2", diff --git a/src/DetectChanges/BCBreak/FunctionBased/ParameterDefaultValueChanged.php b/src/DetectChanges/BCBreak/FunctionBased/ParameterDefaultValueChanged.php index 4635b12e..e559e664 100644 --- a/src/DetectChanges/BCBreak/FunctionBased/ParameterDefaultValueChanged.php +++ b/src/DetectChanges/BCBreak/FunctionBased/ParameterDefaultValueChanged.php @@ -4,11 +4,15 @@ namespace Roave\BackwardCompatibility\DetectChanges\BCBreak\FunctionBased; +use PhpParser\Node\Expr; +use PhpParser\PrettyPrinter\Standard; +use PhpParser\PrettyPrinterAbstract; use Psl\Dict; use Psl\Str; use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\Changes; use Roave\BackwardCompatibility\Formatter\FunctionName; +use Roave\BetterReflection\NodeCompiler\Exception\UnableToCompileNode; use Roave\BetterReflection\Reflection\ReflectionFunction; use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflection\ReflectionParameter; @@ -22,10 +26,12 @@ final class ParameterDefaultValueChanged implements FunctionBased { private FunctionName $formatFunction; + private PrettyPrinterAbstract $prettyPrinter; public function __construct() { $this->formatFunction = new FunctionName(); + $this->prettyPrinter = new Standard(); } public function __invoke( @@ -38,8 +44,27 @@ public function __invoke( $changes = Changes::empty(); foreach (Dict\intersect_by_key($fromParametersWithDefaults, $toParametersWithDefaults) as $parameterIndex => $parameter) { - $defaultValueFrom = $parameter->getDefaultValue(); - $defaultValueTo = $toParametersWithDefaults[$parameterIndex]->getDefaultValue(); + // add default value to null to help psalm + $defaultValueFrom = null; + $defaultValueTo = null; + + try { + $defaultValueFrom = $parameter->getDefaultValue(); + $defaultValueTo = $toParametersWithDefaults[$parameterIndex]->getDefaultValue(); + } catch (UnableToCompileNode $unableToCompileNode) { + $parameterDefaultExpression = $parameter->getDefaultValueExpression(); + $toParameterDefaultExpression = $toParametersWithDefaults[$parameterIndex]->getDefaultValueExpression(); + + if ( + $toParameterDefaultExpression instanceof Expr && + $parameterDefaultExpression instanceof Expr && + $this->prettyPrinter->prettyPrintExpr($toParameterDefaultExpression) === $this->prettyPrinter->prettyPrintExpr($parameterDefaultExpression) + ) { + continue; + } + + throw $unableToCompileNode; + } if ($defaultValueFrom === $defaultValueTo) { continue; diff --git a/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterDefaultValueChangedTest.php b/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterDefaultValueChangedTest.php index 0e332395..3740fb2a 100644 --- a/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterDefaultValueChangedTest.php +++ b/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterDefaultValueChangedTest.php @@ -12,6 +12,8 @@ use Roave\BetterReflection\Reflection\ReflectionFunction; use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflector\DefaultReflector; +use Roave\BetterReflection\SourceLocator\Type\AggregateSourceLocator; +use Roave\BetterReflection\SourceLocator\Type\PhpInternalSourceLocator; use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator; use function array_combine; @@ -53,7 +55,8 @@ public function testDiffs( */ public function functionsToBeTested(): array { - $astLocator = (new BetterReflection())->astLocator(); + $astLocator = (new BetterReflection())->astLocator(); + $sourceStubber = (new BetterReflection())->sourceStubber(); $fromLocator = new StringSourceLocator( <<<'PHP' @@ -71,7 +74,14 @@ function positionOfOptionalParameterChanged($a = 2, $b, $c = 1) {} class C { static function changed1($a = 1) {} function changed2($a = 1) {} + function notChangedNewInitializer($a = new stdClass()) {} + function notChangedNewEnum($a = D::A) {} + function changedNewEnumAndNewInitializer() {} + function changedRemovedNewEnumAndNewInitializer($a = D::A, $b = new stdClass()) {} } + enum D: string { + case A = 'A'; + } } PHP , @@ -94,6 +104,13 @@ function positionOfOptionalParameterChanged($a, $b = 2, $c = 1) {} class C { static function changed1($a = 2) {} function changed2($a = 2) {} + function notChangedNewInitializer($a = new stdClass()) {} + function notChangedNewEnum($a = D::A) {} + function changedNewEnumAndNewInitializer($a = D::A, $b = new stdClass()) {} + function changedRemovedNewEnumAndNewInitializer() {} + } + enum D: string { + case A = 'A'; } } PHP @@ -101,8 +118,14 @@ function changed2($a = 2) {} $astLocator, ); - $fromReflector = new DefaultReflector($fromLocator); - $toReflector = new DefaultReflector($toLocator); + $fromReflector = new DefaultReflector(new AggregateSourceLocator([ + $fromLocator, + new PhpInternalSourceLocator($astLocator, $sourceStubber), + ])); + $toReflector = new DefaultReflector(new AggregateSourceLocator([ + $toLocator, + new PhpInternalSourceLocator($astLocator, $sourceStubber), + ])); $functions = [ 'changed' => ['[BC] CHANGED: Default parameter value for parameter $a of changed() changed from 1 to 2'], @@ -142,6 +165,26 @@ function changed2($a = 2) {} self::getMethod($toReflector->reflectClass('C'), 'changed2'), ['[BC] CHANGED: Default parameter value for parameter $a of C#changed2() changed from 1 to 2'], ], + 'C#notChangedNewInitializer' => [ + self::getMethod($fromReflector->reflectClass('C'), 'notChangedNewInitializer'), + self::getMethod($toReflector->reflectClass('C'), 'notChangedNewInitializer'), + [], + ], + 'C#notChangedNewEnum' => [ + self::getMethod($fromReflector->reflectClass('C'), 'notChangedNewEnum'), + self::getMethod($toReflector->reflectClass('C'), 'notChangedNewEnum'), + [], + ], + 'C#changedNewEnumAndNewInitializer' => [ + self::getMethod($fromReflector->reflectClass('C'), 'changedNewEnumAndNewInitializer'), + self::getMethod($toReflector->reflectClass('C'), 'changedNewEnumAndNewInitializer'), + [], + ], + 'C#changedRemovedNewEnumAndNewInitializer' => [ + self::getMethod($fromReflector->reflectClass('C'), 'changedRemovedNewEnumAndNewInitializer'), + self::getMethod($toReflector->reflectClass('C'), 'changedRemovedNewEnumAndNewInitializer'), + [], + ], ], ); }