diff --git a/build/target-repository/docs/rector_rules_overview.md b/build/target-repository/docs/rector_rules_overview.md
index 9b44b8bb876..a13ae60d05c 100644
--- a/build/target-repository/docs/rector_rules_overview.md
+++ b/build/target-repository/docs/rector_rules_overview.md
@@ -1,4 +1,4 @@
-# 406 Rules Overview
+# 409 Rules Overview
@@ -64,7 +64,7 @@
- [Transform](#transform) (34)
-- [TypeDeclaration](#typedeclaration) (34)
+- [TypeDeclaration](#typedeclaration) (37)
- [Visibility](#visibility) (3)
@@ -5659,23 +5659,8 @@ Add null default to properties with PHP 7.4 property nullable type
Changes property type by `@var` annotations or default value.
-:wrench: **configure it!**
-
- class: [`Rector\Php74\Rector\Property\TypedPropertyRector`](../rules/Php74/Rector/Property/TypedPropertyRector.php)
-```php
-use Rector\Config\RectorConfig;
-use Rector\Php74\Rector\Property\TypedPropertyRector;
-
-return static function (RectorConfig $rectorConfig): void {
- $rectorConfig->ruleWithConfiguration(TypedPropertyRector::class, [
- TypedPropertyRector::INLINE_PUBLIC => false,
- ]);
-};
-```
-
-↓
-
```diff
final class SomeClass
{
@@ -5826,8 +5811,23 @@ Change `$this::class` to static::class or self::class depends on class modifier
Change simple property init and assign to constructor promotion
+:wrench: **configure it!**
+
- class: [`Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector`](../rules/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector.php)
+```php
+use Rector\Config\RectorConfig;
+use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector;
+
+return static function (RectorConfig $rectorConfig): void {
+ $rectorConfig->ruleWithConfiguration(ClassPropertyAssignToConstructorPromotionRector::class, [
+ ClassPropertyAssignToConstructorPromotionRector::INLINE_PUBLIC => false,
+ ]);
+};
+```
+
+↓
+
```diff
class SomeClass
{
@@ -9296,6 +9296,25 @@ Change `@return` types and type from static analysis to type declarations if not
+### ReturnTypeFromReturnDirectArrayRector
+
+Add return type from return direct array
+
+- class: [`Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnDirectArrayRector`](../rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromReturnDirectArrayRector.php)
+
+```diff
+ final class AddReturnArray
+ {
+- public function getArray()
++ public function getArray(): array
+ {
+ return [1, 2, 3];
+ }
+ }
+```
+
+
+
### ReturnTypeFromReturnNewRector
Add return type to function like with return new
@@ -9334,6 +9353,27 @@ Add strict return type based on returned strict expr type
+### ReturnTypeFromStrictConstantReturnRector
+
+Add strict type declaration based on returned constants
+
+- class: [`Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictConstantReturnRector`](../rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictConstantReturnRector.php)
+
+```diff
+ class SomeClass
+ {
+ public const NAME = 'name';
+
+- public function run()
++ public function run(): string
+ {
+ return self::NAME;
+ }
+ }
+```
+
+
+
### ReturnTypeFromStrictNativeCallRector
Add strict return type based native function or class method return
@@ -9374,6 +9414,30 @@ Add strict return array type based on created empty array and returned
+### ReturnTypeFromStrictTypedCallRector
+
+Add return type from strict return type of call
+
+- class: [`Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector`](../rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictTypedCallRector.php)
+
+```diff
+ final class SomeClass
+ {
+- public function getData()
++ public function getData(): int
+ {
+ return $this->getNumber();
+ }
+
+ private function getNumber(): int
+ {
+ return 1000;
+ }
+ }
+```
+
+
+
### ReturnTypeFromStrictTypedPropertyRector
Add return method return type based on strict typed property
diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/FixtureInlinePublicDisable/final_class_non_typed_protected_property.php.inc b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/FixtureInlinePublicDisable/final_class_non_typed_protected_property.php.inc
new file mode 100644
index 00000000000..86f5ab54cc6
--- /dev/null
+++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/FixtureInlinePublicDisable/final_class_non_typed_protected_property.php.inc
@@ -0,0 +1,31 @@
+x = $x;
+ }
+}
+
+?>
+-----
+
diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/FixtureInlinePublicDisable/non_final_non_typed_private_property.php.inc b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/FixtureInlinePublicDisable/non_final_non_typed_private_property.php.inc
new file mode 100644
index 00000000000..74aea1f086e
--- /dev/null
+++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/FixtureInlinePublicDisable/non_final_non_typed_private_property.php.inc
@@ -0,0 +1,31 @@
+x = $x;
+ }
+}
+
+?>
+-----
+
diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/FixtureInlinePublicDisable/skip_non_typed_non_final_class_protected_property.php.inc b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/FixtureInlinePublicDisable/skip_non_typed_non_final_class_protected_property.php.inc
new file mode 100644
index 00000000000..766a5c81689
--- /dev/null
+++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/FixtureInlinePublicDisable/skip_non_typed_non_final_class_protected_property.php.inc
@@ -0,0 +1,16 @@
+x = $x;
+ }
+}
diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/FixtureInlinePublicDisable/typed_non_final_class_protected_property.php.inc b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/FixtureInlinePublicDisable/typed_non_final_class_protected_property.php.inc
new file mode 100644
index 00000000000..41bda608153
--- /dev/null
+++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/FixtureInlinePublicDisable/typed_non_final_class_protected_property.php.inc
@@ -0,0 +1,28 @@
+x = $x;
+ }
+}
+
+?>
+-----
+
\ No newline at end of file
diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/InlinePublicDisableTest.php b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/InlinePublicDisableTest.php
new file mode 100644
index 00000000000..7f62fa20f45
--- /dev/null
+++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/InlinePublicDisableTest.php
@@ -0,0 +1,29 @@
+doTestFile($filePath);
+ }
+
+ public function provideData(): Iterator
+ {
+ return $this->yieldFilesFromDirectory(__DIR__ . '/FixtureInlinePublicDisable');
+ }
+
+ public function provideConfigFilePath(): string
+ {
+ return __DIR__ . '/config/configured_rule_disable_inline_public.php';
+ }
+}
diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/config/auto_import_configured_rule.php b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/config/auto_import_configured_rule.php
index 8fa482a914d..3bd25f27c77 100644
--- a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/config/auto_import_configured_rule.php
+++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/config/auto_import_configured_rule.php
@@ -7,5 +7,7 @@
return static function (RectorConfig $rectorConfig): void {
$rectorConfig->importNames();
- $rectorConfig->rule(ClassPropertyAssignToConstructorPromotionRector::class);
+ $rectorConfig->ruleWithConfiguration(ClassPropertyAssignToConstructorPromotionRector::class, [
+ ClassPropertyAssignToConstructorPromotionRector::INLINE_PUBLIC => true,
+ ]);
};
diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/config/configured_rule.php b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/config/configured_rule.php
index 7d335b78e44..2202792ff48 100644
--- a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/config/configured_rule.php
+++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/config/configured_rule.php
@@ -6,5 +6,7 @@
use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector;
return static function (RectorConfig $rectorConfig): void {
- $rectorConfig->rule(ClassPropertyAssignToConstructorPromotionRector::class);
+ $rectorConfig->ruleWithConfiguration(ClassPropertyAssignToConstructorPromotionRector::class, [
+ ClassPropertyAssignToConstructorPromotionRector::INLINE_PUBLIC => true,
+ ]);
};
diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/config/configured_rule_disable_inline_public.php b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/config/configured_rule_disable_inline_public.php
new file mode 100644
index 00000000000..404b796d8e3
--- /dev/null
+++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/config/configured_rule_disable_inline_public.php
@@ -0,0 +1,11 @@
+rule(ClassPropertyAssignToConstructorPromotionRector::class);
+};
diff --git a/rules/Php74/Guard/MakePropertyTypedGuard.php b/rules/Php74/Guard/MakePropertyTypedGuard.php
index d84e5ceb8ee..e008ae5afdc 100644
--- a/rules/Php74/Guard/MakePropertyTypedGuard.php
+++ b/rules/Php74/Guard/MakePropertyTypedGuard.php
@@ -4,25 +4,12 @@
namespace Rector\Php74\Guard;
-use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
-use PHPStan\Reflection\ClassReflection;
-use Rector\Core\Exception\ShouldNotHappenException;
-use Rector\Core\NodeAnalyzer\PropertyAnalyzer;
-use Rector\Core\NodeManipulator\PropertyManipulator;
-use Rector\Core\Reflection\ReflectionResolver;
-use Rector\NodeNameResolver\NodeNameResolver;
-use Rector\NodeTypeResolver\Node\AttributeKey;
-use Rector\Privatization\Guard\ParentPropertyLookupGuard;
final class MakePropertyTypedGuard
{
public function __construct(
- private readonly NodeNameResolver $nodeNameResolver,
- private readonly PropertyAnalyzer $propertyAnalyzer,
- private readonly PropertyManipulator $propertyManipulator,
- private readonly ParentPropertyLookupGuard $parentPropertyLookupGuard,
- private readonly ReflectionResolver $reflectionResolver
+ private readonly PropertyTypeChangeGuard $propertyTypeChangeGuard
) {
}
@@ -32,55 +19,6 @@ public function isLegal(Property $property, bool $inlinePublic = true): bool
return false;
}
- if (count($property->props) > 1) {
- return false;
- }
-
- $classReflection = $this->reflectionResolver->resolveClassReflection($property);
- if (! $classReflection instanceof ClassReflection) {
- return false;
- }
-
- /**
- * - trait properties are unpredictable based on class context they appear in
- * - on interface properties as well, as interface not allowed to have property
- */
- if (! $classReflection->isClass()) {
- return false;
- }
-
- $propertyName = $this->nodeNameResolver->getName($property);
-
- if ($this->propertyManipulator->isUsedByTrait($classReflection, $propertyName)) {
- return false;
- }
-
- if ($inlinePublic) {
- return ! $this->propertyAnalyzer->hasForbiddenType($property);
- }
-
- if ($property->isPrivate()) {
- return ! $this->propertyAnalyzer->hasForbiddenType($property);
- }
-
- return $this->isSafeProtectedProperty($property);
- }
-
- private function isSafeProtectedProperty(Property $property): bool
- {
- if (! $property->isProtected()) {
- return false;
- }
-
- $parentNode = $property->getAttribute(AttributeKey::PARENT_NODE);
- if (! $parentNode instanceof Class_) {
- throw new ShouldNotHappenException();
- }
-
- if (! $parentNode->isFinal()) {
- return false;
- }
-
- return $this->parentPropertyLookupGuard->isLegal($property);
+ return $this->propertyTypeChangeGuard->isLegal($property, $inlinePublic);
}
}
diff --git a/rules/Php74/Guard/PropertyTypeChangeGuard.php b/rules/Php74/Guard/PropertyTypeChangeGuard.php
new file mode 100644
index 00000000000..2ffecc7a2bb
--- /dev/null
+++ b/rules/Php74/Guard/PropertyTypeChangeGuard.php
@@ -0,0 +1,90 @@
+props) > 1) {
+ return false;
+ }
+
+ $classReflection = $this->reflectionResolver->resolveClassReflection($property);
+ if (! $classReflection instanceof ClassReflection) {
+ return false;
+ }
+
+ /**
+ * - trait properties are unpredictable based on class context they appear in
+ * - on interface properties as well, as interface not allowed to have property
+ */
+ if (! $classReflection->isClass()) {
+ return false;
+ }
+
+ $propertyName = $this->nodeNameResolver->getName($property);
+
+ if ($this->propertyManipulator->isUsedByTrait($classReflection, $propertyName)) {
+ return false;
+ }
+
+ if ($this->propertyAnalyzer->hasForbiddenType($property)) {
+ return false;
+ }
+
+ if ($inlinePublic) {
+ return true;
+ }
+
+ if ($property->isPrivate()) {
+ return true;
+ }
+
+ if ($isConstructorPromotion) {
+ return true;
+ }
+
+ return $this->isSafeProtectedProperty($property);
+ }
+
+ private function isSafeProtectedProperty(Property $property): bool
+ {
+ if (! $property->isProtected()) {
+ return false;
+ }
+
+ $parentNode = $property->getAttribute(AttributeKey::PARENT_NODE);
+ if (! $parentNode instanceof Class_) {
+ throw new ShouldNotHappenException();
+ }
+
+ if (! $parentNode->isFinal()) {
+ return false;
+ }
+
+ return $this->parentPropertyLookupGuard->isLegal($property);
+ }
+}
diff --git a/rules/Php80/Guard/MakePropertyPromotionGuard.php b/rules/Php80/Guard/MakePropertyPromotionGuard.php
new file mode 100644
index 00000000000..ea65435e0d0
--- /dev/null
+++ b/rules/Php80/Guard/MakePropertyPromotionGuard.php
@@ -0,0 +1,44 @@
+propertyTypeChangeGuard->isLegal($property, $inlinePublic, true)) {
+ return false;
+ }
+
+ if ($class->isFinal()) {
+ return true;
+ }
+
+ if ($inlinePublic) {
+ return true;
+ }
+
+ if ($property->isPrivate()) {
+ return true;
+ }
+
+ if (! $param->type instanceof Node) {
+ return true;
+ }
+
+ return $property->type instanceof Node;
+ }
+}
diff --git a/rules/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector.php b/rules/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector.php
index 7ab663ea265..2857b1be0c7 100644
--- a/rules/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector.php
+++ b/rules/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector.php
@@ -16,18 +16,19 @@
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
+use Rector\Core\Contract\Rector\AllowEmptyConfigurableRectorInterface;
use Rector\Core\NodeAnalyzer\ParamAnalyzer;
-use Rector\Core\NodeAnalyzer\PropertyAnalyzer;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\MethodName;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\DeadCode\PhpDoc\TagRemover\VarTagRemover;
use Rector\Naming\VariableRenamer;
use Rector\NodeTypeResolver\Node\AttributeKey;
+use Rector\Php80\Guard\MakePropertyPromotionGuard;
use Rector\Php80\NodeAnalyzer\PromotedPropertyCandidateResolver;
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
-use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
+use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
@@ -35,15 +36,31 @@
*
* @see \Rector\Tests\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector\ClassPropertyAssignToConstructorPromotionRectorTest
*/
-final class ClassPropertyAssignToConstructorPromotionRector extends AbstractRector implements MinPhpVersionInterface
+final class ClassPropertyAssignToConstructorPromotionRector extends AbstractRector implements MinPhpVersionInterface, AllowEmptyConfigurableRectorInterface
{
+ /**
+ * @api
+ * @var string
+ */
+ public const INLINE_PUBLIC = 'inline_public';
+
+ /**
+ * Default to false, which only apply changes:
+ *
+ * – private modifier property
+ * - protected/public modifier property when property typed
+ *
+ * Set to true will allow change whether property is typed or not as far as not forbidden, eg: callable type, null type, etc.
+ */
+ private bool $inlinePublic = false;
+
public function __construct(
private readonly PromotedPropertyCandidateResolver $promotedPropertyCandidateResolver,
private readonly VariableRenamer $variableRenamer,
private readonly VarTagRemover $varTagRemover,
private readonly ParamAnalyzer $paramAnalyzer,
private readonly PhpDocTypeChanger $phpDocTypeChanger,
- private readonly PropertyAnalyzer $propertyAnalyzer
+ private readonly MakePropertyPromotionGuard $makePropertyPromotionGuard
) {
}
@@ -52,7 +69,7 @@ public function getRuleDefinition(): RuleDefinition
return new RuleDefinition(
'Change simple property init and assign to constructor promotion',
[
- new CodeSample(
+ new ConfiguredCodeSample(
<<<'CODE_SAMPLE'
class SomeClass
{
@@ -75,11 +92,20 @@ public function __construct(
}
}
CODE_SAMPLE
+ ,
+ [
+ self::INLINE_PUBLIC => false,
+ ]
),
]
);
}
+ public function configure(array $configuration): void
+ {
+ $this->inlinePublic = $configuration[self::INLINE_PUBLIC] ?? (bool) current($configuration);
+ }
+
/**
* @return array>
*/
@@ -112,7 +138,7 @@ public function refactor(Node $node): ?Node
continue;
}
- if ($this->propertyAnalyzer->hasForbiddenType($property)) {
+ if (! $this->makePropertyPromotionGuard->isLegal($node, $property, $param, $this->inlinePublic)) {
continue;
}