diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__basic.php.inc b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__basic.php.inc new file mode 100644 index 00000000000..fdbbcfe3b65 --- /dev/null +++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__basic.php.inc @@ -0,0 +1,35 @@ +x = $x; + } +} + +?> +----- + diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__default_value_in_param.php.inc b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__default_value_in_param.php.inc new file mode 100644 index 00000000000..70b2aa11eb1 --- /dev/null +++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__default_value_in_param.php.inc @@ -0,0 +1,35 @@ +x = $x; + } +} + +?> +----- + diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__non_nullable_param_with_null_default.php.inc b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__non_nullable_param_with_null_default.php.inc new file mode 100644 index 00000000000..ae084310e99 --- /dev/null +++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__non_nullable_param_with_null_default.php.inc @@ -0,0 +1,35 @@ +x = $x; + } +} + +?> +----- + diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__non_nullable_param_with_null_default_and_non_nullable_property.php.inc b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__non_nullable_param_with_null_default_and_non_nullable_property.php.inc new file mode 100644 index 00000000000..a028195641d --- /dev/null +++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__non_nullable_param_with_null_default_and_non_nullable_property.php.inc @@ -0,0 +1,35 @@ +x = $x; + } +} + +?> +----- + diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__nullable_param.php.inc b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__nullable_param.php.inc new file mode 100644 index 00000000000..29128df2c5c --- /dev/null +++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__nullable_param.php.inc @@ -0,0 +1,35 @@ +x = $x; + } +} + +?> +----- + diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__nullable_param_and_default_value.php.inc b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__nullable_param_and_default_value.php.inc new file mode 100644 index 00000000000..40f2f4c5fbc --- /dev/null +++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__nullable_param_and_default_value.php.inc @@ -0,0 +1,35 @@ +x = $x; + } +} + +?> +----- + diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__nullable_param_and_non_nullable_property.php.inc b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__nullable_param_and_non_nullable_property.php.inc new file mode 100644 index 00000000000..f42207f5e34 --- /dev/null +++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__nullable_param_and_non_nullable_property.php.inc @@ -0,0 +1,35 @@ +x = $x; + } +} + +?> +----- + diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__union_with_null_in_param.php.inc b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__union_with_null_in_param.php.inc new file mode 100644 index 00000000000..bdfa4a9cc2e --- /dev/null +++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__union_with_null_in_param.php.inc @@ -0,0 +1,35 @@ +x = $x; + } +} + +?> +----- + diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__union_with_null_in_param_and_default_value.php.inc b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__union_with_null_in_param_and_default_value.php.inc new file mode 100644 index 00000000000..66090020cb8 --- /dev/null +++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__union_with_null_in_param_and_default_value.php.inc @@ -0,0 +1,35 @@ +x = $x; + } +} + +?> +----- + diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__union_with_null_in_param_and_non_nullable_property.php.inc b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__union_with_null_in_param_and_non_nullable_property.php.inc new file mode 100644 index 00000000000..49ee90ea0dc --- /dev/null +++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/with_interface_and_its_implementation__union_with_null_in_param_and_non_nullable_property.php.inc @@ -0,0 +1,35 @@ +x = $x; + } +} + +?> +----- + diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Source/SomeInterface.php b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Source/SomeInterface.php new file mode 100644 index 00000000000..036a459cfef --- /dev/null +++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Source/SomeInterface.php @@ -0,0 +1,5 @@ +type instanceof Node) { + if ($this->shouldUsePropertyTypeForPromotedParam($property, $param)) { $param->type = $property->type; return; } - if (! $param->default instanceof Expr) { + if (! $param->type instanceof Node) { return; } - if (! $param->type instanceof Node) { + $paramType = $this->getType($param->type); + + if ($this->shouldRemoveNullFromForPromotedParamType($property, $param)) { + $paramType = TypeCombinator::removeNull($paramType); + $param->type = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($paramType, TypeKind::PARAM); + } + + if (! $param->default instanceof Expr) { return; } $defaultType = $this->getType($param->default); - $paramType = $this->getType($param->type); if ($this->typeComparator->isSubtype($defaultType, $paramType)) { return; @@ -376,4 +386,46 @@ private function shouldSkipPropertyOrParam(Property $property, Param $param): bo && $property->hooks !== [] && ! $this->nodeComparator->areNodesEqual($property->type, $param->type); } + + private function shouldRemoveNullFromForPromotedParamType(Property $property, Param $param): bool + { + if ($property->type === null || $param->type === null) { + return false; + } + + if ($param->default !== null && $this->valueResolver->isNull($param->default)) { + return false; + } + + $propertyType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($property->type); + $propertyTypeWithoutNull = TypeCombinator::removeNull($propertyType); + + if (! $this->typeComparator->areTypesEqual($propertyTypeWithoutNull, $propertyType)) { + return false; + } + + $paramType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($param->type); + $paramTypeWithoutNull = TypeCombinator::removeNull($paramType); + + return ! $this->typeComparator->areTypesEqual($paramTypeWithoutNull, $paramType); + } + + private function shouldUsePropertyTypeForPromotedParam(Property $property, Param $param): bool + { + if ($property->type === null) { + return false; + } + + if ($param->type === null) { + return true; + } + + $propertyType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($property->type); + $propertyTypeWithoutNull = TypeCombinator::removeNull($propertyType); + + $paramType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($param->type); + $paramTypeWithoutNull = TypeCombinator::removeNull($paramType); + + return $this->typeComparator->areTypesEqual($propertyTypeWithoutNull, $paramTypeWithoutNull); + } }