diff --git a/.github/workflows/remove_unused_deps.yaml b/.github/workflows/remove_unused_deps.yaml deleted file mode 100644 index 060e8cae841..00000000000 --- a/.github/workflows/remove_unused_deps.yaml +++ /dev/null @@ -1,39 +0,0 @@ -name: Remove Unused Dependencies - -on: - pull_request: null - -jobs: - remove_unused_deps: - strategy: - fail-fast: false - - runs-on: ubuntu-latest - timeout-minutes: 8 - - if: github.event.pull_request.head.repo.full_name == 'rectorphp/rector-src' - steps: - - - uses: actions/checkout@v5 - with: - # Must be used to trigger workflow after push - token: ${{ secrets.ACCESS_TOKEN }} - - - - uses: shivammathur/setup-php@v2 - with: - php-version: 8.4 - coverage: none - - - run: composer install --no-progress --ansi - - ## detect unused dependencies and remove them from composer.json - - run: php scripts/remove-unused-deps.php --ansi - - - - # commit only to core contributors who have repository access - uses: stefanzweifel/git-auto-commit-action@v7 - with: - commit_message: '[ci-review] Remove unused dependencies' - commit_author: 'GitHub Action ' - commit_user_email: 'action@github.com' diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index db0052313ec..58f2834a1f3 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -6,8 +6,6 @@ on: branches: - main - - env: # see https://github.com/composer/composer/issues/9368#issuecomment-718112361 COMPOSER_ROOT_VERSION: "dev-main" @@ -39,35 +37,3 @@ jobs: - uses: "ramsey/composer-install@v4" - run: vendor/bin/fastunit tests rules-tests utils/phpstan/tests - - # optional fast feedback on pull requests: run only the tests whose static - # dependency closure changed. NOT a merge gate -- the full "tests" job above - # stays authoritative, since -tia over-approximates but cannot see dynamic - # (reflection / class-string) dependencies. - tests_tia: - if: github.event_name == 'pull_request' - runs-on: ubuntu-latest - timeout-minutes: 4 - - name: PHP 8.4 tests (impacted only) - steps: - - uses: actions/checkout@v5 - - # restore the newest cached hash snapshot; save a fresh one per commit - - uses: actions/cache@v4 - with: - path: .fastunit-cache - key: fastunit-tia-${{ github.sha }} - restore-keys: | - fastunit-tia- - - - - uses: shivammathur/setup-php@v2 - with: - php-version: '8.4' - coverage: none - ini-values: zend.assertions=1 - - - uses: "ramsey/composer-install@v4" - - - run: vendor/bin/fastunit -tia tests rules-tests utils/phpstan/tests diff --git a/composer.json b/composer.json index 7df76cb23d9..c0492771014 100644 --- a/composer.json +++ b/composer.json @@ -53,8 +53,7 @@ "rector/swiss-knife": "^2.4.1", "shipmonk/composer-dependency-analyser": "^1.8", "symplify/easy-coding-standard": "^13.2.13", - "symplify/phpstan-extensions": "^12.0.2", - "symplify/phpstan-rules": "^14.12", + "symplify/phpstan-rules": "^14.12.3", "tomasvotruba/class-leak": "^2.1", "tomasvotruba/fast-unit": "^0.1", "tomasvotruba/type-coverage": "^2.3", @@ -106,7 +105,6 @@ "@test" ], "test": "vendor/bin/fastunit tests rules-tests utils/phpstan/tests", - "test-tia": "vendor/bin/fastunit -tia tests rules-tests utils/phpstan/tests", "check-cs": "vendor/bin/ecs check --ansi", "fix-cs": "vendor/bin/ecs check --fix --ansi", "phpstan": "vendor/bin/phpstan analyse --ansi --memory-limit=512M", diff --git a/phpstan.neon b/phpstan.neon index 08501a16a7e..1446fd13de6 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2,29 +2,15 @@ includes: - vendor/symplify/phpstan-rules/config/symplify-rules.neon - vendor/symplify/phpstan-rules/config/rector-rules.neon -services: - - - class: Rector\Utils\PHPStan\Rule\RegisterRelatedPolyfillRectorRule - arguments: - polyfillConfigFilePath: %currentWorkingDirectory%/config/set/php-polyfills.php - tags: - - phpstan.rules.rule - - - - class: Rector\Utils\PHPStan\Rule\CheaperGuardFirstRule - tags: - - phpstan.rules.rule - - - - class: Rector\Utils\PHPStan\Rule\SingleServiceRegistrationRule - tags: - - phpstan.rules.rule +rules: + - Rector\Utils\PHPStan\Rule\CheaperGuardFirstRule + - Rector\Utils\PHPStan\Rule\SingleServiceRegistrationRule + - Rector\Utils\PHPStan\Rule\RegisterRelatedPolyfillRectorRule parameters: level: 8 - reportUnmatchedIgnoredErrors: false - + # reportUnmatchedIgnoredErrors: false errorFormat: symplify # see https://phpstan.org/writing-php-code/phpdoc-types#global-type-aliases @@ -36,7 +22,6 @@ parameters: treatPhpDocTypesAsCertain: false paths: - - rector.php - bin - config - src @@ -46,6 +31,7 @@ parameters: - rules-tests - utils - scripts + - rector.php - e2e/e2eTestRunner.php scanDirectories: @@ -57,12 +43,9 @@ parameters: - '*tests/*/Source/*' - '*tests/*/Source*' - # see https://github.com/TomasVotruba/type-coverage - type_perfect: - no_mixed: true - null_over_false: true - narrow_param: true - narrow_return: true + # see https://github.com/symplify/phpstan-rules + symplify: + pathStrings: true # see https://github.com/TomasVotruba/type-coverage type_coverage: @@ -71,6 +54,11 @@ parameters: param_type: 99 property_type: 99 constant_type: 99 + type_perfect: + no_mixed: true + null_over_false: true + narrow_param: true + narrow_return: true # see https://github.com/TomasVotruba/unused-public unused_public: @@ -79,437 +67,379 @@ parameters: constants: true ignoreErrors: - # required generics on interface array, not helpful - - - message: '#Method (.*?)\:\:__construct\(\) has parameter#' - identifier: missingType.generics + # the deprecated set objects are still resolved internally, until every extension bonds its rules - - message: '#(.*?) with generic interface (.*?)Interface does not specify its types#' - identifier: missingType.generics - - # phpstan class instance - - identifier: phpstanApi.class - - # phpstan class constant value - - identifier: phpstanApi.classConstant - - # phpstan class construction - - identifier: phpstanApi.constructor - - # phpstan instanceof - - identifier: phpstanApi.instanceofAssumption + message: '#deprecated (class|interface) Rector\\(Set|Bridge)\\#' + path: src/Configuration/RectorConfigBuilder.php - # assert phpunit - - identifier: method.alreadyNarrowedType - path: tests + identifier: argument.templateType + path: rules/TypeDeclaration/Rector/FunctionLike/AddClosureParamTypeForArrayReduceRector.php - # runtime php id - - identifier: greaterOrEqual.alwaysTrue - path: src/Util/FileHasher.php + identifier: argument.type + message: '#(.*?) class\-string, string given#' - # on runtime check - - identifier: deadCode.unreachable - paths: - - src/Console/Notifier.php - - src/Util/FileHasher.php + identifier: argument.type + message: '#Parameter \#1 \$phpVersion of method Rector\\Config\\RectorConfig\:\:phpVersion\(\) expects 50200\|50300\|50400\|50500\|50600\|70000\|70100\|70200\|70300\|70400\|80000\|80100\|80200\|80300\|80400\|80500\|80600\|100000, 79999 given#' - # deliberately kept out of the php81 set, as it fires too often to be applied by default; - # it stays available to register directly with withRules() + # node vs stmts mix - - identifier: rector.upgradeDowngradeRegisteredInSet - path: rules/Php81/Rector/FuncCall/NullToStrictStringFuncCallArgRector.php + identifier: argument.type + message: '#expects array, array given#' - # deprecated rules, kept out of the php sets, as they turn a doc annotation into a runtime deprecation + # false positive, can accept non-class string - - identifier: rector.upgradeDowngradeRegisteredInSet - path: rules/Php84/Rector/Class_/DeprecatedAnnotationToDeprecatedAttributeRector.php + identifier: argument.type + message: '#Parameter \#1 \$name of method PHPStan\\BetterReflection\\Reflection\\Adapter\\ReflectionClass\:\:getAttributes\(\) expects class\-string\|null, string given#' + # false positive, checked above - - identifier: rector.upgradeDowngradeRegisteredInSet - path: rules/Php85/Rector/Const_/ConstAndTraitDeprecatedAttributeRector.php + identifier: argument.type + message: '#Parameter \#1 \$items of class PhpParser\\Node\\Expr\\Array_ constructor expects array, array given#' + path: rules/Php71/Rector/List_/ListToArrayDestructRector.php - # is nested expr - - message: '#Access to an undefined property PhpParser\\Node\\Expr\:\:\$expr#' - path: rules/DeadCode/NodeManipulator/LivingCodeManipulator.php + identifier: argument.type + message: '#Parameter \#3 \$assign of method Rector\\CodeQuality\\Rector\\FunctionLike\\SimplifyUselessVariableRector\:\:processSimplifyUselessVariable\(\) expects PhpParser\\Node\\Expr\\Assign\|PhpParser\\Node\\Expr\\AssignOp, PhpParser\\Node\\Expr given#' + path: rules/CodeQuality/Rector/FunctionLike/SimplifyUselessVariableRector.php - # know type + # scope vs mutating scope - - message: '#Access to an undefined property PhpParser\\Node\:\:\$expr#' - path: src/PhpParser/Printer/BetterStandardPrinter.php + identifier: argument.type + message: '#Parameter \#3 \$nodeCallback of method PHPStan\\Analyser\\NodeScopeResolver\:\:processNodes\(\) expects callable\(PhpParser\\Node, PHPStan\\Analyser\\Scope\)\: void, callable\(PhpParser\\Node, PHPStan\\Analyser\\MutatingScope\)\: void given#' + # list vs array - - message: '#Function "var_dump\(\)" cannot be used/left in the code#' - path: src/functions/node_helper.php + identifier: argument.type + message: '#Parameter (.*?) expects list<(.*?)>, array<(.*?)> given#' - - message: '#Function "class_exists\(\)" cannot be used/left in the code#' - path: src/Configuration/OnlyRuleResolver.php - - # lack of generic array in nikic/php-parser - - '#Method (.*?) should return array but returns array#' + identifier: argument.type + paths: + - rules/Privatization/TypeManipulator/TypeNormalizer.php + - rules/TypeDeclaration/Rector/FunctionLike/AddClosureParamTypeForArrayReduceRector.php + - rules/TypeDeclarationDocblocks/Rector/Class_/AddVarArrayDocblockFromDimFetchAssignRector.php + - src/NodeTypeResolver/PHPStan/Type/TypeFactory.php - # generics nullable bugs - - message: '#Method (.*?) should return (.*?)\|null but returns PhpParser\\Node\|null#' - path: src/PhpParser/Node/BetterNodeFinder.php + identifier: arguments.count + message: '#Callable callable\(PHPStan\\Type\\Type\)\: PHPStan\\Type\\Type invoked with 2 parameters, 1 required#' + # classes are part of *.php.inc fixture - - message: '#Function "property_exists\(\)" cannot be used/left in the code#' + identifier: class.notFound + message: '#Class (.*?) not found#' paths: - # on PhpParser Nodes - - src/NodeNameResolver/NodeNameResolver.php - - src/BetterPhpDocParser/PhpDocParser/BetterPhpDocParser.php - - src/BetterPhpDocParser/PhpDocParser/DoctrineAnnotationDecorator.php - - - '#(.*?) class\-string, string given#' + - rules-tests/Arguments/Rector/ClassMethod/ReplaceArgumentDefaultValueRector/config + - rules-tests/TypeDeclaration/Rector/ClassMethod/AddReturnTypeDeclarationRector/config + - rules-tests/Renaming/Rector/Name/RenameClassRector/config + - rules-tests/Renaming/Rector/MethodCall/RenameMethodRector/config + - rules-tests/Arguments/Rector/ClassMethod/ArgumentAdderRector/config - - message: '#Use explicit return value over magic &reference#' + identifier: deadCode.unreachable paths: - - src/PhpDocParser/PhpDocParser/PhpDocNodeTraverser.php - - rules/Php70/EregToPcreTransformer.php - - src/BetterPhpDocParser/PhpDocManipulator/PhpDocClassRenamer.php - - src/NodeTypeResolver/PHPStan/Type/TypeFactory.php + - src/Console/Notifier.php + - src/Util/FileHasher.php - - '#Method Rector\\Arguments\\ArgumentDefaultValueReplacer\:\:processReplaces\(\) should return \(TCall of PhpParser\\Node\\Expr\\FuncCall\|PhpParser\\Node\\Expr\\MethodCall\|PhpParser\\Node\\Expr\\New_\|PhpParser\\Node\\Expr\\StaticCall\|PhpParser\\Node\\Stmt\\ClassMethod\)\|null but returns PhpParser\\Node\\Stmt\\ClassMethod\|null#' + # stmts aware/expression generics + - + identifier: generics.notGeneric + message: '#PhpParser\\Node\\Stmt\\Expression is not generic#' - # native filesystem calls, required for performance reasons + # runtime php id - - message: '#@(.*?) is forbidden to use#' - paths: - - src/Caching/ValueObject/Storage/FileCacheStorage.php + identifier: greaterOrEqual.alwaysTrue + path: src/Util/FileHasher.php - # many internal cases - - '#Calling (.*?) is not covered by backward compatibility promise\. The method might change in a minor PHPStan version#' + # runtime comparison + - + identifier: greaterOrEqual.alwaysTrue + message: '#Comparison operation ".*" between int<\d+, \d+> and \d+ is always true#' # known value object, nullable due to typed property - + identifier: method.nonObject message: '#Cannot call method (.*?)\(\) on (.*?)\\ProcessPool\|null#' path: src/Parallel/Application/ParallelFileProcessor.php - # internal reflection - - '#Instead of "new ClassReflection\(\)" use ReflectionProvider service or "\(new PHPStan\\Reflection\\ClassReflection\(\)\)" for static reflection to work#' - - '#Callable callable\(PHPStan\\Type\\Type\)\: PHPStan\\Type\\Type invoked with 2 parameters, 1 required#' - - # known value - - '#Method (.*?) should return 50200\|50300\|50400\|50500\|50600\|70000\|70100\|70200\|70300\|70400\|80000\|80100\|80200\|80300\|80400\|80500\|80600\|100000 but returns int#' - - - message: '#Function "class_exists\(\)" cannot be used/left in the code#' - paths: - # autoload check in bin file - - bin/rector.php - # for config class reflection - - src/Bootstrap/ExtensionConfigResolver.php - - src/Validation/RectorConfigValidator.php - # for phpunit version check - - src/Testing/PHPUnit/AbstractLazyTestCase.php - # future node class exists check - - src/Reporting/DeprecatedRulesReporter.php + identifier: missingType.callable + message: '#Method Rector\\Util\\ArrayParametersMerger\:\:mergeLeftToRightWithCallable\(\) has parameter \$mergeCallback with no signature specified for callable#' + path: src/Util/ArrayParametersMerger.php + # required generics on interface array, not helpful - - message: '#@\\ini_set\(.*\)" is forbidden to use#' - path: bin/rector.php + identifier: missingType.generics + message: '#Method (.*?)\:\:__construct\(\) has parameter#' - # known existing class - - message: '#Instead of "instanceof/is_a\(\)" use ReflectionProvider service or "\(new ObjectType\(\)\)\->isSuperTypeOf\(\)" for static reflection to work#' - path: src/Skipper/Skipper/SkipSkipper.php - - # the local instanceof for known types - - '#Instead of "instanceof/is_a\(\)" use ReflectionProvider service or "\(new ObjectType\(\)\)\->isSuperTypeOf\(\)" for static reflection to work#' + identifier: missingType.generics + message: '#(.*?) with generic interface (.*?)Interface does not specify its types#' - # required for reflection + # generated class in /vendor - - message: '#Function "(.*?)\(\)" cannot be used/left in the code#' - path: src/Util/Reflection/PrivatesAccessor.php + identifier: nullCoalesce.offset + message: '#Offset (.*?) on null on left side of \?\? does not exist#' + path: src/Bootstrap/ExtensionConfigResolver.php + # false positive - - message: '#Method Rector\\Util\\ArrayParametersMerger\:\:mergeLeftToRightWithCallable\(\) has parameter \$mergeCallback with no signature specified for callable#' - path: src/Util/ArrayParametersMerger.php + identifier: offsetAccess.invalidOffset + path: src/CustomRules/SimpleNodeDumper.php - # fixture Rector rules - - identifier: symplify.seeAnnotationToTest - path: tests/Issues/ + identifier: offsetAccess.nonArray + path: src/PhpParser/NodeTraverser/RectorNodeTraverser.php - # classes are part of *.php.inc fixture + # known non-empty class method - - message: '#Class (.*?) not found#' - paths: - - rules-tests/Arguments/Rector/ClassMethod/ReplaceArgumentDefaultValueRector/config - - rules-tests/TypeDeclaration/Rector/ClassMethod/AddReturnTypeDeclarationRector/config - - rules-tests/Renaming/Rector/Name/RenameClassRector/config - - rules-tests/Renaming/Rector/MethodCall/RenameMethodRector/config - - rules-tests/Arguments/Rector/ClassMethod/ArgumentAdderRector/config + identifier: offsetAccess.notFound + message: '#Offset 0 might not exist on array\|null#' + path: rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php - - message: '#Function "(function_exists|dump_node)\(\)" cannot be used/left in the code#' - path: src/functions/node_helper.php + identifier: offsetAccess.notFound + message: '#Offset float\|int\|string might not exist on string#' + path: rules/Php70/EregToPcreTransformer.php - # stmts aware/expression generics - - '#PhpParser\\Node\\Stmt\\Expression is not generic#' + # phpstan internalls + - identifier: phpstanApi.class + - identifier: phpstanApi.classConstant + - identifier: phpstanApi.constructor + - identifier: phpstanApi.instanceofAssumption + - identifier: phpstanApi.method - # chicken/egg + # buggy, # see https://github.com/rectorphp/rector-src/actions/runs/11798721617/job/32865546672?pr=6422#step:5:110 - - message: '#Function "(d|dd)\(\)" cannot be used/left in the code#' - path: tests/debug_functions.php + identifier: phpstanApi.instanceofType + message: '#Doing instanceof PHPStan\\Type\\.+ is error\-prone and deprecated#' - # debug functions + # is nested expr - - message: '#Function "function_exists\(\)" cannot be used/left in the code\: use ReflectionProvider\->has\*\(\) instead#' - path: tests/debug_functions.php + identifier: property.notFound + paths: + - rules/DeadCode/NodeManipulator/LivingCodeManipulator.php + - src/PhpParser/Printer/BetterStandardPrinter.php + - src/CustomRules/SimpleNodeDumper.php - # checks for rector always autoloaded rules only - - message: '#Function "(class_exists|interface_exists)\(\)" cannot be used/left in the code\: use ReflectionProvider\->has\*\(\) instead#' - path: src/Skipper/SkipCriteriaResolver/SkippedClassResolver.php - - # dev rule - - '#Class "Rector\\Utils\\Rector\\MoveAbstractRectorToChildrenRector" is missing @see annotation with test case class reference#' - - # optional as changes behavior, should be used explicitly outside PHP upgrade - - '#Register "Rector\\Php73\\Rector\\FuncCall\\JsonThrowOnErrorRector" service to "php73\.php" config set#' - - '#Register "Rector\\Php80\\Rector\\NotIdentical\\MbStrContainsRector" service to "php80\.php" config set#' - - '#Register "Rector\\Php85\\Rector\\StmtsAwareInterface\\SequentialAssignmentsToPipeOperatorRector" service to "php85\.php" config set#' - - '#Register "Rector\\Php85\\Rector\\Expression\\NestedFuncCallsToPipeOperatorRector" service to "php85\.php" config set#' - - '#Register "Rector\\Php84\\Rector\\Class_\\PropertyHookRector" service to "php84\.php" config set#' + identifier: rector.noClassReflectionStaticReflection + paths: + - scripts + - src/Configuration/OnlyRuleResolver.php + - src/Util/Reflection/PrivatesAccessor.php - # closure detailed - - '#Method Rector\\Config\\RectorConfig\:\:singleton\(\) has parameter \$concrete with no signature specified for Closure#' + # the local instanceof for known types + - + identifier: rector.noInstanceOfStaticReflection + message: '#Instead of "instanceof/is_a\(\)" use ReflectionProvider service or "\(new ObjectType\(\)\)\->isSuperTypeOf\(\)" for static reflection to work#' - # dynamic printer + # outside sets on purpose, as risky - - message: '#Use explicit names over dynamic ones#' - paths: - - src/CustomRules/SimpleNodeDumper.php - - src/PhpDocParser/PhpDocParser/PhpDocNodeTraverser.php + identifier: rector.upgradeDowngradeRegisteredInSet + paths: + - rules/Php81/Rector/FuncCall/NullToStrictStringFuncCallArgRector.php + - rules/Php80/Rector/NotIdentical/MbStrContainsRector.php - # known node variables + # lack of generic array in nikic/php-parser - - message: '#Access to an undefined property PhpParser\\Node\\Scalar\:\:\$value#' - path: src/CustomRules/SimpleNodeDumper.php + identifier: return.type + message: '#Method (.*?) should return array but returns array#' + # generics nullable bugs - - message: '#Avoid static access of constants, as they can change value\. Use interface and contract method instead#' + identifier: return.type paths: - # caching and message of specific child Rector rules - - src/Rector/AbstractRector.php - - src/PostRector/Rector/AbstractPostRector.php - # for cache - - src/Testing/PHPUnit/AbstractRectorTestCase.php + - src/PhpParser/Node/BetterNodeFinder.php + - rules/DeadCode/Rector/Class_/RemoveRefactorDuplicatedNodeInstanceCheckRector.php - # generated class in /vendor + # known value - - message: '#Offset (.*?) on null on left side of \?\? does not exist#' - path: src/Bootstrap/ExtensionConfigResolver.php + identifier: return.type + message: '#Method (.*?) should return 50200\|50300\|50400\|50500\|50600\|70000\|70100\|70200\|70300\|70400\|80000\|80100\|80200\|80300\|80400\|80500\|80600\|100000 but returns int#' - # wider types for external use + # from constant string - - message: '#Parameters should have "PhpParser\\Node\\Stmt\\ClassMethod" types as the only types passed to this method#' - path: src/Reflection/ClassModifierChecker.php + identifier: return.type + message: '#Method Rector\\.*::filterPolyfillPackages\(\) should return array\<#' - # false positive - should be fixed - - - message: '#Parameters should have "PhpParser\\Node\\Expr\\Closure" types as the only types passed to this method#' - - message: '#Parameters should have "PhpParser\\Node\\Stmt\\ClassMethod" types as the only types passed to this method#' + identifier: return.type paths: - - src/VendorLocker/ParentClassMethodTypeOverrideGuard.php - - # more advanced usage, but not always working - # see https://github.com/rectorphp/rector-src/actions/runs/11798721617/job/32865546672?pr=6422#step:5:110 - - '#Doing instanceof PHPStan\\Type\\.+ is error\-prone and deprecated#' + - src/NodeTypeResolver/PHPStan/Type/TypeFactory.php + - rules/Arguments/ArgumentDefaultValueReplacer.php - # allowed internally only - - message: '#Fetching (deprecated )?class constant (.*?) of (deprecated )?class (Rector\\Set\\ValueObject\\DowngradeLevelSetList|Rector\\Symfony\\Set\\(.*?))#' - path: src/Configuration/RectorConfigBuilder.php + identifier: return.type + message: '#should return non\-empty\-string but returns string#' - # the deprecated set objects are still resolved internally, until every extension bonds its rules + # from mapper interface - - message: '#deprecated (class|interface) Rector\\(Set|Bridge)\\#' - paths: - - src/Set/SetManager.php - - src/Bridge/SetProviderCollector.php - - src/Configuration/RectorConfigBuilder.php - - tests/Set/ValueObject/ComposerTriggeredSetTest.php - - tests/Set/SetManager/SetManagerTest.php + identifier: return.unusedType + message: '#mapToPhpParserNode\(\) never returns PhpParser\\.* so it can be removed from the return#' - # runtime comparison - - '#Comparison operation ".*" between int<\d+, \d+> and \d+ is always true#' + # false positive + - + identifier: return.unusedType + message: '#Method (.*?)refactor\(\) (never returns|should return) (.*?)#' + path: rules/Php70/Rector/If_/IfToSpaceshipRector.php - # from mapper interface - - '#mapToPhpParserNode\(\) never returns PhpParser\\.* so it can be removed from the return#' + - + identifier: symplify.forbiddenFuncCall + message: '#Function "var_dump\(\)" cannot be used/left in the code#' + path: src/functions/node_helper.php - # from constant string - - '#Method Rector\\.*::filterPolyfillPackages\(\) should return array\<#' + - + identifier: symplify.forbiddenFuncCall + message: '#Function "class_exists\(\)" cannot be used/left in the code#' + path: src/Configuration/OnlyRuleResolver.php - - identifier: typePerfect.noMixedMethodCaller + identifier: symplify.forbiddenFuncCall + message: '#Function "property_exists\(\)" cannot be used/left in the code#' paths: - - src/PhpParser/Parser/RectorParser.php + - src/NodeNameResolver/NodeNameResolver.php + - src/BetterPhpDocParser/PhpDocParser/BetterPhpDocParser.php + - src/BetterPhpDocParser/PhpDocParser/DoctrineAnnotationDecorator.php - - path: src/NodeTypeResolver/PHPStan/Type/TypeFactory.php - message: '#Method Rector\\NodeTypeResolver\\PHPStan\\Type\\TypeFactory\:\:uniquateTypes\(\) should return array but returns list#' + identifier: symplify.forbiddenFuncCall + message: '#Function "class_exists\(\)" cannot be used/left in the code#' + paths: + - bin/rector.php + - src/Bootstrap/ExtensionConfigResolver.php + - src/Validation/RectorConfigValidator.php + - src/Testing/PHPUnit/AbstractLazyTestCase.php + - src/Reporting/DeprecatedRulesReporter.php - # known types + # required for reflection - - message: '#PHPDoc tag @var with type array is not subtype of native type array>#' - path: rules/Naming/PhpArray/ArrayFilter.php - - - '#Parameter \#1 \$phpVersion of method Rector\\Config\\RectorConfig\:\:phpVersion\(\) expects 50200\|50300\|50400\|50500\|50600\|70000\|70100\|70200\|70300\|70400\|80000\|80100\|80200\|80300\|80400\|80500\|80600\|100000, 79999 given#' - - # node vs stmts mix - - '#expects array, array given#' - - '#should return non\-empty\-string but returns string#' + identifier: symplify.forbiddenFuncCall + message: '#Function "(.*?)\(\)" cannot be used/left in the code#' + path: src/Util/Reflection/PrivatesAccessor.php - # known non-empty class method - - message: '#Offset 0 might not exist on array\|null#' - path: rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php - - # false positive, can accept non-class string - - '#Parameter \#1 \$name of method PHPStan\\BetterReflection\\Reflection\\Adapter\\ReflectionClass\:\:getAttributes\(\) expects class\-string\|null, string given#' + identifier: symplify.forbiddenFuncCall + message: '#Function "(function_exists|dump_node)\(\)" cannot be used/left in the code#' + path: src/functions/node_helper.php - # false positive, checked above - - - path: rules/Php71/Rector/List_/ListToArrayDestructRector.php - message: '#Parameter \#1 \$items of class PhpParser\\Node\\Expr\\Array_ constructor expects array, array given#' + # chicken/egg - - path: rules/CodeQuality/Rector/FunctionLike/SimplifyUselessVariableRector.php - message: '#Parameter \#3 \$assign of method Rector\\CodeQuality\\Rector\\FunctionLike\\SimplifyUselessVariableRector\:\:processSimplifyUselessVariable\(\) expects PhpParser\\Node\\Expr\\Assign\|PhpParser\\Node\\Expr\\AssignOp, PhpParser\\Node\\Expr given#' + identifier: symplify.forbiddenFuncCall + message: '#Function "(d|dd)\(\)" cannot be used/left in the code#' + path: tests/debug_functions.php - # scope vs mutating scope - - '#Parameter \#3 \$nodeCallback of method PHPStan\\Analyser\\NodeScopeResolver\:\:processNodes\(\) expects callable\(PhpParser\\Node, PHPStan\\Analyser\\Scope\)\: void, callable\(PhpParser\\Node, PHPStan\\Analyser\\MutatingScope\)\: void given#' + # debug functions + - + identifier: symplify.forbiddenFuncCall + message: '#Function "function_exists\(\)" cannot be used/left in the code\: use ReflectionProvider\->has\*\(\) instead#' + path: tests/debug_functions.php - # list vs array - - '#Parameter (.*?) expects list<(.*?)>, array<(.*?)> given#' + # checks for rector always autoloaded rules only + - + identifier: symplify.forbiddenFuncCall + message: '#Function "(class_exists|interface_exists)\(\)" cannot be used/left in the code\: use ReflectionProvider\->has\*\(\) instead#' + path: src/Skipper/SkipCriteriaResolver/SkippedClassResolver.php - - identifier: symplify.noConstructorOverride - path: src/StaticTypeMapper/ValueObject/Type/SimpleStaticType.php + # native filesystem calls, required for performance reasons + - + identifier: symplify.forbiddenNode + message: '#@(.*?) is forbidden to use#' + path: src/Caching/ValueObject/Storage/FileCacheStorage.php - - identifier: arrayValues.list - path: rules/CodingStyle/Application/UseImportsAdder.php + identifier: symplify.forbiddenNode + message: '#@\\ini_set\(.*\)" is forbidden to use#' + path: bin/rector.php - - message: '#Offset float\|int\|string might not exist on string#' - path: rules/Php70/EregToPcreTransformer.php + identifier: symplify.forbiddenStaticClassConstFetch + message: '#Avoid static access of constants, as they can change value\. Use interface and contract method instead#' + paths: + - src/PostRector/Rector/AbstractPostRector.php + - src/Testing/PHPUnit/AbstractRectorTestCase.php - - identifier: symplify.noReference - message: '#Use explicit return value over magic &reference#' + identifier: symplify.forbiddenStaticClassConstFetch + path: src/Rector/AbstractRector.php - # false positive - - identifier: offsetAccess.invalidOffset - path: src/CustomRules/SimpleNodeDumper.php + identifier: symplify.noConstructorOverride + path: src/StaticTypeMapper/ValueObject/Type/SimpleStaticType.php - - '#Method Rector\\DeadCode\\Rector\\Class_\\RemoveRefactorDuplicatedNodeInstanceCheckRector\:\:getInstanceofNodeClass\(\) should return class\-string\|null but returns class\-string#' + # dynamic printer + - + identifier: symplify.noDynamicName + message: '#Use explicit names over dynamic ones#' + paths: + - src/CustomRules/SimpleNodeDumper.php + - src/PhpDocParser/PhpDocParser/PhpDocNodeTraverser.php # copied from /vendor, to keep as original as possible - identifier: symplify.noDynamicName path: src/PhpParser/NodeTraverser/RectorNodeTraverser.php - - - identifier: offsetAccess.nonArray - path: src/PhpParser/NodeTraverser/RectorNodeTraverser.php - # variable is expected in included/required file - - identifier: closure.unusedUse - message: '#Anonymous function has an unused use \$container#' + identifier: symplify.noReference + message: '#Use explicit return value over magic &reference#' paths: - - src/Autoloading/BootstrapFilesIncluder.php + - src/PhpDocParser/PhpDocParser/PhpDocNodeTraverser.php + - rules/Php70/EregToPcreTransformer.php + - src/BetterPhpDocParser/PhpDocManipulator/PhpDocClassRenamer.php + - src/NodeTypeResolver/PHPStan/Type/TypeFactory.php - # false positive - - message: '#Method (.*?)refactor\(\) (never returns|should return) (.*?)#' - paths: - - rules/Php70/Rector/If_/IfToSpaceshipRector.php + identifier: symplify.noReference + message: '#Use explicit return value over magic &reference#' + # fixture Rector rules - - identifier: rector.noIntegerRefactorReturn - paths: - # valid, as use REMOVE_NODE - - rules/DeadCode/Rector/Expression/RemoveDeadStmtRector.php - - rules/DeadCode/Rector/If_/RemoveDeadInstanceOfRector.php - - rules/DeadCode/Rector/ConstFetch/RemovePhpVersionIdCheckRector.php - - rules/DeadCode/Rector/If_/UnwrapFutureCompatibleIfPhpVersionRector.php + identifier: symplify.seeAnnotationToTest + path: tests/Issues/ - # deprecated + # dev rule - - identifier: public.method.unused - paths: - - rules/CodeQuality/ValueObject/KeyAndExpr.php + identifier: symplify.seeAnnotationToTest + message: '#Class "Rector\\Utils\\Rector\\MoveAbstractRectorToChildrenRector" is missing @see annotation with test case class reference#' - - identifier: public.classConstant.unused - paths: - - rules/Php55/Rector/String_/StringClassNameToClassConstantRector.php - - rules/Php81/Enum/AttributeName.php + identifier: symplify.seeAnnotationToTest + path: tests/PhpParser/NodeTraverser/StopTraverseOnTypeChange/Class_ + # wider types for external use - - identifier: symplify.seeAnnotationToTest - paths: - - tests/PhpParser/NodeTraverser/StopTraverseOnTypeChange/Class_ - - # deprecated rule - - '#Register "Rector\\Php70\\Rector\\StaticCall\\StaticCallOnNonStaticToInstanceCallRector" service to "php70\.php" config set#' - - '#Class "Rector\\Php70\\Rector\\StaticCall\\StaticCallOnNonStaticToInstanceCallRector" is missing @see annotation with test case class reference#' - - '#Class "Rector\\TypeDeclaration\\Rector\\ClassMethod\\StrictStringParamConcatRector" is missing @see annotation with test case class reference#' - - '#Class "Rector\\CodingStyle\\Rector\\Enum_\\EnumCaseToPascalCaseRector" is missing @see annotation with test case class reference#' - - '#Class "Rector\\CodeQuality\\Rector\\Concat\\JoinStringConcatRector" is missing @see annotation with test case class reference#' - - '#Class "Rector\\CodeQuality\\Rector\\Switch_\\SwitchTrueToIfRector" is missing @see annotation with test case class reference#' - - '#Class "Rector\\TypeDeclarationDocblocks\\Rector\\ClassMethod\\AddReturnDocblockForDimFetchArrayFromAssignsRector" is missing @see annotation with test case class reference#' - - '#Class "Rector\\Assert\\Rector\\ClassMethod\\AddAssertArrayFromClassMethodDocblockRector" is missing @see annotation with test case class reference#' - - '#Class "Rector\\TypeDeclarationDocblocks\\Rector\\ClassMethod\\AddParamArrayDocblockBasedOnArrayMapRector" is missing @see annotation with test case class reference#' - - '#Class "Rector\\TypeDeclaration\\Rector\\ClassMethod\\AddReturnArrayDocblockBasedOnArrayMapRector" is missing @see annotation with test case class reference#' - - '#Class "Rector\\Transform\\Rector\\FuncCall\\FuncCallToMethodCallRector" is missing @see annotation with test case class reference#' - - '#Class "Rector\\Transform\\Rector\\Scalar\\ScalarValueToConstFetchRector" is missing @see annotation with test case class reference#' - - '#Class "Rector\\DeadCode\\Rector\\ClassLike\\RemoveAnnotationRector" is missing @see annotation with test case class reference#' - - '#Class "Rector\\Transform\\Rector\\Class_\\AddInterfaceByTraitRector" is missing @see annotation with test case class reference#' - - '#Class "Rector\\Php84\\Rector\\Class_\\DeprecatedAnnotationToDeprecatedAttributeRector" is missing @see annotation with test case class reference#' - - '#Class "Rector\\Php85\\Rector\\Const_\\ConstAndTraitDeprecatedAttributeRector" is missing @see annotation with test case class reference#' - - # @todo fix in phpstan-rules - - - identifier: symplify.noMissnamedDocTag - path: rules/TypeDeclarationDocblocks/TypeResolver/ConstantArrayTypeGeneralizer.php + identifier: typePerfect.narrowPublicClassMethodParamType + message: '#Parameters should have "PhpParser\\Node\\Stmt\\ClassMethod" types as the only types passed to this method#' + path: src/Reflection/ClassModifierChecker.php + # false positive - should be fixed - - identifier: varTag.nativeType - path: src/BetterPhpDocParser/PhpDocParser/StaticDoctrineAnnotationParser.php + identifier: typePerfect.narrowPublicClassMethodParamType + message: '#Parameters should have "PhpParser\\Node\\Expr\\Closure" types as the only types passed to this method#' - - identifier: argument.type - paths: - - rules/Privatization/TypeManipulator/TypeNormalizer.php - - rules/TypeDeclaration/Rector/FunctionLike/AddClosureParamTypeForArrayMapRector.php - - rules/TypeDeclaration/Rector/FunctionLike/AddClosureParamTypeForArrayReduceRector.php - - rules/TypeDeclarationDocblocks/Rector/Class_/AddVarArrayDocblockFromDimFetchAssignRector.php - - src/NodeTypeResolver/PHPStan/Type/TypeFactory.php + identifier: typePerfect.narrowPublicClassMethodParamType + message: '#Parameters should have "PhpParser\\Node\\Stmt\\ClassMethod" types as the only types passed to this method#' + path: src/VendorLocker/ParentClassMethodTypeOverrideGuard.php - - identifier: argument.templateType - paths: - - rules/TypeDeclaration/Rector/FunctionLike/AddClosureParamTypeForArrayMapRector.php - - rules/TypeDeclaration/Rector/FunctionLike/AddClosureParamTypeForArrayReduceRector.php + identifier: typePerfect.narrowReturnObjectType + message: '#Provide more specific return type "Iterator|PhpParser\\Node" over abstract one#' - - '#Provide more specific return type "Iterator|PhpParser\\Node" over abstract one#' + - + identifier: typePerfect.noMixedMethodCaller + path: src/PhpParser/Parser/RectorParser.php - # BC layer + # known types - - message: '#Access to deprecated property \$file of class Rector\\Rector\\AbstractRector#' - path: src/Rector/AbstractRector.php + identifier: varTag.nativeType + message: '#PHPDoc tag @var with type array is not subtype of native type array>#' + path: rules/Naming/PhpArray/ArrayFilter.php - # allowed - - message: '#"@\\simplexml_load_string\(\$junitXml\)" is forbidden to use#' - path: scripts/remove-unused-deps.php + identifier: varTag.nativeType + path: src/BetterPhpDocParser/PhpDocParser/StaticDoctrineAnnotationParser.php diff --git a/rules-tests/DeadCode/Rector/Expression/RemoveDeadStmtRector/Fixture/skip_pipe_operator.php.inc b/rules-tests/DeadCode/Rector/Expression/RemoveDeadStmtRector/FixturePhp85/skip_pipe_operator.php.inc similarity index 100% rename from rules-tests/DeadCode/Rector/Expression/RemoveDeadStmtRector/Fixture/skip_pipe_operator.php.inc rename to rules-tests/DeadCode/Rector/Expression/RemoveDeadStmtRector/FixturePhp85/skip_pipe_operator.php.inc diff --git a/rules-tests/DeadCode/Rector/Expression/RemoveDeadStmtRector/Fixture/skip_void_cast.php.inc b/rules-tests/DeadCode/Rector/Expression/RemoveDeadStmtRector/FixturePhp85/skip_void_cast.php.inc similarity index 100% rename from rules-tests/DeadCode/Rector/Expression/RemoveDeadStmtRector/Fixture/skip_void_cast.php.inc rename to rules-tests/DeadCode/Rector/Expression/RemoveDeadStmtRector/FixturePhp85/skip_void_cast.php.inc diff --git a/rules-tests/DeadCode/Rector/Expression/RemoveDeadStmtRector/RemoveDeadStmtRectorTest.php b/rules-tests/DeadCode/Rector/Expression/RemoveDeadStmtRector/RemoveDeadStmtRectorTest.php index 4f15ac9fd92..6024095d54a 100644 --- a/rules-tests/DeadCode/Rector/Expression/RemoveDeadStmtRector/RemoveDeadStmtRectorTest.php +++ b/rules-tests/DeadCode/Rector/Expression/RemoveDeadStmtRector/RemoveDeadStmtRectorTest.php @@ -6,6 +6,7 @@ use Iterator; use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\RequiresPhp; use Rector\Testing\PHPUnit\AbstractRectorTestCase; final class RemoveDeadStmtRectorTest extends AbstractRectorTestCase @@ -13,16 +14,6 @@ final class RemoveDeadStmtRectorTest extends AbstractRectorTestCase #[DataProvider('provideData')] public function test(string $filePath): void { - if ( - ( - str_ends_with($filePath, 'skip_pipe_operator.php.inc') - || - str_ends_with($filePath, 'skip_void_cast.php.inc') - ) - && PHP_VERSION_ID < 80500) { - $this->markTestSkipped('test contains php 8.5 syntax early before transformation'); - } - $this->doTestFile($filePath); } @@ -31,6 +22,18 @@ public static function provideData(): Iterator return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); } + #[RequiresPhp('>= 8.5.0')] + #[DataProvider('provideDataPhp85')] + public function testPhp85(string $filePath): void + { + $this->doTestFile($filePath); + } + + public static function provideDataPhp85(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/FixturePhp85'); + } + #[DataProvider('provideDataForTestKeepComments')] public function testKeepComments(string $filePath): void { diff --git a/rules-tests/TypeDeclaration/Rector/Function_/AddFunctionVoidReturnTypeWhereNoReturnRector/Fixture/some_function.php.inc b/rules-tests/TypeDeclaration/Rector/Function_/AddFunctionVoidReturnTypeWhereNoReturnRector/Fixture/some_function.php.inc index ed413fe5b16..e6354cf821d 100644 --- a/rules-tests/TypeDeclaration/Rector/Function_/AddFunctionVoidReturnTypeWhereNoReturnRector/Fixture/some_function.php.inc +++ b/rules-tests/TypeDeclaration/Rector/Function_/AddFunctionVoidReturnTypeWhereNoReturnRector/Fixture/some_function.php.inc @@ -1,6 +1,6 @@ + * @return mixed[] */ public function resolveFromStmtsAndVariable(array $stmts, ?Assign $emptyArrayAssign): array { diff --git a/rules/CodeQuality/ValueObject/KeyAndExpr.php b/rules/CodeQuality/ValueObject/KeyAndExpr.php deleted file mode 100644 index d1d9a79ba3b..00000000000 --- a/rules/CodeQuality/ValueObject/KeyAndExpr.php +++ /dev/null @@ -1,39 +0,0 @@ -keyExpr; - } - - public function getExpr(): Expr - { - return $this->expr; - } - - /** - * @return Comment[] - */ - public function getComments(): array - { - return $this->comments; - } -} diff --git a/rules/DeadCode/Rector/Class_/RemoveRefactorDuplicatedNodeInstanceCheckRector.php b/rules/DeadCode/Rector/Class_/RemoveRefactorDuplicatedNodeInstanceCheckRector.php index 4308015a630..dd61e5f73e2 100644 --- a/rules/DeadCode/Rector/Class_/RemoveRefactorDuplicatedNodeInstanceCheckRector.php +++ b/rules/DeadCode/Rector/Class_/RemoveRefactorDuplicatedNodeInstanceCheckRector.php @@ -179,7 +179,6 @@ private function getInstanceofNodeClass(Instanceof_ $instanceof): ?string /** @var ClassReflection $classReflection */ $classReflection = $checkedClassType->getClassReflection(); - if (! $classReflection->is(Node::class)) { return null; } diff --git a/rules/DeadCode/Rector/ConstFetch/RemovePhpVersionIdCheckRector.php b/rules/DeadCode/Rector/ConstFetch/RemovePhpVersionIdCheckRector.php index 4ed4a62f3e2..82e237461b1 100644 --- a/rules/DeadCode/Rector/ConstFetch/RemovePhpVersionIdCheckRector.php +++ b/rules/DeadCode/Rector/ConstFetch/RemovePhpVersionIdCheckRector.php @@ -16,7 +16,6 @@ use PhpParser\NodeVisitor; use Rector\Php\PhpVersionProvider; use Rector\Rector\AbstractRector; -use Rector\ValueObject\PhpVersion; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -25,15 +24,9 @@ */ final class RemovePhpVersionIdCheckRector extends AbstractRector { - /** - * @var PhpVersion::*|null - */ - private int|null $phpVersion; - public function __construct( private readonly PhpVersionProvider $phpVersionProvider, ) { - $this->phpVersion = $this->phpVersionProvider->provide(); } public function getRuleDefinition(): RuleDefinition @@ -84,8 +77,6 @@ public function getNodeTypes(): array */ public function refactor(Node $node): null|array|int { - $this->phpVersion ??= $this->phpVersionProvider->provide(); - if (! $node->cond instanceof BinaryOp) { return null; } @@ -151,7 +142,7 @@ private function refactorSmallerLeft(Smaller $smaller): ?int return null; } - if ($this->phpVersion >= $value->value) { + if ($this->phpVersionProvider->provide() >= $value->value) { return NodeVisitor::REMOVE_NODE; } @@ -168,7 +159,7 @@ private function refactorSmallerRight(Smaller $smaller, If_ $if): null|array|int return null; } - if ($this->phpVersion < $value->value) { + if ($this->phpVersionProvider->provide() < $value->value) { return null; } @@ -189,7 +180,7 @@ private function refactorGreaterOrEqualLeft(GreaterOrEqual $greaterOrEqual, If_ return null; } - if ($this->phpVersion < $value->value) { + if ($this->phpVersionProvider->provide() < $value->value) { return null; } @@ -210,7 +201,7 @@ private function refactorGreaterOrEqualRight(GreaterOrEqual $greaterOrEqual): ?i return null; } - if ($this->phpVersion >= $value->value) { + if ($this->phpVersionProvider->provide() >= $value->value) { return NodeVisitor::REMOVE_NODE; } @@ -243,7 +234,7 @@ private function refactorGreaterLeft(Greater $greater, If_ $if): null|array|int return null; } - if ($this->phpVersion < $value->value) { + if ($this->phpVersionProvider->provide() < $value->value) { return null; } @@ -264,7 +255,7 @@ private function refactorGreaterRight(Greater $greater): ?int return null; } - if ($this->phpVersion >= $value->value) { + if ($this->phpVersionProvider->provide() >= $value->value) { return NodeVisitor::REMOVE_NODE; } diff --git a/rules/Php55/Rector/String_/StringClassNameToClassConstantRector.php b/rules/Php55/Rector/String_/StringClassNameToClassConstantRector.php index 07d3d371347..9029e7b5b46 100644 --- a/rules/Php55/Rector/String_/StringClassNameToClassConstantRector.php +++ b/rules/Php55/Rector/String_/StringClassNameToClassConstantRector.php @@ -4,7 +4,6 @@ namespace Rector\Php55\Rector\String_; -use Deprecated; use PhpParser\Node; use PhpParser\Node\Expr\ClassConstFetch; use PhpParser\Node\Name\FullyQualified; @@ -24,9 +23,6 @@ */ final class StringClassNameToClassConstantRector extends AbstractRector implements MinPhpVersionInterface, ConfigurableRectorInterface { - #[Deprecated(message: 'since 2.2.12. Default behavior now.')] - public const string SHOULD_KEEP_PRE_SLASH = 'should_keep_pre_slash'; - /** * @var string[] */ diff --git a/rules/Php81/Enum/AttributeName.php b/rules/Php81/Enum/AttributeName.php index 9d46ad7b7c6..87d92fc171b 100644 --- a/rules/Php81/Enum/AttributeName.php +++ b/rules/Php81/Enum/AttributeName.php @@ -6,11 +6,5 @@ final class AttributeName { - /** - * Available since PHP 8.1 - * @see https://php.watch/versions/8.1/ReturnTypeWillChange - */ - public const string RETURN_TYPE_WILL_CHANGE = 'ReturnTypeWillChange'; - public const string ALLOW_DYNAMIC_PROPERTIES = 'AllowDynamicProperties'; } diff --git a/rules/TypeDeclarationDocblocks/TypeResolver/ConstantArrayTypeGeneralizer.php b/rules/TypeDeclarationDocblocks/TypeResolver/ConstantArrayTypeGeneralizer.php index 3ca83ab2218..e033dac4791 100644 --- a/rules/TypeDeclarationDocblocks/TypeResolver/ConstantArrayTypeGeneralizer.php +++ b/rules/TypeDeclarationDocblocks/TypeResolver/ConstantArrayTypeGeneralizer.php @@ -17,8 +17,6 @@ final class ConstantArrayTypeGeneralizer { /** - * @var int - * * Using 10-level array @return docblocks makes code very hard to read, * lets limit it to reasonable level */ @@ -45,7 +43,6 @@ public function generalize( $genericKeyType = $this->typeNormalizer->generalizeConstantTypes($constantArrayType->getKeyType()); $itemType = $constantArrayType->getItemType(); - if ($itemType instanceof NeverType) { return ArrayShapeNode::createSealed([]); } diff --git a/scripts/remove-unused-deps.php b/scripts/remove-unused-deps.php deleted file mode 100644 index 11e6277505f..00000000000 --- a/scripts/remove-unused-deps.php +++ /dev/null @@ -1,48 +0,0 @@ -/dev/null', $outputLines); -$junitXml = implode("\n", $outputLines); - -$simpleXml = @simplexml_load_string($junitXml); -if (! $simpleXml instanceof SimpleXMLElement) { - $symfonyStyle->error('Failed to parse composer-dependency-analyser output'); - exit(1); -} - -// 2. collect unused dependencies from the "unused dependencies" testsuite -$unusedDependencies = []; -foreach ($simpleXml->testsuite as $testsuite) { - if ((string) $testsuite['name'] !== 'unused dependencies') { - continue; - } - - foreach ($testsuite->testcase as $testcase) { - $unusedDependencies[] = (string) $testcase['name']; - } -} - -if ($unusedDependencies === []) { - $symfonyStyle->success('No unused dependencies found'); - exit(0); -} - -$symfonyStyle->listing($unusedDependencies); - -// 3. remove unused dependencies from composer.json (composer auto-detects require/require-dev) -// the autocommit to the branch is handled by the workflow's git-auto-commit-action -foreach ($unusedDependencies as $unusedDependency) { - exec(sprintf('composer remove %s --no-update --no-interaction 2>&1', escapeshellarg($unusedDependency))); -} - -$symfonyStyle->success(sprintf('Removed %d unused dependency(ies) from composer.json', count($unusedDependencies))); diff --git a/tests/NodeTypeResolver/StaticTypeMapper/StaticTypeMapperTest.php b/tests/NodeTypeResolver/StaticTypeMapper/StaticTypeMapperTest.php index 9b48149da29..15295781528 100644 --- a/tests/NodeTypeResolver/StaticTypeMapper/StaticTypeMapperTest.php +++ b/tests/NodeTypeResolver/StaticTypeMapper/StaticTypeMapperTest.php @@ -67,7 +67,6 @@ public function testMapPHPStanTypeToPHPStanPhpDocTypeNode(): void $phpStanDocTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($iterableType); $this->assertInstanceOf(GenericTypeNode::class, $phpStanDocTypeNode); - $this->assertInstanceOf(IdentifierTypeNode::class, $phpStanDocTypeNode->type); } public function testMixed(): void diff --git a/tests/PhpAttribute/Printer/PhpAttributeGroupFactoryTest.php b/tests/PhpAttribute/Printer/PhpAttributeGroupFactoryTest.php index c6f9df331a8..7092bb7f836 100644 --- a/tests/PhpAttribute/Printer/PhpAttributeGroupFactoryTest.php +++ b/tests/PhpAttribute/Printer/PhpAttributeGroupFactoryTest.php @@ -5,7 +5,6 @@ namespace Rector\Tests\PhpAttribute\Printer; use PhpParser\Node\Arg; -use PhpParser\Node\AttributeGroup; use Rector\BetterPhpDocParser\PhpDoc\ArrayItemNode; use Rector\BetterPhpDocParser\PhpDoc\StringNode; use Rector\PhpAttribute\NodeFactory\PhpAttributeGroupFactory; @@ -32,7 +31,7 @@ public function testCreateFromClassWithItems(): void ] ); - $this->assertInstanceOf(AttributeGroup::class, $attributeGroup); + $this->assertNotEmpty($attributeGroup->attrs); } public function testCreateArgsFromItems(): void diff --git a/utils-tests-runner/fast-phpunit b/utils-tests-runner/fast-phpunit new file mode 100755 index 00000000000..66a99da5779 Binary files /dev/null and b/utils-tests-runner/fast-phpunit differ diff --git a/utils/phpstan/src/Rule/RegisterRelatedPolyfillRectorRule.php b/utils/phpstan/src/Rule/RegisterRelatedPolyfillRectorRule.php index 847bd241074..19188ebce90 100644 --- a/utils/phpstan/src/Rule/RegisterRelatedPolyfillRectorRule.php +++ b/utils/phpstan/src/Rule/RegisterRelatedPolyfillRectorRule.php @@ -23,9 +23,11 @@ { private const string ERROR_MESSAGE = 'Class "%s" implements RelatedPolyfillInterface, but is not registered in config/set/php-polyfills.php. Register it there.'; - public function __construct( - private string $polyfillConfigFilePath - ) { + private string $polyfillConfigFilePath; + + public function __construct(?string $polyfillConfigFilePath = null) + { + $this->polyfillConfigFilePath = $polyfillConfigFilePath ?? __DIR__ . '/../../../../config/set/php-polyfills.php'; } public function getNodeType(): string