From 5d5dc83a56528ad45bf796dea58aa087a94d8b32 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 3 Aug 2023 21:32:15 +0700 Subject: [PATCH 1/4] [TypeDeclaration] Add nullable param from null compare on StrictStringParamConcatRector --- .../nullable_param_from_null_compare.php.inc | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 rules-tests/TypeDeclaration/Rector/ClassMethod/StrictStringParamConcatRector/Fixture/nullable_param_from_null_compare.php.inc diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/StrictStringParamConcatRector/Fixture/nullable_param_from_null_compare.php.inc b/rules-tests/TypeDeclaration/Rector/ClassMethod/StrictStringParamConcatRector/Fixture/nullable_param_from_null_compare.php.inc new file mode 100644 index 00000000000..e625cb0ea0c --- /dev/null +++ b/rules-tests/TypeDeclaration/Rector/ClassMethod/StrictStringParamConcatRector/Fixture/nullable_param_from_null_compare.php.inc @@ -0,0 +1,35 @@ + +----- + From 4eda5291305861ca777d47956a1eadee6db1b43d Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 3 Aug 2023 21:59:57 +0700 Subject: [PATCH 2/4] nullable --- .../StrictStringParamConcatRector.php | 70 +++++++++++++------ 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/rules/TypeDeclaration/Rector/ClassMethod/StrictStringParamConcatRector.php b/rules/TypeDeclaration/Rector/ClassMethod/StrictStringParamConcatRector.php index 7d21214ae85..cd3c56c4068 100644 --- a/rules/TypeDeclaration/Rector/ClassMethod/StrictStringParamConcatRector.php +++ b/rules/TypeDeclaration/Rector/ClassMethod/StrictStringParamConcatRector.php @@ -11,11 +11,15 @@ use PhpParser\Node\Expr\Variable; use PhpParser\Node\FunctionLike; use PhpParser\Node\Identifier; +use PhpParser\Node\NullableType; use PhpParser\Node\Param; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Function_; use PhpParser\NodeTraverser; +use PHPStan\Type\MixedType; +use PHPStan\Type\Type; +use PHPStan\Type\TypeCombinator; use Rector\Core\Rector\AbstractRector; use Rector\VendorLocker\ParentClassMethodTypeOverrideGuard; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; @@ -82,11 +86,21 @@ public function refactor(Node $node): ?Node continue; } - if (! $this->isParamConcatted($param, $node)) { + $variableConcattedFromParam = $this->resolveVariableConcattedFromParam($param, $node); + if (! $variableConcattedFromParam instanceof Variable) { continue; } - $param->type = new Identifier('string'); + $nativeType = $this->nodeTypeResolver->getNativeType($variableConcattedFromParam); + + if ($nativeType instanceof MixedType && $nativeType->getSubtractedType() instanceof Type && TypeCombinator::containsNull( + $nativeType->getSubtractedType() + )) { + $param->type = new NullableType(new Identifier('string')); + } else { + $param->type = new Identifier('string'); + } + $hasChanged = true; } @@ -97,40 +111,46 @@ public function refactor(Node $node): ?Node return null; } - private function isParamConcatted(Param $param, ClassMethod|Function_|Closure $functionLike): bool - { + private function resolveVariableConcattedFromParam( + Param $param, + ClassMethod|Function_|Closure $functionLike + ): ?Variable { if ($functionLike->stmts === null) { - return false; + return null; } if ($param->default instanceof Expr && ! $this->getType($param->default)->isString()->yes()) { - return false; + return null; } $paramName = $this->getName($param); - $isParamConcatted = false; + $variableConcatted = null; $this->traverseNodesWithCallable($functionLike->stmts, function (Node $node) use ( $paramName, - &$isParamConcatted, + &$variableConcatted, ): int|null { // skip nested class and function nodes if ($node instanceof FunctionLike || $node instanceof Class_) { return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN; } - if ($this->isAssignConcat($node, $paramName)) { - $isParamConcatted = true; + $variableAssignConcat = $this->resolveAssignConcatVariable($node, $paramName); + if ($variableAssignConcat instanceof Variable) { + $variableConcatted = $node; + return NodeTraverser::STOP_TRAVERSAL; } - if ($this->isBinaryConcat($node, $paramName)) { - $isParamConcatted = true; + $variableBinaryConcat = $this->resolveBinaryConcatVariable($node, $paramName); + if ($variableBinaryConcat instanceof Variable) { + $variableConcatted = $variableBinaryConcat; + return NodeTraverser::STOP_TRAVERSAL; } return null; }); - return $isParamConcatted; + return $variableConcatted; } private function isVariableWithSameParam(Expr $expr, string $paramName): bool @@ -142,29 +162,37 @@ private function isVariableWithSameParam(Expr $expr, string $paramName): bool return $this->isName($expr, $paramName); } - private function isAssignConcat(Node $node, string $paramName): bool + private function resolveAssignConcatVariable(Node $node, string $paramName): ?Variable { if (! $node instanceof Concat) { - return false; + return null; } if ($this->isVariableWithSameParam($node->var, $paramName)) { - return true; + return $node->var; + } + + if ($this->isVariableWithSameParam($node->expr, $paramName)) { + return $node->expr; } - return $this->isVariableWithSameParam($node->expr, $paramName); + return null; } - private function isBinaryConcat(Node $node, string $paramName): bool + private function resolveBinaryConcatVariable(Node $node, string $paramName): ?Variable { if (! $node instanceof Expr\BinaryOp\Concat) { - return false; + return null; } if ($this->isVariableWithSameParam($node->left, $paramName)) { - return true; + return $node->left; + } + + if ($this->isVariableWithSameParam($node->right, $paramName)) { + return $node->right; } - return $this->isVariableWithSameParam($node->right, $paramName); + return null; } } From dfad1b54013065ace3028263def2ff0acb3a8ef4 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 3 Aug 2023 22:00:42 +0700 Subject: [PATCH 3/4] nullable --- .../Rector/ClassMethod/StrictStringParamConcatRector.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rules/TypeDeclaration/Rector/ClassMethod/StrictStringParamConcatRector.php b/rules/TypeDeclaration/Rector/ClassMethod/StrictStringParamConcatRector.php index cd3c56c4068..0afe8b0c0dc 100644 --- a/rules/TypeDeclaration/Rector/ClassMethod/StrictStringParamConcatRector.php +++ b/rules/TypeDeclaration/Rector/ClassMethod/StrictStringParamConcatRector.php @@ -162,7 +162,7 @@ private function isVariableWithSameParam(Expr $expr, string $paramName): bool return $this->isName($expr, $paramName); } - private function resolveAssignConcatVariable(Node $node, string $paramName): ?Variable + private function resolveAssignConcatVariable(Node $node, string $paramName): ?Expr { if (! $node instanceof Concat) { return null; @@ -179,7 +179,7 @@ private function resolveAssignConcatVariable(Node $node, string $paramName): ?Va return null; } - private function resolveBinaryConcatVariable(Node $node, string $paramName): ?Variable + private function resolveBinaryConcatVariable(Node $node, string $paramName): ?Expr { if (! $node instanceof Expr\BinaryOp\Concat) { return null; From 0436336c354257159b9a2daad4dde350e7b6b007 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 3 Aug 2023 15:02:57 +0000 Subject: [PATCH 4/4] [ci-review] Rector Rectify --- .../Rector/ClassMethod/StrictStringParamConcatRector.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rules/TypeDeclaration/Rector/ClassMethod/StrictStringParamConcatRector.php b/rules/TypeDeclaration/Rector/ClassMethod/StrictStringParamConcatRector.php index 0afe8b0c0dc..e8ff5d77f2b 100644 --- a/rules/TypeDeclaration/Rector/ClassMethod/StrictStringParamConcatRector.php +++ b/rules/TypeDeclaration/Rector/ClassMethod/StrictStringParamConcatRector.php @@ -135,8 +135,8 @@ private function resolveVariableConcattedFromParam( return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN; } - $variableAssignConcat = $this->resolveAssignConcatVariable($node, $paramName); - if ($variableAssignConcat instanceof Variable) { + $expr = $this->resolveAssignConcatVariable($node, $paramName); + if ($expr instanceof Variable) { $variableConcatted = $node; return NodeTraverser::STOP_TRAVERSAL; }