diff --git a/dev-tools/phpstan/baseline.php b/dev-tools/phpstan/baseline.php index 8d64eb2b995..0377e2dd625 100644 --- a/dev-tools/phpstan/baseline.php +++ b/dev-tools/phpstan/baseline.php @@ -325,12 +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' => '#^Method PhpCsFixer\\\\Console\\\\Report\\\\FixReport\\\\CheckstyleReporter\\:\\:generate\\(\\) should return string but returns string\\|false\\.$#', 'identifier' => 'return.type', 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 1de24ae69b8..4091796c419 100644 --- a/src/Console/Output/Progress/ProgressOutputFactory.php +++ b/src/Console/Output/Progress/ProgressOutputFactory.php @@ -48,6 +48,7 @@ public function create(string $outputType, OutputContext $context): ProgressOutp ); } + // @phpstan-ignore-next-line new.noConstructor return new (self::OUTPUT_TYPE_MAP[$outputType])($context); } diff --git a/src/Fixer/Alias/RandomApiMigrationFixer.php b/src/Fixer/Alias/RandomApiMigrationFixer.php index e8c0701db54..7f2b8cff390 100644 --- a/src/Fixer/Alias/RandomApiMigrationFixer.php +++ b/src/Fixer/Alias/RandomApiMigrationFixer.php @@ -99,6 +99,8 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void [$functionName, $openParenthesis, $closeParenthesis] = $boundaries; $count = $argumentsAnalyzer->countArguments($tokens, $openParenthesis, $closeParenthesis); + \assert(isset(self::ARGUMENT_COUNTS[$functionIdentity])); // for PHPStan + if (!\in_array($count, self::ARGUMENT_COUNTS[$functionIdentity], true)) { continue 2; } diff --git a/src/Fixer/Casing/MagicMethodCasingFixer.php b/src/Fixer/Casing/MagicMethodCasingFixer.php index 88658bed7ad..d8eaa3d0af0 100644 --- a/src/Fixer/Casing/MagicMethodCasingFixer.php +++ b/src/Fixer/Casing/MagicMethodCasingFixer.php @@ -177,13 +177,18 @@ 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::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 { diff --git a/src/Fixer/Operator/LongToShorthandOperatorFixer.php b/src/Fixer/Operator/LongToShorthandOperatorFixer.php index af309d31d40..230996213d2 100644 --- a/src/Fixer/Operator/LongToShorthandOperatorFixer.php +++ b/src/Fixer/Operator/LongToShorthandOperatorFixer.php @@ -133,6 +133,8 @@ protected function isOperatorTokenCandidate(Tokens $tokens, int $index): bool protected function getReplacementToken(Token $token): Token { + \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 98c3b9f6a0a..0af7856d4ca 100644 --- a/src/Fixer/PhpUnit/PhpUnitDedicateAssertFixer.php +++ b/src/Fixer/PhpUnit/PhpUnitDedicateAssertFixer.php @@ -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::FIX_MAP[$content])) { - $expectedCount = self::FIX_MAP[$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::FIX_MAP[$content][$isPositive]) { + if (false === $fixDetails[$isPositive]) { return; } - $tokens[$assertCall['index']] = new Token([T_STRING, self::FIX_MAP[$content][$isPositive]]); + $tokens[$assertCall['index']] = new Token([T_STRING, $fixDetails[$isPositive]]); $this->removeFunctionCall($tokens, $testDefaultNamespaceTokenIndex, $testIndex, $testOpenIndex, $testCloseIndex); - if (self::FIX_MAP[$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/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/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/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];