Skip to content

Detect global user functions (e.g. polyfills) #210

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

Merged
merged 4 commits into from
Dec 30, 2024
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
8 changes: 2 additions & 6 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,6 @@ jobs:
repo: mimmi20/ua-device-type
-
repo: mimmi20/ua-normalizer
-
repo: numero2/contao-marketing-suite
cdaArgs: --disable-ext-analysis --config=depcheck.php
-
repo: numero2/contao-opengraph3
cdaArgs: --config=depcheck.php
Expand All @@ -176,6 +173,7 @@ jobs:
-
repo: phpstan/phpstan-src
cdaArgs: --disable-ext-analysis --config=build/composer-dependency-analyser.php
php: 8.4
-
repo: qossmic/deptrac-src
-
Expand Down Expand Up @@ -208,8 +206,6 @@ jobs:
repo: shipmonk-rnd/phpstan-rules
-
repo: symplify/config-transformer
-
repo: teamneusta/pimcore-testing-framework
-
repo: wallabag/wallabag
cdaArgs: --disable-ext-analysis
Expand All @@ -236,7 +232,7 @@ jobs:
name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.3
php-version: ${{ matrix.php || '8.3' }}
ini-file: development

-
Expand Down
3 changes: 3 additions & 0 deletions scripts/refresh-e2e.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ function outputYaml(array $items): void
$result[] = [
'repo' => 'phpstan/phpstan-src',
'cdaArgs' => '--config=build/composer-dependency-analyser.php',
'php' => '8.4',
];
$result[] = [
'repo' => 'qossmic/deptrac-src',
Expand Down Expand Up @@ -109,6 +110,8 @@ function outputYaml(array $items): void
|| $item['repo'] === 'symplify/phpstan-rules'
|| $item['repo'] === 'contao-thememanager/core'
|| $item['repo'] === 'oveleon/contao-recommendation-bundle'
|| $item['repo'] === 'numero2/contao-marketing-suite' // since 1.8.2 (shadow symfony/contracts via trigger_deprecation)
|| $item['repo'] === 'teamneusta/pimcore-testing-framework' // since 1.8.2 (shadow symfony/contracts via trigger_deprecation)
) {
unset($result[$index]); // failing builds
}
Expand Down
11 changes: 6 additions & 5 deletions src/Analyser.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class Analyser
*
* @var array<string, SymbolKind::*>
*/
private $extensionSymbolKinds = [];
private $knownSymbolKinds = [];

