Skip to content

Commit bf7271c

Browse files
authored
Fix string resolution with leading backslas (#363)
Closes #356
1 parent a6b95ec commit bf7271c

File tree

4 files changed

+146
-31
lines changed

4 files changed

+146
-31
lines changed

psysh.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the humbug/php-scoper package.
7+
*
8+
* Copyright (c) 2017 Théo FIDRY <[email protected]>,
9+
* Pádraic Brady <[email protected]>
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
return [
16+
'meta' => [
17+
'title' => 'Internal symbols',
18+
// Default values. If not specified will be the one used
19+
'prefix' => 'Humbug',
20+
'whitelist' => [],
21+
'whitelist-global-constants' => true,
22+
'whitelist-global-classes' => false,
23+
'whitelist-global-functions' => true,
24+
'registered-classes' => [],
25+
'registered-functions' => [],
26+
],
27+
28+
'Empty file' => <<<'PHP'
29+
<?php
30+
31+
namespace Psy\Reflection;
32+
33+
class ReflectionClassConstant implements \Reflector
34+
{
35+
public static function create($class, $name)
36+
{
37+
if (\class_exists('\\ReflectionClassConstant')) {
38+
return new \ReflectionClassConstant($class, $name);
39+
}
40+
return new self($class, $name);
41+
}
42+
}
43+
44+
----
45+
<?php
46+
47+
namespace Humbug\Psy\Reflection;
48+
49+
class ReflectionClassConstant implements \Reflector
50+
{
51+
public static function create($class, $name)
52+
{
53+
if (\class_exists('Humbug\\ReflectionClassConstant')) {
54+
return new \ReflectionClassConstant($class, $name);
55+
}
56+
return new self($class, $name);
57+
}
58+
}
59+
60+
PHP
61+
,
62+
];

specs/misc/internal-symbols.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
'registered-functions' => [],
2626
],
2727

28-
'Empty file' => <<<'PHP'
28+
'Known internal symbols that used to or still require a patch in the Reflector' => <<<'PHP'
2929
<?php
3030
3131
namespace Acme;
@@ -77,6 +77,8 @@
7777
use parallel\Runtime\Error\IllegalInstruction;
7878
use parallel\Runtime\Error\IllegalParameter;
7979
use parallel\Runtime\Error\IllegalReturn;
80+
#https://github.com/bobthecow/psysh/issues/581#issuecomment-560137900
81+
use ReflectionClassConstant;
8082
8183
use function parallel\bootstrap;
8284
use function parallel\run;
@@ -305,6 +307,8 @@
305307
use parallel\Runtime\Error\IllegalInstruction;
306308
use parallel\Runtime\Error\IllegalParameter;
307309
use parallel\Runtime\Error\IllegalReturn;
310+
#https://github.com/bobthecow/psysh/issues/581#issuecomment-560137900
311+
use ReflectionClassConstant;
308312
use function parallel\bootstrap;
309313
use function parallel\run;
310314
use function pcov\collect;

