Skip to content

Commit 71d7d6e

Browse files
committed
[Php85] Remove context arg from finfo_buffer calls
1 parent 65e3739 commit 71d7d6e

6 files changed

Lines changed: 239 additions & 1 deletion

File tree

config/set/php85.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
use Rector\Config\RectorConfig;
66
use Rector\Php85\Rector\ArrayDimFetch\ArrayFirstLastRector;
7+
use Rector\Php85\Rector\FuncCall\RemoveFinfoBufferContextArgRector;
78

89
return static function (RectorConfig $rectorConfig): void {
9-
$rectorConfig->rules([ArrayFirstLastRector::class]);
10+
$rectorConfig->rules([ArrayFirstLastRector::class, RemoveFinfoBufferContextArgRector::class]);
1011
};
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\Php85\Rector\FuncCall\RemoveFinfoBufferContextArgRector\RemoveFinfoBufferContextArgRectorTest\Fixture;
6+
7+
finfo_buffer($finfo, $fileContents);
8+
finfo_buffer($finfo, $fileContents, FILEINFO_NONE);
9+
finfo_buffer($finfo, $fileContents, FILEINFO_NONE, $context);
10+
finfo_buffer($finfo, $fileContents, FILEINFO_NONE, context: $context);
11+
finfo_buffer($finfo, $fileContents, flags: FILEINFO_NONE, context: $context);
12+
finfo_buffer($finfo, $fileContents, context: $context);
13+
finfo_buffer($finfo, $fileContents, context: $context, flags: FILEINFO_NONE);
14+
finfo_buffer(...[$finfo, $fileContents]);
15+
finfo_buffer(...[$finfo, $fileContents, $context]);
16+
finfo_buffer(...[$finfo, $fileContents, FILEINFO_NONE, $context]);
17+
18+
function foo(\finfo $finfo): void
19+
{
20+
$finfo->buffer($fileContents, FILEINFO_NONE, $context);
21+
$finfo->buffer($fileContents, FILEINFO_NONE, context: $context);
22+
$finfo->buffer($fileContents, flags: FILEINFO_NONE, context: $context);
23+
$finfo->buffer($fileContents, context: $context);
24+
$finfo->buffer($fileContents, context: $context, flags: FILEINFO_NONE);
25+
$finfo->buffer(...[$fileContents]);
26+
$finfo->buffer(...[$fileContents, $context]);
27+
$finfo->buffer(...[$fileContents, FILEINFO_NONE, $context]);
28+
}
29+
30+
?>
31+
-----
32+
<?php
33+
34+
declare(strict_types=1);
35+
36+
namespace Rector\Tests\Php85\Rector\FuncCall\RemoveFinfoBufferContextArgRector\RemoveFinfoBufferContextArgRectorTest\Fixture;
37+
38+
finfo_buffer($finfo, $fileContents);
39+
finfo_buffer($finfo, $fileContents, FILEINFO_NONE);
40+
finfo_buffer($finfo, $fileContents, FILEINFO_NONE);
41+
finfo_buffer($finfo, $fileContents, FILEINFO_NONE);
42+
finfo_buffer($finfo, $fileContents, flags: FILEINFO_NONE);
43+
finfo_buffer($finfo, $fileContents);
44+
finfo_buffer($finfo, $fileContents, flags: FILEINFO_NONE);
45+
finfo_buffer(...[$finfo, $fileContents]);
46+
finfo_buffer(...[$finfo, $fileContents, $context]);
47+
finfo_buffer(...[$finfo, $fileContents, FILEINFO_NONE, $context]);
48+
49+
function foo(\finfo $finfo): void
50+
{
51+
$finfo->buffer($fileContents, FILEINFO_NONE);
52+
$finfo->buffer($fileContents, FILEINFO_NONE);
53+
$finfo->buffer($fileContents, flags: FILEINFO_NONE);
54+
$finfo->buffer($fileContents);
55+
$finfo->buffer($fileContents, flags: FILEINFO_NONE);
56+
$finfo->buffer(...[$fileContents]);
57+
$finfo->buffer(...[$fileContents, $context]);
58+
$finfo->buffer(...[$fileContents, FILEINFO_NONE, $context]);
59+
}
60+
61+
?>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\Php85\Rector\FuncCall\RemoveFinfoBufferContextArgRector\RemoveFinfoBufferContextArgRectorTest;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class RemoveFinfoBufferContextArgRectorTest extends AbstractRectorTestCase
12+
{
13+
#[DataProvider('provideData')]
14+
public function test(string $filePath): void
15+
{
16+
$this->doTestFile($filePath);
17+
}
18+
19+
public static function provideData(): Iterator
20+
{
21+
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
22+
}
23+
24+
public function provideConfigFilePath(): string
25+
{
26+
return __DIR__ . '/config/configured_rule.php';
27+
}
28+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use Rector\Php85\Rector\FuncCall\RemoveFinfoBufferContextArgRector;
7+
use Rector\ValueObject\PhpVersion;
8+
9+
return static function (RectorConfig $rectorConfig): void {
10+
$rectorConfig->rule(RemoveFinfoBufferContextArgRector::class);
11+
12+
$rectorConfig->phpVersion(PhpVersion::PHP_85);
13+
};
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Php85\Rector\FuncCall;
6+
7+
use PhpCsFixer\FixerDefinition\CodeSample;
8+
use PhpParser\Node;
9+
use PhpParser\Node\Arg;
10+
use PhpParser\Node\Expr;
11+
use PhpParser\Node\Expr\CallLike;
12+
use PhpParser\Node\Expr\FuncCall;
13+
use PhpParser\Node\Expr\MethodCall;
14+
use PhpParser\Node\Identifier;
15+
use PHPStan\Type\ObjectType;
16+
use Rector\NodeAnalyzer\ArgsAnalyzer;
17+
use Rector\Rector\AbstractRector;
18+
use Rector\ValueObject\PhpVersionFeature;
19+
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
20+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
21+
22+
/**
23+
* @see https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_the_context_parameter_for_finfo_buffer
24+
* @see \Rector\Tests\Php85\Rector\FuncCall\RemoveFinfoBufferContextArgRector\RemoveFinfoBufferContextArgRectorTest
25+
*/
26+
final class RemoveFinfoBufferContextArgRector extends AbstractRector implements MinPhpVersionInterface
27+
{
28+
public function __construct(
29+
private readonly ArgsAnalyzer $argsAnalyzer,
30+
) {
31+
}
32+
33+
public function getRuleDefinition(): RuleDefinition
34+
{
35+
return new RuleDefinition('Remove argument by position by function name', [
36+
new CodeSample(
37+
<<<'CODE_SAMPLE'
38+
finfo_buffer($finfo, $fileContents, FILEINFO_NONE, []);
39+
CODE_SAMPLE
40+
,
41+
<<<'CODE_SAMPLE'
42+
finfo_buffer($finfo, $fileContents, FILEINFO_NONE);
43+
CODE_SAMPLE
44+
),
45+
]);
46+
}
47+
48+
/**
49+
* @return array<class-string<Node>>
50+
*/
51+
public function getNodeTypes(): array
52+
{
53+
return [FuncCall::class, MethodCall::class];
54+
}
55+
56+
/**
57+
* @param FuncCall $node
58+
*/
59+
public function refactor(Node $node): ?Node
60+
{
61+
if ($node->name instanceof Expr) {
62+
return null;
63+
}
64+
65+
if ($node->name instanceof FuncCall && $node->name->name !== 'finfo_buffer') {
66+
return null;
67+
}
68+
69+
$objectType = new ObjectType(\finfo::class);
70+
if ($node->name instanceof MethodCall && (! $this->nodeTypeResolver->isObjectType(
71+
$objectType
72+
) || $node->name->name !== 'buffer')) {
73+
return null;
74+
}
75+
76+
if ($this->removeContextArg($node)) {
77+
return $node;
78+
}
79+
80+
return null;
81+
}
82+
83+
public function provideMinPhpVersion(): int
84+
{
85+
return PhpVersionFeature::DEPRECATE_FINFO_BUFFER_CONTEXT;
86+
}
87+
88+
/**
89+
* @param FuncCall|MethodCall $funcCall
90+
*/
91+
private function removeContextArg(CallLike $funcCall): bool
92+
{
93+
// In `finfo::buffer` method calls, the first parameter, compared to `finfo_buffer`, does not exist.
94+
$methodArgCorrection = 0;
95+
if ($funcCall instanceof MethodCall) {
96+
$methodArgCorrection = -1;
97+
}
98+
99+
if (count($funcCall->args) <= 2 + $methodArgCorrection) {
100+
return false;
101+
}
102+
103+
// Argument 3 ($flags) and argument 4 ($context) are optional, thus named parameters must be considered
104+
if (! $this->argsAnalyzer->hasNamedArg($funcCall->args)) {
105+
if (count($funcCall->args) < 4 + $methodArgCorrection) {
106+
return false;
107+
}
108+
109+
unset($funcCall->args[3 + $methodArgCorrection]);
110+
111+
return true;
112+
}
113+
114+
foreach ($funcCall->args as $position => $arg) {
115+
// Cannot handle variadic args
116+
if (! $arg instanceof Arg) {
117+
return false;
118+
}
119+
120+
if ($arg->name instanceof Identifier && $arg->name->name === 'context') {
121+
unset($funcCall->args[$position]);
122+
123+
return true;
124+
}
125+
}
126+
127+
return false;
128+
}
129+
}

src/ValueObject/PhpVersionFeature.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,4 +768,10 @@ final class PhpVersionFeature
768768
* @var int
769769
*/
770770
public const ARRAY_ANY = PhpVersion::PHP_84;
771+
772+
/**
773+
* @see https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_the_context_parameter_for_finfo_buffer
774+
* @var int
775+
*/
776+
public const DEPRECATE_FINFO_BUFFER_CONTEXT = PhpVersion::PHP_85;
771777
}

0 commit comments

Comments
 (0)