PluginProbe
WPIDE – File Manager & Code Editor / 3.5.9
WPIDE – File Manager & Code Editor v3.5.9
3.5.9 3.5.8 3.5.7 2.0.14 2.0.15 2.0.16 2.0.2 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1 2.2 2.3 2.3.1 2.3.2 2.4.0 2.5 2.6 3.0 3.1 3.2 3.3 All 55 releases
wpide / vendor / nikic / php-parser / lib / PhpParser / NameContext.php

NameContext.php in WPIDE – File Manager & Code Editor 3.5.9, at vendor/nikic/php-parser/lib/PhpParser/NameContext.php

286 lines 9.7 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;
4
5 use PhpParser\Node\Name;
6 use PhpParser\Node\Name\FullyQualified;
7 use PhpParser\Node\Stmt;
8
9 class NameContext
10 {
11 /** @var null|Name Current namespace */
12 protected $namespace;
13
14 /** @var Name[][] Map of format [aliasType => [aliasName => originalName]] */
15 protected $aliases = [];
16
17 /** @var Name[][] Same as $aliases but preserving original case */
18 protected $origAliases = [];
19
20 /** @var ErrorHandler Error handler */
21 protected $errorHandler;
22
23 /**
24 * Create a name context.
25 *
26 * @param ErrorHandler $errorHandler Error handling used to report errors
27 */
28 public function __construct(ErrorHandler $errorHandler) {
29 $this->errorHandler = $errorHandler;
30 }
31
32 /**
33 * Start a new namespace.
34 *
35 * This also resets the alias table.
36 *
37 * @param Name|null $namespace Null is the global namespace
38 */
39 public function startNamespace(?Name $namespace = null) {
40 $this->namespace = $namespace;
41 $this->origAliases = $this->aliases = [
42 Stmt\Use_::TYPE_NORMAL => [],
43 Stmt\Use_::TYPE_FUNCTION => [],
44 Stmt\Use_::TYPE_CONSTANT => [],
45 ];
46 }
47
48 /**
49 * Add an alias / import.
50 *
51 * @param Name $name Original name
52 * @param string $aliasName Aliased name
53 * @param int $type One of Stmt\Use_::TYPE_*
54 * @param array $errorAttrs Attributes to use to report an error
55 */
56 public function addAlias(Name $name, string $aliasName, int $type, array $errorAttrs = []) {
57 // Constant names are case sensitive, everything else case insensitive
58 if ($type === Stmt\Use_::TYPE_CONSTANT) {
59 $aliasLookupName = $aliasName;
60 } else {
61 $aliasLookupName = strtolower($aliasName);
62 }
63
64 if (isset($this->aliases[$type][$aliasLookupName])) {
65 $typeStringMap = [
66 Stmt\Use_::TYPE_NORMAL => '',
67 Stmt\Use_::TYPE_FUNCTION => 'function ',
68 Stmt\Use_::TYPE_CONSTANT => 'const ',
69 ];
70
71 $this->errorHandler->handleError(new Error(
72 sprintf(
73 'Cannot use %s%s as %s because the name is already in use',
74 $typeStringMap[$type], $name, $aliasName
75 ),
76 $errorAttrs
77 ));
78 return;
79 }
80
81 $this->aliases[$type][$aliasLookupName] = $name;
82 $this->origAliases[$type][$aliasName] = $name;
83 }
84
85 /**
86 * Get current namespace.
87 *
88 * @return null|Name Namespace (or null if global namespace)
89 */
90 public function getNamespace() {
91 return $this->namespace;
92 }
93
94 /**
95 * Get resolved name.
96 *
97 * @param Name $name Name to resolve
98 * @param int $type One of Stmt\Use_::TYPE_{FUNCTION|CONSTANT}
99 *
100 * @return null|Name Resolved name, or null if static resolution is not possible
101 */
102 public function getResolvedName(Name $name, int $type) {
103 // don't resolve special class names
104 if ($type === Stmt\Use_::TYPE_NORMAL && $name->isSpecialClassName()) {
105 if (!$name->isUnqualified()) {
106 $this->errorHandler->handleError(new Error(
107 sprintf("'\\%s' is an invalid class name", $name->toString()),
108 $name->getAttributes()
109 ));
110 }
111 return $name;
112 }
113
114 // fully qualified names are already resolved
115 if ($name->isFullyQualified()) {
116 return $name;
117 }
118
119 // Try to resolve aliases
120 if (null !== $resolvedName = $this->resolveAlias($name, $type)) {
121 return $resolvedName;
122 }
123
124 if ($type !== Stmt\Use_::TYPE_NORMAL && $name->isUnqualified()) {
125 if (null === $this->namespace) {
126 // outside of a namespace unaliased unqualified is same as fully qualified
127 return new FullyQualified($name, $name->getAttributes());
128 }
129
130 // Cannot resolve statically
131 return null;
132 }
133
134 // if no alias exists prepend current namespace
135 return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
136 }
137
138 /**
139 * Get resolved class name.
140 *
141 * @param Name $name Class ame to resolve
142 *
143 * @return Name Resolved name
144 */
145 public function getResolvedClassName(Name $name) : Name {
146 return $this->getResolvedName($name, Stmt\Use_::TYPE_NORMAL);
147 }
148
149 /**
150 * Get possible ways of writing a fully qualified name (e.g., by making use of aliases).
151 *
152 * @param string $name Fully-qualified name (without leading namespace separator)
153 * @param int $type One of Stmt\Use_::TYPE_*
154 *
155 * @return Name[] Possible representations of the name
156 */
157 public function getPossibleNames(string $name, int $type) : array {
158 $lcName = strtolower($name);
159
160 if ($type === Stmt\Use_::TYPE_NORMAL) {
161 // self, parent and static must always be unqualified
162 if ($lcName === "self" || $lcName === "parent" || $lcName === "static") {
163 return [new Name($name)];
164 }
165 }
166
167 // Collect possible ways to write this name, starting with the fully-qualified name
168 $possibleNames = [new FullyQualified($name)];
169
170 if (null !== $nsRelativeName = $this->getNamespaceRelativeName($name, $lcName, $type)) {
171 // Make sure there is no alias that makes the normally namespace-relative name
172 // into something else
173 if (null === $this->resolveAlias($nsRelativeName, $type)) {
174 $possibleNames[] = $nsRelativeName;
175 }
176 }
177
178 // Check for relevant namespace use statements
179 foreach ($this->origAliases[Stmt\Use_::TYPE_NORMAL] as $alias => $orig) {
180 $lcOrig = $orig->toLowerString();
181 if (0 === strpos($lcName, $lcOrig . '\\')) {
182 $possibleNames[] = new Name($alias . substr($name, strlen($lcOrig)));
183 }
184 }
185
186 // Check for relevant type-specific use statements
187 foreach ($this->origAliases[$type] as $alias => $orig) {
188 if ($type === Stmt\Use_::TYPE_CONSTANT) {
189 // Constants are are complicated-sensitive
190 $normalizedOrig = $this->normalizeConstName($orig->toString());
191 if ($normalizedOrig === $this->normalizeConstName($name)) {
192 $possibleNames[] = new Name($alias);
193 }
194 } else {
195 // Everything else is case-insensitive
196 if ($orig->toLowerString() === $lcName) {
197 $possibleNames[] = new Name($alias);
198 }
199 }
200 }
201
202 return $possibleNames;
203 }
204
205 /**
206 * Get shortest representation of this fully-qualified name.
207 *
208 * @param string $name Fully-qualified name (without leading namespace separator)
209 * @param int $type One of Stmt\Use_::TYPE_*
210 *
211 * @return Name Shortest representation
212 */
213 public function getShortName(string $name, int $type) : Name {
214 $possibleNames = $this->getPossibleNames($name, $type);
215
216 // Find shortest name
217 $shortestName = null;
218 $shortestLength = \INF;
219 foreach ($possibleNames as $possibleName) {
220 $length = strlen($possibleName->toCodeString());
221 if ($length < $shortestLength) {
222 $shortestName = $possibleName;
223 $shortestLength = $length;
224 }
225 }
226
227 return $shortestName;
228 }
229
230 private function resolveAlias(Name $name, $type) {
231 $firstPart = $name->getFirst();
232
233 if ($name->isQualified()) {
234 // resolve aliases for qualified names, always against class alias table
235 $checkName = strtolower($firstPart);
236 if (isset($this->aliases[Stmt\Use_::TYPE_NORMAL][$checkName])) {
237 $alias = $this->aliases[Stmt\Use_::TYPE_NORMAL][$checkName];
238 return FullyQualified::concat($alias, $name->slice(1), $name->getAttributes());
239 }
240 } elseif ($name->isUnqualified()) {
241 // constant aliases are case-sensitive, function aliases case-insensitive
242 $checkName = $type === Stmt\Use_::TYPE_CONSTANT ? $firstPart : strtolower($firstPart);
243 if (isset($this->aliases[$type][$checkName])) {
244 // resolve unqualified aliases
245 return new FullyQualified($this->aliases[$type][$checkName], $name->getAttributes());
246 }
247 }
248
249 // No applicable aliases
250 return null;
251 }
252
253 private function getNamespaceRelativeName(string $name, string $lcName, int $type) {
254 if (null === $this->namespace) {
255 return new Name($name);
256 }
257
258 if ($type === Stmt\Use_::TYPE_CONSTANT) {
259 // The constants true/false/null always resolve to the global symbols, even inside a
260 // namespace, so they may be used without qualification
261 if ($lcName === "true" || $lcName === "false" || $lcName === "null") {
262 return new Name($name);
263 }
264 }
265
266 $namespacePrefix = strtolower($this->namespace . '\\');
267 if (0 === strpos($lcName, $namespacePrefix)) {
268 return new Name(substr($name, strlen($namespacePrefix)));
269 }
270
271 return null;
272 }
273
274 private function normalizeConstName(string $name) {
275 $nsSep = strrpos($name, '\\');
276 if (false === $nsSep) {
277 return $name;
278 }
279
280 // Constants have case-insensitive namespace and case-sensitive short-name
281 $ns = substr($name, 0, $nsSep);
282 $shortName = substr($name, $nsSep + 1);
283 return strtolower($ns) . '\\' . $shortName;
284 }
285 }
286