specs/string-literal/func-arg.php

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,56 +34,79 @@
3434
foo('\\Humbug\\Symfony\\Component\\Yaml\\Ya_1');
3535
3636
foo('DateTime');
37+
foo('\\DateTime');
3738
foo('Swift');
39+
foo('\\Swift');
3840
foo(['DateTime', 'autoload']);
41+
foo(['\\DateTime', 'autoload']);
3942
foo(['Swift', 'autoload']);
43+
foo(['\\Swift', 'autoload']);
4044
4145
spl_autoload_register(['Swift', 'autoload']);
46+
spl_autoload_register(['\Swift', 'autoload']);
4247
spl_autoload_register(['Humbug\\Swift', 'autoload']);
4348
spl_autoload_register(['\\Humbug\\Swift', 'autoload']);
49+
spl_autoload_register(['\\Humbug\\Swift', 'autoload']);
4450
spl_autoload_register(['DateTime', 'autoload']);
51+
spl_autoload_register(['\\DateTime', 'autoload']);
4552
4653
is_a($swift, 'Swift');
54+
is_a($swift, '\\Swift');
4755
is_a($swift, 'Humbug\\Swift');
4856
is_a($swift, '\\Humbug\\Swift');
4957
is_a($swift, 'DateTime');
58+
is_a($swift, '\\DateTime');
5059
5160
is_subclass_of($swift, 'Swift');
52-
is_subclass_of($swift, 'Humbug\Swift');
53-
is_subclass_of($swift, '\Humbug\Swift');
61+
is_subclass_of($swift, '\\Swift');
62+
is_subclass_of($swift, 'Humbug\\Swift');
63+
is_subclass_of($swift, '\\Humbug\\Swift');
5464
is_subclass_of($swift, 'DateTime');
65+
is_subclass_of($swift, '\\DateTime');
5566
is_subclass_of('Mailer', 'Swift');
56-
is_subclass_of('Humbug\Mailer', 'Humbug\Swift');
57-
is_subclass_of('\Humbug\Mailer', '\Humbug\Swift');
67+
is_subclass_of('\\Mailer', '\\Swift');
68+
is_subclass_of('Humbug\\Mailer', 'Humbug\\Swift');
69+
is_subclass_of('Humbug\\Mailer', 'Humbug\\Swift');
70+
is_subclass_of('\\Humbug\\Mailer', '\\Humbug\\Swift');
5871
is_subclass_of('Mailer', 'DateTime');
72+
is_subclass_of('\\Mailer', '\\DateTime');
5973
6074
interface_exists('Swift');
61-
interface_exists('Humbug\Swift');
62-
interface_exists('\Humbug\Swift');
75+
interface_exists('\\Swift');
76+
interface_exists('Humbug\\Swift');
77+
interface_exists('\\Humbug\\Swift');
6378
interface_exists('DateTime');
79+
interface_exists('\\DateTime');
6480
6581
class_exists('Swift');
66-
class_exists('Humbug\Swift');
67-
class_exists('\Humbug\Swift');
82+
class_exists('\\Swift');
83+
class_exists('Humbug\\Swift');
84+
class_exists('\\Humbug\\Swift');
6885
class_exists('DateTime');
86+
class_exists('\\DateTime');
6987
7088
trait_exists('Swift');
71-
trait_exists('Humbug\Swift');
72-
trait_exists('\Humbug\Swift');
89+
trait_exists('\\Swift');
90+
trait_exists('Humbug\\Swift');
91+
trait_exists('\\Humbug\\Swift');
7392
trait_exists('DateTime');
93+
trait_exists('\\DateTime');
7494
7595
function_exists('dump');
76-
function_exists('Humbug\dump');
77-
function_exists('\Humbug\dump');
96+
function_exists('Humbug\\dump');
97+
function_exists('\Humbug\\dump');
7898
function_exists('var_dump');
7999
80100
class_alias('Swift', 'Mailer');
81-
class_alias('Humbug\Swift', 'Mailer');
82-
class_alias('\Humbug\Swift', 'Mailer');
101+
class_alias('\\Swift', '\\Mailer');
102+
class_alias('Humbug\\Swift', 'Mailer');
103+
class_alias('\\Humbug\\Swift', '\\Mailer');
83104
class_alias('DateTime', 'DateTimeInterface');
105+
class_alias('\\DateTime', '\\DateTimeInterface');
84106
85107
($this->colorize)('fg-green', '✔');
86108
($this->colorize)(['Soft', 'autoload']);
109+
($this->colorize)(['\\Soft', 'autoload']);
87110
88111
----
89112
<?php
@@ -95,47 +118,70 @@ class_alias('DateTime', 'DateTimeInterface');
95118
\Humbug\foo('Humbug\\Symfony\\Component\\Yaml\\Ya_1');
96119
\Humbug\foo('Humbug\\Symfony\\Component\\Yaml\\Ya_1');
97120
\Humbug\foo('DateTime');
121+
\Humbug\foo('\\DateTime');
98122
\Humbug\foo('Swift');
123+
\Humbug\foo('\\Swift');
99124
\Humbug\foo(['DateTime', 'autoload']);
125+
\Humbug\foo(['\\DateTime', 'autoload']);
100126
\Humbug\foo(['Swift', 'autoload']);
127+
\Humbug\foo(['\\Swift', 'autoload']);
128+
\spl_autoload_register(['Humbug\\Swift', 'autoload']);
129+
\spl_autoload_register(['Humbug\\Swift', 'autoload']);
101130
\spl_autoload_register(['Humbug\\Swift', 'autoload']);
102131
\spl_autoload_register(['Humbug\\Swift', 'autoload']);
103132
\spl_autoload_register(['Humbug\\Swift', 'autoload']);
104133
\spl_autoload_register(['DateTime', 'autoload']);
134+
\spl_autoload_register(['\\DateTime', 'autoload']);
135+
\is_a($swift, 'Humbug\\Swift');
105136
\is_a($swift, 'Humbug\\Swift');
106137
\is_a($swift, 'Humbug\\Swift');
107138
\is_a($swift, 'Humbug\\Swift');
108139
\is_a($swift, 'DateTime');
140+
\is_a($swift, '\\DateTime');
141+
\is_subclass_of($swift, 'Humbug\\Swift');
109142
\is_subclass_of($swift, 'Humbug\\Swift');
110143
\is_subclass_of($swift, 'Humbug\\Swift');
111144
\is_subclass_of($swift, 'Humbug\\Swift');
112145
\is_subclass_of($swift, 'DateTime');
146+
\is_subclass_of($swift, '\\DateTime');
147+
\is_subclass_of('Humbug\\Mailer', 'Humbug\\Swift');
148+
\is_subclass_of('Humbug\\Mailer', 'Humbug\\Swift');
113149
\is_subclass_of('Humbug\\Mailer', 'Humbug\\Swift');
114150
\is_subclass_of('Humbug\\Mailer', 'Humbug\\Swift');
115151
\is_subclass_of('Humbug\\Mailer', 'Humbug\\Swift');
116152
\is_subclass_of('Humbug\\Mailer', 'DateTime');
153+
\is_subclass_of('Humbug\\Mailer', '\\DateTime');
154+
\interface_exists('Humbug\\Swift');
117155
\interface_exists('Humbug\\Swift');
118156
\interface_exists('Humbug\\Swift');
119157
\interface_exists('Humbug\\Swift');
120158
\interface_exists('DateTime');
159+
\interface_exists('\\DateTime');
160+
\class_exists('Humbug\\Swift');
121161
\class_exists('Humbug\\Swift');
122162
\class_exists('Humbug\\Swift');
123163
\class_exists('Humbug\\Swift');
124164
\class_exists('DateTime');
165+
\class_exists('\\DateTime');
166+
\trait_exists('Humbug\\Swift');
125167
\trait_exists('Humbug\\Swift');
126168
\trait_exists('Humbug\\Swift');
127169
\trait_exists('Humbug\\Swift');
128170
\trait_exists('DateTime');
171+
\trait_exists('\\DateTime');
129172
\function_exists('Humbug\\dump');
130173
\function_exists('Humbug\\dump');
131174
\function_exists('Humbug\\dump');
132175
\function_exists('var_dump');
133176
\class_alias('Humbug\\Swift', 'Humbug\\Mailer');
134177
\class_alias('Humbug\\Swift', 'Humbug\\Mailer');
135178
\class_alias('Humbug\\Swift', 'Humbug\\Mailer');
179+
\class_alias('Humbug\\Swift', 'Humbug\\Mailer');
136180
\class_alias('DateTime', 'DateTimeInterface');
181+
\class_alias('\\DateTime', '\\DateTimeInterface');
137182
($this->colorize)('fg-green', '✔');
138183
($this->colorize)(['Soft', 'autoload']);
184+
($this->colorize)(['\\Soft', 'autoload']);
139185

