From 1dce92840a42d316eff9fb4929c141475f99617c Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Fri, 10 Oct 2025 14:27:06 +0200 Subject: [PATCH 1/5] remove deprecated ConvertStaticPrivateConstantToSelfRector --- ...nvertStaticPrivateConstantToSelfRector.php | 77 ------------------- 1 file changed, 77 deletions(-) delete mode 100644 rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php diff --git a/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php b/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php deleted file mode 100644 index 781587db8f3..00000000000 --- a/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php +++ /dev/null @@ -1,77 +0,0 @@ -> - */ - public function getNodeTypes(): array - { - return [Class_::class]; - } - - /** - * @param Class_ $node - */ - public function refactor(Node $node): ?Class_ - { - throw new ShouldNotHappenException(sprintf( - 'The %s rule is deprecated. Use %s instead', - self::class, - ConvertStaticToSelfRector::class, - )); - } -} From 886ae8047b4d03f6bd98468945a55b5e93adc4be Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Fri, 10 Oct 2025 14:40:19 +0200 Subject: [PATCH 2/5] [code-quality] Add VariableConstFetchToClassConstFetchRector --- .../Fixture/skip_dynamic_name.php.inc | 15 ++++ .../Fixture/skip_known_class.php.inc | 15 ++++ .../Fixture/some_class.php.inc | 35 ++++++++ .../Source/ClassWithConstants.php | 8 ++ ...eConstFetchToClassConstFetchRectorTest.php | 28 ++++++ .../config/configured_rule.php | 10 +++ ...iableConstFetchToClassConstFetchRector.php | 86 +++++++++++++++++++ .../NamespaceBeforeClassNameResolver.php | 6 +- src/Config/Level/CodeQualityLevel.php | 2 + 9 files changed, 200 insertions(+), 5 deletions(-) create mode 100644 rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/skip_dynamic_name.php.inc create mode 100644 rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/skip_known_class.php.inc create mode 100644 rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/some_class.php.inc create mode 100644 rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Source/ClassWithConstants.php create mode 100644 rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/VariableConstFetchToClassConstFetchRectorTest.php create mode 100644 rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/config/configured_rule.php create mode 100644 rules/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector.php diff --git a/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/skip_dynamic_name.php.inc b/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/skip_dynamic_name.php.inc new file mode 100644 index 00000000000..7ef4f4d0275 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/skip_dynamic_name.php.inc @@ -0,0 +1,15 @@ + +----- + diff --git a/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Source/ClassWithConstants.php b/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Source/ClassWithConstants.php new file mode 100644 index 00000000000..8b71de777e1 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Source/ClassWithConstants.php @@ -0,0 +1,8 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/config/configured_rule.php b/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/config/configured_rule.php new file mode 100644 index 00000000000..ed190ac0165 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/config/configured_rule.php @@ -0,0 +1,10 @@ +rule(VariableConstFetchToClassConstFetchRector::class); +}; diff --git a/rules/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector.php b/rules/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector.php new file mode 100644 index 00000000000..58a7a5f6976 --- /dev/null +++ b/rules/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector.php @@ -0,0 +1,86 @@ +> + */ + public function getNodeTypes(): array + { + return [ClassConstFetch::class]; + } + + /** + * @param ClassConstFetch $node + */ + public function refactor(Node $node): ?ClassConstFetch + { + if (! $node->class instanceof Expr) { + return null; + } + + if (! $node->name instanceof Node\Identifier) { + return null; + } + + $constantName = $this->getName($node->name); + + $classObjectType = $this->getType($node->class); + if (! $classObjectType instanceof ObjectType) { + return null; + } + + if (! $classObjectType->hasConstant($constantName)->yes()) { + return null; + } + + $node->class = new Node\Name\FullyQualified($classObjectType->getClassName()); + + return $node; + } +} diff --git a/rules/CodingStyle/ClassNameImport/NamespaceBeforeClassNameResolver.php b/rules/CodingStyle/ClassNameImport/NamespaceBeforeClassNameResolver.php index aa1ab6e466b..5459b90210e 100644 --- a/rules/CodingStyle/ClassNameImport/NamespaceBeforeClassNameResolver.php +++ b/rules/CodingStyle/ClassNameImport/NamespaceBeforeClassNameResolver.php @@ -15,10 +15,6 @@ public function resolve(FullyQualifiedObjectType $fullyQualifiedObjectType): str return $className === $shortName ? '' - : substr( - $className, - 0, - -strlen($shortName) - 1 - ); + : substr($className, 0, -strlen($shortName) - 1); } } diff --git a/src/Config/Level/CodeQualityLevel.php b/src/Config/Level/CodeQualityLevel.php index de46a440cc4..9f9a3629b10 100644 --- a/src/Config/Level/CodeQualityLevel.php +++ b/src/Config/Level/CodeQualityLevel.php @@ -15,6 +15,7 @@ use Rector\CodeQuality\Rector\Class_\ConvertStaticToSelfRector; use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector; use Rector\CodeQuality\Rector\Class_\RemoveReadonlyPropertyVisibilityOnReadonlyClassRector; +use Rector\CodeQuality\Rector\ClassConstFetch\VariableConstFetchToClassConstFetchRector; use Rector\CodeQuality\Rector\ClassMethod\ExplicitReturnNullRector; use Rector\CodeQuality\Rector\ClassMethod\InlineArrayReturnAssignRector; use Rector\CodeQuality\Rector\ClassMethod\LocallyCalledStaticMethodToNonStaticRector; @@ -153,6 +154,7 @@ final class CodeQualityLevel IssetOnPropertyObjectToPropertyExistsRector::class, NewStaticToNewSelfRector::class, UnwrapSprintfOneArgumentRector::class, + VariableConstFetchToClassConstFetchRector::class, SwitchNegatedTernaryRector::class, SingularSwitchToIfRector::class, SimplifyIfNullableReturnRector::class, From 36b2cf4193471d922258eadcc8add30f63bf9bad Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Fri, 10 Oct 2025 14:55:24 +0200 Subject: [PATCH 3/5] include override in cild class --- .../Fixture/allow_override.php.inc | 35 +++++++++++++++++++ .../Fixture/parent_hop_fetch.php.inc | 35 +++++++++++++++++++ .../Fixture/skip_doc_type.php.inc | 18 ++++++++++ .../Fixture/skip_unknown_class.php.inc | 13 +++++++ .../Source/ChildClassNotWithConstant.php | 10 ++++++ .../Source/ClassWithConstants.php | 6 +++- ...iableConstFetchToClassConstFetchRector.php | 11 ++++-- 7 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/allow_override.php.inc create mode 100644 rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/parent_hop_fetch.php.inc create mode 100644 rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/skip_doc_type.php.inc create mode 100644 rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/skip_unknown_class.php.inc create mode 100644 rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Source/ChildClassNotWithConstant.php diff --git a/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/allow_override.php.inc b/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/allow_override.php.inc new file mode 100644 index 00000000000..b942c9a08c4 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/allow_override.php.inc @@ -0,0 +1,35 @@ + +----- + diff --git a/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/parent_hop_fetch.php.inc b/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/parent_hop_fetch.php.inc new file mode 100644 index 00000000000..baad0ae5c26 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/parent_hop_fetch.php.inc @@ -0,0 +1,35 @@ + +----- + diff --git a/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/skip_doc_type.php.inc b/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/skip_doc_type.php.inc new file mode 100644 index 00000000000..e069bd24aed --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Fixture/skip_doc_type.php.inc @@ -0,0 +1,18 @@ +name instanceof Node\Identifier) { + if (! $node->name instanceof Identifier) { return null; } $constantName = $this->getName($node->name); + if (! is_string($constantName)) { + return null; + } - $classObjectType = $this->getType($node->class); + $classObjectType = $this->nodeTypeResolver->getNativeType($node->class); if (! $classObjectType instanceof ObjectType) { return null; } @@ -79,7 +84,7 @@ public function refactor(Node $node): ?ClassConstFetch return null; } - $node->class = new Node\Name\FullyQualified($classObjectType->getClassName()); + $node->class = new FullyQualified($classObjectType->getClassName()); return $node; } From 2afd0a5a64c1b595b280f983e3c7c7ab4e538e8f Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Fri, 10 Oct 2025 16:50:26 +0200 Subject: [PATCH 4/5] raise deps --- composer.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index 032bceb95a7..4308326a3f3 100644 --- a/composer.json +++ b/composer.json @@ -17,16 +17,16 @@ "composer/pcre": "^3.3.0", "composer/semver": "^3.4", "composer/xdebug-handler": "^3.0.5", - "doctrine/inflector": "^2.0.10", - "illuminate/container": "^11.45", + "doctrine/inflector": "^2.1", + "illuminate/container": "^11.46", "nette/utils": "^4.0", "nikic/php-parser": "^5.6.1", "ocramius/package-versions": "^2.10", "ondram/ci-detector": "^4.2", - "phpstan/phpdoc-parser": "^2.2", + "phpstan/phpdoc-parser": "^2.3", "phpstan/phpstan": "^2.1.26", "react/event-loop": "^1.5", - "react/promise": "^3.2", + "react/promise": "^3.3", "react/socket": "^1.16", "rector/extension-installer": "^0.11.2", "rector/rector-doctrine": "dev-main", @@ -44,7 +44,7 @@ }, "require-dev": { "php-parallel-lint/php-parallel-lint": "^1.4", - "phpecs/phpecs": "^2.1", + "phpecs/phpecs": "^2.2", "phpstan/extension-installer": "^1.4", "phpstan/phpstan-deprecation-rules": "^2.0", "phpstan/phpstan-phpunit": "^2.0", @@ -56,8 +56,8 @@ "rector/type-perfect": "^2.1", "shipmonk/composer-dependency-analyser": "^1.8", "symplify/phpstan-extensions": "^12.0", - "symplify/phpstan-rules": "^14.6.11", - "symplify/vendor-patches": "^11.4", + "symplify/phpstan-rules": "^14.8", + "symplify/vendor-patches": "^11.5", "tomasvotruba/class-leak": "^2.0", "tracy/tracy": "^2.10" }, From 3c8a82b9f01b1a85b859c3eb170d153679d59993 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Fri, 10 Oct 2025 16:53:19 +0200 Subject: [PATCH 5/5] misc --- phpstan.neon | 5 +++++ src/CustomRules/SimpleNodeDumper.php | 21 ++++++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 756eba937d9..1d142cab5b7 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -345,3 +345,8 @@ parameters: - identifier: symplify.noReference message: '#Use explicit return value over magic &reference#' + + # false positive + - + identifier: offsetAccess.invalidOffset + path: src/CustomRules/SimpleNodeDumper.php diff --git a/src/CustomRules/SimpleNodeDumper.php b/src/CustomRules/SimpleNodeDumper.php index d756d8f81c1..28878ad11b9 100644 --- a/src/CustomRules/SimpleNodeDumper.php +++ b/src/CustomRules/SimpleNodeDumper.php @@ -20,6 +20,16 @@ */ final class SimpleNodeDumper { + /** + * @var array + */ + private const INCLUDE_TYPE_MAP = [ + Include_::TYPE_INCLUDE => 'TYPE_INCLUDE', + Include_::TYPE_INCLUDE_ONCE => 'TYPE_INCLUDE_ONCE', + Include_::TYPE_REQUIRE => 'TYPE_REQUIRE', + Include_::TYPE_REQUIRE_ONCE => 'TYPE_REQUIRE_ONCE', + ]; + /** * @param Node[]|Node|mixed[] $node */ @@ -120,18 +130,11 @@ private static function dumpFlags(mixed $flags): string private static function dumpIncludeType(int|float|string $type): string { - $map = [ - Include_::TYPE_INCLUDE => 'TYPE_INCLUDE', - Include_::TYPE_INCLUDE_ONCE => 'TYPE_INCLUDE_ONCE', - Include_::TYPE_REQUIRE => 'TYPE_REQUIRE', - Include_::TYPE_REQUIRE_ONCE => 'TYPE_REQUIRE_ONCE', - ]; - - if (! isset($map[$type])) { + if (! isset(self::INCLUDE_TYPE_MAP[$type])) { return (string) $type; } - return $map[$type] . ' (' . $type . ')'; + return self::INCLUDE_TYPE_MAP[$type] . ' (' . $type . ')'; } private static function dumpUseType(mixed $type): string