29
29
use PhpCsFixer \Tokenizer \CT ;
30
30
use PhpCsFixer \Tokenizer \Token ;
31
31
use PhpCsFixer \Tokenizer \Tokens ;
32
+ use PhpCsFixer \Tokenizer \TokensAnalyzer ;
32
33
33
34
final class NoSuperfluousPhpdocTagsFixer extends AbstractFixer implements ConfigurableFixerInterface
34
35
{
@@ -106,14 +107,44 @@ public function isCandidate(Tokens $tokens): bool
106
107
*/
107
108
protected function applyFix (\SplFileInfo $ file , Tokens $ tokens ): void
108
109
{
110
+ $ tokensAnalyzer = new TokensAnalyzer ($ tokens );
111
+
109
112
$ namespaceUseAnalyzer = new NamespaceUsesAnalyzer ();
110
113
$ shortNames = [];
114
+ $ currentSymbol = null ;
115
+ $ currentSymbolEndIndex = null ;
111
116
112
117
foreach ($ namespaceUseAnalyzer ->getDeclarationsFromTokens ($ tokens ) as $ namespaceUseAnalysis ) {
113
118
$ shortNames [strtolower ($ namespaceUseAnalysis ->getShortName ())] = '\\' .strtolower ($ namespaceUseAnalysis ->getFullName ());
114
119
}
115
120
121
+ $ symbolKinds = [T_CLASS , T_INTERFACE ];
122
+ if (\defined ('T_ENUM ' )) { // @TODO drop the condition when requiring PHP 8.1+
123
+ $ symbolKinds [] = T_ENUM ;
124
+ }
125
+
116
126
foreach ($ tokens as $ index => $ token ) {
127
+ if ($ index === $ currentSymbolEndIndex ) {
128
+ $ currentSymbol = null ;
129
+ $ currentSymbolEndIndex = null ;
130
+
131
+ continue ;
132
+ }
133
+
134
+ if ($ token ->isGivenKind (T_CLASS ) && $ tokensAnalyzer ->isAnonymousClass ($ index )) {
135
+ continue ;
136
+ }
137
+
138
+ if ($ token ->isGivenKind ($ symbolKinds )) {
139
+ $ currentSymbol = $ tokens [$ tokens ->getNextMeaningfulToken ($ index )]->getContent ();
140
+ $ currentSymbolEndIndex = $ tokens ->findBlockEnd (
141
+ Tokens::BLOCK_TYPE_CURLY_BRACE ,
142
+ $ tokens ->getNextTokenOfKind ($ index , ['{ ' ]),
143
+ );
144
+
145
+ continue ;
146
+ }
147
+
117
148
if (!$ token ->isGivenKind (T_DOC_COMMENT )) {
118
149
continue ;
119
150
}
@@ -131,9 +162,9 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
131
162
}
132
163
133
164
if ('function ' === $ documentedElement ['type ' ]) {
134
- $ content = $ this ->fixFunctionDocComment ($ content , $ tokens , $ documentedElement , $ shortNames );
165
+ $ content = $ this ->fixFunctionDocComment ($ content , $ tokens , $ documentedElement , $ currentSymbol , $ shortNames );
135
166
} elseif ('property ' === $ documentedElement ['type ' ]) {
136
- $ content = $ this ->fixPropertyDocComment ($ content , $ tokens , $ documentedElement , $ shortNames );
167
+ $ content = $ this ->fixPropertyDocComment ($ content , $ tokens , $ documentedElement , $ currentSymbol , $ shortNames );
137
168
} elseif ('classy ' === $ documentedElement ['type ' ]) {
138
169
$ content = $ this ->fixClassDocComment ($ content , $ documentedElement );
139
170
} else {
@@ -250,8 +281,13 @@ private function findDocumentedElement(Tokens $tokens, int $docCommentIndex): ?a
250
281
return null ;
251
282
}
252
283
253
- private function fixFunctionDocComment (string $ content , Tokens $ tokens , array $ element , array $ shortNames ): string
254
- {
284
+ private function fixFunctionDocComment (
285
+ string $ content ,
286
+ Tokens $ tokens ,
287
+ array $ element ,
288
+ ?string $ currentSymbol ,
289
+ array $ shortNames
290
+ ): string {
255
291
$ docBlock = new DocBlock ($ content );
256
292
257
293
$ openingParenthesisIndex = $ tokens ->getNextTokenOfKind ($ element ['index ' ], ['( ' ]);
@@ -274,15 +310,15 @@ private function fixFunctionDocComment(string $content, Tokens $tokens, array $e
274
310
continue ;
275
311
}
276
312
277
- if (!isset ($ argumentsInfo [$ argumentName ]) || $ this ->annotationIsSuperfluous ($ annotation , $ argumentsInfo [$ argumentName ], $ shortNames )) {
313
+ if (!isset ($ argumentsInfo [$ argumentName ]) || $ this ->annotationIsSuperfluous ($ annotation , $ argumentsInfo [$ argumentName ], $ currentSymbol , $ shortNames )) {
278
314
$ annotation ->remove ();
279
315
}
280
316
}
281
317
282
318
$ returnTypeInfo = $ this ->getReturnTypeInfo ($ tokens , $ closingParenthesisIndex );
283
319
284
320
foreach ($ docBlock ->getAnnotationsOfType ('return ' ) as $ annotation ) {
285
- if ($ this ->annotationIsSuperfluous ($ annotation , $ returnTypeInfo , $ shortNames )) {
321
+ if ($ this ->annotationIsSuperfluous ($ annotation , $ returnTypeInfo , $ currentSymbol , $ shortNames )) {
286
322
$ annotation ->remove ();
287
323
}
288
324
}
@@ -292,8 +328,13 @@ private function fixFunctionDocComment(string $content, Tokens $tokens, array $e
292
328
return $ docBlock ->getContent ();
293
329
}
294
330
295
- private function fixPropertyDocComment (string $ content , Tokens $ tokens , array $ element , array $ shortNames ): string
296
- {
331
+ private function fixPropertyDocComment (
332
+ string $ content ,
333
+ Tokens $ tokens ,
334
+ array $ element ,
335
+ ?string $ currentSymbol ,
336
+ array $ shortNames
337
+ ): string {
297
338
if (\count ($ element ['types ' ]) > 0 ) {
298
339
$ propertyTypeInfo = $ this ->parseTypeHint ($ tokens , array_key_first ($ element ['types ' ]));
299
340
} else {
@@ -306,7 +347,7 @@ private function fixPropertyDocComment(string $content, Tokens $tokens, array $e
306
347
$ docBlock = new DocBlock ($ content );
307
348
308
349
foreach ($ docBlock ->getAnnotationsOfType ('var ' ) as $ annotation ) {
309
- if ($ this ->annotationIsSuperfluous ($ annotation , $ propertyTypeInfo , $ shortNames )) {
350
+ if ($ this ->annotationIsSuperfluous ($ annotation , $ propertyTypeInfo , $ currentSymbol , $ shortNames )) {
310
351
$ annotation ->remove ();
311
352
}
312
353
}
@@ -432,8 +473,12 @@ private function parseTypeHint(Tokens $tokens, int $index): array
432
473
/**
433
474
* @param array<string, string> $symbolShortNames
434
475
*/
435
- private function annotationIsSuperfluous (Annotation $ annotation , array $ info , array $ symbolShortNames ): bool
436
- {
476
+ private function annotationIsSuperfluous (
477
+ Annotation $ annotation ,
478
+ array $ info ,
479
+ ?string $ currentSymbol ,
480
+ array $ symbolShortNames
481
+ ): bool {
437
482
if ('param ' === $ annotation ->getTag ()->getName ()) {
438
483
$ regex = '/@param\s+[^\$]+\s(?:\&\s*)?(?:\.{3}\s*)?\$\S+\s+\S/ ' ;
439
484
} elseif ('var ' === $ annotation ->getTag ()->getName ()) {
@@ -446,7 +491,7 @@ private function annotationIsSuperfluous(Annotation $annotation, array $info, ar
446
491
return false ;
447
492
}
448
493
449
- $ annotationTypes = $ this ->toComparableNames ($ annotation ->getTypes (), $ symbolShortNames );
494
+ $ annotationTypes = $ this ->toComparableNames ($ annotation ->getTypes (), $ currentSymbol , $ symbolShortNames );
450
495
451
496
if (['null ' ] === $ annotationTypes ) {
452
497
return false ;
@@ -462,7 +507,7 @@ private function annotationIsSuperfluous(Annotation $annotation, array $info, ar
462
507
$ actualTypes [] = 'null ' ;
463
508
}
464
509
465
- return $ annotationTypes === $ this ->toComparableNames ($ actualTypes , $ symbolShortNames );
510
+ return $ annotationTypes === $ this ->toComparableNames ($ actualTypes , $ currentSymbol , $ symbolShortNames );
466
511
}
467
512
468
513
/**
@@ -476,10 +521,14 @@ private function annotationIsSuperfluous(Annotation $annotation, array $info, ar
476
521
*
477
522
* @return array The normalized types
478
523
*/
479
- private function toComparableNames (array $ types , array $ symbolShortNames ): array
524
+ private function toComparableNames (array $ types , ? string $ currentSymbol , array $ symbolShortNames ): array
480
525
{
481
526
$ normalized = array_map (
482
- static function (string $ type ) use ($ symbolShortNames ): string {
527
+ static function (string $ type ) use ($ currentSymbol , $ symbolShortNames ): string {
528
+ if ('self ' === $ type && null !== $ currentSymbol ) {
529
+ $ type = $ currentSymbol ;
530
+ }
531
+
483
532
$ type = strtolower ($ type );
484
533
485
534
if (str_contains ($ type , '& ' )) {
0 commit comments