1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\PhpDocParser\Ast\PhpDoc;
4:
5: use PHPStan\PhpDocParser\Ast\Node;
6: use PHPStan\PhpDocParser\Ast\NodeAttributes;
7: use function array_column;
8: use function array_filter;
9: use function array_map;
10: use function implode;
11:
12: class PhpDocNode implements Node
13: {
14:
15: use NodeAttributes;
16:
17: /** @var PhpDocChildNode[] */
18: public array $children;
19:
20: /**
21: * @param PhpDocChildNode[] $children
22: */
23: public function __construct(array $children)
24: {
25: $this->children = $children;
26: }
27:
28: /**
29: * @return PhpDocTagNode[]
30: */
31: public function getTags(): array
32: {
33: return array_filter($this->children, static fn (PhpDocChildNode $child): bool => $child instanceof PhpDocTagNode);
34: }
35:
36: /**
37: * @return PhpDocTagNode[]
38: */
39: public function getTagsByName(string $tagName): array
40: {
41: return array_filter($this->getTags(), static fn (PhpDocTagNode $tag): bool => $tag->name === $tagName);
42: }
43:
44: /**
45: * @return VarTagValueNode[]
46: */
47: public function getVarTagValues(string $tagName = '@var'): array
48: {
49: return array_filter(
50: array_column($this->getTagsByName($tagName), 'value'),
51: static fn (PhpDocTagValueNode $value): bool => $value instanceof VarTagValueNode,
52: );
53: }
54:
55: /**
56: * @return ParamTagValueNode[]
57: */
58: public function getParamTagValues(string $tagName = '@param'): array
59: {
60: return array_filter(
61: array_column($this->getTagsByName($tagName), 'value'),
62: static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamTagValueNode,
63: );
64: }
65:
66: /**
67: * @return TypelessParamTagValueNode[]
68: */
69: public function getTypelessParamTagValues(string $tagName = '@param'): array
70: {
71: return array_filter(
72: array_column($this->getTagsByName($tagName), 'value'),
73: static fn (PhpDocTagValueNode $value): bool => $value instanceof TypelessParamTagValueNode,
74: );
75: }
76:
77: /**
78: * @return ParamImmediatelyInvokedCallableTagValueNode[]
79: */
80: public function getParamImmediatelyInvokedCallableTagValues(string $tagName = '@param-immediately-invoked-callable'): array
81: {
82: return array_filter(
83: array_column($this->getTagsByName($tagName), 'value'),
84: static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamImmediatelyInvokedCallableTagValueNode,
85: );
86: }
87:
88: /**
89: * @return ParamLaterInvokedCallableTagValueNode[]
90: */
91: public function getParamLaterInvokedCallableTagValues(string $tagName = '@param-later-invoked-callable'): array
92: {
93: return array_filter(
94: array_column($this->getTagsByName($tagName), 'value'),
95: static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamLaterInvokedCallableTagValueNode,
96: );
97: }
98:
99: /**
100: * @return ParamClosureThisTagValueNode[]
101: */
102: public function getParamClosureThisTagValues(string $tagName = '@param-closure-this'): array
103: {
104: return array_filter(
105: array_column($this->getTagsByName($tagName), 'value'),
106: static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamClosureThisTagValueNode,
107: );
108: }
109:
110: /**
111: * @return PureUnlessCallableIsImpureTagValueNode[]
112: */
113: public function getPureUnlessCallableIsImpureTagValues(string $tagName = '@pure-unless-callable-is-impure'): array
114: {
115: return array_filter(
116: array_column($this->getTagsByName($tagName), 'value'),
117: static fn (PhpDocTagValueNode $value): bool => $value instanceof PureUnlessCallableIsImpureTagValueNode,
118: );
119: }
120:
121: /**
122: * @return TemplateTagValueNode[]
123: */
124: public function getTemplateTagValues(string $tagName = '@template'): array
125: {
126: return array_filter(
127: array_column($this->getTagsByName($tagName), 'value'),
128: static fn (PhpDocTagValueNode $value): bool => $value instanceof TemplateTagValueNode,
129: );
130: }
131:
132: /**
133: * @return ExtendsTagValueNode[]
134: */
135: public function getExtendsTagValues(string $tagName = '@extends'): array
136: {
137: return array_filter(
138: array_column($this->getTagsByName($tagName), 'value'),
139: static fn (PhpDocTagValueNode $value): bool => $value instanceof ExtendsTagValueNode,
140: );
141: }
142:
143: /**
144: * @return ImplementsTagValueNode[]
145: */
146: public function getImplementsTagValues(string $tagName = '@implements'): array
147: {
148: return array_filter(
149: array_column($this->getTagsByName($tagName), 'value'),
150: static fn (PhpDocTagValueNode $value): bool => $value instanceof ImplementsTagValueNode,
151: );
152: }
153:
154: /**
155: * @return UsesTagValueNode[]
156: */
157: public function getUsesTagValues(string $tagName = '@use'): array
158: {
159: return array_filter(
160: array_column($this->getTagsByName($tagName), 'value'),
161: static fn (PhpDocTagValueNode $value): bool => $value instanceof UsesTagValueNode,
162: );
163: }
164:
165: /**
166: * @return ReturnTagValueNode[]
167: */
168: public function getReturnTagValues(string $tagName = '@return'): array
169: {
170: return array_filter(
171: array_column($this->getTagsByName($tagName), 'value'),
172: static fn (PhpDocTagValueNode $value): bool => $value instanceof ReturnTagValueNode,
173: );
174: }
175:
176: /**
177: * @return ThrowsTagValueNode[]
178: */
179: public function getThrowsTagValues(string $tagName = '@throws'): array
180: {
181: return array_filter(
182: array_column($this->getTagsByName($tagName), 'value'),
183: static fn (PhpDocTagValueNode $value): bool => $value instanceof ThrowsTagValueNode,
184: );
185: }
186:
187: /**
188: * @return MixinTagValueNode[]
189: */
190: public function getMixinTagValues(string $tagName = '@mixin'): array
191: {
192: return array_filter(
193: array_column($this->getTagsByName($tagName), 'value'),
194: static fn (PhpDocTagValueNode $value): bool => $value instanceof MixinTagValueNode,
195: );
196: }
197:
198: /**
199: * @return RequireExtendsTagValueNode[]
200: */
201: public function getRequireExtendsTagValues(string $tagName = '@phpstan-require-extends'): array
202: {
203: return array_filter(
204: array_column($this->getTagsByName($tagName), 'value'),
205: static fn (PhpDocTagValueNode $value): bool => $value instanceof RequireExtendsTagValueNode,
206: );
207: }
208:
209: /**
210: * @return RequireImplementsTagValueNode[]
211: */
212: public function getRequireImplementsTagValues(string $tagName = '@phpstan-require-implements'): array
213: {
214: return array_filter(
215: array_column($this->getTagsByName($tagName), 'value'),
216: static fn (PhpDocTagValueNode $value): bool => $value instanceof RequireImplementsTagValueNode,
217: );
218: }
219:
220: /**
221: * @return SealedTagValueNode[]
222: */
223: public function getSealedTagValues(string $tagName = '@phpstan-sealed'): array
224: {
225: return array_filter(
226: array_column($this->getTagsByName($tagName), 'value'),
227: static fn (PhpDocTagValueNode $value): bool => $value instanceof SealedTagValueNode,
228: );
229: }
230:
231: /**
232: * @return DeprecatedTagValueNode[]
233: */
234: public function getDeprecatedTagValues(): array
235: {
236: return array_filter(
237: array_column($this->getTagsByName('@deprecated'), 'value'),
238: static fn (PhpDocTagValueNode $value): bool => $value instanceof DeprecatedTagValueNode,
239: );
240: }
241:
242: /**
243: * @return PropertyTagValueNode[]
244: */
245: public function getPropertyTagValues(string $tagName = '@property'): array
246: {
247: return array_filter(
248: array_column($this->getTagsByName($tagName), 'value'),
249: static fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,
250: );
251: }
252:
253: /**
254: * @return PropertyTagValueNode[]
255: */
256: public function getPropertyReadTagValues(string $tagName = '@property-read'): array
257: {
258: return array_filter(
259: array_column($this->getTagsByName($tagName), 'value'),
260: static fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,
261: );
262: }
263:
264: /**
265: * @return PropertyTagValueNode[]
266: */
267: public function getPropertyWriteTagValues(string $tagName = '@property-write'): array
268: {
269: return array_filter(
270: array_column($this->getTagsByName($tagName), 'value'),
271: static fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,
272: );
273: }
274:
275: /**
276: * @return MethodTagValueNode[]
277: */
278: public function getMethodTagValues(string $tagName = '@method'): array
279: {
280: return array_filter(
281: array_column($this->getTagsByName($tagName), 'value'),
282: static fn (PhpDocTagValueNode $value): bool => $value instanceof MethodTagValueNode,
283: );
284: }
285:
286: /**
287: * @return TypeAliasTagValueNode[]
288: */
289: public function getTypeAliasTagValues(string $tagName = '@phpstan-type'): array
290: {
291: return array_filter(
292: array_column($this->getTagsByName($tagName), 'value'),
293: static fn (PhpDocTagValueNode $value): bool => $value instanceof TypeAliasTagValueNode,
294: );
295: }
296:
297: /**
298: * @return TypeAliasImportTagValueNode[]
299: */
300: public function getTypeAliasImportTagValues(string $tagName = '@phpstan-import-type'): array
301: {
302: return array_filter(
303: array_column($this->getTagsByName($tagName), 'value'),
304: static fn (PhpDocTagValueNode $value): bool => $value instanceof TypeAliasImportTagValueNode,
305: );
306: }
307:
308: /**
309: * @return AssertTagValueNode[]
310: */
311: public function getAssertTagValues(string $tagName = '@phpstan-assert'): array
312: {
313: return array_filter(
314: array_column($this->getTagsByName($tagName), 'value'),
315: static fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagValueNode,
316: );
317: }
318:
319: /**
320: * @return AssertTagPropertyValueNode[]
321: */
322: public function getAssertPropertyTagValues(string $tagName = '@phpstan-assert'): array
323: {
324: return array_filter(
325: array_column($this->getTagsByName($tagName), 'value'),
326: static fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagPropertyValueNode,
327: );
328: }
329:
330: /**
331: * @return AssertTagMethodValueNode[]
332: */
333: public function getAssertMethodTagValues(string $tagName = '@phpstan-assert'): array
334: {
335: return array_filter(
336: array_column($this->getTagsByName($tagName), 'value'),
337: static fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagMethodValueNode,
338: );
339: }
340:
341: /**
342: * @return SelfOutTagValueNode[]
343: */
344: public function getSelfOutTypeTagValues(string $tagName = '@phpstan-this-out'): array
345: {
346: return array_filter(
347: array_column($this->getTagsByName($tagName), 'value'),
348: static fn (PhpDocTagValueNode $value): bool => $value instanceof SelfOutTagValueNode,
349: );
350: }
351:
352: /**
353: * @return ParamOutTagValueNode[]
354: */
355: public function getParamOutTypeTagValues(string $tagName = '@param-out'): array
356: {
357: return array_filter(
358: array_column($this->getTagsByName($tagName), 'value'),
359: static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamOutTagValueNode,
360: );
361: }
362:
363: public function __toString(): string
364: {
365: $children = array_map(
366: static function (PhpDocChildNode $child): string {
367: $s = (string) $child;
368: return $s === '' ? '' : ' ' . $s;
369: },
370: $this->children,
371: );
372: return "/**\n *" . implode("\n *", $children) . "\n */";
373: }
374:
375: }
376: