diff --git a/composer.json b/composer.json index 58872368362..a5dfe0e5823 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,7 @@ "symfony/polyfill-mbstring": "^1.28", "symfony/polyfill-php80": "^1.28", "symfony/polyfill-php81": "^1.28", - "symfony/process": "^5.4 || ^6.0 || ^7.0", + "symfony/process": "^5.4 || ^6.0 || ^7.0 <7.2", "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0" }, "require-dev": { diff --git a/dev-tools/composer.json b/dev-tools/composer.json index e5240236a55..178bcbe8624 100644 --- a/dev-tools/composer.json +++ b/dev-tools/composer.json @@ -9,9 +9,9 @@ "mi-schi/phpmd-extension": "^4.3.0", "phpmd/phpmd": "^2.15.0", "phpstan/extension-installer": "^1.4.3", - "phpstan/phpstan": "^2.0.2", - "phpstan/phpstan-phpunit": "^2.0.1", - "phpstan/phpstan-strict-rules": "^2.0.0", + "phpstan/phpstan": "^2.0.4", + "phpstan/phpstan-phpunit": "^2.0.2", + "phpstan/phpstan-strict-rules": "^2.0.1", "phpstan/phpstan-symfony": "^2.0.0" }, "config": { diff --git a/dev-tools/composer.lock b/dev-tools/composer.lock index 8e594a2d0b7..f8b09fd2dbc 100644 --- a/dev-tools/composer.lock +++ b/dev-tools/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ebc0bb7af2d85a08528251d53a7038f7", + "content-hash": "ae17b12bb9e8524934ef96b341e4c6ab", "packages": [ { "name": "composer-unused/contracts", @@ -762,16 +762,16 @@ }, { "name": "phpstan/phpstan", - "version": "2.0.2", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "6c98c7600fc717b2c78c11ef60040d5b1e359c82" + "reference": "50d276fc3bf1430ec315f2f109bbde2769821524" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6c98c7600fc717b2c78c11ef60040d5b1e359c82", - "reference": "6c98c7600fc717b2c78c11ef60040d5b1e359c82" + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/50d276fc3bf1430ec315f2f109bbde2769821524", + "reference": "50d276fc3bf1430ec315f2f109bbde2769821524" }, "require": { "php": "^7.4|^8.0" @@ -793,20 +793,20 @@ }, { "name": "phpstan/phpstan-phpunit", - "version": "2.0.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "4b6ad7fab8683ff4efd7887ba26ef8ee171c7475" + "reference": "2cedfb72dfd0e9c5d636f837b945c9f20c943bdb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/4b6ad7fab8683ff4efd7887ba26ef8ee171c7475", - "reference": "4b6ad7fab8683ff4efd7887ba26ef8ee171c7475" + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/2cedfb72dfd0e9c5d636f837b945c9f20c943bdb", + "reference": "2cedfb72dfd0e9c5d636f837b945c9f20c943bdb" }, "require": { "php": "^7.4 || ^8.0", - "phpstan/phpstan": "^2.0" + "phpstan/phpstan": "^2.0.4" }, "type": "phpstan-extension", "extra": { @@ -829,20 +829,20 @@ }, { "name": "phpstan/phpstan-strict-rules", - "version": "2.0.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-strict-rules.git", - "reference": "a4a6a08bd4a461e516b9c3b8fdbf0f1883b34158" + "reference": "ed6fea0ad4ad9c7e25f3ad2e7c4d420cf1e67fe3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/a4a6a08bd4a461e516b9c3b8fdbf0f1883b34158", - "reference": "a4a6a08bd4a461e516b9c3b8fdbf0f1883b34158" + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/ed6fea0ad4ad9c7e25f3ad2e7c4d420cf1e67fe3", + "reference": "ed6fea0ad4ad9c7e25f3ad2e7c4d420cf1e67fe3" }, "require": { "php": "^7.4 || ^8.0", - "phpstan/phpstan": "^2.0" + "phpstan/phpstan": "^2.0.4" }, "type": "phpstan-extension", "extra": { @@ -1738,13 +1738,13 @@ "packages-dev": [], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { "php": "^8.3" }, - "platform-dev": [], + "platform-dev": {}, "platform-overrides": { "php": "8.3" }, diff --git a/dev-tools/phpstan/baseline.php b/dev-tools/phpstan/baseline.php index 4befd0d8b9d..dcc14cc8b94 100644 --- a/dev-tools/phpstan/baseline.php +++ b/dev-tools/phpstan/baseline.php @@ -325,18 +325,6 @@ 'count' => 1, 'path' => __DIR__ . '/../../src/Console/Output/ErrorOutput.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Offset int might not exist on array\\<1\\|2\\|3\\|4\\|5\\|6, array\\{symbol\\: string, format\\: string, description\\: string\\}\\>\\.$#', - 'identifier' => 'offsetAccess.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/Console/Output/Progress/DotsOutput.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Offset string might not exist on array\\\\>\\.$#', - 'identifier' => 'offsetAccess.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/Console/Output/Progress/ProgressOutputFactory.php', -]; $ignoreErrors[] = [ 'message' => '#^Method PhpCsFixer\\\\Console\\\\Report\\\\FixReport\\\\CheckstyleReporter\\:\\:generate\\(\\) should return string but returns string\\|false\\.$#', 'identifier' => 'return.type', @@ -745,24 +733,6 @@ 'count' => 1, 'path' => __DIR__ . '/../../src/Fixer/AbstractPhpUnitFixer.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Offset 0 might not exist on array\\\\.$#', - 'identifier' => 'offsetAccess.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/Fixer/Alias/EregToPregFixer.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Offset 1 might not exist on array\\\\.$#', - 'identifier' => 'offsetAccess.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/Fixer/Alias/EregToPregFixer.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Offset 2 might not exist on array\\\\.$#', - 'identifier' => 'offsetAccess.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/Fixer/Alias/EregToPregFixer.php', -]; $ignoreErrors[] = [ 'message' => '#^Offset 2 might not exist on non\\-empty\\-list\\\\>\\.$#', 'identifier' => 'offsetAccess.notFound', @@ -775,12 +745,6 @@ 'count' => 1, 'path' => __DIR__ . '/../../src/Fixer/Alias/PowToExponentiationFixer.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Offset string might not exist on array\\\\>\\.$#', - 'identifier' => 'offsetAccess.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/Fixer/Alias/RandomApiMigrationFixer.php', -]; $ignoreErrors[] = [ 'message' => '#^Offset 0 might not exist on list\\\\.$#', 'identifier' => 'offsetAccess.notFound', @@ -835,12 +799,6 @@ 'count' => 1, 'path' => __DIR__ . '/../../src/Fixer/Casing/MagicConstantCasingFixer.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Offset string might not exist on array\\\\.$#', - 'identifier' => 'offsetAccess.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/Fixer/Casing/MagicMethodCasingFixer.php', -]; $ignoreErrors[] = [ 'message' => '#^Cannot access offset \'elements\' on array\\{index\\: int, open\\: int\\|null, close\\: int\\<0, max\\>, elements\\: list\\\\}\\|false\\.$#', 'identifier' => 'offsetAccess.nonOffsetAccessible', @@ -1597,12 +1555,6 @@ 'count' => 1, 'path' => __DIR__ . '/../../src/Fixer/Operator/BinaryOperatorSpacesFixer.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Offset string might not exist on array\\\\.$#', - 'identifier' => 'offsetAccess.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/Fixer/Operator/LongToShorthandOperatorFixer.php', -]; $ignoreErrors[] = [ 'message' => '#^Method PhpCsFixer\\\\Fixer\\\\Operator\\\\TernaryToElvisOperatorFixer\\:\\:getAfterOperator\\(\\) should return array\\{start\\: int, end\\: int\\} but returns array\\{start\\: int\\|null, end\\?\\: int\\|null\\}\\.$#', 'identifier' => 'return.type', @@ -1681,12 +1633,6 @@ 'count' => 2, 'path' => __DIR__ . '/../../src/Fixer/PhpUnit/PhpUnitDedicateAssertFixer.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Offset string might not exist on array\\\\.$#', - 'identifier' => 'offsetAccess.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/Fixer/PhpUnit/PhpUnitDedicateAssertFixer.php', -]; $ignoreErrors[] = [ 'message' => '#^Offset \'expectExceptionMessageRegExp\' might not exist on array\\\\.$#', 'identifier' => 'offsetAccess.notFound', @@ -1753,12 +1699,6 @@ 'count' => 1, 'path' => __DIR__ . '/../../src/Fixer/PhpUnit/PhpUnitNoExpectationAnnotationFixer.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Offset \'assertAttributeEquals\'\\|\'assertAttributeNotEquals\'\\|\'assertEquals\'\\|\'assertNotEquals\' might not exist on array\\\\.$#', - 'identifier' => 'offsetAccess.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/Fixer/PhpUnit/PhpUnitStrictFixer.php', -]; $ignoreErrors[] = [ 'message' => '#^Method PhpCsFixer\\\\Fixer\\\\PhpUnit\\\\PhpUnitTestAnnotationFixer\\:\\:updateLines\\(\\) should return list\\ but returns array\\, PhpCsFixer\\\\DocBlock\\\\Line\\>\\.$#', 'identifier' => 'return.type', @@ -2089,12 +2029,6 @@ 'count' => 1, 'path' => __DIR__ . '/../../src/Fixer/Whitespace/ArrayIndentationFixer.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Offset \'break\'\\|\'case\'\\|\'continue\'\\|\'declare\'\\|\'default\'\\|\'do\'\\|\'exit\'\\|\'for\'\\|\'foreach\'\\|\'goto\'\\|\'if\'\\|\'include\'\\|\'include_once\'\\|\'phpdoc\'\\|\'require\'\\|\'require_once\'\\|\'return\'\\|\'switch\'\\|\'throw\'\\|\'try\'\\|\'while\'\\|\'yield\'\\|\'yield_from\' might not exist on array\\\\.$#', - 'identifier' => 'offsetAccess.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/Fixer/Whitespace/BlankLineBeforeStatementFixer.php', -]; $ignoreErrors[] = [ 'message' => '#^Offset int\\<0, max\\> might not exist on list\\\\.$#', 'identifier' => 'offsetAccess.notFound', @@ -2923,12 +2857,6 @@ 'count' => 1, 'path' => __DIR__ . '/../../tests/Fixer/FunctionNotation/NullableTypeDeclarationForDefaultNullValueFixerTest.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Offset \'operators\' might not exist on array\\\\.$#', - 'identifier' => 'offsetAccess.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../tests/Fixer/Operator/LongToShorthandOperatorFixerTest.php', -]; $ignoreErrors[] = [ 'message' => '#^Only booleans are allowed in a negated boolean, string\\|false given\\.$#', 'identifier' => 'booleanNot.exprNotBoolean', @@ -3229,12 +3157,6 @@ 'count' => 1, 'path' => __DIR__ . '/../../tests/Test/TestCaseUtils.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Property PhpCsFixer\\\\Tests\\\\Test\\\\TokensWithObservedTransformers\\:\\:\\$observedModificationsPerTransformer \\(array\\\\>\\) does not accept non\\-empty\\-array\\\\>\\.$#', - 'identifier' => 'assign.propertyType', - 'count' => 1, - 'path' => __DIR__ . '/../../tests/Test/TokensWithObservedTransformers.php', -]; $ignoreErrors[] = [ 'message' => '#^Property PhpCsFixer\\\\Tests\\\\TestCase\\:\\:\\$actualDeprecations \\(list\\\\) does not accept array\\, string\\>\\.$#', 'identifier' => 'assign.propertyType', diff --git a/src/Console/ConfigurationResolver.php b/src/Console/ConfigurationResolver.php index f85b494ff12..05c976a8603 100644 --- a/src/Console/ConfigurationResolver.php +++ b/src/Console/ConfigurationResolver.php @@ -166,7 +166,7 @@ final class ConfigurationResolver private ?array $path = null; /** - * @var null|string + * @var null|ProgressOutputType::* */ private $progress; @@ -409,6 +409,8 @@ static function (string $rawPath) use ($cwd, $filesystem): string { } /** + * @return ProgressOutputType::* + * * @throws InvalidConfigurationException */ public function getProgressType(): string diff --git a/src/Console/Output/Progress/DotsOutput.php b/src/Console/Output/Progress/DotsOutput.php index 57bbacb612c..221f65afe5e 100644 --- a/src/Console/Output/Progress/DotsOutput.php +++ b/src/Console/Output/Progress/DotsOutput.php @@ -30,7 +30,7 @@ final class DotsOutput implements ProgressOutputInterface * * @var array */ - private static array $eventStatusMap = [ + private const EVENT_STATUS_MAP = [ FileProcessed::STATUS_NO_CHANGES => ['symbol' => '.', 'format' => '%s', 'description' => 'no changes'], FileProcessed::STATUS_FIXED => ['symbol' => 'F', 'format' => '%s', 'description' => 'fixed'], FileProcessed::STATUS_SKIPPED => ['symbol' => 'S', 'format' => '%s', 'description' => 'skipped (cached or empty file)'], @@ -81,7 +81,7 @@ public function __wakeup(): void public function onFixerFileProcessed(FileProcessed $event): void { - $status = self::$eventStatusMap[$event->getStatus()]; + $status = self::EVENT_STATUS_MAP[$event->getStatus()]; $this->getOutput()->write($this->getOutput()->isDecorated() ? \sprintf($status['format'], $status['symbol']) : $status['symbol']); ++$this->processedFiles; @@ -108,9 +108,9 @@ public function printLegend(): void { $symbols = []; - foreach (self::$eventStatusMap as $status) { + foreach (self::EVENT_STATUS_MAP as $status) { $symbol = $status['symbol']; - if ('' === $symbol || isset($symbols[$symbol])) { + if (isset($symbols[$symbol])) { continue; } diff --git a/src/Console/Output/Progress/ProgressOutputFactory.php b/src/Console/Output/Progress/ProgressOutputFactory.php index 71027d833aa..27fa75707e8 100644 --- a/src/Console/Output/Progress/ProgressOutputFactory.php +++ b/src/Console/Output/Progress/ProgressOutputFactory.php @@ -22,14 +22,17 @@ final class ProgressOutputFactory { /** - * @var array> + * @var array> */ - private static array $outputTypeMap = [ + private const OUTPUT_TYPE_MAP = [ ProgressOutputType::NONE => NullOutput::class, ProgressOutputType::DOTS => DotsOutput::class, ProgressOutputType::BAR => PercentageBarOutput::class, ]; + /** + * @param ProgressOutputType::* $outputType + */ public function create(string $outputType, OutputContext $context): ProgressOutputInterface { if (null === $context->getOutput()) { @@ -45,7 +48,10 @@ public function create(string $outputType, OutputContext $context): ProgressOutp ); } - return new self::$outputTypeMap[$outputType]($context); + $outputClass = self::OUTPUT_TYPE_MAP[$outputType]; + + // @phpstan-ignore-next-line new.noConstructor + return new $outputClass($context); } private function isBuiltInType(string $outputType): bool diff --git a/src/DocBlock/Annotation.php b/src/DocBlock/Annotation.php index 49aa45932a0..3e967d57933 100644 --- a/src/DocBlock/Annotation.php +++ b/src/DocBlock/Annotation.php @@ -31,7 +31,7 @@ final class Annotation * * @var list */ - private static array $tags = [ + private const TAGS = [ 'method', 'param', 'property', @@ -127,7 +127,7 @@ public function __toString(): string */ public static function getTagsWithTypes(): array { - return self::$tags; + return self::TAGS; } /** @@ -291,7 +291,7 @@ public function getContent(): string public function supportTypes(): bool { - return \in_array($this->getTag()->getName(), self::$tags, true); + return \in_array($this->getTag()->getName(), self::TAGS, true); } /** diff --git a/src/Fixer/Alias/EregToPregFixer.php b/src/Fixer/Alias/EregToPregFixer.php index 396658c3894..f75798611d7 100644 --- a/src/Fixer/Alias/EregToPregFixer.php +++ b/src/Fixer/Alias/EregToPregFixer.php @@ -33,7 +33,7 @@ final class EregToPregFixer extends AbstractFixer * @var list> the list of the ext/ereg function names, their preg equivalent and the preg modifier(s), if any * all condensed in an array of arrays */ - private static array $functions = [ + private const FUNCTIONS = [ ['ereg', 'preg_match', ''], ['eregi', 'preg_match', 'i'], ['ereg_replace', 'preg_replace', ''], @@ -82,7 +82,7 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void $end = $tokens->count() - 1; $functionsAnalyzer = new FunctionsAnalyzer(); - foreach (self::$functions as $map) { + foreach (self::FUNCTIONS as $map) { // the sequence is the function name, followed by "(" and a quoted string $seq = [[T_STRING, $map[0]], '(', [T_CONSTANT_ENCAPSED_STRING]]; $currIndex = 0; diff --git a/src/Fixer/Alias/RandomApiMigrationFixer.php b/src/Fixer/Alias/RandomApiMigrationFixer.php index 9909eb7a10b..7f2b8cff390 100644 --- a/src/Fixer/Alias/RandomApiMigrationFixer.php +++ b/src/Fixer/Alias/RandomApiMigrationFixer.php @@ -48,7 +48,7 @@ final class RandomApiMigrationFixer extends AbstractFunctionReferenceFixer imple /** * @var array> */ - private static array $argumentCounts = [ + private const ARGUMENT_COUNTS = [ 'getrandmax' => [0], 'mt_rand' => [1, 2], 'rand' => [0, 2], @@ -99,7 +99,9 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void [$functionName, $openParenthesis, $closeParenthesis] = $boundaries; $count = $argumentsAnalyzer->countArguments($tokens, $openParenthesis, $closeParenthesis); - if (!\in_array($count, self::$argumentCounts[$functionIdentity], true)) { + \assert(isset(self::ARGUMENT_COUNTS[$functionIdentity])); // for PHPStan + + if (!\in_array($count, self::ARGUMENT_COUNTS[$functionIdentity], true)) { continue 2; } @@ -130,7 +132,7 @@ protected function createConfigurationDefinition(): FixerConfigurationResolverIn ->setAllowedTypes(['array']) ->setAllowedValues([static function (array $value): bool { foreach ($value as $functionName => $replacement) { - if (!\array_key_exists($functionName, self::$argumentCounts)) { + if (!\array_key_exists($functionName, self::ARGUMENT_COUNTS)) { throw new InvalidOptionsException(\sprintf( 'Function "%s" is not handled by the fixer.', $functionName diff --git a/src/Fixer/Basic/NonPrintableCharacterFixer.php b/src/Fixer/Basic/NonPrintableCharacterFixer.php index 7c3acfbaf77..44fe6093e9b 100644 --- a/src/Fixer/Basic/NonPrintableCharacterFixer.php +++ b/src/Fixer/Basic/NonPrintableCharacterFixer.php @@ -46,15 +46,10 @@ final class NonPrintableCharacterFixer extends AbstractFixer implements Configur /** @use ConfigurableFixerTrait<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> */ use ConfigurableFixerTrait; - /** - * @var array - */ - private array $symbolsReplace; - /** * @var list */ - private static array $tokens = [ + private const TOKENS = [ T_STRING_VARNAME, T_INLINE_HTML, T_VARIABLE, @@ -64,6 +59,11 @@ final class NonPrintableCharacterFixer extends AbstractFixer implements Configur T_DOC_COMMENT, ]; + /** + * @var array + */ + private array $symbolsReplace; + public function __construct() { parent::__construct(); @@ -102,7 +102,7 @@ public function isRisky(): bool public function isCandidate(Tokens $tokens): bool { - return $tokens->isAnyTokenKindsFound(self::$tokens); + return $tokens->isAnyTokenKindsFound(self::TOKENS); } protected function createConfigurationDefinition(): FixerConfigurationResolverInterface @@ -171,7 +171,7 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void continue; } - if ($token->isGivenKind(self::$tokens)) { + if ($token->isGivenKind(self::TOKENS)) { $newContent = strtr($content, $replacements); // variable name cannot contain space diff --git a/src/Fixer/Casing/LowercaseKeywordsFixer.php b/src/Fixer/Casing/LowercaseKeywordsFixer.php index f11b9988db7..53f98d15ef7 100644 --- a/src/Fixer/Casing/LowercaseKeywordsFixer.php +++ b/src/Fixer/Casing/LowercaseKeywordsFixer.php @@ -28,11 +28,6 @@ */ final class LowercaseKeywordsFixer extends AbstractFixer { - /** - * @var list - */ - private static array $excludedTokens = [T_HALT_COMPILER]; - public function getDefinition(): FixerDefinitionInterface { return new FixerDefinition( @@ -64,7 +59,7 @@ public function isCandidate(Tokens $tokens): bool protected function applyFix(\SplFileInfo $file, Tokens $tokens): void { foreach ($tokens as $index => $token) { - if ($token->isKeyword() && !$token->isGivenKind(self::$excludedTokens)) { + if ($token->isKeyword() && !$token->isGivenKind([T_HALT_COMPILER])) { $tokens[$index] = new Token([$token->getId(), strtolower($token->getContent())]); } } diff --git a/src/Fixer/Casing/MagicMethodCasingFixer.php b/src/Fixer/Casing/MagicMethodCasingFixer.php index 544d2cbb9a4..d8eaa3d0af0 100644 --- a/src/Fixer/Casing/MagicMethodCasingFixer.php +++ b/src/Fixer/Casing/MagicMethodCasingFixer.php @@ -26,7 +26,7 @@ final class MagicMethodCasingFixer extends AbstractFixer /** * @var array */ - private static array $magicNames = [ + private const MAGIC_NAMES = [ '__call' => '__call', '__callstatic' => '__callStatic', '__clone' => '__clone', @@ -177,17 +177,22 @@ private function isStaticMethodCall(Tokens $tokens, int $index): bool return $tokens[$tokens->getNextMeaningfulToken($index)]->equals('('); } + /** + * @phpstan-assert-if-true key-of $name + */ private function isMagicMethodName(string $name): bool { - return isset(self::$magicNames[$name]); + return isset(self::MAGIC_NAMES[$name]); } /** - * @param string $name name of a magic method + * @param key-of $name name of a magic method + * + * @return value-of */ private function getMagicMethodNameInCorrectCasing(string $name): string { - return self::$magicNames[$name]; + return self::MAGIC_NAMES[$name]; } private function setTokenToCorrectCasing(Tokens $tokens, int $index, string $nameInCorrectCasing): void diff --git a/src/Fixer/ClassNotation/OrderedClassElementsFixer.php b/src/Fixer/ClassNotation/OrderedClassElementsFixer.php index af3340c4382..71febf692de 100644 --- a/src/Fixer/ClassNotation/OrderedClassElementsFixer.php +++ b/src/Fixer/ClassNotation/OrderedClassElementsFixer.php @@ -74,7 +74,7 @@ final class OrderedClassElementsFixer extends AbstractFixer implements Configura /** * @var array> Array containing all class element base types (keys) and their parent types (values) */ - private static array $typeHierarchy = [ + private const TYPE_HIERARCHY = [ 'use_trait' => null, 'public' => null, 'protected' => null, @@ -115,7 +115,7 @@ final class OrderedClassElementsFixer extends AbstractFixer implements Configura /** * @var array Array containing special method types */ - private static array $specialTypes = [ + private const SPECIAL_TYPES = [ 'construct' => null, 'destruct' => null, 'magic' => null, @@ -207,9 +207,9 @@ public function AWs(){} ], 'Accepts a subset of pre-defined element types, special element groups, and custom patterns. -Element types: `[\''.implode('\', \'', array_keys(self::$typeHierarchy)).'\']` +Element types: `[\''.implode('\', \'', array_keys(self::TYPE_HIERARCHY)).'\']` -Special element types: `[\''.implode('\', \'', array_keys(self::$specialTypes)).'\']` +Special element types: `[\''.implode('\', \'', array_keys(self::SPECIAL_TYPES)).'\']` Custom values: @@ -237,7 +237,7 @@ protected function configurePostNormalisation(): void $this->typePosition[$type] = $position++; } - foreach (self::$typeHierarchy as $type => $parents) { + foreach (self::TYPE_HIERARCHY as $type => $parents) { if (isset($this->typePosition[$type])) { continue; } @@ -297,7 +297,7 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void protected function createConfigurationDefinition(): FixerConfigurationResolverInterface { - $builtIns = array_keys(array_merge(self::$typeHierarchy, self::$specialTypes)); + $builtIns = array_keys(array_merge(self::TYPE_HIERARCHY, self::SPECIAL_TYPES)); return new FixerConfigurationResolver([ (new FixerOptionBuilder('order', 'List of strings defining order of elements.')) @@ -519,7 +519,7 @@ private function sortElements(array $elements): array return $this->typePosition["method:{$element['name']}"]; } - if (\array_key_exists($type, self::$specialTypes)) { + if (\array_key_exists($type, self::SPECIAL_TYPES)) { if (isset($this->typePosition[$type])) { $position = $this->typePosition[$type]; diff --git a/src/Fixer/LanguageConstruct/SingleSpaceAfterConstructFixer.php b/src/Fixer/LanguageConstruct/SingleSpaceAfterConstructFixer.php index 7ca0c4e379c..586c37c969a 100644 --- a/src/Fixer/LanguageConstruct/SingleSpaceAfterConstructFixer.php +++ b/src/Fixer/LanguageConstruct/SingleSpaceAfterConstructFixer.php @@ -49,7 +49,7 @@ final class SingleSpaceAfterConstructFixer extends AbstractProxyFixer implements /** * @var array */ - private static array $tokenMap = [ + private const TOKEN_MAP = [ 'abstract' => T_ABSTRACT, 'as' => T_AS, 'attribute' => CT::T_ATTRIBUTE_CLOSE, @@ -193,7 +193,7 @@ protected function createProxyFixers(): array protected function createConfigurationDefinition(): FixerConfigurationResolverInterface { - $defaults = self::$tokenMap; + $defaults = self::TOKEN_MAP; $tokens = array_keys($defaults); unset($defaults['type_colon']); diff --git a/src/Fixer/Naming/NoHomoglyphNamesFixer.php b/src/Fixer/Naming/NoHomoglyphNamesFixer.php index ff91d5c1333..8bd9fccbd84 100644 --- a/src/Fixer/Naming/NoHomoglyphNamesFixer.php +++ b/src/Fixer/Naming/NoHomoglyphNamesFixer.php @@ -48,7 +48,7 @@ final class NoHomoglyphNamesFixer extends AbstractFixer * * @var array */ - private static array $replacements = [ + private const REPLACEMENTS = [ 'O' => '0', '0' => '0', 'I' => '1', @@ -220,7 +220,7 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void continue; } - $replaced = Preg::replaceCallback('/[^[:ascii:]]/u', static fn (array $matches): string => self::$replacements[$matches[0]] ?? $matches[0], $token->getContent(), -1, $count); + $replaced = Preg::replaceCallback('/[^[:ascii:]]/u', static fn (array $matches): string => self::REPLACEMENTS[$matches[0]] ?? $matches[0], $token->getContent(), -1, $count); if ($count > 0) { $tokens->offsetSet($index, new Token([$token->getId(), $replaced])); diff --git a/src/Fixer/Operator/BinaryOperatorSpacesFixer.php b/src/Fixer/Operator/BinaryOperatorSpacesFixer.php index cf2f84f44b3..5ecd14d30d7 100644 --- a/src/Fixer/Operator/BinaryOperatorSpacesFixer.php +++ b/src/Fixer/Operator/BinaryOperatorSpacesFixer.php @@ -150,24 +150,10 @@ final class BinaryOperatorSpacesFixer extends AbstractFixer implements Configura '??=', ]; - /** - * Keep track of the deepest level ever achieved while - * parsing the code. Used later to replace alignment - * placeholders with spaces. - */ - private int $deepestLevel; - - /** - * Level counter of the current nest level. - * So one level alignments are not mixed with - * other level ones. - */ - private int $currentLevel; - /** * @var list */ - private static array $allowedValues = [ + private const ALLOWED_VALUES = [ self::ALIGN, self::ALIGN_BY_SCOPE, self::ALIGN_SINGLE_SPACE, @@ -180,6 +166,20 @@ final class BinaryOperatorSpacesFixer extends AbstractFixer implements Configura null, ]; + /** + * Keep track of the deepest level ever achieved while + * parsing the code. Used later to replace alignment + * placeholders with spaces. + */ + private int $deepestLevel; + + /** + * Level counter of the current nest level. + * So one level alignments are not mixed with + * other level ones. + */ + private int $currentLevel; + private TokensAnalyzer $tokensAnalyzer; /** @@ -368,7 +368,7 @@ protected function createConfigurationDefinition(): FixerConfigurationResolverIn return new FixerConfigurationResolver([ (new FixerOptionBuilder('default', 'Default fix strategy.')) ->setDefault(self::SINGLE_SPACE) - ->setAllowedValues(self::$allowedValues) + ->setAllowedValues(self::ALLOWED_VALUES) ->getOption(), (new FixerOptionBuilder('operators', 'Dictionary of `binary operator` => `fix strategy` values that differ from the default strategy. Supported are: '.Utils::naturalLanguageJoinWithBackticks(self::SUPPORTED_OPERATORS).'.')) ->setAllowedTypes(['array']) @@ -384,14 +384,14 @@ protected function createConfigurationDefinition(): FixerConfigurationResolverIn ); } - if (!\in_array($value, self::$allowedValues, true)) { + if (!\in_array($value, self::ALLOWED_VALUES, true)) { throw new InvalidOptionsException( \sprintf( 'Unexpected value for operator "%s", expected any of %s, got "%s".', $operator, Utils::naturalLanguageJoin(array_map( static fn ($value): string => Utils::toString($value), - self::$allowedValues + self::ALLOWED_VALUES )), \is_object($value) ? \get_class($value) : (null === $value ? 'null' : \gettype($value).'#'.$value) ) diff --git a/src/Fixer/Operator/LongToShorthandOperatorFixer.php b/src/Fixer/Operator/LongToShorthandOperatorFixer.php index fad4c48a6d1..230996213d2 100644 --- a/src/Fixer/Operator/LongToShorthandOperatorFixer.php +++ b/src/Fixer/Operator/LongToShorthandOperatorFixer.php @@ -27,7 +27,7 @@ final class LongToShorthandOperatorFixer extends AbstractShortOperatorFixer /** * @var array */ - private static array $operators = [ + private const OPERATORS = [ '+' => [T_PLUS_EQUAL, '+='], '-' => [T_MINUS_EQUAL, '-='], '*' => [T_MUL_EQUAL, '*='], @@ -75,7 +75,7 @@ public function isRisky(): bool public function isCandidate(Tokens $tokens): bool { - if ($tokens->isAnyTokenKindsFound(array_keys(self::$operators))) { + if ($tokens->isAnyTokenKindsFound(array_keys(self::OPERATORS))) { return true; } @@ -85,7 +85,7 @@ public function isCandidate(Tokens $tokens): bool protected function applyFix(\SplFileInfo $file, Tokens $tokens): void { - $this->operatorTypes = array_keys(self::$operators); + $this->operatorTypes = array_keys(self::OPERATORS); $this->tokensAnalyzer = new TokensAnalyzer($tokens); parent::applyFix($file, $tokens); @@ -133,6 +133,8 @@ protected function isOperatorTokenCandidate(Tokens $tokens, int $index): bool protected function getReplacementToken(Token $token): Token { - return new Token(self::$operators[$token->getContent()]); + \assert(isset(self::OPERATORS[$token->getContent()])); // for PHPStan + + return new Token(self::OPERATORS[$token->getContent()]); } } diff --git a/src/Fixer/PhpUnit/PhpUnitDedicateAssertFixer.php b/src/Fixer/PhpUnit/PhpUnitDedicateAssertFixer.php index 07688253e00..0af7856d4ca 100644 --- a/src/Fixer/PhpUnit/PhpUnitDedicateAssertFixer.php +++ b/src/Fixer/PhpUnit/PhpUnitDedicateAssertFixer.php @@ -48,7 +48,7 @@ final class PhpUnitDedicateAssertFixer extends AbstractPhpUnitFixer implements C /** * @var array */ - private static array $fixMap = [ + private const FIX_MAP = [ 'array_key_exists' => [ 'positive' => 'assertArrayHasKey', 'negative' => 'assertArrayNotHasKey', @@ -321,8 +321,9 @@ private function fixAssertTrueFalse(Tokens $tokens, ArgumentsAnalyzer $arguments $arguments = $argumentsAnalyzer->getArguments($tokens, $testOpenIndex, $testCloseIndex); $isPositive = 'asserttrue' === $assertCall['loweredName']; - if (\is_array(self::$fixMap[$content])) { - $expectedCount = self::$fixMap[$content]['argument_count'] ?? 1; + if (isset(self::FIX_MAP[$content]) && \is_array(self::FIX_MAP[$content])) { + $fixDetails = self::FIX_MAP[$content]; + $expectedCount = $fixDetails['argument_count'] ?? 1; if ($expectedCount !== \count($arguments)) { return; @@ -330,14 +331,14 @@ private function fixAssertTrueFalse(Tokens $tokens, ArgumentsAnalyzer $arguments $isPositive = $isPositive ? 'positive' : 'negative'; - if (false === self::$fixMap[$content][$isPositive]) { + if (false === $fixDetails[$isPositive]) { return; } - $tokens[$assertCall['index']] = new Token([T_STRING, self::$fixMap[$content][$isPositive]]); + $tokens[$assertCall['index']] = new Token([T_STRING, $fixDetails[$isPositive]]); $this->removeFunctionCall($tokens, $testDefaultNamespaceTokenIndex, $testIndex, $testOpenIndex, $testCloseIndex); - if (self::$fixMap[$content]['swap_arguments'] ?? false) { + if ($fixDetails['swap_arguments'] ?? false) { if (2 !== $expectedCount) { throw new \RuntimeException('Can only swap two arguments, please update map or logic.'); } diff --git a/src/Fixer/PhpUnit/PhpUnitStrictFixer.php b/src/Fixer/PhpUnit/PhpUnitStrictFixer.php index c9f9552d48d..f3d8fcc8fc3 100644 --- a/src/Fixer/PhpUnit/PhpUnitStrictFixer.php +++ b/src/Fixer/PhpUnit/PhpUnitStrictFixer.php @@ -49,7 +49,7 @@ final class PhpUnitStrictFixer extends AbstractPhpUnitFixer implements Configura /** * @var array */ - private static array $assertionMap = [ + private const ASSERTION_MAP = [ 'assertAttributeEquals' => 'assertAttributeSame', 'assertAttributeNotEquals' => 'assertAttributeNotSame', 'assertEquals' => 'assertSame', @@ -107,7 +107,7 @@ protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $en $functionsAnalyzer = new FunctionsAnalyzer(); foreach ($this->configuration['assertions'] as $methodBefore) { - $methodAfter = self::$assertionMap[$methodBefore]; + $methodAfter = self::ASSERTION_MAP[$methodBefore]; for ($index = $startIndex; $index < $endIndex; ++$index) { $methodIndex = $tokens->getNextTokenOfKind($index, [[T_STRING, $methodBefore]]); @@ -141,7 +141,7 @@ protected function createConfigurationDefinition(): FixerConfigurationResolverIn return new FixerConfigurationResolver([ (new FixerOptionBuilder('assertions', 'List of assertion methods to fix.')) ->setAllowedTypes(['string[]']) - ->setAllowedValues([new AllowedValueSubset(array_keys(self::$assertionMap))]) + ->setAllowedValues([new AllowedValueSubset(array_keys(self::ASSERTION_MAP))]) ->setDefault([ 'assertAttributeEquals', 'assertAttributeNotEquals', diff --git a/src/Fixer/Phpdoc/PhpdocReturnSelfReferenceFixer.php b/src/Fixer/Phpdoc/PhpdocReturnSelfReferenceFixer.php index d0cd912d957..a8eb6aef831 100644 --- a/src/Fixer/Phpdoc/PhpdocReturnSelfReferenceFixer.php +++ b/src/Fixer/Phpdoc/PhpdocReturnSelfReferenceFixer.php @@ -49,7 +49,7 @@ final class PhpdocReturnSelfReferenceFixer extends AbstractFixer implements Conf /** * @var list */ - private static array $toTypes = [ + private const TO_TYPES = [ '$this', 'static', 'self', @@ -166,11 +166,11 @@ protected function createConfigurationDefinition(): FixerConfigurationResolverIn )); } - if (!\in_array($to, self::$toTypes, true)) { + if (!\in_array($to, self::TO_TYPES, true)) { throw new InvalidOptionsException(\sprintf( 'Unknown value "%s", expected any of %s.', \is_object($to) ? \get_class($to) : \gettype($to).(\is_resource($to) ? '' : '#'.$to), - Utils::naturalLanguageJoin(self::$toTypes) + Utils::naturalLanguageJoin(self::TO_TYPES) )); } diff --git a/src/Fixer/Whitespace/BlankLineBeforeStatementFixer.php b/src/Fixer/Whitespace/BlankLineBeforeStatementFixer.php index 404354a10cb..9256de3b6ed 100644 --- a/src/Fixer/Whitespace/BlankLineBeforeStatementFixer.php +++ b/src/Fixer/Whitespace/BlankLineBeforeStatementFixer.php @@ -50,7 +50,7 @@ final class BlankLineBeforeStatementFixer extends AbstractFixer implements Confi /** * @var array */ - private static array $tokenMap = [ + private const TOKEN_MAP = [ 'break' => T_BREAK, 'case' => T_CASE, 'continue' => T_CONTINUE, @@ -256,7 +256,7 @@ protected function configurePostNormalisation(): void $fixTokenMap = []; foreach ($this->configuration['statements'] as $key) { - $fixTokenMap[$key] = self::$tokenMap[$key]; + $fixTokenMap[$key] = self::TOKEN_MAP[$key]; } $this->fixTokenMap = array_values($fixTokenMap); @@ -297,7 +297,7 @@ protected function createConfigurationDefinition(): FixerConfigurationResolverIn return new FixerConfigurationResolver([ (new FixerOptionBuilder('statements', 'List of statements which must be preceded by an empty line.')) ->setAllowedTypes(['string[]']) - ->setAllowedValues([new AllowedValueSubset(array_keys(self::$tokenMap))]) + ->setAllowedValues([new AllowedValueSubset(array_keys(self::TOKEN_MAP))]) ->setDefault([ 'break', 'continue', diff --git a/src/Fixer/Whitespace/NoExtraBlankLinesFixer.php b/src/Fixer/Whitespace/NoExtraBlankLinesFixer.php index dbb7be39965..8f0555b58df 100644 --- a/src/Fixer/Whitespace/NoExtraBlankLinesFixer.php +++ b/src/Fixer/Whitespace/NoExtraBlankLinesFixer.php @@ -53,7 +53,7 @@ final class NoExtraBlankLinesFixer extends AbstractFixer implements Configurable /** * @var list */ - private static array $availableTokens = [ + private const AVAILABLE_TOKENS = [ 'attribute', 'break', 'case', @@ -301,7 +301,7 @@ protected function createConfigurationDefinition(): FixerConfigurationResolverIn return new FixerConfigurationResolver([ (new FixerOptionBuilder('tokens', 'List of tokens to fix.')) ->setAllowedTypes(['string[]']) - ->setAllowedValues([new AllowedValueSubset(self::$availableTokens)]) + ->setAllowedValues([new AllowedValueSubset(self::AVAILABLE_TOKENS)]) ->setDefault(['extra']) ->getOption(), ]); diff --git a/src/Runner/Event/FileProcessed.php b/src/Runner/Event/FileProcessed.php index e90206e5530..b9d4bcda1b7 100644 --- a/src/Runner/Event/FileProcessed.php +++ b/src/Runner/Event/FileProcessed.php @@ -37,11 +37,17 @@ final class FileProcessed extends Event public const STATUS_EXCEPTION = 5; public const STATUS_LINT = 6; + /** + * @var self::STATUS_* + */ private int $status; private ?string $fileRelativePath; private ?string $fileHash; + /** + * @param self::STATUS_* $status + */ public function __construct(int $status, ?string $fileRelativePath = null, ?string $fileHash = null) { $this->status = $status; @@ -49,6 +55,9 @@ public function __construct(int $status, ?string $fileRelativePath = null, ?stri $this->fileHash = $fileHash; } + /** + * @return self::STATUS_* + */ public function getStatus(): int { return $this->status; diff --git a/src/Tokenizer/Analyzer/Analysis/TypeAnalysis.php b/src/Tokenizer/Analyzer/Analysis/TypeAnalysis.php index 34d68be9560..e0676574e2d 100644 --- a/src/Tokenizer/Analyzer/Analysis/TypeAnalysis.php +++ b/src/Tokenizer/Analyzer/Analysis/TypeAnalysis.php @@ -29,7 +29,7 @@ final class TypeAnalysis implements StartEndTokenAwareAnalysis * * @var list */ - private static array $reservedTypes = [ + private const RESERVED_TYPES = [ 'array', 'bool', 'callable', @@ -96,7 +96,7 @@ public function getEndIndex(): int public function isReservedType(): bool { - return \in_array(strtolower($this->name), self::$reservedTypes, true); + return \in_array(strtolower($this->name), self::RESERVED_TYPES, true); } public function isNullable(): bool diff --git a/tests/Console/Output/Progress/ProgressOutputFactoryTest.php b/tests/Console/Output/Progress/ProgressOutputFactoryTest.php index 7d12820fd8c..b5feb9193fb 100644 --- a/tests/Console/Output/Progress/ProgressOutputFactoryTest.php +++ b/tests/Console/Output/Progress/ProgressOutputFactoryTest.php @@ -39,6 +39,7 @@ public function testValidProcessOutputIsCreated( OutputContext $context, string $expectedOutputClass ): void { + // @phpstan-ignore-next-line argument.type as we explicitly test non-valid $outputType self::assertInstanceOf($expectedOutputClass, (new ProgressOutputFactory())->create($outputType, $context)); } @@ -63,9 +64,9 @@ public function testExceptionIsThrownForUnsupportedProcessOutputType(): void { $this->expectException(\InvalidArgumentException::class); - (new ProgressOutputFactory())->create( - 'boom', - new OutputContext(new SymfonyNullOutput(), 100, 10) - ); + $outputContext = new OutputContext(new SymfonyNullOutput(), 100, 10); + + // @phpstan-ignore-next-line argument.type as we explicitly test non-valid $outputType + (new ProgressOutputFactory())->create('boom', $outputContext); } } diff --git a/tests/Fixer/Casing/MagicMethodCasingFixerTest.php b/tests/Fixer/Casing/MagicMethodCasingFixerTest.php index 294ea0cf315..e095adc3e27 100644 --- a/tests/Fixer/Casing/MagicMethodCasingFixerTest.php +++ b/tests/Fixer/Casing/MagicMethodCasingFixerTest.php @@ -39,7 +39,7 @@ public function testFix(string $expected, ?string $input = null): void */ public static function provideFixCases(): iterable { - $allMethodNames = \Closure::bind(static fn (): array => MagicMethodCasingFixer::$magicNames, null, MagicMethodCasingFixer::class)(); + $allMethodNames = \Closure::bind(static fn (): array => MagicMethodCasingFixer::MAGIC_NAMES, null, MagicMethodCasingFixer::class)(); // '__callStatic' yield 'method declaration for "__callstatic".' => [ diff --git a/tests/Fixer/Operator/LongToShorthandOperatorFixerTest.php b/tests/Fixer/Operator/LongToShorthandOperatorFixerTest.php index a8dd068ec44..7ee153af953 100644 --- a/tests/Fixer/Operator/LongToShorthandOperatorFixerTest.php +++ b/tests/Fixer/Operator/LongToShorthandOperatorFixerTest.php @@ -137,9 +137,7 @@ public static function provideFixCases(): iterable ]; // test simple with all operators - - $reflection = new \ReflectionClass(LongToShorthandOperatorFixer::class); - $operators = $reflection->getStaticProperties()['operators']; + $operators = \Closure::bind(static fn (): array => LongToShorthandOperatorFixer::OPERATORS, null, LongToShorthandOperatorFixer::class)(); foreach ($operators as $operator => $info) { $shortHand = $info[1];