Skip to content

Commit f440c76

Browse files
committed
Printer - preserve and add parentheses as needed
1 parent b9b6cf0 commit f440c76

10 files changed

+924
-11
lines changed

src/Ast/Type/ArrayTypeNode.php

+8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ public function __construct(TypeNode $type)
2020

2121
public function __toString(): string
2222
{
23+
if (
24+
$this->type instanceof CallableTypeNode
25+
|| $this->type instanceof ConstTypeNode
26+
|| $this->type instanceof NullableTypeNode
27+
) {
28+
return '(' . $this->type . ')[]';
29+
}
30+
2331
return $this->type . '[]';
2432
}
2533

src/Ast/Type/IntersectionTypeNode.php

+8-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\PhpDocParser\Ast\Type;
44

55
use PHPStan\PhpDocParser\Ast\NodeAttributes;
6+
use function array_map;
67
use function implode;
78

89
class IntersectionTypeNode implements TypeNode
@@ -24,7 +25,13 @@ public function __construct(array $types)
2425

2526
public function __toString(): string
2627
{
27-
return '(' . implode(' & ', $this->types) . ')';
28+
return '(' . implode(' & ', array_map(static function (TypeNode $type): string {
29+
if ($type instanceof NullableTypeNode) {
30+
return '(' . $type . ')';
31+
}
32+
33+
return (string) $type;
34+
}, $this->types)) . ')';
2835
}
2936

3037
}

src/Ast/Type/OffsetAccessTypeNode.php

+8
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ public function __construct(TypeNode $type, TypeNode $offset)
2323

2424
public function __toString(): string
2525
{
26+
if (
27+
$this->type instanceof CallableTypeNode
28+
|| $this->type instanceof ConstTypeNode
29+
|| $this->type instanceof NullableTypeNode
30+
) {
31+
return '(' . $this->type . ')[' . $this->offset . ']';
32+
}
33+
2634
return $this->type . '[' . $this->offset . ']';
2735
}
2836

src/Ast/Type/UnionTypeNode.php

+8-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\PhpDocParser\Ast\Type;
44

55
use PHPStan\PhpDocParser\Ast\NodeAttributes;
6+
use function array_map;
67
use function implode;
78

89
class UnionTypeNode implements TypeNode
@@ -24,7 +25,13 @@ public function __construct(array $types)
2425

2526
public function __toString(): string
2627
{
27-
return '(' . implode(' | ', $this->types) . ')';
28+
return '(' . implode(' | ', array_map(static function (TypeNode $type): string {
29+
if ($type instanceof NullableTypeNode) {
30+
return '(' . $type . ')';
31+
}
32+
33+
return (string) $type;
34+
}, $this->types)) . ')';
2835
}
2936

3037
}

src/Parser/TokenIterator.php

+60
Original file line numberDiff line numberDiff line change
@@ -268,4 +268,64 @@ private function throwError(int $expectedTokenType, ?string $expectedTokenValue
268268
);
269269
}
270270

271+
/**
272+
* Check whether the position is directly preceded by a certain token type.
273+
*
274+
* During this check TOKEN_HORIZONTAL_WS and TOKEN_PHPDOC_EOL are skipped
275+
*/
276+
public function hasTokenImmediatelyBefore(int $pos, int $expectedTokenType): bool
277+
{
278+
$tokens = $this->tokens;
279+
$pos--;
280+
for (; $pos >= 0; $pos--) {
281+
$token = $tokens[$pos];
282+
$type = $token[Lexer::TYPE_OFFSET];
283+
if ($type === $expectedTokenType) {
284+
return true;
285+
}
286+
if (!in_array($type, [
287+
Lexer::TOKEN_HORIZONTAL_WS,
288+
Lexer::TOKEN_PHPDOC_EOL,
289+
], true)) {
290+
break;
291+
}
292+
}
293+
return false;
294+
}
295+
296+
/**
297+
* Check whether the position is directly followed by a certain token type.
298+
*
299+
* During this check TOKEN_HORIZONTAL_WS and TOKEN_PHPDOC_EOL are skipped
300+
*/
301+
public function hasTokenImmediatelyAfter(int $pos, int $expectedTokenType): bool
302+
{
303+
$tokens = $this->tokens;
304+
$pos++;
305+
for ($c = count($tokens); $pos < $c; $pos++) {
306+
$token = $tokens[$pos];
307+
$type = $token[Lexer::TYPE_OFFSET];
308+
if ($type === $expectedTokenType) {
309+
return true;
310+
}
311+
if (!in_array($type, [
312+
Lexer::TOKEN_HORIZONTAL_WS,
313+
Lexer::TOKEN_PHPDOC_EOL,
314+
], true)) {
315+
break;
316+
}
317+
}
318+
319+
return false;
320+
}
321+
322+
/**
323+
* Whether the given position is immediately surrounded by parenthesis.
324+
*/
325+
public function hasParentheses(int $startPos, int $endPos): bool
326+
{
327+
return $this->hasTokenImmediatelyBefore($startPos, Lexer::TOKEN_OPEN_PARENTHESES)
328+
&& $this->hasTokenImmediatelyAfter($endPos, Lexer::TOKEN_CLOSE_PARENTHESES);
329+
}
330+
271331
}

0 commit comments

Comments
 (0)