From a503f547ee2bad203126777137a1a85f6e885de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Sat, 9 Jun 2018 13:56:51 +0100 Subject: [PATCH] Fix usage with grouped constant statements (#219) --- README.md | 18 +++++++ specs/const/const-declaration.php | 22 ++++++++ .../NodeVisitor/ConstStmtReplacer.php | 54 +++++++++++-------- tests/Scoper/PhpScoperTest.php | 21 ++++++-- 4 files changed, 89 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index b0c08be7..b507cd1f 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ potentially very difficult to debug due to dissimilar or unsupported package ver - [PSR-0 support](#psr-0-support) - [String values](#string-values) - [Native functions and constants shadowing](#native-functions-shadowing) + - [Grouped constants whitelisting](#grouped-constants-whitelisting) - [Composer](#composer) - [Composer Plugins](#composer-plugins) - [Contributing](#contributing) @@ -543,6 +544,23 @@ is_array([]); The situation is exactly the same for constants. +### Grouped constants whitelisting + +When a grouped constant declaration like the following is given: + +```php +const X = 'foo', Y = 'bar'; +``` + +PHP-Scoper will not be able to whitelist either `X` or `Y`. The statement +above should be replaced by multiple constant statements: + +```php +const X = 'foo'; +const Y = 'bar'; +``` + + ### Composer PHP-Scoper does not support prefixing the dumped Composer autoloader and autoloading files. This is why you have to diff --git a/specs/const/const-declaration.php b/specs/const/const-declaration.php index ff3307ab..7187ce0d 100644 --- a/specs/const/const-declaration.php +++ b/specs/const/const-declaration.php @@ -26,6 +26,7 @@ [ + 'whitelist' => ['X'], + 'payload' => <<<'PHP' +consts); + foreach ($node->consts as $constant) { + /** @var Node\Const_ $constant */ + $resolvedConstantName = $this->nameResolver->resolveName( + new Name( + (string) $constant->name, + $node->getAttributes() + ) + )->getName(); - $resolvedConstantName = $this->nameResolver->resolveName( - new Name( - (string) $constant->name, - $node->getAttributes() // Take the parent node attribute since no "parent" attribute is recorded in - // Node\Const_ - // TODO: check with nikic if this is expected - ) - )->getName(); + if (false === $this->whitelist->isClassWhitelisted((string) $resolvedConstantName)) { + continue; + } - if (false === $this->whitelist->isClassWhitelisted((string) $resolvedConstantName)) { - return $node; + if (count($node->consts) > 1) { + throw new UnexpectedValueException( + 'Whitelisting a constant declared in a grouped constant statement (e.g. `const FOO = ' + .'\'foo\', BAR = \'bar\'; is not supported. Consider breaking it down in multiple constant ' + .'declaration statements' + ); + } + + return new Expression( + new FuncCall( + new FullyQualified('define'), + [ + new String_((string) $resolvedConstantName), + $constant->value, + ] + ) + ); } - return new Expression( - new FuncCall( - new FullyQualified('define'), - [ - new String_((string) $resolvedConstantName), - $constant->value, - ] - ) - ); + return $node; } } diff --git a/tests/Scoper/PhpScoperTest.php b/tests/Scoper/PhpScoperTest.php index 5c70fe88..a4558156 100644 --- a/tests/Scoper/PhpScoperTest.php +++ b/tests/Scoper/PhpScoperTest.php @@ -36,6 +36,7 @@ use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator; use Symfony\Component\Finder\Finder; use Throwable; +use UnexpectedValueException; use function Humbug\PhpScoper\create_fake_patcher; use function Humbug\PhpScoper\create_parser; use function implode; @@ -422,7 +423,7 @@ function (...$args) use (&$i): bool { /** * @dataProvider provideValidFiles */ - public function test_can_scope_valid_files(string $spec, string $contents, string $prefix, Whitelist $whitelist, string $expected) + public function test_can_scope_valid_files(string $spec, string $contents, string $prefix, Whitelist $whitelist, ?string $expected) { $filePath = 'file.php'; @@ -448,7 +449,21 @@ public function test_can_scope_valid_files(string $spec, string $contents, strin ) ); - $actual = $this->scoper->scope($filePath, $contents, $prefix, $patchers, $whitelist); + try { + $actual = $this->scoper->scope($filePath, $contents, $prefix, $patchers, $whitelist); + + if (null === $expected) { + $this->fail('Expected exception to be thrown.'); + } + } catch (UnexpectedValueException $exception) { + if (null !== $expected) { + throw $exception; + } + + $this->assertTrue(true); + + return; + } $formattedWhitelist = 0 === count($whitelist) ? '[]' @@ -559,7 +574,7 @@ private function parseSpecFile(array $meta, $fixtureTitle, $fixtureSet): Generat $fixtureSet['whitelist-global-constants'] ?? $meta['whitelist-global-constants'], ...($fixtureSet['whitelist'] ?? $meta['whitelist']) ), - $payloadParts[1], // Expected output + '' === $payloadParts[1] ? null : $payloadParts[1], // Expected output ]; } }