From a638a676b4c23c70ed65e52463a4c193d72d2c7d Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 5 Sep 2022 19:48:03 +0200 Subject: [PATCH] [PHP 7.4] Fix literator separator string/int missmatch in PHPStan type (#2913) * add fixture failing scope * fix printing of raw value and literal separator --- .phpstorm.meta.php | 2 ++ .../NodeTypeResolver/Node/AttributeKey.php | 6 +++++ phpstan.neon | 3 ++- .../{fixture.php.inc => big_floats.php.inc} | 8 ++---- .../Fixture/big_integers.php.inc | 27 +++++++++++++++++++ .../Fixture/skip_low_valuefixture.php.inc | 11 ++++++++ .../AddLiteralSeparatorToNumberRector.php | 6 ++++- .../Printer/BetterStandardPrinter.php | 23 ++++++++++++++-- 8 files changed, 76 insertions(+), 10 deletions(-) rename rules-tests/Php74/Rector/LNumber/AddLiteralSeparatorToNumberRector/Fixture/{fixture.php.inc => big_floats.php.inc} (79%) create mode 100644 rules-tests/Php74/Rector/LNumber/AddLiteralSeparatorToNumberRector/Fixture/big_integers.php.inc create mode 100644 rules-tests/Php74/Rector/LNumber/AddLiteralSeparatorToNumberRector/Fixture/skip_low_valuefixture.php.inc diff --git a/.phpstorm.meta.php b/.phpstorm.meta.php index 89bfac1a231..5fbecf5b972 100644 --- a/.phpstorm.meta.php +++ b/.phpstorm.meta.php @@ -47,6 +47,7 @@ \PhpParser\Node::getAttribute(), 0, \Rector\NodeTypeResolver\Node\AttributeKey::SCOPE, + \Rector\NodeTypeResolver\Node\AttributeKey::REPRINT_RAW_VALUE, \Rector\NodeTypeResolver\Node\AttributeKey::PARENT_NODE, \Rector\NodeTypeResolver\Node\AttributeKey::NEXT_NODE, \Rector\NodeTypeResolver\Node\AttributeKey::PREVIOUS_NODE, @@ -67,6 +68,7 @@ \PhpParser\Node::setAttribute(), 0, \Rector\NodeTypeResolver\Node\AttributeKey::SCOPE, + \Rector\NodeTypeResolver\Node\AttributeKey::REPRINT_RAW_VALUE, \Rector\NodeTypeResolver\Node\AttributeKey::PARENT_NODE, \Rector\NodeTypeResolver\Node\AttributeKey::NEXT_NODE, \Rector\NodeTypeResolver\Node\AttributeKey::PREVIOUS_NODE, diff --git a/packages/NodeTypeResolver/Node/AttributeKey.php b/packages/NodeTypeResolver/Node/AttributeKey.php index 177c3074915..f7568afcf86 100644 --- a/packages/NodeTypeResolver/Node/AttributeKey.php +++ b/packages/NodeTypeResolver/Node/AttributeKey.php @@ -158,4 +158,10 @@ final class AttributeKey * @var string */ public const PHP_ATTRIBUTE_NAME = 'php_attribute_name'; + + /** + * Helper attribute to reprint raw value of int/float/string + * @var string + */ + public const REPRINT_RAW_VALUE = 'reprint_raw_value'; } diff --git a/phpstan.neon b/phpstan.neon index 2fda820b9a7..24641c734b1 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -551,8 +551,9 @@ parameters: message: '#Instead of "DateTime" class/interface use "Nette\\Utils\\DateTime"#' path: src/Application/VersionResolver.php + # complex multiprinter - - message: '#Class cognitive complexity is 55, keep it under 50#' + message: '#Class cognitive complexity is \d+, keep it under 50#' path: src/PhpParser/Printer/BetterStandardPrinter.php #41 # validate class-string input diff --git a/rules-tests/Php74/Rector/LNumber/AddLiteralSeparatorToNumberRector/Fixture/fixture.php.inc b/rules-tests/Php74/Rector/LNumber/AddLiteralSeparatorToNumberRector/Fixture/big_floats.php.inc similarity index 79% rename from rules-tests/Php74/Rector/LNumber/AddLiteralSeparatorToNumberRector/Fixture/fixture.php.inc rename to rules-tests/Php74/Rector/LNumber/AddLiteralSeparatorToNumberRector/Fixture/big_floats.php.inc index fa1e147b74a..9e1262e8532 100644 --- a/rules-tests/Php74/Rector/LNumber/AddLiteralSeparatorToNumberRector/Fixture/fixture.php.inc +++ b/rules-tests/Php74/Rector/LNumber/AddLiteralSeparatorToNumberRector/Fixture/big_floats.php.inc @@ -2,12 +2,10 @@ namespace Rector\Tests\Php74\Rector\LNumber\AddLiteralSeparatorToNumberRector\Fixture; -class Fixture +final class BigFloats { public function run() { - $int = 1000; - $int2 = 1000000; $float = 1000.0; $float2 = 1000000.0; $float3 = 1000500.001; @@ -20,12 +18,10 @@ class Fixture namespace Rector\Tests\Php74\Rector\LNumber\AddLiteralSeparatorToNumberRector\Fixture; -class Fixture +final class BigFloats { public function run() { - $int = 1000; - $int2 = 1_000_000; $float = 1000.0; $float2 = 1_000_000.0; $float3 = 1_000_500.001; diff --git a/rules-tests/Php74/Rector/LNumber/AddLiteralSeparatorToNumberRector/Fixture/big_integers.php.inc b/rules-tests/Php74/Rector/LNumber/AddLiteralSeparatorToNumberRector/Fixture/big_integers.php.inc new file mode 100644 index 00000000000..aae90158e3a --- /dev/null +++ b/rules-tests/Php74/Rector/LNumber/AddLiteralSeparatorToNumberRector/Fixture/big_integers.php.inc @@ -0,0 +1,27 @@ + +----- + diff --git a/rules-tests/Php74/Rector/LNumber/AddLiteralSeparatorToNumberRector/Fixture/skip_low_valuefixture.php.inc b/rules-tests/Php74/Rector/LNumber/AddLiteralSeparatorToNumberRector/Fixture/skip_low_valuefixture.php.inc new file mode 100644 index 00000000000..64b4e99cc5b --- /dev/null +++ b/rules-tests/Php74/Rector/LNumber/AddLiteralSeparatorToNumberRector/Fixture/skip_low_valuefixture.php.inc @@ -0,0 +1,11 @@ +value = $literalSeparatedNumber; + // this cannot be integer directly to $node->value, as PHPStan sees it as error type + // @see https://github.com/rectorphp/rector/issues/7454 + $node->setAttribute(AttributeKey::RAW_VALUE, $literalSeparatedNumber); + $node->setAttribute(AttributeKey::REPRINT_RAW_VALUE, true); + $node->setAttribute(AttributeKey::ORIGINAL_NODE, null); return $node; } diff --git a/src/PhpParser/Printer/BetterStandardPrinter.php b/src/PhpParser/Printer/BetterStandardPrinter.php index ab20d29122b..9c96d0efff9 100644 --- a/src/PhpParser/Printer/BetterStandardPrinter.php +++ b/src/PhpParser/Printer/BetterStandardPrinter.php @@ -18,6 +18,7 @@ use PhpParser\Node\Name\FullyQualified; use PhpParser\Node\Scalar\DNumber; use PhpParser\Node\Scalar\EncapsedStringPart; +use PhpParser\Node\Scalar\LNumber; use PhpParser\Node\Scalar\String_; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; @@ -252,8 +253,8 @@ protected function pSingleQuotedString(string $string): string */ protected function pScalar_DNumber(DNumber $dNumber): string { - if (is_string($dNumber->value)) { - return $dNumber->value; + if ($this->shouldPrintNewRawValue($dNumber)) { + return (string) $dNumber->getAttribute(AttributeKey::RAW_VALUE); } return parent::pScalar_DNumber($dNumber); @@ -469,6 +470,24 @@ protected function pModifiers(int $modifiers): string . (($modifiers & Class_::MODIFIER_READONLY) !== 0 ? 'readonly ' : ''); } + /** + * Invoke re-print even if only raw value was changed. + * That allows PHPStan to use int strict types, while changing the value with literal "_" + */ + protected function pScalar_LNumber(LNumber $lNumber): string|int + { + if ($this->shouldPrintNewRawValue($lNumber)) { + return (string) $lNumber->getAttribute(AttributeKey::RAW_VALUE); + } + + return parent::pScalar_LNumber($lNumber); + } + + private function shouldPrintNewRawValue(LNumber|DNumber $lNumber): bool + { + return $lNumber->getAttribute(AttributeKey::REPRINT_RAW_VALUE) === true; + } + private function resolveContentOnExpr(Expr $expr, string $content): string { $parentNode = $expr->getAttribute(AttributeKey::PARENT_NODE);