7
7
use PhpParser \NodeTraverser ;
8
8
use PhpParser \NodeVisitor \NameResolver ;
9
9
use PhpParser \Token ;
10
+ use PHPStan \Analyser \FileAnalyserResult ;
10
11
use PHPStan \Analyser \Ignore \IgnoreLexer ;
11
12
use PHPStan \Analyser \Ignore \IgnoreParseException ;
12
13
use PHPStan \DependencyInjection \Container ;
13
14
use PHPStan \File \FileReader ;
14
15
use PHPStan \ShouldNotHappenException ;
15
16
use function array_filter ;
17
+ use function array_key_last ;
16
18
use function array_map ;
19
+ use function array_values ;
17
20
use function count ;
18
21
use function implode ;
19
22
use function in_array ;
30
33
use const T_DOC_COMMENT ;
31
34
use const T_WHITESPACE ;
32
35
36
+ /**
37
+ * @phpstan-import-type Identifier from FileAnalyserResult
38
+ */
33
39
final class RichParser implements Parser
34
40
{
35
41
@@ -111,7 +117,7 @@ public function parseString(string $sourceCode): array
111
117
112
118
/**
113
119
* @param Token[] $tokens
114
- * @return array{lines: array<int, non-empty-list<string >|null>, errors: array<int, non-empty-list<string>>}
120
+ * @return array{lines: array<int, non-empty-list<Identifier >|null>, errors: array<int, non-empty-list<string>>}
115
121
*/
116
122
private function getLinesToIgnore (array $ tokens ): array
117
123
{
@@ -268,33 +274,29 @@ private function getLinesToIgnoreForTokenByIgnoreComment(
268
274
}
269
275
270
276
/**
271
- * @return non-empty-list<string >
277
+ * @return non-empty-list<Identifier >
272
278
* @throws IgnoreParseException
273
279
*/
274
280
private function parseIdentifiers (string $ text , int $ ignorePos ): array
275
281
{
276
282
$ text = substr ($ text , $ ignorePos + strlen ('@phpstan-ignore ' ));
277
- $ originalTokens = $ this ->ignoreLexer ->tokenize ($ text );
278
- $ tokens = [];
279
-
280
- foreach ($ originalTokens as $ originalToken ) {
281
- if ($ originalToken [IgnoreLexer::TYPE_OFFSET ] === IgnoreLexer::TOKEN_WHITESPACE ) {
282
- continue ;
283
- }
284
- $ tokens [] = $ originalToken ;
285
- }
283
+ $ tokens = $ this ->ignoreLexer ->tokenize ($ text );
286
284
287
285
$ c = count ($ tokens );
288
286
289
287
$ identifiers = [];
288
+ $ comment = null ;
290
289
$ openParenthesisCount = 0 ;
291
290
$ expected = [IgnoreLexer::TOKEN_IDENTIFIER ];
291
+ $ lastTokenTypeLabel = '@phpstan-ignore ' ;
292
292
293
293
for ($ i = 0 ; $ i < $ c ; $ i ++) {
294
- $ lastTokenTypeLabel = isset ($ tokenType ) ? $ this ->ignoreLexer ->getLabel ($ tokenType ) : '@phpstan-ignore ' ;
294
+ if (isset ($ tokenType ) && $ tokenType !== IgnoreLexer::TOKEN_WHITESPACE ) {
295
+ $ lastTokenTypeLabel = $ this ->ignoreLexer ->getLabel ($ tokenType );
296
+ }
295
297
[IgnoreLexer::VALUE_OFFSET => $ content , IgnoreLexer::TYPE_OFFSET => $ tokenType , IgnoreLexer::LINE_OFFSET => $ tokenLine ] = $ tokens [$ i ];
296
298
297
- if ($ expected !== null && !in_array ($ tokenType , $ expected , true )) {
299
+ if ($ expected !== null && !in_array ($ tokenType , [... $ expected, IgnoreLexer:: TOKEN_WHITESPACE ] , true )) {
298
300
$ tokenTypeLabel = $ this ->ignoreLexer ->getLabel ($ tokenType );
299
301
$ otherTokenContent = $ tokenType === IgnoreLexer::TOKEN_OTHER ? sprintf (" '%s' " , $ content ) : '' ;
300
302
$ expectedLabels = implode (' or ' , array_map (fn ($ token ) => $ this ->ignoreLexer ->getLabel ($ token ), $ expected ));
@@ -303,6 +305,9 @@ private function parseIdentifiers(string $text, int $ignorePos): array
303
305
}
304
306
305
307
if ($ tokenType === IgnoreLexer::TOKEN_OPEN_PARENTHESIS ) {
308
+ if ($ openParenthesisCount > 0 ) {
309
+ $ comment .= $ content ;
310
+ }
306
311
$ openParenthesisCount ++;
307
312
$ expected = null ;
308
313
continue ;
@@ -311,17 +316,25 @@ private function parseIdentifiers(string $text, int $ignorePos): array
311
316
if ($ tokenType === IgnoreLexer::TOKEN_CLOSE_PARENTHESIS ) {
312
317
$ openParenthesisCount --;
313
318
if ($ openParenthesisCount === 0 ) {
319
+ $ key = array_key_last ($ identifiers );
320
+ if ($ key !== null ) {
321
+ $ identifiers [$ key ]['comment ' ] = $ comment ;
322
+ $ comment = null ;
323
+ }
314
324
$ expected = [IgnoreLexer::TOKEN_COMMA , IgnoreLexer::TOKEN_END ];
325
+ } else {
326
+ $ comment .= $ content ;
315
327
}
316
328
continue ;
317
329
}
318
330
319
331
if ($ openParenthesisCount > 0 ) {
332
+ $ comment .= $ content ;
320
333
continue ; // waiting for comment end
321
334
}
322
335
323
336
if ($ tokenType === IgnoreLexer::TOKEN_IDENTIFIER ) {
324
- $ identifiers [] = $ content ;
337
+ $ identifiers [] = [ ' name ' => $ content, ' comment ' => null ] ;
325
338
$ expected = [IgnoreLexer::TOKEN_COMMA , IgnoreLexer::TOKEN_END , IgnoreLexer::TOKEN_OPEN_PARENTHESIS ];
326
339
continue ;
327
340
}
@@ -340,7 +353,7 @@ private function parseIdentifiers(string $text, int $ignorePos): array
340
353
throw new IgnoreParseException ('Missing identifier ' , 1 );
341
354
}
342
355
343
- return $ identifiers ;
356
+ return array_values ( $ identifiers) ;
344
357
}
345
358
346
359
}
0 commit comments