From 26b32e6e4dc53de0166c5e7d46a76ebdb4118929 Mon Sep 17 00:00:00 2001 From: Matthias Schmidt Date: Sat, 9 Aug 2025 05:59:45 +0200 Subject: [PATCH] [Php85] Remove context arg from finfo_buffer calls --- config/set/php85.php | 3 +- .../Fixture/fixture.php.inc | 61 ++++++++ .../Fixture/skip_different_cases.php.inc | 51 +++++++ .../RemoveFinfoBufferContextArgRectorTest.php | 28 ++++ .../config/configured_rule.php | 13 ++ .../RemoveFinfoBufferContextArgRector.php | 136 ++++++++++++++++++ src/ValueObject/PhpVersionFeature.php | 6 + 7 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 rules-tests/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector/Fixture/fixture.php.inc create mode 100644 rules-tests/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector/Fixture/skip_different_cases.php.inc create mode 100644 rules-tests/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector/RemoveFinfoBufferContextArgRectorTest.php create mode 100644 rules-tests/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector/config/configured_rule.php create mode 100644 rules/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector.php diff --git a/config/set/php85.php b/config/set/php85.php index f228b79c8e4..09bf0a9d481 100644 --- a/config/set/php85.php +++ b/config/set/php85.php @@ -4,6 +4,7 @@ use Rector\Config\RectorConfig; use Rector\Php85\Rector\ArrayDimFetch\ArrayFirstLastRector; +use Rector\Php85\Rector\FuncCall\RemoveFinfoBufferContextArgRector; use Rector\Removing\Rector\FuncCall\RemoveFuncCallArgRector; use Rector\Removing\ValueObject\RemoveFuncCallArg; use Rector\Renaming\Rector\FuncCall\RenameFunctionRector; @@ -11,7 +12,7 @@ use Rector\Renaming\ValueObject\MethodCallRename; return static function (RectorConfig $rectorConfig): void { - $rectorConfig->rules([ArrayFirstLastRector::class]); + $rectorConfig->rules([ArrayFirstLastRector::class, RemoveFinfoBufferContextArgRector::class]); $rectorConfig->ruleWithConfiguration( RemoveFuncCallArgRector::class, diff --git a/rules-tests/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector/Fixture/fixture.php.inc b/rules-tests/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector/Fixture/fixture.php.inc new file mode 100644 index 00000000000..f45896a4263 --- /dev/null +++ b/rules-tests/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector/Fixture/fixture.php.inc @@ -0,0 +1,61 @@ +buffer($fileContents, FILEINFO_NONE, $context); + $finfo->buffer($fileContents, FILEINFO_NONE, context: $context); + $finfo->buffer($fileContents, flags: FILEINFO_NONE, context: $context); + $finfo->buffer($fileContents, context: $context); + $finfo->buffer($fileContents, context: $context, flags: FILEINFO_NONE); + $finfo->buffer(...[$fileContents]); + $finfo->buffer(...[$fileContents, $context]); + $finfo->buffer(...[$fileContents, FILEINFO_NONE, $context]); +} + +?> +----- +buffer($fileContents, FILEINFO_NONE); + $finfo->buffer($fileContents, FILEINFO_NONE); + $finfo->buffer($fileContents, flags: FILEINFO_NONE); + $finfo->buffer($fileContents); + $finfo->buffer($fileContents, flags: FILEINFO_NONE); + $finfo->buffer(...[$fileContents]); + $finfo->buffer(...[$fileContents, $context]); + $finfo->buffer(...[$fileContents, FILEINFO_NONE, $context]); +} + +?> diff --git a/rules-tests/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector/Fixture/skip_different_cases.php.inc b/rules-tests/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector/Fixture/skip_different_cases.php.inc new file mode 100644 index 00000000000..010068cba81 --- /dev/null +++ b/rules-tests/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector/Fixture/skip_different_cases.php.inc @@ -0,0 +1,51 @@ +file($fileContents, FILEINFO_NONE, $context); + $finfo->file($fileContents, FILEINFO_NONE, context: $context); + $finfo->file($fileContents, flags: FILEINFO_NONE, context: $context); +} + +function bar($otherObject): void +{ + $finfo->buffer($fileContents, FILEINFO_NONE, $context); + $finfo->buffer($fileContents, FILEINFO_NONE, context: $context); + $finfo->buffer($fileContents, flags: FILEINFO_NONE, context: $context); +} + +?> +----- +file($fileContents, FILEINFO_NONE, $context); + $finfo->file($fileContents, FILEINFO_NONE, context: $context); + $finfo->file($fileContents, flags: FILEINFO_NONE, context: $context); +} + +function bar($otherObject): void +{ + $finfo->buffer($fileContents, FILEINFO_NONE, $context); + $finfo->buffer($fileContents, FILEINFO_NONE, context: $context); + $finfo->buffer($fileContents, flags: FILEINFO_NONE, context: $context); +} + +?> diff --git a/rules-tests/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector/RemoveFinfoBufferContextArgRectorTest.php b/rules-tests/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector/RemoveFinfoBufferContextArgRectorTest.php new file mode 100644 index 00000000000..3f811dfff45 --- /dev/null +++ b/rules-tests/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector/RemoveFinfoBufferContextArgRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector/config/configured_rule.php b/rules-tests/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector/config/configured_rule.php new file mode 100644 index 00000000000..61a845d4f75 --- /dev/null +++ b/rules-tests/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector/config/configured_rule.php @@ -0,0 +1,13 @@ +rule(RemoveFinfoBufferContextArgRector::class); + + $rectorConfig->phpVersion(PhpVersion::PHP_85); +}; diff --git a/rules/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector.php b/rules/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector.php new file mode 100644 index 00000000000..ac625bdc26c --- /dev/null +++ b/rules/Php85/Rector/FuncCall/RemoveFinfoBufferContextArgRector.php @@ -0,0 +1,136 @@ +> + */ + public function getNodeTypes(): array + { + return [FuncCall::class, MethodCall::class]; + } + + /** + * @param FuncCall $node + */ + public function refactor(Node $node): ?Node + { + if ($node->name instanceof Expr) { + return null; + } + + if ($node instanceof FuncCall && ! $this->isName($node->name, 'finfo_buffer')) { + return null; + } + + $objectType = new ObjectType('finfo'); + if ($node instanceof MethodCall && (! $this->nodeTypeResolver->isObjectType( + $node->var, + $objectType + ) || ! $this->isName($node->name, 'buffer'))) { + return null; + } + + if ($this->removeContextArg($node)) { + return $node; + } + + return null; + } + + public function provideMinPhpVersion(): int + { + return PhpVersionFeature::DEPRECATE_FINFO_BUFFER_CONTEXT; + } + + /** + * @param FuncCall|MethodCall $funcCall + */ + private function removeContextArg(CallLike $funcCall): bool + { + // In `finfo::buffer` method calls, the first parameter, compared to `finfo_buffer`, does not exist. + $methodArgCorrection = 0; + if ($funcCall instanceof MethodCall) { + $methodArgCorrection = -1; + } + + if (count($funcCall->args) <= 2 + $methodArgCorrection) { + return false; + } + + // Cannot handle variadic args + foreach ($funcCall->args as $position => $arg) { + if (! $arg instanceof Arg) { + return false; + } + } + + /** @var array $args */ + $args = $funcCall->args; + + // Argument 3 ($flags) and argument 4 ($context) are optional, thus named parameters must be considered + if (! $this->argsAnalyzer->hasNamedArg($args)) { + if (count($args) < 4 + $methodArgCorrection) { + return false; + } + + unset($funcCall->args[3 + $methodArgCorrection]); + + return true; + } + + foreach ($args as $position => $arg) { + if ($arg->name instanceof Identifier && $arg->name->name === 'context') { + unset($funcCall->args[$position]); + + return true; + } + } + + return false; + } +} diff --git a/src/ValueObject/PhpVersionFeature.php b/src/ValueObject/PhpVersionFeature.php index 998219643c1..ff83bac1998 100644 --- a/src/ValueObject/PhpVersionFeature.php +++ b/src/ValueObject/PhpVersionFeature.php @@ -768,4 +768,10 @@ final class PhpVersionFeature * @var int */ public const ARRAY_ANY = PhpVersion::PHP_84; + + /** + * @see https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_the_context_parameter_for_finfo_buffer + * @var int + */ + public const DEPRECATE_FINFO_BUFFER_CONTEXT = PhpVersion::PHP_85; }