/**
* @param array<string, ClassLoader> $classLoaders vendorDir => ClassLoader (e.g. result of \Composer\Autoload\ClassLoader::getRegisteredLoaders())
Expand Down Expand Up @@ -392,7 +392,7 @@ private function getUsedSymbolsInFile(string $filePath): array
}

return (new UsedSymbolExtractor($code))->parseUsedSymbols(
$this->extensionSymbolKinds
$this->knownSymbolKinds
);
}

Expand Down Expand Up @@ -553,7 +553,7 @@ private function initExistingSymbols(Configuration $config): void
$this->ignoredSymbols[$constantName] = true;
} else {
$this->extensionSymbols[SymbolKind::CONSTANT][$constantName] = $extensionName;
$this->extensionSymbolKinds[strtolower($constantName)] = SymbolKind::CONSTANT;
$this->knownSymbolKinds[strtolower($constantName)] = SymbolKind::CONSTANT;
}
}
}
Expand All @@ -567,6 +567,7 @@ private function initExistingSymbols(Configuration $config): void
if ($reflectionFunction->getExtension() === null) {
if (is_string($functionFilePath)) {
$this->definedFunctions[$functionName] = Path::normalize($functionFilePath);
$this->knownSymbolKinds[$functionName] = SymbolKind::FUNCTION;
}
} else {
$extensionName = $this->getNormalizedExtensionName($reflectionFunction->getExtension()->name);
Expand All @@ -575,7 +576,7 @@ private function initExistingSymbols(Configuration $config): void
$this->ignoredSymbols[$functionName] = true;
} else {
$this->extensionSymbols[SymbolKind::FUNCTION][$functionName] = $extensionName;
$this->extensionSymbolKinds[$functionName] = SymbolKind::FUNCTION;
$this->knownSymbolKinds[$functionName] = SymbolKind::FUNCTION;
}
}
}
Expand All @@ -598,7 +599,7 @@ private function initExistingSymbols(Configuration $config): void
$this->ignoredSymbols[$classLikeName] = true;
} else {
$this->extensionSymbols[SymbolKind::CLASSLIKE][$classLikeName] = $extensionName;
$this->extensionSymbolKinds[strtolower($classLikeName)] = SymbolKind::CLASSLIKE;
$this->knownSymbolKinds[strtolower($classLikeName)] = SymbolKind::CLASSLIKE;
}
}
}
Expand Down
18 changes: 9 additions & 9 deletions src/UsedSymbolExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ public function __construct(string $code)
* It does not produce any local names in current namespace
* - this results in very limited functionality in files without namespace
*
* @param array<string, SymbolKind::*> $extensionSymbols
* @param array<string, SymbolKind::*> $knownSymbols
* @return array<SymbolKind::*, array<string, list<int>>>
* @license Inspired by https://github.com/doctrine/annotations/blob/2.0.0/lib/Doctrine/Common/Annotations/TokenParser.php
*/
public function parseUsedSymbols(
array $extensionSymbols
array $knownSymbols
): array
{
$usedSymbols = [];
Expand Down Expand Up @@ -124,7 +124,7 @@ public function parseUsedSymbols(
case PHP_VERSION_ID >= 80000 ? T_NAME_FULLY_QUALIFIED : -1:
$symbolName = $this->normalizeBackslash($token[1]);
$lowerSymbolName = strtolower($symbolName);
$kind = $extensionSymbols[$lowerSymbolName] ?? $this->getFqnSymbolKind($this->pointer - 2, $this->pointer, $inAttributeSquareLevel !== null);
$kind = $knownSymbols[$lowerSymbolName] ?? $this->getFqnSymbolKind($this->pointer - 2, $this->pointer, $inAttributeSquareLevel !== null);
$usedSymbols[$kind][$symbolName][] = $token[2];
break;

Expand All @@ -140,7 +140,7 @@ public function parseUsedSymbols(
}

$lowerSymbolName = strtolower($symbolName);
$kind = $extensionSymbols[$lowerSymbolName] ?? $this->getFqnSymbolKind($this->pointer - 2, $this->pointer, $inAttributeSquareLevel !== null);
$kind = $knownSymbols[$lowerSymbolName] ?? $this->getFqnSymbolKind($this->pointer - 2, $this->pointer, $inAttributeSquareLevel !== null);
$usedSymbols[$kind][$symbolName][] = $token[2];

break;
Expand All @@ -160,9 +160,9 @@ public function parseUsedSymbols(
$kind = $useStatementKinds[$name];
$usedSymbols[$kind][$symbolName][] = $token[2];

} elseif (isset($extensionSymbols[$lowerName])) {
} elseif (isset($knownSymbols[$lowerName])) {
$symbolName = $name;
$kind = $extensionSymbols[$lowerName];
$kind = $knownSymbols[$lowerName];

if (!$inGlobalScope && $kind === SymbolKind::CLASSLIKE) {
break; // cannot use class-like symbols in non-global scope when not imported
Expand Down Expand Up @@ -192,7 +192,7 @@ public function parseUsedSymbols(
$lowerSymbolName = strtolower($symbolName);

if ($symbolName !== '') { // e.g. \array (NS separator followed by not-a-name)
$kind = $extensionSymbols[$lowerSymbolName] ?? $this->getFqnSymbolKind($pointerBeforeName, $this->pointer - 1, false);
$kind = $knownSymbols[$lowerSymbolName] ?? $this->getFqnSymbolKind($pointerBeforeName, $this->pointer - 1, false);
$usedSymbols[$kind][$symbolName][] = $token[2];
}

Expand All @@ -213,9 +213,9 @@ public function parseUsedSymbols(
$kind = $useStatementKinds[$name];
$usedSymbols[$kind][$symbolName][] = $token[2];

} elseif (isset($extensionSymbols[$lowerName])) {
} elseif (isset($knownSymbols[$lowerName])) {
$symbolName = $name;
$kind = $extensionSymbols[$lowerName];
$kind = $knownSymbols[$lowerName];

if (!$inGlobalScope && $kind === SymbolKind::CLASSLIKE) {
break; // cannot use class-like symbols in non-global scope when not imported
Expand Down
11 changes: 10 additions & 1 deletion tests/UsedSymbolExtractorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ public function provideVariants(): iterable
'PHPUnit\Framework\Error' => [14],
'LogicException' => [15, 20],
],
SymbolKind::FUNCTION => [
'user_defined_function' => [38],
],
],
[
'user_defined_function' => SymbolKind::FUNCTION,
],
];

Expand Down Expand Up @@ -113,7 +119,6 @@ public function provideVariants(): iterable
];

yield 'global namespace' => [

__DIR__ . '/data/not-autoloaded/used-symbols/global-namespace.php',
[
SymbolKind::CLASSLIKE => [
Expand All @@ -122,8 +127,12 @@ public function provideVariants(): iterable
],
SymbolKind::FUNCTION => [
'PHPUnit\Framework\assertSame' => [7],
'user_defined_function' => [12],
],
],
[
strtolower('user_defined_function') => SymbolKind::FUNCTION,
],
];

yield 'curly braces' => [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@
class Foo {
public function someFunction(string $foo): void
{

user_defined_function();
}
}
2 changes: 1 addition & 1 deletion tests/data/not-autoloaded/used-symbols/various-usages.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class Foo {

public function foo(Error $error): void // not PHPUnit\Framework\Error anymore
{

user_defined_function();
}

}
Loading