5
5
namespace PhpStaticAnalysis \RectorRule ;
6
6
7
7
use PhpParser \Node ;
8
+ use PhpParser \Node \Arg ;
8
9
use PhpParser \Node \Attribute ;
9
10
use PhpParser \Node \AttributeGroup ;
10
11
use PhpParser \Node \Expr \Variable ;
12
+ use PhpParser \Node \Identifier ;
11
13
use PhpParser \Node \Name \FullyQualified ;
12
14
use PhpParser \Node \Scalar ;
15
+ use PhpParser \Node \Scalar \String_ ;
13
16
use PhpParser \Node \Stmt ;
17
+ use PhpParser \Node \Stmt \Class_ ;
18
+ use PhpParser \Node \Stmt \ClassConst ;
19
+ use PhpParser \Node \Stmt \ClassMethod ;
20
+ use PhpParser \Node \Stmt \Function_ ;
21
+ use PhpParser \Node \Stmt \Interface_ ;
22
+ use PhpParser \Node \Stmt \Trait_ ;
23
+ use PhpParser \Node \Stmt \TraitUse ;
14
24
use PHPStan \PhpDocParser \Ast \PhpDoc \DeprecatedTagValueNode ;
15
25
use PHPStan \PhpDocParser \Ast \PhpDoc \ExtendsTagValueNode ;
16
26
use PHPStan \PhpDocParser \Ast \PhpDoc \GenericTagValueNode ;
27
37
use PHPStan \PhpDocParser \Ast \PhpDoc \SelfOutTagValueNode ;
28
38
use PHPStan \PhpDocParser \Ast \PhpDoc \TemplateTagValueNode ;
29
39
use PHPStan \PhpDocParser \Ast \PhpDoc \ThrowsTagValueNode ;
40
+ use PHPStan \PhpDocParser \Ast \PhpDoc \TypeAliasImportTagValueNode ;
41
+ use PHPStan \PhpDocParser \Ast \PhpDoc \TypeAliasTagValueNode ;
30
42
use PHPStan \PhpDocParser \Ast \PhpDoc \UsesTagValueNode ;
31
43
use PHPStan \PhpDocParser \Ast \PhpDoc \VarTagValueNode ;
32
44
use PHPStan \PhpDocParser \Ast \Type \IdentifierTypeNode ;
@@ -61,6 +73,8 @@ final class AnnotationsToAttributesRector extends AbstractRector implements Conf
61
73
62
74
private bool $ usePropertyAttributeForVarAnnotation = false ;
63
75
76
+ private bool $ useTypeAttributeForTypeClassAnnotation = false ;
77
+
64
78
public function __construct (
65
79
private PhpDocTagRemover $ phpDocTagRemover ,
66
80
private AttributeGroupNamedArgumentManipulator $ attributeGroupNamedArgumentManipulator ,
@@ -138,6 +152,8 @@ public function configure(array $configuration): void
138
152
$ this ->useTypeAttributeForReturnAnnotation = $ value ;
139
153
} elseif (is_bool ($ value ) && $ key == 'usePropertyAttributeForVarAnnotation ' ) {
140
154
$ this ->usePropertyAttributeForVarAnnotation = $ value ;
155
+ } elseif (is_bool ($ value ) && $ key == 'useTypeAttributeForTypeClassAnnotation ' ) {
156
+ $ this ->useTypeAttributeForTypeClassAnnotation = $ value ;
141
157
} elseif (is_array ($ value ) && $ key == 'excludeAnnotations ' ) {
142
158
$ excludedAnnotations = $ value ;
143
159
}
@@ -165,13 +181,13 @@ public function configure(array $configuration): void
165
181
public function getNodeTypes (): array
166
182
{
167
183
return [
168
- Stmt \ Class_::class,
169
- Stmt \ ClassConst::class,
170
- Stmt \ ClassMethod::class,
171
- Stmt \ Function_::class,
172
- Stmt \ Interface_::class,
184
+ Class_::class,
185
+ ClassConst::class,
186
+ ClassMethod::class,
187
+ Function_::class,
188
+ Interface_::class,
173
189
Stmt \Property::class,
174
- Stmt \ Trait_::class
190
+ Trait_::class
175
191
];
176
192
}
177
193
@@ -195,7 +211,7 @@ public function refactor(Node $node): ?Node
195
211
}
196
212
197
213
if ($ this ->addParamAttributeOnParameters &&
198
- ($ node instanceof Stmt \ ClassMethod || $ node instanceof Stmt \ Function_)) {
214
+ ($ node instanceof ClassMethod || $ node instanceof Function_)) {
199
215
foreach ($ attributeGroups as $ attrKey => $ attributeGroup ) {
200
216
foreach ($ attributeGroup ->attrs as $ key => $ attribute ) {
201
217
$ attributeName = (string )$ attribute ->name ;
@@ -223,9 +239,9 @@ public function refactor(Node $node): ?Node
223
239
}
224
240
}
225
241
226
- if ($ node instanceof Stmt \ Class_) {
242
+ if ($ node instanceof Class_) {
227
243
foreach ($ node ->stmts as $ stmt ) {
228
- if ($ stmt instanceof Stmt \ TraitUse) {
244
+ if ($ stmt instanceof TraitUse) {
229
245
$ phpDocInfo = $ this ->phpDocInfoFactory ->createFromNode ($ stmt );
230
246
if ($ phpDocInfo instanceof PhpDocInfo) {
231
247
$ useAttributeGroups = $ this ->processAnnotations ($ phpDocInfo );
@@ -273,24 +289,24 @@ private function processAnnotations(PhpDocInfo $phpDocInfo): array
273
289
$ methodSignature = substr ($ methodSignature , 0 , -(strlen ($ attributeComment ) + 1 ));
274
290
}
275
291
$ args = [
276
- new Node \ Arg (new Scalar \ String_ ($ methodSignature ))
292
+ new Arg (new String_ ($ methodSignature ))
277
293
];
278
294
break ;
279
295
case $ tagValueNode instanceof ParamOutTagValueNode:
280
296
case $ tagValueNode instanceof ParamTagValueNode:
281
297
$ args = [
282
- new Node \ Arg (
283
- value: new Scalar \ String_ ((string )($ tagValueNode ->type )),
284
- name: new Node \ Identifier (substr ($ tagValueNode ->parameterName , 1 ))
298
+ new Arg (
299
+ value: new String_ ((string )($ tagValueNode ->type )),
300
+ name: new Identifier (substr ($ tagValueNode ->parameterName , 1 ))
285
301
)
286
302
];
287
303
$ attributeComment = $ tagValueNode ->description ;
288
304
break ;
289
305
case $ tagValueNode instanceof PropertyTagValueNode:
290
306
$ args = [
291
- new Node \ Arg (
292
- value: new Scalar \ String_ ((string )($ tagValueNode ->type )),
293
- name: new Node \ Identifier (substr ($ tagValueNode ->propertyName , 1 ))
307
+ new Arg (
308
+ value: new String_ ((string )($ tagValueNode ->type )),
309
+ name: new Identifier (substr ($ tagValueNode ->propertyName , 1 ))
294
310
)
295
311
];
296
312
$ attributeComment = $ tagValueNode ->description ;
@@ -306,16 +322,16 @@ private function processAnnotations(PhpDocInfo $phpDocInfo): array
306
322
case $ tagValueNode instanceof UsesTagValueNode:
307
323
case $ tagValueNode instanceof VarTagValueNode:
308
324
$ args = [
309
- new Node \ Arg (new Scalar \ String_ ((string )($ tagValueNode ->type )))
325
+ new Arg (new String_ ((string )($ tagValueNode ->type )))
310
326
];
311
327
$ attributeComment = $ tagValueNode ->description ;
312
328
break ;
313
329
case $ tagValueNode instanceof TemplateTagValueNode:
314
330
$ args = [
315
- new Node \ Arg (new Scalar \ String_ ($ tagValueNode ->name ))
331
+ new Arg (new String_ ($ tagValueNode ->name ))
316
332
];
317
333
if ($ tagValueNode ->bound instanceof IdentifierTypeNode) {
318
- $ args [] = new Node \ Arg (new Scalar \ String_ ($ tagValueNode ->bound ->name ));
334
+ $ args [] = new Arg (new String_ ($ tagValueNode ->bound ->name ));
319
335
}
320
336
$ attributeComment = $ tagValueNode ->description ;
321
337
break ;
@@ -327,13 +343,36 @@ private function processAnnotations(PhpDocInfo $phpDocInfo): array
327
343
$ parts = explode (' ' , $ remainingText );
328
344
$ namespace = array_shift ($ parts );
329
345
if ($ namespace ) {
330
- $ args [] = new Node \ Arg (new Scalar \ String_ ($ namespace ));
346
+ $ args [] = new Arg (new String_ ($ namespace ));
331
347
$ attributeComment = implode (' ' , $ parts );
332
348
}
333
349
} else {
334
350
$ attributeComment = (string )$ tagValueNode ;
335
351
}
336
352
break ;
353
+ case $ tagValueNode instanceof TypeAliasTagValueNode:
354
+ if ($ this ->useTypeAttributeForTypeClassAnnotation ) {
355
+ $ alias = (string )($ tagValueNode );
356
+ $ args = [
357
+ new Arg (new String_ ($ alias ))
358
+ ];
359
+ } else {
360
+ $ args = [
361
+ new Arg (
362
+ value: new String_ ((string )($ tagValueNode ->type )),
363
+ name: new Identifier ($ tagValueNode ->alias )
364
+ )
365
+ ];
366
+ }
367
+ break ;
368
+ case $ tagValueNode instanceof TypeAliasImportTagValueNode:
369
+ $ args = [
370
+ new Arg (
371
+ value: new String_ ((string )($ tagValueNode ->importedFrom )),
372
+ name: new Identifier ($ tagValueNode ->importedAlias )
373
+ )
374
+ ];
375
+ break ;
337
376
default :
338
377
continue 2 ;
339
378
}
@@ -376,6 +415,9 @@ private function matchAnnotationToAttribute(
376
415
} elseif (str_starts_with ($ tagName , 'phpstan- ' )) {
377
416
$ tagName = substr ($ tagName , 8 );
378
417
}
418
+ if ($ this ->useTypeAttributeForTypeClassAnnotation && $ tagName == 'type ' ) {
419
+ $ tagName = 'var ' ;
420
+ }
379
421
if (isset ($ this ->annotationsToAttributes [$ tagName ])) {
380
422
return $ this ->annotationsToAttributes [$ tagName ];
381
423
}
0 commit comments