Skip to content

Commit

Permalink
bug #6224 ArgumentsAnalyzer - support PHP8.1 readonly (SpacePossum)
Browse files Browse the repository at this point in the history
This PR was merged into the master branch.

Discussion
----------

ArgumentsAnalyzer - support PHP8.1 readonly

closes #6221

Commits
-------

8daa46e ArgumentsAnalyzer - support PHP8.1 readonly
  • Loading branch information
SpacePossum committed Jan 9, 2022
2 parents 4ba8952 + 8daa46e commit f4b0017
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 26 deletions.
Expand Up @@ -98,8 +98,8 @@ protected function createConfigurationDefinition(): FixerConfigurationResolverIn
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
$functionsAnalyzer = new FunctionsAnalyzer();

$tokenKinds = [T_FUNCTION];

if (\PHP_VERSION_ID >= 70400) {
$tokenKinds[] = T_FN;
}
Expand All @@ -112,7 +112,6 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
}

$arguments = $functionsAnalyzer->getFunctionArguments($tokens, $index);

$this->fixFunctionParameters($tokens, $arguments);
}
}
Expand Down
24 changes: 17 additions & 7 deletions src/Tokenizer/Analyzer/ArgumentsAnalyzer.php
Expand Up @@ -87,6 +87,16 @@ public function getArguments(Tokens $tokens, int $openParenthesis, int $closePar

public function getArgumentInfo(Tokens $tokens, int $argumentStart, int $argumentEnd): ArgumentAnalysis
{
static $skipTypes = null;

if (null === $skipTypes) {
$skipTypes = [T_ELLIPSIS, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE];

if (\defined('T_READONLY')) { // @TODO: drop condition when PHP 8.1+ is required
$skipTypes[] = T_READONLY;
}
}

$info = [
'default' => null,
'name' => null,
Expand All @@ -101,10 +111,16 @@ public function getArgumentInfo(Tokens $tokens, int $argumentStart, int $argumen
for ($index = $argumentStart; $index <= $argumentEnd; ++$index) {
$token = $tokens[$index];

if (\defined('T_ATTRIBUTE') && $token->isGivenKind(T_ATTRIBUTE)) {
$index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ATTRIBUTE, $index);

continue;
}

if (
$token->isComment()
|| $token->isWhitespace()
|| $token->isGivenKind([T_ELLIPSIS, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE])
|| $token->isGivenKind($skipTypes)
|| $token->equals('&')
) {
continue;
Expand All @@ -122,12 +138,6 @@ public function getArgumentInfo(Tokens $tokens, int $argumentStart, int $argumen
continue;
}

if (\defined('T_ATTRIBUTE') && $token->isGivenKind(T_ATTRIBUTE)) {
$index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ATTRIBUTE, $index);

continue;
}

if ($sawName) {
$info['default'] .= $token->getContent();
} else {
Expand Down
Expand Up @@ -500,4 +500,27 @@ function foo2(?string &/*comment*/$param2 = null) {}
yield [$cases[0], $cases[1]];
yield [$cases[1], $cases[0], ['use_nullable_type_declaration' => false]];
}

/**
* @dataProvider provideFix81Cases
* @requires PHP 8.1
*/
public function testFix81(string $expected): void
{
$this->doTest($expected);
}

public function provideFix81Cases(): iterable
{
yield [
'<?php
class Foo
{
public function __construct(
protected readonly ?bool $nullable = null,
) {}
}
',
];
}
}
88 changes: 71 additions & 17 deletions tests/Tokenizer/Analyzer/ArgumentsAnalyzerTest.php
Expand Up @@ -86,16 +86,14 @@ public function testArguments73(string $code, int $openIndex, int $closeIndex, a
static::assertSame($arguments, $analyzer->getArguments($tokens, $openIndex, $closeIndex));
}

public function provideArguments73Cases(): array
public function provideArguments73Cases(): iterable
{
return [
['<?php foo($a,);', 2, 5, [3 => 3]],
['<?php foo($a,/**/);', 2, 6, [3 => 3]],
['<?php foo($a(1,2,3,4,5),);', 2, 16, [3 => 14]],
['<?php foo($a(1,2,3,4,5,),);', 2, 17, [3 => 15]],
['<?php foo($a(1,2,3,4,5,),);', 4, 15, [5 => 5, 7 => 7, 9 => 9, 11 => 11, 13 => 13]],
['<?php bar($a, $b , ) ;', 2, 10, [3 => 3, 5 => 7]],
];
yield ['<?php foo($a,);', 2, 5, [3 => 3]];
yield ['<?php foo($a,/**/);', 2, 6, [3 => 3]];
yield ['<?php foo($a(1,2,3,4,5),);', 2, 16, [3 => 14]];
yield ['<?php foo($a(1,2,3,4,5,),);', 2, 17, [3 => 15]];
yield ['<?php foo($a(1,2,3,4,5,),);', 4, 15, [5 => 5, 7 => 7, 9 => 9, 11 => 11, 13 => 13]];
yield ['<?php bar($a, $b , ) ;', 2, 10, [3 => 3, 5 => 7]];
}

/**
Expand Down Expand Up @@ -146,10 +144,7 @@ public function testArgumentInfo(string $code, int $openIndex, int $closeIndex,
$tokens = Tokens::fromCode($code);
$analyzer = new ArgumentsAnalyzer();

static::assertSame(
serialize($expected),
serialize($analyzer->getArgumentInfo($tokens, $openIndex, $closeIndex))
);
self::assertArgumentAnalysis($expected, $analyzer->getArgumentInfo($tokens, $openIndex, $closeIndex));
}

public function provideArgumentsInfoCases(): \Generator
Expand Down Expand Up @@ -284,10 +279,7 @@ public function testArgumentInfo80(string $code, int $openIndex, int $closeIndex
$tokens = Tokens::fromCode($code);
$analyzer = new ArgumentsAnalyzer();

static::assertSame(
serialize($expected),
serialize($analyzer->getArgumentInfo($tokens, $openIndex, $closeIndex))
);
self::assertArgumentAnalysis($expected, $analyzer->getArgumentInfo($tokens, $openIndex, $closeIndex));
}

public function provideArgumentsInfo80Cases(): \Generator
Expand Down Expand Up @@ -326,4 +318,66 @@ public function provideArgumentsInfo80Cases(): \Generator
];
}
}

/**
* @requires PHP 8.1
* @dataProvider provideArgumentsInfo81Cases
*/
public function testArgumentInfo81(string $code, int $openIndex, int $closeIndex, ArgumentAnalysis $expected): void
{
$tokens = Tokens::fromCode($code);
$analyzer = new ArgumentsAnalyzer();

self::assertArgumentAnalysis($expected, $analyzer->getArgumentInfo($tokens, $openIndex, $closeIndex));
}

public function provideArgumentsInfo81Cases(): \Generator
{
yield [
'<?php
class Foo
{
public function __construct(
protected readonly ?bool $nullable = true,
) {}
}
',
13,
25,
new ArgumentAnalysis(
'$nullable',
21,
'true',
new TypeAnalysis(
'?bool',
18,
19
)
),
];
}

private static function assertArgumentAnalysis(ArgumentAnalysis $expected, ArgumentAnalysis $actual): void
{
static::assertSame($expected->getDefault(), $actual->getDefault(), 'Default.');
static::assertSame($expected->getName(), $actual->getName(), 'Name.');
static::assertSame($expected->getNameIndex(), $actual->getNameIndex(), 'Name index.');
static::assertSame($expected->hasDefault(), $actual->hasDefault(), 'Has default.');
static::assertSame($expected->hasTypeAnalysis(), $actual->hasTypeAnalysis(), 'Has type analysis.');

if ($expected->hasTypeAnalysis()) {
$expectedTypeAnalysis = $expected->getTypeAnalysis();
$actualTypeAnalysis = $actual->getTypeAnalysis();

static::assertSame($expectedTypeAnalysis->getEndIndex(), $actualTypeAnalysis->getEndIndex(), 'Type analysis end index.');
static::assertSame($expectedTypeAnalysis->getName(), $actualTypeAnalysis->getName(), 'Type analysis name.');
static::assertSame($expectedTypeAnalysis->getStartIndex(), $actualTypeAnalysis->getStartIndex(), 'Type analysis start index.');
static::assertSame($expectedTypeAnalysis->isNullable(), $actualTypeAnalysis->isNullable(), 'Type analysis nullable.');
static::assertSame($expectedTypeAnalysis->isReservedType(), $actualTypeAnalysis->isReservedType(), 'Type analysis reserved type.');
} else {
static::assertNull($actual->getTypeAnalysis());
}

static::assertSame(serialize($expected), serialize($actual));
}
}

0 comments on commit f4b0017

Please sign in to comment.