11
11
use PHPStan \File \FileReader ;
12
12
use PHPStan \ShouldNotHappenException ;
13
13
use function array_filter ;
14
+ use function count ;
15
+ use function implode ;
14
16
use function is_string ;
17
+ use function preg_match_all ;
18
+ use function sprintf ;
15
19
use function str_contains ;
16
20
use function strpos ;
17
21
use function substr ;
18
22
use function substr_count ;
19
23
use const ARRAY_FILTER_USE_KEY ;
24
+ use const PREG_OFFSET_CAPTURE ;
20
25
use const T_COMMENT ;
21
26
use const T_DOC_COMMENT ;
22
27
@@ -25,6 +30,10 @@ class RichParser implements Parser
25
30
26
31
public const VISITOR_SERVICE_TAG = 'phpstan.parser.richParserNodeVisitor ' ;
27
32
33
+ private const PHPDOC_TAG_REGEX = '(@(?:[a-z][a-z0-9- \\\\]+:)?[a-z][a-z0-9- \\\\]*+) ' ;
34
+
35
+ private const PHPDOC_DOCTRINE_TAG_REGEX = '(@[a-z_ \\\\][a-z0-9_\: \\\\]*[a-z_][a-z0-9_]*) ' ;
36
+
28
37
public function __construct (
29
38
private \PhpParser \Parser $ parser ,
30
39
private Lexer $ lexer ,
@@ -107,11 +116,27 @@ private function getLinesToIgnore(array $tokens): array
107
116
$ text = $ token [1 ];
108
117
$ line = $ token [2 ];
109
118
110
- if ($ this ->enableIgnoreErrorsWithinPhpDocs ) {
111
- $ lines = $ lines +
112
- $ this ->getLinesToIgnoreForTokenByIgnoreComment ($ text , $ line , '@phpstan-ignore-next-line ' , true ) +
113
- $ this ->getLinesToIgnoreForTokenByIgnoreComment ($ text , $ line , '@phpstan-ignore-line ' );
114
-
119
+ if ($ this ->enableIgnoreErrorsWithinPhpDocs && $ type === T_DOC_COMMENT ) {
120
+ $ lines += $ this ->getLinesToIgnoreForTokenByIgnoreComment ($ text , $ line , '@phpstan-ignore-line ' );
121
+ if (str_contains ($ text , '@phpstan-ignore-next-line ' )) {
122
+ $ pattern = sprintf ('~%s~si ' , implode ('| ' , [self ::PHPDOC_TAG_REGEX , self ::PHPDOC_DOCTRINE_TAG_REGEX ]));
123
+ $ r = preg_match_all ($ pattern , $ text , $ pregMatches , PREG_OFFSET_CAPTURE );
124
+ if ($ r !== false ) {
125
+ $ c = count ($ pregMatches [0 ]);
126
+ if ($ c > 0 ) {
127
+ [$ lastMatchTag , $ lastMatchOffset ] = $ pregMatches [0 ][$ c - 1 ];
128
+ if ($ lastMatchTag === '@phpstan-ignore-next-line ' ) {
129
+ // this will let us ignore errors outside of PHPDoc
130
+ // and also cut off the PHPDoc text before the last tag
131
+ $ lineToIgnore = $ line + 1 + substr_count ($ text , "\n" );
132
+ $ lines [$ lineToIgnore ] = null ;
133
+ $ text = substr ($ text , 0 , $ lastMatchOffset );
134
+ }
135
+ }
136
+ }
137
+
138
+ $ lines += $ this ->getLinesToIgnoreForTokenByIgnoreComment ($ text , $ line , '@phpstan-ignore-next-line ' , true );
139
+ }
115
140
} else {
116
141
if (str_contains ($ text , '@phpstan-ignore-next-line ' )) {
117
142
$ line ++;
0 commit comments