140186
PHP
141187
,

src/PhpParser/NodeVisitor/StringScalarPrefixer.php

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,15 @@
1414

1515
namespace Humbug\PhpScoper\PhpParser\NodeVisitor;
1616

17+
use function array_key_exists;
18+
use function array_shift;
19+
use function array_values;
1720
use Humbug\PhpScoper\Reflector;
1821
use Humbug\PhpScoper\Whitelist;
22+
use function implode;
23+
use function in_array;
24+
use function is_string;
25+
use function ltrim;
1926
use PhpParser\Node;
2027
use PhpParser\Node\Arg;
2128
use PhpParser\Node\Const_;
@@ -33,12 +40,6 @@
3340
use PhpParser\Node\Stmt\PropertyProperty;
3441
use PhpParser\Node\Stmt\Return_;
3542
use PhpParser\NodeVisitorAbstract;
36-
use function array_key_exists;
37-
use function array_shift;
38-
use function array_values;
39-
use function implode;
40-
use function in_array;
41-
use function is_string;
4243
use function preg_match;
4344
use function strpos;
4445
use function strtolower;
@@ -107,6 +108,8 @@ private function prefixStringScalar(String_ $string): String_
107108
return $string;
108109
}
109110

111+
$normalizedValue = ltrim($string->value, '\\');
112+
110113
if ($this->whitelist->belongsToWhitelistedNamespace($string->value)) {
111114
return $string;
112115
}
@@ -120,11 +123,11 @@ private function prefixStringScalar(String_ $string): String_
120123
// namespace or a completely unrelated string.
121124

