Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PhpdocTo(Param|Property|Return)TypeFixer - fix for type intersections #6188

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 3 additions & 7 deletions src/DocBlock/TypeExpression.php
Expand Up @@ -29,7 +29,7 @@ final class TypeExpression
* @internal
*/
public const REGEX_TYPES = '
(?<types> # alternation of several types separated by `|`
(?<types> # several types separated by `|` or `&`
(?<type> # single type
\?? # optionally nullable
(?:
Expand Down Expand Up @@ -88,13 +88,9 @@ final class TypeExpression
[\\\\\w-]++
)
)
(?: # intersection
\h*&\h*
(?&type)
)*
)
(?:
\h*\|\h*
\h*[|&]\h*
(?&type)
)*
)
Expand Down Expand Up @@ -129,7 +125,7 @@ public function __construct(string $value, ?NamespaceAnalysis $namespace, array

$this->types[] = $matches['type'];
$value = Preg::replace(
'/^'.preg_quote($matches['type'], '/').'(\h*\|\h*)?/',
'/^'.preg_quote($matches['type'], '/').'(\h*[|&]\h*)?/',
'',
$value
);
Expand Down
4 changes: 2 additions & 2 deletions src/Fixer/Phpdoc/NoSuperfluousPhpdocTagsFixer.php
Expand Up @@ -386,7 +386,7 @@ private function parseTypeHint(Tokens $tokens, int $index): array
while (true) {
$type = '';

while ($tokens[$index]->isGivenKind([T_NS_SEPARATOR, T_STATIC, T_STRING, CT::T_ARRAY_TYPEHINT, T_CALLABLE, CT::T_TYPE_INTERSECTION])) {
while ($tokens[$index]->isGivenKind([T_NS_SEPARATOR, T_STATIC, T_STRING, CT::T_ARRAY_TYPEHINT, T_CALLABLE])) {
$type .= $tokens[$index]->getContent();
$index = $tokens->getNextMeaningfulToken($index);
}
Expand All @@ -397,7 +397,7 @@ private function parseTypeHint(Tokens $tokens, int $index): array

$types[] = $type;

if (!$tokens[$index]->isGivenKind(CT::T_TYPE_ALTERNATION)) {
if (!$tokens[$index]->isGivenKind([CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION])) {
break;
}

Expand Down
4 changes: 2 additions & 2 deletions tests/DocBlock/AnnotationTest.php
Expand Up @@ -382,11 +382,11 @@ public function provideTypeParsingCases(): array
'/** @var class-string<Foo> */',
],
[
['A&B'],
['A', 'B'],
'/** @var A&B */',
],
[
['A & B'],
['A', 'B'],
'/** @var A & B */',
],
[
Expand Down
4 changes: 2 additions & 2 deletions tests/DocBlock/TypeExpressionTest.php
Expand Up @@ -69,8 +69,8 @@ public function provideGetTypesCases(): \Generator
yield ['null|true|false|1|1.5|\'a\'|"b"', ['null', 'true', 'false', '1', '1.5', "'a'", '"b"']];
yield ['int | "a" | A<B<C, D>, E<F::*|G[]>>', ['int', '"a"', 'A<B<C, D>, E<F::*|G[]>>']];
yield ['class-string<Foo>', ['class-string<Foo>']];
yield ['A&B', ['A&B']];
yield ['A & B', ['A & B']];
yield ['A&B', ['A', 'B']];
yield ['A & B', ['A', 'B']];
yield ['array{1: bool, 2: bool}', ['array{1: bool, 2: bool}']];
yield ['array{a: int|string, b?: bool}', ['array{a: int|string, b?: bool}']];
yield ['array{\'a\': "a", "b"?: \'b\'}', ['array{\'a\': "a", "b"?: \'b\'}']];
Expand Down
18 changes: 18 additions & 0 deletions tests/Fixer/FunctionNotation/PhpdocToParamTypeFixerTest.php
Expand Up @@ -416,6 +416,24 @@ function bar() {
}
',
],
'intersection types' => [
'<?php
/** @param Bar&Baz $x */
function bar($x) {}
',
],
'very long class name before ampersand' => [
'<?php
/** @param Baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar&Baz $x */
function bar($x) {}
',
],
'very long class name after ampersand' => [
'<?php
/** @param Bar&Baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz $x */
function bar($x) {}
',
],
];
}
}
Expand Up @@ -449,6 +449,15 @@ public abstract function getFoo();
'<?php new class { /** @var int */ private int $foo; };',
'<?php new class { /** @var int */ private $foo; };',
],
'intersection types' => [
'<?php class Foo { /** @var Bar&Baz */ private $x; }',
],
'very long class name before ampersand' => [
'<?php class Foo { /** @var Baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar&Baz */ private $x; }',
],
'very long class name after ampersand' => [
'<?php class Foo { /** @var Bar&Baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz */ private $x; }',
],
];
}

Expand Down
18 changes: 18 additions & 0 deletions tests/Fixer/FunctionNotation/PhpdocToReturnTypeFixerTest.php
Expand Up @@ -313,6 +313,24 @@ function my_foo() {}
'<?php /** @return string[]|int[] */ function my_foo(): array {}',
'<?php /** @return string[]|int[] */ function my_foo() {}',
],
'intersection types' => [
'<?php
/** @return Bar&Baz */
function bar() {}
',
],
'very long class name before ampersand' => [
'<?php
/** @return Baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar&Baz */
function bar() {}
',
],
'very long class name after ampersand' => [
'<?php
/** @return Bar&Baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz */
function bar() {}
',
],
];
}

Expand Down