Skip to content

Commit 3416dc6

Browse files
committed
Callable parameter and return type have attributes
1 parent ecb7789 commit 3416dc6

File tree

2 files changed

+89
-11
lines changed

2 files changed

+89
-11
lines changed

src/Parser/TypeParser.php

+20-5
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,12 @@ public function parse(TokenIterator $tokens): Ast\Type\TypeNode
6161
return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
6262
}
6363

64-
private function enrichWithAttributes(TokenIterator $tokens, Ast\Type\TypeNode $type, int $startLine, int $startIndex): Ast\Type\TypeNode
64+
/**
65+
* @template T of Ast\Node
66+
* @param T $type
67+
* @return T
68+
*/
69+
private function enrichWithAttributes(TokenIterator $tokens, Ast\Node $type, int $startLine, int $startIndex): Ast\Node
6570
{
6671
$endLine = $tokens->currentTokenLine();
6772
$endIndex = $tokens->currentTokenIndex();
@@ -139,7 +144,7 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
139144
}
140145

141146
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_THIS_VARIABLE)) {
142-
$type = new Ast\Type\ThisTypeNode();
147+
$type = $this->enrichWithAttributes($tokens, new Ast\Type\ThisTypeNode(), $startLine, $startIndex);
143148

144149
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
145150
$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
@@ -151,7 +156,7 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
151156
$currentTokenValue = $tokens->currentTokenValue();
152157
$tokens->pushSavePoint(); // because of ConstFetchNode
153158
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) {
154-
$type = new Ast\Type\IdentifierTypeNode($currentTokenValue);
159+
$type = $this->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode($currentTokenValue), $startLine, $startIndex);
155160

156161
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
157162
$tokens->dropSavePoint(); // because of ConstFetchNode
@@ -454,7 +459,10 @@ private function parseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNod
454459

455460
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
456461
$tokens->consumeTokenType(Lexer::TOKEN_COLON);
457-
$returnType = $this->parseCallableReturnType($tokens);
462+
463+
$startLine = $tokens->currentTokenLine();
464+
$startIndex = $tokens->currentTokenIndex();
465+
$returnType = $this->enrichWithAttributes($tokens, $this->parseCallableReturnType($tokens), $startLine, $startIndex);
458466

459467
return new Ast\Type\CallableTypeNode($identifier, $parameters, $returnType);
460468
}
@@ -463,6 +471,8 @@ private function parseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNod
463471
/** @phpstan-impure */
464472
private function parseCallableParameter(TokenIterator $tokens): Ast\Type\CallableTypeParameterNode
465473
{
474+
$startLine = $tokens->currentTokenLine();
475+
$startIndex = $tokens->currentTokenIndex();
466476
$type = $this->parse($tokens);
467477
$isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE);
468478
$isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC);
@@ -476,7 +486,12 @@ private function parseCallableParameter(TokenIterator $tokens): Ast\Type\Callabl
476486
}
477487

478488
$isOptional = $tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL);
479-
return new Ast\Type\CallableTypeParameterNode($type, $isReference, $isVariadic, $parameterName, $isOptional);
489+
return $this->enrichWithAttributes(
490+
$tokens,
491+
new Ast\Type\CallableTypeParameterNode($type, $isReference, $isVariadic, $parameterName, $isOptional),
492+
$startLine,
493+
$startIndex
494+
);
480495
}
481496

482497

tests/PHPStan/Parser/TypeParserTest.php

+69-6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode;
99
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
1010
use PHPStan\PhpDocParser\Ast\ConstExpr\QuoteAwareConstExprStringNode;
11+
use PHPStan\PhpDocParser\Ast\Node;
1112
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeItemNode;
1213
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode;
1314
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
@@ -2006,11 +2007,73 @@ static function (TypeNode $typeNode): TypeNode {
20062007
],
20072008
],
20082009
];
2010+
2011+
yield [
2012+
'callable(Foo, Bar): void',
2013+
[
2014+
[
2015+
static function (TypeNode $typeNode): TypeNode {
2016+
return $typeNode;
2017+
},
2018+
'callable(Foo, Bar): void',
2019+
1,
2020+
1,
2021+
0,
2022+
9,
2023+
],
2024+
[
2025+
static function (CallableTypeNode $typeNode): TypeNode {
2026+
return $typeNode->identifier;
2027+
},
2028+
'callable',
2029+
1,
2030+
1,
2031+
0,
2032+
0,
2033+
],
2034+
[
2035+
static function (CallableTypeNode $typeNode): Node {
2036+
return $typeNode->parameters[0];
2037+
},
2038+
'Foo',
2039+
1,
2040+
1,
2041+
2,
2042+
2,
2043+
],
2044+
[
2045+
static function (CallableTypeNode $typeNode): TypeNode {
2046+
return $typeNode->returnType;
2047+
},
2048+
'void',
2049+
1,
2050+
1,
2051+
9,
2052+
9,
2053+
],
2054+
],
2055+
];
2056+
2057+
yield [
2058+
'$this',
2059+
[
2060+
[
2061+
static function (TypeNode $typeNode): TypeNode {
2062+
return $typeNode;
2063+
},
2064+
'$this',
2065+
1,
2066+
1,
2067+
0,
2068+
0,
2069+
],
2070+
],
2071+
];
20092072
}
20102073

20112074
/**
20122075
* @dataProvider dataLinesAndIndexes
2013-
* @param list<array{callable(TypeNode): TypeNode, string, int, int, int, int}> $assertions
2076+
* @param list<array{callable(Node): Node, string, int, int, int, int}> $assertions
20142077
*/
20152078
public function testLinesAndIndexes(string $input, array $assertions): void
20162079
{
@@ -2025,16 +2088,16 @@ public function testLinesAndIndexes(string $input, array $assertions): void
20252088
foreach ($assertions as [$callable, $expectedContent, $startLine, $endLine, $startIndex, $endIndex]) {
20262089
$typeToAssert = $callable($typeNode);
20272090

2091+
$this->assertSame($startLine, $typeToAssert->getAttribute(Attribute::START_LINE));
2092+
$this->assertSame($endLine, $typeToAssert->getAttribute(Attribute::END_LINE));
2093+
$this->assertSame($startIndex, $typeToAssert->getAttribute(Attribute::START_INDEX));
2094+
$this->assertSame($endIndex, $typeToAssert->getAttribute(Attribute::END_INDEX));
2095+
20282096
$content = '';
20292097
for ($i = $startIndex; $i <= $endIndex; $i++) {
20302098
$content .= $tokensArray[$i][Lexer::VALUE_OFFSET];
20312099
}
2032-
20332100
$this->assertSame($expectedContent, $content);
2034-
$this->assertSame($startLine, $typeToAssert->getAttribute(Attribute::START_LINE));
2035-
$this->assertSame($endLine, $typeToAssert->getAttribute(Attribute::END_LINE));
2036-
$this->assertSame($startIndex, $typeToAssert->getAttribute(Attribute::START_INDEX));
2037-
$this->assertSame($endIndex, $typeToAssert->getAttribute(Attribute::END_INDEX));
20382101
}
20392102
}
20402103

0 commit comments

Comments
 (0)