122125
if ($parentNode instanceof Arg) {
123-
return $this->prefixStringArg($string, $parentNode);
126+
return $this->prefixStringArg($string, $parentNode, $normalizedValue);
124127
}
125128

126129
if ($parentNode instanceof ArrayItem) {
127-
return $this->prefixArrayItemString($string, $parentNode);
130+
return $this->prefixArrayItemString($string, $parentNode, $normalizedValue);
128131
}
129132

130133
if (false === (
@@ -145,7 +148,7 @@ private function prefixStringScalar(String_ $string): String_
145148
;
146149
}
147150

148-
private function prefixStringArg(String_ $string, Arg $parentNode): String_
151+
private function prefixStringArg(String_ $string, Arg $parentNode, string $normalizedValue): String_
149152
{
150153
$callerNode = ParentNodeAppender::getParent($parentNode);
151154

@@ -154,7 +157,7 @@ private function prefixStringArg(String_ $string, Arg $parentNode): String_
154157
}
155158

156159
if ($callerNode instanceof FuncCall) {
157-
return $this->prefixFunctionStringArg($string, $callerNode);
160+
return $this->prefixFunctionStringArg($string, $callerNode, $normalizedValue);
158161
}
159162

160163
if ($callerNode instanceof StaticCall) {
@@ -181,7 +184,7 @@ private function prefixNewStringArg(String_ $string, New_ $newNode): String_
181184
return $this->createPrefixedStringIfDoesNotBelongToGlobalNamespace($string);
182185
}
183186

184-
private function prefixFunctionStringArg(String_ $string, FuncCall $functionNode): String_
187+
private function prefixFunctionStringArg(String_ $string, FuncCall $functionNode, string $normalizedValue): String_
185188
{
186189
// In the case of a function call, we allow to prefix strings which could be classes belonging to the global
187190
// namespace in some cases
@@ -196,7 +199,7 @@ private function prefixFunctionStringArg(String_ $string, FuncCall $functionNode
196199
}
197200

198201
if ('function_exists' === $functionName) {
199-
return $this->reflector->isFunctionInternal($string->value)
202+
return $this->reflector->isFunctionInternal($normalizedValue)
200203
? $string
201204
: $this->createPrefixedString($string)
202205
;
@@ -211,7 +214,7 @@ private function prefixFunctionStringArg(String_ $string, FuncCall $functionNode
211214
return $string;
212215
}
213216

214-
return $this->reflector->isClassInternal($string->value)
217+
return $this->reflector->isClassInternal($normalizedValue)
215218
? $string
216219
: $this->createPrefixedString($string)
217220
;
@@ -221,7 +224,7 @@ private function prefixFunctionStringArg(String_ $string, FuncCall $functionNode
221224
(
222225
$this->whitelist->isSymbolWhitelisted($string->value, true)
223226
|| $this->whitelist->isGlobalWhitelistedConstant($string->value)
224-
|| $this->reflector->isConstantInternal($string->value)
227+
|| $this->reflector->isConstantInternal($normalizedValue)
225228
)
226229
? $string
227230
: $this->createPrefixedString($string)
@@ -249,7 +252,7 @@ private function prefixStaticCallStringArg(String_ $string, StaticCall $callNode
249252
return $this->createPrefixedStringIfDoesNotBelongToGlobalNamespace($string);
250253
}
251254

252-
private function prefixArrayItemString(String_ $string, ArrayItem $parentNode): String_
255+
private function prefixArrayItemString(String_ $string, ArrayItem $parentNode, string $normalizedValue): String_
253256
{
254257
// ArrayItem can lead to two results: either the string is used for `spl_autoload_register()`, e.g.
255258
// `spl_autoload_register(['Swift', 'autoload'])` in which case the string `'Swift'` is guaranteed to be class
@@ -293,7 +296,7 @@ private function prefixArrayItemString(String_ $string, ArrayItem $parentNode):
293296
return ('spl_autoload_register' === $functionName
294297
&& array_key_exists(0, $arrayNode->items)
295298
&& $arrayItemNode === $arrayNode->items[0]
296-
&& false === $this->reflector->isClassInternal($string->value)
299+
&& false === $this->reflector->isClassInternal($normalizedValue)
297300
)
298301
? $this->createPrefixedString($string)
299302
: $string

0 commit comments

Comments
 (0)