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

PhpdocTypesOrderFixer - fix for intersection types #6243

Merged
merged 1 commit into from Feb 4, 2022
Merged
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
2 changes: 1 addition & 1 deletion src/DocBlock/Annotation.php
Expand Up @@ -208,7 +208,7 @@ public function setTypes(array $types): void
{
$pattern = '/'.preg_quote($this->getTypesContent(), '/').'/';

$this->lines[0]->setContent(Preg::replace($pattern, implode('|', $types), $this->lines[0]->getContent(), 1));
$this->lines[0]->setContent(Preg::replace($pattern, implode($this->getTypeExpression()->getTypesGlue(), $types), $this->lines[0]->getContent(), 1));

$this->clearCache();
}
Expand Down
17 changes: 13 additions & 4 deletions src/DocBlock/TypeExpression.php
Expand Up @@ -99,7 +99,7 @@ final class TypeExpression
)
)
(?:
\h*[|&]\h*
\h*(?<glue>[|&])\h*
(?&type)
)*
)
Expand All @@ -120,6 +120,8 @@ final class TypeExpression
*/
private $innerTypeExpressions = [];

private string $typesGlue = '|';

/**
* @var null|NamespaceAnalysis
*/
Expand Down Expand Up @@ -165,15 +167,15 @@ static function (array $type) { return $type['expression']->toString(); },
/**
* @param callable(self $a, self $b): int $compareCallback
*/
public function sortUnionTypes(callable $compareCallback): void
public function sortTypes(callable $compareCallback): void
{
foreach (array_reverse($this->innerTypeExpressions) as [
'start_index' => $startIndex,
'expression' => $inner,
]) {
$initialValueLength = \strlen($inner->toString());

$inner->sortUnionTypes($compareCallback);
$inner->sortTypes($compareCallback);

$this->value = substr_replace(
$this->value,
Expand All @@ -190,10 +192,15 @@ static function (array $type): self { return $type['expression']; },
$compareCallback
);

$this->value = implode('|', $this->getTypes());
$this->value = implode($this->getTypesGlue(), $this->getTypes());
}
}

public function getTypesGlue(): string
{
return $this->typesGlue;
}

public function getCommonType(): ?string
{
$aliases = $this->getAliases();
Expand Down Expand Up @@ -254,6 +261,8 @@ private function parse(): void
return;
}

$this->typesGlue = $matches['glue'] ?? $this->typesGlue;

$index = '' !== $matches['nullable'] ? 1 : 0;

if ($matches['type'] !== $matches['types']) {
Expand Down
2 changes: 1 addition & 1 deletion src/Fixer/Phpdoc/PhpdocTypesOrderFixer.php
Expand Up @@ -170,7 +170,7 @@ private function sortTypes(TypeExpression $typeExpression): array
return Preg::replace('/^\\??\\\?/', '', $type);
};

$typeExpression->sortUnionTypes(
$typeExpression->sortTypes(
function (TypeExpression $a, TypeExpression $b) use ($normalizeType): int {
$a = $normalizeType($a->toString());
$b = $normalizeType($b->toString());
Expand Down
1 change: 1 addition & 0 deletions tests/DocBlock/AnnotationTest.php
Expand Up @@ -473,6 +473,7 @@ public function provideTypesCases(): array
[['RUNTIMEEEEeXCEPTION'], [\Throwable::class], "*\t@throws\t \t RUNTIMEEEEeXCEPTION\t\t\t\t\t\t\t\n\n\n", "*\t@throws\t \t Throwable\t\t\t\t\t\t\t\n\n\n"],
[['RUNTIMEEEEeXCEPTION'], [\Throwable::class], "*@throws\t \t RUNTIMEEEEeXCEPTION\t\t\t\t\t\t\t\n\n\n", "*@throws\t \t Throwable\t\t\t\t\t\t\t\n\n\n"],
[['string'], ['string', 'null'], ' * @method string getString()', ' * @method string|null getString()'],
[['Foo', 'Bar'], ['Bar', 'Foo'], ' * @param Foo&Bar $x', ' * @param Bar&Foo $x'],
];
}

Expand Down
32 changes: 28 additions & 4 deletions tests/DocBlock/TypeExpressionTest.php
Expand Up @@ -86,6 +86,22 @@ public function provideGetTypesCases(): \Generator
yield ['array < int , callable ( string ) : bool >', ['array < int , callable ( string ) : bool >']];
}

/**
* @dataProvider provideGetTypesGlueCases
*/
public function testGetTypesGlue(string $expectedTypesGlue, string $typesExpression): void
{
$expression = new TypeExpression($typesExpression, null, []);
static::assertSame($expectedTypesGlue, $expression->getTypesGlue());
}

public static function provideGetTypesGlueCases(): iterable
{
yield ['|', 'string']; // for backward behaviour
yield ['|', 'bool|string'];
yield ['&', 'Foo&Bar'];
}

/**
* @param NamespaceUseAnalysis[] $namespaceUses
*
Expand Down Expand Up @@ -181,20 +197,20 @@ public function provideAllowsNullCases(): \Generator
}

/**
* @dataProvider provideSortUnionTypesCases
* @dataProvider provideSortTypesCases
*/
public function testSortUnionTypes(string $typesExpression, string $expectResult): void
public function testSortTypes(string $typesExpression, string $expectResult): void
{
$expression = new TypeExpression($typesExpression, null, []);

$expression->sortUnionTypes(static function (TypeExpression $a, TypeExpression $b): int {
$expression->sortTypes(static function (TypeExpression $a, TypeExpression $b): int {
return strcasecmp($a->toString(), $b->toString());
});

static::assertSame($expectResult, $expression->toString());
}

public function provideSortUnionTypesCases(): iterable
public function provideSortTypesCases(): iterable
{
yield 'not a union type' => [
'int',
Expand Down Expand Up @@ -264,5 +280,13 @@ public function provideSortUnionTypesCases(): iterable
'?array{0: Foo|Bar}',
'?array{0: Bar|Foo}',
];
yield 'simple types alternation' => [
'array<Foo&Bar>',
'array<Bar&Foo>',
];
yield 'nesty stuff' => [
'array<Level11&array<Level2|array<Level31&Level32>>>',
'array<array<array<Level31&Level32>|Level2>&Level11>',
];
}
}
16 changes: 16 additions & 0 deletions tests/Fixer/Phpdoc/PhpdocTypesOrderFixerTest.php
Expand Up @@ -411,6 +411,22 @@ public function provideFixWithAlphaAlgorithmCases(): array
[
'<?php /** @return array<int, callable(array<string, null|string> , DateTime): bool> */',
],
[
'<?php /** @return A&B&C */',
'<?php /** @return A&C&B */',
],
[
'<?php /** @return array<A&B&C> */',
'<?php /** @return array<A&C&B> */',
],
[
'<?php /** @return array<A&B&C>|bool|string */',
'<?php /** @return bool|array<A&B&C>|string */',
SpacePossum marked this conversation as resolved.
Show resolved Hide resolved
],
[
'<?php /** @return A&B<X|Y|Z>&C&D */',
'<?php /** @return A&D&B<X|Y|Z>&C */',
],
];
}

Expand Down