From eb62a174cd0307ed14a25b9ccad653c8060158e7 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sat, 20 Jun 2026 12:19:12 +0200 Subject: [PATCH] [TypeDeclaration][DeadCode] Skip class with Doctrine static function mapping (loadMetadata) in TypedPropertyFromAssignsRector and RemoveUnusedPrivatePropertyRector --- .../skip_static_function_mapping.php.inc | 18 +++++++++++++++ .../skip_static_function_mapping.php.inc | 23 +++++++++++++++++++ .../RemoveUnusedPrivatePropertyRector.php | 7 ++++++ .../TypedPropertyFromAssignsRector.php | 7 ++++++ 4 files changed, 55 insertions(+) create mode 100644 rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/skip_static_function_mapping.php.inc create mode 100644 rules-tests/TypeDeclaration/Rector/Property/TypedPropertyFromAssignsRector/Fixture/Doctrine/skip_static_function_mapping.php.inc diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/skip_static_function_mapping.php.inc b/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/skip_static_function_mapping.php.inc new file mode 100644 index 00000000000..b306ca5994c --- /dev/null +++ b/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/skip_static_function_mapping.php.inc @@ -0,0 +1,18 @@ +mapField([ + 'fieldName' => 'name', + 'type' => 'string', + ]); + } +} diff --git a/rules-tests/TypeDeclaration/Rector/Property/TypedPropertyFromAssignsRector/Fixture/Doctrine/skip_static_function_mapping.php.inc b/rules-tests/TypeDeclaration/Rector/Property/TypedPropertyFromAssignsRector/Fixture/Doctrine/skip_static_function_mapping.php.inc new file mode 100644 index 00000000000..cda7d32a418 --- /dev/null +++ b/rules-tests/TypeDeclaration/Rector/Property/TypedPropertyFromAssignsRector/Fixture/Doctrine/skip_static_function_mapping.php.inc @@ -0,0 +1,23 @@ +name = 'string'; + } + + public static function loadMetadata(ClassMetadata $metadata): void + { + $metadata->mapField([ + 'fieldName' => 'name', + 'type' => 'string', + ]); + } +} diff --git a/rules/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector.php b/rules/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector.php index 68adc8295cb..1466e1a65e9 100644 --- a/rules/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector.php +++ b/rules/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector.php @@ -8,6 +8,7 @@ use PhpParser\Node\Arg; use PhpParser\Node\Expr\Assign; use PhpParser\Node\Stmt\Class_; +use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Expression; use PhpParser\Node\Stmt\Property; use PhpParser\Node\Stmt\Return_; @@ -144,6 +145,12 @@ private function shouldRemoveProperty(Class_ $class, Property $property): bool private function shouldSkipClass(Class_ $class): bool { + // skip Doctrine static function mapping, properties are mapped in loadMetadata() method + // @see https://www.doctrine-project.org/projects/doctrine-orm/en/3.6/reference/php-mapping.html#static-function + if ($class->getMethod('loadMetadata') instanceof ClassMethod) { + return true; + } + foreach ($class->stmts as $stmt) { // unclear what property can be used there if ($stmt instanceof TraitUse) { diff --git a/rules/TypeDeclaration/Rector/Property/TypedPropertyFromAssignsRector.php b/rules/TypeDeclaration/Rector/Property/TypedPropertyFromAssignsRector.php index 076f5a00b35..98d0554d24b 100644 --- a/rules/TypeDeclaration/Rector/Property/TypedPropertyFromAssignsRector.php +++ b/rules/TypeDeclaration/Rector/Property/TypedPropertyFromAssignsRector.php @@ -8,6 +8,7 @@ use PhpParser\Node\Expr; use PhpParser\Node\NullableType; use PhpParser\Node\Stmt\Class_; +use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Property; use PhpParser\Node\UnionType as NodeUnionType; use PHPStan\Reflection\ClassReflection; @@ -129,6 +130,12 @@ public function provideMinPhpVersion(): int */ public function refactor(Node $node): ?Node { + // skip Doctrine static function mapping, properties are mapped in loadMetadata() method + // @see https://www.doctrine-project.org/projects/doctrine-orm/en/3.6/reference/php-mapping.html#static-function + if ($node->getMethod('loadMetadata') instanceof ClassMethod) { + return null; + } + $hasChanged = false; $classReflection = null;