Skip to content

Commit

Permalink
Fix internal symbol declaration (#722)
Browse files Browse the repository at this point in the history
This is the analogue to #706.
  • Loading branch information
theofidry authored Nov 7, 2022
1 parent 4501e36 commit 1a30d98
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 46 deletions.
45 changes: 3 additions & 42 deletions scoper.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,56 +46,17 @@
return $files;
})();

$polyfillsBootstraps = array_map(
static fn (SplFileInfo $fileInfo) => $fileInfo->getPathname(),
iterator_to_array(
Finder::create()
->files()
->in(__DIR__.'/vendor/symfony/polyfill-*')
->name('bootstrap*.php'),
false,
),
);

$polyfillsStubs = array_map(
static fn (SplFileInfo $fileInfo) => $fileInfo->getPathname(),
iterator_to_array(
Finder::create()
->files()
->in(__DIR__.'/vendor/symfony/polyfill-*/Resources/stubs')
->name('*.php'),
false,
),
);

$symfonyDeprecationContracts = array_map(
static fn (SplFileInfo $fileInfo) => $fileInfo->getPathname(),
iterator_to_array(
Finder::create()
->files()
->in(__DIR__.'/vendor/symfony/deprecation-contracts')
->name('*.php'),
false,
),
);

return [
'whitelist' => [
Finder::class,
],
'exclude-namespaces' => [
'Symfony\Polyfill',
],
'expose-global-functions' => true,
'expose-global-classes' => true,
'exclude-constants' => [
// Symfony global constants
'/^SYMFONY\_[\p{L}_]+$/',
],
'exclude-files' => [
...$jetBrainStubs,
...$polyfillsBootstraps,
...$polyfillsStubs,
...$symfonyDeprecationContracts,
],
'exclude-files' => $jetBrainStubs,
'patchers' => [
//
// PHPStorm stub map: leave it unchanged
Expand Down
4 changes: 4 additions & 0 deletions specs/class-const/global-scope-single-level.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ class Command

'Constant call on a class belonging to the global namespace which is excluded' => [
'exclude-namespaces' => ['/^$/'],
'expected-recorded-classes' => [
['Command', 'Humbug\Command'],
],
'payload' => <<<'PHP'
<?php
Expand All @@ -68,6 +71,7 @@ class Command {}
class Command
{
}
\class_alias('Humbug\\Command', 'Command', \false);
\Command::MAIN_CONST;
}

Expand Down
4 changes: 4 additions & 0 deletions specs/class-static-prop/global-scope-single-level.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ class Command

'Constant call on a class belonging to the global namespace which is excluded' => [
'exclude-namespaces' => ['/^$/'],
'expected-recorded-classes' => [
['Command', 'Humbug\Command'],
],
'payload' => <<<'PHP'
<?php
Expand All @@ -68,6 +71,7 @@ class Command {}
class Command
{
}
\class_alias('Humbug\\Command', 'Command', \false);
\Command::$mainStaticProp;
}

Expand Down
9 changes: 8 additions & 1 deletion specs/class/abstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ public abstract function b();

'Declaration in the global namespace with the global namespace excluded' => [
'exclude-namespaces' => ['/^$/'],
'expected-recorded-classes' => [
['A', 'Humbug\A'],
],
'payload' => <<<'PHP'
<?php
Expand All @@ -106,6 +109,7 @@ public function a()
}
public abstract function b();
}
\class_alias('Humbug\\A', 'A', \false);
}

PHP,
Expand Down Expand Up @@ -143,7 +147,9 @@ public abstract function b();
'Declaration of an exposed class in the global namespace which is excluded' => [
'exclude-namespaces' => ['/^$/'],
'expose-classes' => ['A'],
'expected-recorded-classes' => [],
'expected-recorded-classes' => [
['A', 'Humbug\A'],
],
'payload' => <<<'PHP'
<?php
Expand All @@ -162,6 +168,7 @@ public function a()
}
public abstract function b();
}
\class_alias('Humbug\\A', 'A', \false);
}

