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" }, 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/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 @@ + +----- + diff --git a/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Source/ChildClassNotWithConstant.php b/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Source/ChildClassNotWithConstant.php new file mode 100644 index 00000000000..91f30122e86 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector/Source/ChildClassNotWithConstant.php @@ -0,0 +1,10 @@ +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/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, - )); - } -} diff --git a/rules/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector.php b/rules/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector.php new file mode 100644 index 00000000000..4e06232d457 --- /dev/null +++ b/rules/CodeQuality/Rector/ClassConstFetch/VariableConstFetchToClassConstFetchRector.php @@ -0,0 +1,91 @@ +> + */ + 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 Identifier) { + return null; + } + + $constantName = $this->getName($node->name); + if (! is_string($constantName)) { + return null; + } + + $classObjectType = $this->nodeTypeResolver->getNativeType($node->class); + if (! $classObjectType instanceof ObjectType) { + return null; + } + + if (! $classObjectType->hasConstant($constantName)->yes()) { + return null; + } + + $node->class = new 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, 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