From 4f2d2d12ddfc2cebe4511c7de381bfb861afdc4a Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 14 Jul 2021 14:13:55 +0700 Subject: [PATCH] [DeadCode] Skip RemoveUnusedNonEmptyArrayBeforeForeachRector on array param has default null (#433) Co-authored-by: GitHub Action --- .../Fixture/skip_param_default_null.php.inc | 13 ++++++++++ .../DateTimeToDateTimeInterfaceRector.php | 8 ++++--- .../UselessIfCondBeforeForeachDetector.php | 11 +++++---- ...DowngradeNullableTypeDeclarationRector.php | 20 ++++------------ ...wngradeContravariantArgumentTypeRector.php | 6 +++-- ...ertyAssignToConstructorPromotionRector.php | 14 +++++++---- .../ConstructorPropertyTypeInferer.php | 13 ++++++---- src/NodeAnalyzer/ParamAnalyzer.php | 24 ++++++++++++++++++- 8 files changed, 75 insertions(+), 34 deletions(-) create mode 100644 rules-tests/DeadCode/Rector/If_/RemoveUnusedNonEmptyArrayBeforeForeachRector/Fixture/skip_param_default_null.php.inc diff --git a/rules-tests/DeadCode/Rector/If_/RemoveUnusedNonEmptyArrayBeforeForeachRector/Fixture/skip_param_default_null.php.inc b/rules-tests/DeadCode/Rector/If_/RemoveUnusedNonEmptyArrayBeforeForeachRector/Fixture/skip_param_default_null.php.inc new file mode 100644 index 00000000000..0feede231c1 --- /dev/null +++ b/rules-tests/DeadCode/Rector/If_/RemoveUnusedNonEmptyArrayBeforeForeachRector/Fixture/skip_param_default_null.php.inc @@ -0,0 +1,13 @@ + diff --git a/rules/CodeQuality/Rector/ClassMethod/DateTimeToDateTimeInterfaceRector.php b/rules/CodeQuality/Rector/ClassMethod/DateTimeToDateTimeInterfaceRector.php index 7b3dcd5ee07..23f0ecc4019 100644 --- a/rules/CodeQuality/Rector/ClassMethod/DateTimeToDateTimeInterfaceRector.php +++ b/rules/CodeQuality/Rector/ClassMethod/DateTimeToDateTimeInterfaceRector.php @@ -19,6 +19,7 @@ use PHPStan\Type\UnionType; use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger; use Rector\Core\Exception\ShouldNotHappenException; +use Rector\Core\NodeAnalyzer\ParamAnalyzer; use Rector\Core\Rector\AbstractRector; use Rector\Core\ValueObject\MethodName; use Rector\Core\ValueObject\PhpVersionFeature; @@ -39,7 +40,8 @@ final class DateTimeToDateTimeInterfaceRector extends AbstractRector ]; public function __construct( - private PhpDocTypeChanger $phpDocTypeChanger + private PhpDocTypeChanger $phpDocTypeChanger, + private ParamAnalyzer $paramAnalyzer ) { } @@ -110,7 +112,7 @@ public function refactor(Node $node): ?Node private function refactorParamTypeHint(Param $param): void { $fullyQualified = new FullyQualified('DateTimeInterface'); - if ($param->type instanceof NullableType) { + if ($this->paramAnalyzer->isNullable($param)) { $param->type = new NullableType($fullyQualified); return; } @@ -121,7 +123,7 @@ private function refactorParamTypeHint(Param $param): void private function refactorParamDocBlock(Param $param, ClassMethod $classMethod): void { $types = [new ObjectType('DateTime'), new ObjectType('DateTimeImmutable')]; - if ($param->type instanceof NullableType) { + if ($this->paramAnalyzer->isNullable($param)) { $types[] = new NullType(); } diff --git a/rules/DeadCode/UselessIfCondBeforeForeachDetector.php b/rules/DeadCode/UselessIfCondBeforeForeachDetector.php index d9924a92541..d9e0e8fd237 100644 --- a/rules/DeadCode/UselessIfCondBeforeForeachDetector.php +++ b/rules/DeadCode/UselessIfCondBeforeForeachDetector.php @@ -12,10 +12,10 @@ use PhpParser\Node\Expr\BooleanNot; use PhpParser\Node\Expr\Empty_; use PhpParser\Node\Expr\Variable; -use PhpParser\Node\NullableType; use PhpParser\Node\Param; use PhpParser\Node\Stmt\If_; use PHPStan\Type\ArrayType; +use Rector\Core\NodeAnalyzer\ParamAnalyzer; use Rector\Core\PhpParser\Comparing\NodeComparator; use Rector\Core\PhpParser\Node\BetterNodeFinder; use Rector\NodeTypeResolver\NodeTypeResolver; @@ -25,7 +25,8 @@ final class UselessIfCondBeforeForeachDetector public function __construct( private NodeTypeResolver $nodeTypeResolver, private NodeComparator $nodeComparator, - private BetterNodeFinder $betterNodeFinder + private BetterNodeFinder $betterNodeFinder, + private ParamAnalyzer $paramAnalyzer ) { } @@ -61,8 +62,10 @@ public function isMatchingNotEmpty(If_ $if, Expr $foreachExpr): bool if (! $previousParam instanceof Param) { return true; } - - return ! $previousParam->type instanceof NullableType; + if ($this->paramAnalyzer->isNullable($previousParam)) { + return false; + } + return ! $this->paramAnalyzer->hasDefaultNull($previousParam); } /** diff --git a/rules/DowngradePhp71/Rector/FunctionLike/DowngradeNullableTypeDeclarationRector.php b/rules/DowngradePhp71/Rector/FunctionLike/DowngradeNullableTypeDeclarationRector.php index bff088c7085..e5304785fd4 100644 --- a/rules/DowngradePhp71/Rector/FunctionLike/DowngradeNullableTypeDeclarationRector.php +++ b/rules/DowngradePhp71/Rector/FunctionLike/DowngradeNullableTypeDeclarationRector.php @@ -12,6 +12,7 @@ use PhpParser\Node\Stmt\Function_; use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger; use Rector\Core\Exception\ShouldNotHappenException; +use Rector\Core\NodeAnalyzer\ParamAnalyzer; use Rector\Core\Rector\AbstractRector; use Rector\DowngradePhp71\TypeDeclaration\PhpDocFromTypeDeclarationDecorator; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; @@ -24,7 +25,8 @@ final class DowngradeNullableTypeDeclarationRector extends AbstractRector { public function __construct( private PhpDocTypeChanger $phpDocTypeChanger, - private PhpDocFromTypeDeclarationDecorator $phpDocFromTypeDeclarationDecorator + private PhpDocFromTypeDeclarationDecorator $phpDocFromTypeDeclarationDecorator, + private ParamAnalyzer $paramAnalyzer ) { } @@ -90,23 +92,9 @@ public function refactor(Node $node): ?Node return null; } - private function isNullableParam(Param $param): bool - { - if ($param->variadic) { - return false; - } - - if ($param->type === null) { - return false; - } - - // Check it is the union type - return $param->type instanceof NullableType; - } - private function refactorParamType(Param $param, ClassMethod | Function_ | Closure $functionLike): bool { - if (! $this->isNullableParam($param)) { + if (! $this->paramAnalyzer->isNullable($param)) { return false; } diff --git a/rules/DowngradePhp74/Rector/ClassMethod/DowngradeContravariantArgumentTypeRector.php b/rules/DowngradePhp74/Rector/ClassMethod/DowngradeContravariantArgumentTypeRector.php index d582e90a2f0..74020a34860 100644 --- a/rules/DowngradePhp74/Rector/ClassMethod/DowngradeContravariantArgumentTypeRector.php +++ b/rules/DowngradePhp74/Rector/ClassMethod/DowngradeContravariantArgumentTypeRector.php @@ -14,6 +14,7 @@ use PHPStan\Analyser\Scope; use PHPStan\Reflection\ClassReflection; use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger; +use Rector\Core\NodeAnalyzer\ParamAnalyzer; use Rector\Core\Rector\AbstractRector; use Rector\Core\ValueObject\MethodName; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -31,7 +32,8 @@ final class DowngradeContravariantArgumentTypeRector extends AbstractRector { public function __construct( - private PhpDocTypeChanger $phpDocTypeChanger + private PhpDocTypeChanger $phpDocTypeChanger, + private ParamAnalyzer $paramAnalyzer ) { } @@ -150,7 +152,7 @@ private function getDifferentParamTypeFromAncestorClass(Param $param, FunctionLi /** @var Node $paramType */ $paramType = $param->type; - if ($param->type instanceof NullableType) { + if ($this->paramAnalyzer->isNullable($param)) { /** @var NullableType $nullableType */ $nullableType = $paramType; $paramTypeName = $this->getName($nullableType->type); diff --git a/rules/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector.php b/rules/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector.php index 0f55ff33e1e..77251f80e73 100644 --- a/rules/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector.php +++ b/rules/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector.php @@ -13,6 +13,7 @@ use PhpParser\Node\Stmt\Property; use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode; use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey; +use Rector\Core\NodeAnalyzer\ParamAnalyzer; use Rector\Core\Rector\AbstractRector; use Rector\Core\ValueObject\MethodName; use Rector\Core\ValueObject\PhpVersionFeature; @@ -34,7 +35,8 @@ final class ClassPropertyAssignToConstructorPromotionRector extends AbstractRect public function __construct( private PromotedPropertyCandidateResolver $promotedPropertyCandidateResolver, private VariableRenamer $variableRenamer, - private VarTagRemover $varTagRemover + private VarTagRemover $varTagRemover, + private ParamAnalyzer $paramAnalyzer ) { } @@ -166,9 +168,13 @@ private function shouldSkipParam(Param $param): bool return true; } - $type = $param->type instanceof NullableType - ? $param->type->type - : $param->type; + if ($this->paramAnalyzer->isNullable($param)) { + /** @var NullableType $type */ + $type = $param->type; + $type = $type->type; + } else { + $type = $param->type; + } return $type instanceof Identifier && $this->isName($type, 'callable'); } diff --git a/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/ConstructorPropertyTypeInferer.php b/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/ConstructorPropertyTypeInferer.php index 55bd3853bec..0ef560e2fb9 100644 --- a/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/ConstructorPropertyTypeInferer.php +++ b/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/ConstructorPropertyTypeInferer.php @@ -19,6 +19,7 @@ use PHPStan\Type\MixedType; use PHPStan\Type\NullType; use PHPStan\Type\Type; +use Rector\Core\NodeAnalyzer\ParamAnalyzer; use Rector\Core\NodeManipulator\ClassMethodPropertyFetchManipulator; use Rector\Core\PhpParser\Node\BetterNodeFinder; use Rector\Core\ValueObject\MethodName; @@ -42,7 +43,8 @@ public function __construct( private TypeFactory $typeFactory, private StaticTypeMapper $staticTypeMapper, private NodeTypeResolver $nodeTypeResolver, - private BetterNodeFinder $betterNodeFinder + private BetterNodeFinder $betterNodeFinder, + private ParamAnalyzer $paramAnalyzer ) { } @@ -107,10 +109,13 @@ private function resolveParamTypeToPHPStanType(Param $param): Type return new MixedType(); } - if ($param->type instanceof NullableType) { + if ($this->paramAnalyzer->isNullable($param)) { + /** @var NullableType $type */ + $type = $param->type; + $types = []; $types[] = new NullType(); - $types[] = $this->staticTypeMapper->mapPhpParserNodePHPStanType($param->type->type); + $types[] = $this->staticTypeMapper->mapPhpParserNodePHPStanType($type->type); return $this->typeFactory->createMixedPassedOrUnionType($types); } @@ -152,7 +157,7 @@ function (Node $node) use ($propertyName, &$paramStaticType): ?int { private function isParamNullable(Param $param): bool { - if ($param->type instanceof NullableType) { + if ($this->paramAnalyzer->isNullable($param)) { return true; } diff --git a/src/NodeAnalyzer/ParamAnalyzer.php b/src/NodeAnalyzer/ParamAnalyzer.php index 9aa6bf44721..7b412d7e65b 100644 --- a/src/NodeAnalyzer/ParamAnalyzer.php +++ b/src/NodeAnalyzer/ParamAnalyzer.php @@ -5,17 +5,21 @@ namespace Rector\Core\NodeAnalyzer; use PhpParser\Node; +use PhpParser\Node\Expr\ConstFetch; use PhpParser\Node\Expr\Variable; +use PhpParser\Node\NullableType; use PhpParser\Node\Param; use PhpParser\Node\Stmt\ClassMethod; use Rector\Core\PhpParser\Comparing\NodeComparator; use Rector\Core\PhpParser\Node\BetterNodeFinder; +use Rector\Core\PhpParser\Node\Value\ValueResolver; final class ParamAnalyzer { public function __construct( private BetterNodeFinder $betterNodeFinder, - private NodeComparator $nodeComparator + private NodeComparator $nodeComparator, + private ValueResolver $valueResolver ) { } @@ -45,4 +49,22 @@ public function hasPropertyPromotion(array $params): bool return false; } + + public function isNullable(Param $param): bool + { + if ($param->variadic) { + return false; + } + + if ($param->type === null) { + return false; + } + + return $param->type instanceof NullableType; + } + + public function hasDefaultNull(Param $param): bool + { + return $param->default instanceof ConstFetch && $this->valueResolver->isNull($param->default); + } }