Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix internal symbol declaration #722

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
}