Skip to content

Commit 586dfe9

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

7 files changed

Lines changed: 297 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\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\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: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\Php85\Rector\FuncCall\RemoveFinfoBufferContextArgRector\Fixture;
6+
7+
finfo_file($finfo, $fileContents, FILEINFO_NONE, $context);
8+
finfo_file($finfo, $fileContents, FILEINFO_NONE, context: $context);
9+
finfo_file($finfo, $fileContents, flags: FILEINFO_NONE, context: $context);
10+
11+
function foo(\finfo $finfo): void
12+
{
13+
$finfo->file($fileContents, FILEINFO_NONE, $context);
14+
$finfo->file($fileContents, FILEINFO_NONE, context: $context);
15+
$finfo->file($fileContents, flags: FILEINFO_NONE, context: $context);
16+
}
17+
18+
function bar($otherObject): 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+
}
24+
25+
?>
26+
-----
27+
<?php
28+
29+
declare(strict_types=1);
30+
31+
namespace Rector\Tests\Php85\Rector\FuncCall\RemoveFinfoBufferContextArgRector\Fixture;
32+
33+
finfo_file($finfo, $fileContents, FILEINFO_NONE, $context);
34+
finfo_file($finfo, $fileContents, FILEINFO_NONE, context: $context);
35+
finfo_file($finfo, $fileContents, flags: FILEINFO_NONE, context: $context);
36+
37+
function foo(\finfo $finfo): void
38+
{
39+
$finfo->file($fileContents, FILEINFO_NONE, $context);
40+
$finfo->file($fileContents, FILEINFO_NONE, context: $context);
41+
$finfo->file($fileContents, flags: FILEINFO_NONE, context: $context);
42+
}
43+
44+
function bar($otherObject): void
45+
{
46+
$finfo->buffer($fileContents, FILEINFO_NONE, $context);
47+
$finfo->buffer($fileContents, FILEINFO_NONE, context: $context);
48+
$finfo->buffer($fileContents, flags: FILEINFO_NONE, context: $context);
49+
}
50+
51+
?>
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;
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: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Php85\Rector\FuncCall;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Arg;
9+
use PhpParser\Node\Expr;
10+
use PhpParser\Node\Expr\CallLike;
11+
use PhpParser\Node\Expr\FuncCall;
12+
use PhpParser\Node\Expr\MethodCall;
13+
use PhpParser\Node\Identifier;
14+
use PHPStan\Type\ObjectType;
15+
use Rector\NodeAnalyzer\ArgsAnalyzer;
16+
use Rector\Rector\AbstractRector;
17+
use Rector\ValueObject\PhpVersionFeature;
18+
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
19+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
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+
/**
50+
* @return array<class-string<Node>>
51+
*/
52+
public function getNodeTypes(): array
53+
{
54+
return [FuncCall::class, MethodCall::class];
55+
}
56+
57+
/**
58+
* @param FuncCall $node
59+
*/
60+
public function refactor(Node $node): ?Node
61+
{
62+
if ($node->name instanceof Expr) {
63+
return null;
64+
}
65+
66+
if ($node instanceof FuncCall && ! $this->isName($node->name, 'finfo_buffer')) {
67+
return null;
68+
}
69+
70+
$objectType = new ObjectType(\finfo::class);
71+
if ($node instanceof MethodCall && (! $this->nodeTypeResolver->isObjectType(
72+
$node->var,
73+
$objectType
74+
) || ! $this->isName($node->name, 'buffer'))) {
75+
return null;
76+
}
77+
78+
if ($this->removeContextArg($node)) {
79+
return $node;
80+
}
81+
82+
return null;
83+
}
84+
85+
public function provideMinPhpVersion(): int
86+
{
87+
return PhpVersionFeature::DEPRECATE_FINFO_BUFFER_CONTEXT;
88+
}
89+
90+
/**
91+
* @param FuncCall|MethodCall $funcCall
92+
*/
93+
private function removeContextArg(CallLike $funcCall): bool
94+
{
95+
// In `finfo::buffer` method calls, the first parameter, compared to `finfo_buffer`, does not exist.
96+
$methodArgCorrection = 0;
97+
if ($funcCall instanceof MethodCall) {
98+
$methodArgCorrection = -1;
99+
}
100+
101+
if (count($funcCall->args) <= 2 + $methodArgCorrection) {
102+
return false;
103+
}
104+
105+
// Cannot handle variadic args
106+
foreach ($funcCall->args as $position => $arg) {
107+
if (! $arg instanceof Arg) {
108+
return false;
109+
}
110+
}
111+
112+
/** @var array<Arg> $args */
113+
$args = $funcCall->args;
114+
115+
// Argument 3 ($flags) and argument 4 ($context) are optional, thus named parameters must be considered
116+
if (! $this->argsAnalyzer->hasNamedArg($args)) {
117+
if (count($args) < 4 + $methodArgCorrection) {
118+
return false;
119+
}
120+
121+
unset($funcCall->args[3 + $methodArgCorrection]);
122+
123+
return true;
124+
}
125+
126+
foreach ($args as $position => $arg) {
127+
if ($arg->name instanceof Identifier && $arg->name->name === 'context') {
128+
unset($funcCall->args[$position]);
129+
130+
return true;
131+
}
132+
}
133+
134+
return false;
135+
}
136+
}

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)