PHP,
Expand Down
8 changes: 8 additions & 0 deletions specs/class/anonymous.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ public function test()

'Declaration in the global namespace which is excluded' => [
'exclude-namespaces' => ['/^$/'],
'expected-recorded-classes' => [
['A', 'Humbug\A'],
['B', 'Humbug\B'],
['C', 'Humbug\C'],
],
'payload' => <<<'PHP'
<?php
Expand Down Expand Up @@ -209,9 +214,11 @@ public function test() {
interface B
{
}
\class_alias('Humbug\\B', 'B', \false);
interface C
{
}
\class_alias('Humbug\\C', 'C', \false);
new class
{
public function test()
Expand Down Expand Up @@ -239,6 +246,7 @@ public function test()
};
}
}
\class_alias('Humbug\\A', 'A', \false);
}

PHP,
Expand Down
21 changes: 21 additions & 0 deletions specs/class/regular.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,27 @@ public function a()
PHP,
],

'Declaration of an internal class' => [
'expected-recorded-classes' => [
['Normalizer', 'Humbug\Normalizer'],
],
'payload' => <<<'PHP'
<?php
class Normalizer {}
----
<?php
namespace Humbug;
class Normalizer
{
}
\class_alias('Humbug\\Normalizer', 'Normalizer', \false);

PHP,
],

'Declaration in a namespace' => <<<'PHP'
<?php
Expand Down
9 changes: 8 additions & 1 deletion specs/use/use-class.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ class Foo

'Use statement of a class belonging to the global scope which has been excluded' => [
'exclude-namespaces' => [''],
'expected-recorded-classes' => [
['Foo', 'Humbug\Foo'],
],
'payload' => <<<'PHP'
<?php
Expand All @@ -162,6 +165,7 @@ class Foo {}
class Foo
{
}
\class_alias('Humbug\\Foo', 'Foo', \false);
use Foo;
}

Expand All @@ -171,7 +175,9 @@ class Foo
'Use statement of an exposed class belonging to the global scope which has been excluded' => [
'exclude-namespaces' => [''],
'expose-classes' => ['Foo'],
'expected-recorded-classes' => [],
'expected-recorded-classes' => [
['Foo', 'Humbug\Foo'],
],
'payload' => <<<'PHP'
<?php
Expand All @@ -186,6 +192,7 @@ class Foo {}
class Foo
{
}
\class_alias('Humbug\\Foo', 'Foo', \false);
use Foo;
}

Expand Down
18 changes: 16 additions & 2 deletions src/PhpParser/NodeVisitor/ClassIdentifierRecorder.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
use PhpParser\NodeVisitorAbstract;

/**
* Records the user classes which are exposed.
* Records the classes that need to be aliased.
*
* @private
*/
Expand Down Expand Up @@ -65,7 +65,7 @@ public function enterNode(Node $node): Node
throw UnexpectedParsingScenario::create();
}

if ($this->enrichedReflector->isExposedClass((string) $resolvedName)) {
if ($this->shouldBeAliased($resolvedName->toString())) {
$this->symbolsRegistry->recordClass(
$resolvedName,
FullyQualifiedFactory::concat($this->prefix, $resolvedName),
Expand All @@ -74,4 +74,18 @@ public function enterNode(Node $node): Node

return $node;
}

private function shouldBeAliased(string $resolvedName): bool
{
if ($this->enrichedReflector->isExposedClass($resolvedName)) {
return true;
}

// Excluded global classes (for which we found a declaration) need to be
// aliased since otherwise any usage will not point to the prefixed
// version (since it's an alias) but the declaration will now declare
// a prefixed version (due to the namespace).
return $this->enrichedReflector->belongsToGlobalNamespace($resolvedName)
&& $this->enrichedReflector->isClassExcluded($resolvedName);
}
}

0 comments on commit 1a30d98

Please sign in to comment.