PluginProbe
Code Engine – PHP Snippets, AI Functions & Automation for WordPress / 0.5.1
Code Engine – PHP Snippets, AI Functions & Automation for WordPress v0.5.1
0.5.7 0.5.6 0.5.5 0.5.4 0.5.3 0.5.2 0.5.1 0.5.0 0.4.9 0.4.8 0.4.7 0.4.6 trunk 0.0.1 0.0.2 0.2.8 0.2.9 0.3.0 0.3.1 0.3.2 0.3.3 0.3.4 0.3.5 0.3.6 0.3.7 All 33 releases
code-engine / vendor / nikic / php-parser / lib / PhpParser / NodeVisitor / NameResolver.php

NameResolver.php in Code Engine – PHP Snippets, AI Functions & Automation for WordPress 0.5.1, at vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php

263 lines 9.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php declare(strict_types=1);
2
3 namespace PhpParser\NodeVisitor;
4
5 use PhpParser\ErrorHandler;
6 use PhpParser\NameContext;
7 use PhpParser\Node;
8 use PhpParser\Node\Expr;
9 use PhpParser\Node\Name;
10 use PhpParser\Node\Name\FullyQualified;
11 use PhpParser\Node\Stmt;
12 use PhpParser\NodeVisitorAbstract;
13
14 class NameResolver extends NodeVisitorAbstract {
15 /** @var NameContext Naming context */
16 protected NameContext $nameContext;
17
18 /** @var bool Whether to preserve original names */
19 protected bool $preserveOriginalNames;
20
21 /** @var bool Whether to replace resolved nodes in place, or to add resolvedNode attributes */
22 protected bool $replaceNodes;
23
24 /**
25 * Constructs a name resolution visitor.
26 *
27 * Options:
28 * * preserveOriginalNames (default false): An "originalName" attribute will be added to
29 * all name nodes that underwent resolution.
30 * * replaceNodes (default true): Resolved names are replaced in-place. Otherwise, a
31 * resolvedName attribute is added. (Names that cannot be statically resolved receive a
32 * namespacedName attribute, as usual.)
33 *
34 * @param ErrorHandler|null $errorHandler Error handler
35 * @param array{preserveOriginalNames?: bool, replaceNodes?: bool} $options Options
36 */
37 public function __construct(?ErrorHandler $errorHandler = null, array $options = []) {
38 $this->nameContext = new NameContext($errorHandler ?? new ErrorHandler\Throwing());
39 $this->preserveOriginalNames = $options['preserveOriginalNames'] ?? false;
40 $this->replaceNodes = $options['replaceNodes'] ?? true;
41 }
42
43 /**
44 * Get name resolution context.
45 */
46 public function getNameContext(): NameContext {
47 return $this->nameContext;
48 }
49
50 public function beforeTraverse(array $nodes): ?array {
51 $this->nameContext->startNamespace();
52 return null;
53 }
54
55 public function enterNode(Node $node) {
56 if ($node instanceof Stmt\Namespace_) {
57 $this->nameContext->startNamespace($node->name);
58 } elseif ($node instanceof Stmt\Use_) {
59 foreach ($node->uses as $use) {
60 $this->addAlias($use, $node->type, null);
61 }
62 } elseif ($node instanceof Stmt\GroupUse) {
63 foreach ($node->uses as $use) {
64 $this->addAlias($use, $node->type, $node->prefix);
65 }
66 } elseif ($node instanceof Stmt\Class_) {
67 if (null !== $node->extends) {
68 $node->extends = $this->resolveClassName($node->extends);
69 }
70
71 foreach ($node->implements as &$interface) {
72 $interface = $this->resolveClassName($interface);
73 }
74
75 $this->resolveAttrGroups($node);
76 if (null !== $node->name) {
77 $this->addNamespacedName($node);
78 } else {
79 $node->namespacedName = null;
80 }
81 } elseif ($node instanceof Stmt\Interface_) {
82 foreach ($node->extends as &$interface) {
83 $interface = $this->resolveClassName($interface);
84 }
85
86 $this->resolveAttrGroups($node);
87 $this->addNamespacedName($node);
88 } elseif ($node instanceof Stmt\Enum_) {
89 foreach ($node->implements as &$interface) {
90 $interface = $this->resolveClassName($interface);
91 }
92
93 $this->resolveAttrGroups($node);
94 $this->addNamespacedName($node);
95 } elseif ($node instanceof Stmt\Trait_) {
96 $this->resolveAttrGroups($node);
97 $this->addNamespacedName($node);
98 } elseif ($node instanceof Stmt\Function_) {
99 $this->resolveSignature($node);
100 $this->resolveAttrGroups($node);
101 $this->addNamespacedName($node);
102 } elseif ($node instanceof Stmt\ClassMethod
103 || $node instanceof Expr\Closure
104 || $node instanceof Expr\ArrowFunction
105 ) {
106 $this->resolveSignature($node);
107 $this->resolveAttrGroups($node);
108 } elseif ($node instanceof Stmt\Property) {
109 if (null !== $node->type) {
110 $node->type = $this->resolveType($node->type);
111 }
112 $this->resolveAttrGroups($node);
113 } elseif ($node instanceof Stmt\Const_) {
114 foreach ($node->consts as $const) {
115 $this->addNamespacedName($const);
116 }
117 } elseif ($node instanceof Stmt\ClassConst) {
118 if (null !== $node->type) {
119 $node->type = $this->resolveType($node->type);
120 }
121 $this->resolveAttrGroups($node);
122 } elseif ($node instanceof Stmt\EnumCase) {
123 $this->resolveAttrGroups($node);
124 } elseif ($node instanceof Expr\StaticCall
125 || $node instanceof Expr\StaticPropertyFetch
126 || $node instanceof Expr\ClassConstFetch
127 || $node instanceof Expr\New_
128 || $node instanceof Expr\Instanceof_
129 ) {
130 if ($node->class instanceof Name) {
131 $node->class = $this->resolveClassName($node->class);
132 }
133 } elseif ($node instanceof Stmt\Catch_) {
134 foreach ($node->types as &$type) {
135 $type = $this->resolveClassName($type);
136 }
137 } elseif ($node instanceof Expr\FuncCall) {
138 if ($node->name instanceof Name) {
139 $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_FUNCTION);
140 }
141 } elseif ($node instanceof Expr\ConstFetch) {
142 $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_CONSTANT);
143 } elseif ($node instanceof Stmt\TraitUse) {
144 foreach ($node->traits as &$trait) {
145 $trait = $this->resolveClassName($trait);
146 }
147
148 foreach ($node->adaptations as $adaptation) {
149 if (null !== $adaptation->trait) {
150 $adaptation->trait = $this->resolveClassName($adaptation->trait);
151 }
152
153 if ($adaptation instanceof Stmt\TraitUseAdaptation\Precedence) {
154 foreach ($adaptation->insteadof as &$insteadof) {
155 $insteadof = $this->resolveClassName($insteadof);
156 }
157 }
158 }
159 }
160
161 return null;
162 }
163
164 /** @param Stmt\Use_::TYPE_* $type */
165 private function addAlias(Node\UseItem $use, int $type, ?Name $prefix = null): void {
166 // Add prefix for group uses
167 $name = $prefix ? Name::concat($prefix, $use->name) : $use->name;
168 // Type is determined either by individual element or whole use declaration
169 $type |= $use->type;
170
171 $this->nameContext->addAlias(
172 $name, (string) $use->getAlias(), $type, $use->getAttributes()
173 );
174 }
175
176 /** @param Stmt\Function_|Stmt\ClassMethod|Expr\Closure|Expr\ArrowFunction $node */
177 private function resolveSignature($node): void {
178 foreach ($node->params as $param) {
179 $param->type = $this->resolveType($param->type);
180 $this->resolveAttrGroups($param);
181 }
182 $node->returnType = $this->resolveType($node->returnType);
183 }
184
185 /**
186 * @template T of Node\Identifier|Name|Node\ComplexType|null
187 * @param T $node
188 * @return T
189 */
190 private function resolveType(?Node $node): ?Node {
191 if ($node instanceof Name) {
192 return $this->resolveClassName($node);
193 }
194 if ($node instanceof Node\NullableType) {
195 $node->type = $this->resolveType($node->type);
196 return $node;
197 }
198 if ($node instanceof Node\UnionType || $node instanceof Node\IntersectionType) {
199 foreach ($node->types as &$type) {
200 $type = $this->resolveType($type);
201 }
202 return $node;
203 }
204 return $node;
205 }
206
207 /**
208 * Resolve name, according to name resolver options.
209 *
210 * @param Name $name Function or constant name to resolve
211 * @param Stmt\Use_::TYPE_* $type One of Stmt\Use_::TYPE_*
212 *
213 * @return Name Resolved name, or original name with attribute
214 */
215 protected function resolveName(Name $name, int $type): Name {
216 if (!$this->replaceNodes) {
217 $resolvedName = $this->nameContext->getResolvedName($name, $type);
218 if (null !== $resolvedName) {
219 $name->setAttribute('resolvedName', $resolvedName);
220 } else {
221 $name->setAttribute('namespacedName', FullyQualified::concat(
222 $this->nameContext->getNamespace(), $name, $name->getAttributes()));
223 }
224 return $name;
225 }
226
227 if ($this->preserveOriginalNames) {
228 // Save the original name
229 $originalName = $name;
230 $name = clone $originalName;
231 $name->setAttribute('originalName', $originalName);
232 }
233
234 $resolvedName = $this->nameContext->getResolvedName($name, $type);
235 if (null !== $resolvedName) {
236 return $resolvedName;
237 }
238
239 // unqualified names inside a namespace cannot be resolved at compile-time
240 // add the namespaced version of the name as an attribute
241 $name->setAttribute('namespacedName', FullyQualified::concat(
242 $this->nameContext->getNamespace(), $name, $name->getAttributes()));
243 return $name;
244 }
245
246 protected function resolveClassName(Name $name): Name {
247 return $this->resolveName($name, Stmt\Use_::TYPE_NORMAL);
248 }
249
250 protected function addNamespacedName(Node $node): void {
251 $node->namespacedName = Name::concat(
252 $this->nameContext->getNamespace(), (string) $node->name);
253 }
254
255 protected function resolveAttrGroups(Node $node): void {
256 foreach ($node->attrGroups as $attrGroup) {
257 foreach ($attrGroup->attrs as $attr) {
258 $attr->name = $this->resolveClassName($attr->name);
259 }
260 }
261 }
262 }
263