diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 41d2923444..e40c3bac26 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -308,7 +308,7 @@ jobs: e2e-tests: name: "E2E tests" - runs-on: "ubuntu-latest" + runs-on: ${{ matrix.os }} timeout-minutes: 60 strategy: @@ -317,84 +317,127 @@ jobs: - script: "bin/phpstan analyse -l 8 -a tests/e2e/data/timecop.php -c tests/e2e/data/empty.neon tests/e2e/data/timecop.php" tools: "pecl" extensions: "timecop-beta" + os: "ubuntu-latest" - script: "bin/phpstan analyse -l 8 -a tests/e2e/data/soap.php -c tests/e2e/data/empty.neon tests/e2e/data/soap.php" extensions: "soap" + os: "ubuntu-latest" - script: "bin/phpstan analyse -l 8 -a tests/e2e/data/soap.php -c tests/e2e/data/empty.neon tests/e2e/data/soap.php" extensions: "" + os: "ubuntu-latest" - script: "bin/phpstan analyse -l 8 tests/e2e/anon-class/Granularity.php" extensions: "" + os: "ubuntu-latest" - script: "bin/phpstan analyse -l 8 e2e/phpstan-phpunit-190/test.php -c e2e/phpstan-phpunit-190/test.neon" extensions: "" + os: "ubuntu-latest" - script: "bin/phpstan analyse e2e/only-files-not-analysed-trait/src -c e2e/only-files-not-analysed-trait/ignore.neon" extensions: "" + os: "ubuntu-latest" - script: "bin/phpstan analyse e2e/only-files-not-analysed-trait/src/Foo.php e2e/only-files-not-analysed-trait/src/BarTrait.php -c e2e/only-files-not-analysed-trait/no-ignore.neon" extensions: "" + os: "ubuntu-latest" - script: | cd e2e/baseline-uninit-prop-trait ../../bin/phpstan analyse --debug --configuration test-no-baseline.neon --generate-baseline test-baseline.neon ../../bin/phpstan analyse --debug --configuration test.neon + os: "ubuntu-latest" - script: | cd e2e/baseline-uninit-prop-trait ../../bin/phpstan analyse --configuration test-no-baseline.neon --generate-baseline test-baseline.neon ../../bin/phpstan analyse --configuration test.neon + os: "ubuntu-latest" - script: | cd e2e/discussion-11362 composer install ../../bin/phpstan + os: "ubuntu-latest" - script: | cd e2e/bug-11819 ../../bin/phpstan + os: "ubuntu-latest" - script: | cd e2e/composer-and-phpstan-version-config composer install --ignore-platform-reqs ../../bin/phpstan analyze test.php --level=0 + os: "ubuntu-latest" - script: | cd e2e/composer-max-version composer install ../../bin/phpstan analyze test.php --level=0 + os: "ubuntu-latest" - script: | cd e2e/composer-min-max-version composer install ../../bin/phpstan analyze test.php --level=0 + os: "ubuntu-latest" - script: | cd e2e/composer-min-open-end-version composer install ../../bin/phpstan analyze test.php --level=0 + os: "ubuntu-latest" - script: | cd e2e/composer-min-version-v5 composer install --ignore-platform-reqs ../../bin/phpstan analyze test.php --level=0 + os: "ubuntu-latest" - script: | cd e2e/composer-min-version-v7 composer install --ignore-platform-reqs ../../bin/phpstan analyze test.php --level=0 + os: "ubuntu-latest" - script: | cd e2e/composer-min-version composer install ../../bin/phpstan analyze test.php --level=0 + os: "ubuntu-latest" - script: | cd e2e/composer-no-versions composer install ../../bin/phpstan analyze test.php --level=0 + os: "ubuntu-latest" - script: | cd e2e/composer-version-config-invalid OUTPUT=$(../bashunit -a exit_code "1" ../../bin/phpstan) echo "$OUTPUT" ../bashunit -a contains 'Invalid configuration' "$OUTPUT" ../bashunit -a contains 'Invalid PHP version range: phpVersion.max should be greater or equal to phpVersion.min.' "$OUTPUT" + os: "ubuntu-latest" - script: | cd e2e/composer-version-config-patch composer install --ignore-platform-reqs ../../bin/phpstan analyze test.php --level=0 + os: "ubuntu-latest" - script: | cd e2e/composer-version-config composer install ../../bin/phpstan analyze test.php --level=0 + os: "ubuntu-latest" + - script: | + cd e2e/bug-12972 + OUTPUT=$(../bashunit -a exit_code "1" ../../bin/phpstan) + echo "$OUTPUT" + ../bashunit -a contains 'Internal error: Failed opening required' "$OUTPUT" + ../bashunit -a contains 'e2e/bug-12972/src/OTHER/file.php' "$OUTPUT" + os: "ubuntu-latest" + - script: | + cd e2e/bug-12972 + ../../bin/phpstan analyze + os: "macos-latest" + - script: | + cd e2e/bug-12972 + ../../bin/phpstan analyze + os: "windows-latest" steps: - name: "Checkout" uses: actions/checkout@v4 + - name: "Install GNU Patch on macOS" # see https://github.com/cweagans/composer-patches/issues/326 + if: runner.os == 'macOS' + run: | + brew install gpatch + echo "/opt/homebrew/opt/gpatch/libexec/gnubin" >> $GITHUB_PATH + - name: "Install PHP" uses: "shivammathur/setup-php@v2" with: diff --git a/e2e/bug-12972/autoloader.php b/e2e/bug-12972/autoloader.php new file mode 100644 index 0000000000..ea5cc8a051 --- /dev/null +++ b/e2e/bug-12972/autoloader.php @@ -0,0 +1,7 @@ + bool(true) */ + private array $analysedFiles; + + /** + * @param string[] $files + */ + public function __construct(array $files = []) + { + $this->setAnalysedFiles($files); + } + + /** + * @param string[] $files + */ + public function setAnalysedFiles(array $files): void + { + if (FilesystemHelper::isCaseSensitive() === false) { + $files = array_map(static fn (string $file): string => strtolower($file), $files); + } + $this->analysedFiles = array_fill_keys($files, true); + } + + public function isInAnalyzedFiles(string $file): bool + { + if (FilesystemHelper::isCaseSensitive() === false) { + $file = strtolower($file); + } + + return isset($this->analysedFiles[$file]); + } + +} diff --git a/src/Analyser/Analyser.php b/src/Analyser/Analyser.php index 8eea5bacec..1960810ebc 100644 --- a/src/Analyser/Analyser.php +++ b/src/Analyser/Analyser.php @@ -7,7 +7,6 @@ use PHPStan\Collectors\Registry as CollectorRegistry; use PHPStan\Rules\Registry as RuleRegistry; use Throwable; -use function array_fill_keys; use function array_merge; use function count; use function memory_get_peak_usage; @@ -47,7 +46,7 @@ public function analyse( } $this->nodeScopeResolver->setAnalysedFiles($allAnalysedFiles); - $allAnalysedFiles = array_fill_keys($allAnalysedFiles, true); + $analyzedFilesResolver = new AnalysedFilesResolver($allAnalysedFiles); /** @var list $errors */ $errors = []; @@ -78,7 +77,7 @@ public function analyse( try { $fileAnalyserResult = $this->fileAnalyser->analyseFile( $file, - $allAnalysedFiles, + $analyzedFilesResolver, $this->ruleRegistry, $this->collectorRegistry, null, diff --git a/src/Analyser/FileAnalyser.php b/src/Analyser/FileAnalyser.php index 9e16ae4360..1ecc42be72 100644 --- a/src/Analyser/FileAnalyser.php +++ b/src/Analyser/FileAnalyser.php @@ -63,12 +63,11 @@ public function __construct( } /** - * @param array $analysedFiles * @param callable(Node $node, Scope $scope): void|null $outerNodeCallback */ public function analyseFile( string $file, - array $analysedFiles, + AnalysedFilesResolver $analysedFilesResolver, RuleRegistry $ruleRegistry, CollectorRegistry $collectorRegistry, ?callable $outerNodeCallback, @@ -88,13 +87,14 @@ public function analyseFile( $exportedNodes = []; $linesToIgnore = []; $unmatchedLineIgnores = []; + if (is_file($file)) { try { - $this->collectErrors($analysedFiles); + $this->collectErrors($analysedFilesResolver); $parserNodes = $this->parser->parseFile($file); $linesToIgnore = $unmatchedLineIgnores = [$file => $this->getLinesToIgnoreFromTokens($parserNodes)]; $temporaryFileErrors = []; - $nodeCallback = function (Node $node, Scope $scope) use (&$fileErrors, &$fileCollectedData, &$fileDependencies, &$usedTraitFileDependencies, &$exportedNodes, $file, $ruleRegistry, $collectorRegistry, $outerNodeCallback, $analysedFiles, &$linesToIgnore, &$unmatchedLineIgnores, &$temporaryFileErrors): void { + $nodeCallback = function (Node $node, Scope $scope) use (&$fileErrors, &$fileCollectedData, &$fileDependencies, &$usedTraitFileDependencies, &$exportedNodes, $file, $ruleRegistry, $collectorRegistry, $outerNodeCallback, $analysedFilesResolver, &$linesToIgnore, &$unmatchedLineIgnores, &$temporaryFileErrors): void { if ($node instanceof Node\Stmt\Trait_) { foreach (array_keys($linesToIgnore[$file] ?? []) as $lineToIgnore) { if ($lineToIgnore < $node->getStartLine() || $lineToIgnore > $node->getEndLine()) { @@ -205,7 +205,7 @@ public function analyseFile( try { $dependencies = $this->dependencyResolver->resolveDependencies($node, $scope); - foreach ($dependencies->getFileDependencies($scope->getFile(), $analysedFiles) as $dependentFile) { + foreach ($dependencies->getFileDependencies($scope->getFile(), $analysedFilesResolver) as $dependentFile) { $fileDependencies[] = $dependentFile; } if ($dependencies->getExportedNode() !== null) { @@ -224,7 +224,7 @@ public function analyseFile( } $usedTraitDependencies = $this->dependencyResolver->resolveUsedTraitDependencies($node); - foreach ($usedTraitDependencies->getFileDependencies($scope->getFile(), $analysedFiles) as $dependentFile) { + foreach ($usedTraitDependencies->getFileDependencies($scope->getFile(), $analysedFilesResolver) as $dependentFile) { $usedTraitFileDependencies[] = $dependentFile; } }; @@ -330,14 +330,11 @@ private function getLinesToIgnoreFromTokens(array $nodes): array return $nodes[0]->getAttribute('linesToIgnore', []); } - /** - * @param array $analysedFiles - */ - private function collectErrors(array $analysedFiles): void + private function collectErrors(AnalysedFilesResolver $analyzedFilesResolver): void { $this->filteredPhpErrors = []; $this->allPhpErrors = []; - set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) use ($analysedFiles): bool { + set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) use ($analyzedFilesResolver): bool { if ((error_reporting() & $errno) === 0) { // silence @ operator return true; @@ -351,7 +348,7 @@ private function collectErrors(array $analysedFiles): void return true; } - if (!isset($analysedFiles[$errfile])) { + if (!$analyzedFilesResolver->isInAnalyzedFiles($errfile)) { return true; } diff --git a/src/Analyser/Ignore/IgnoredErrorHelperResult.php b/src/Analyser/Ignore/IgnoredErrorHelperResult.php index 529e1ae4a4..ed3865922e 100644 --- a/src/Analyser/Ignore/IgnoredErrorHelperResult.php +++ b/src/Analyser/Ignore/IgnoredErrorHelperResult.php @@ -2,11 +2,10 @@ namespace PHPStan\Analyser\Ignore; +use PHPStan\Analyser\AnalysedFilesResolver; use PHPStan\Analyser\Error; use PHPStan\File\FileHelper; use PHPStan\ShouldNotHappenException; -use function array_fill_keys; -use function array_key_exists; use function array_values; use function count; use function is_array; @@ -43,12 +42,11 @@ public function getErrors(): array /** * @param Error[] $errors - * @param string[] $analysedFiles */ public function process( array $errors, bool $onlyFiles, - array $analysedFiles, + AnalysedFilesResolver $analysedFilesResolver, bool $hasInternalErrors, ): IgnoredErrorHelperProcessedResult { @@ -190,8 +188,6 @@ public function process( ), $unmatchedIgnoredError['file'], $unmatchedIgnoredError['line'], false))->withIdentifier('ignore.count'); } - $analysedFilesKeys = array_fill_keys($analysedFiles, true); - if (!$hasInternalErrors) { foreach ($unmatchedIgnoredErrors as $unmatchedIgnoredError) { $reportUnmatched = $unmatchedIgnoredError['reportUnmatched'] ?? $this->reportUnmatchedIgnoredErrors; @@ -214,7 +210,8 @@ public function process( ), $unmatchedIgnoredError['file'], $unmatchedIgnoredError['line'], false))->withIdentifier('ignore.count'); } } elseif (isset($unmatchedIgnoredError['realPath'])) { - if (!array_key_exists($unmatchedIgnoredError['realPath'], $analysedFilesKeys)) { + + if (!$analysedFilesResolver->isInAnalyzedFiles($unmatchedIgnoredError['realPath'])) { continue; } diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 8c070bb040..4a0ab41668 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -229,8 +229,7 @@ final class NodeScopeResolver private const LOOP_SCOPE_ITERATIONS = 3; private const GENERALIZE_AFTER_ITERATION = 1; - /** @var bool[] filePath(string) => bool(true) */ - private array $analysedFiles = []; + private AnalysedFilesResolver $analysedFilesResolver; /** @var array */ private array $earlyTerminatingMethodNames; @@ -284,6 +283,7 @@ public function __construct( } } $this->earlyTerminatingMethodNames = $earlyTerminatingMethodNames; + $this->analysedFilesResolver = new AnalysedFilesResolver(); } /** @@ -292,7 +292,7 @@ public function __construct( */ public function setAnalysedFiles(array $files): void { - $this->analysedFiles = array_fill_keys($files, true); + $this->analysedFilesResolver->setAnalysedFiles($files); } /** @@ -6275,7 +6275,7 @@ private function processTraitUse(Node\Stmt\TraitUse $node, MutatingScope $classS continue; // trait from eval or from PHP itself } $fileName = $this->fileHelper->normalizePath($traitFileName); - if (!isset($this->analysedFiles[$fileName])) { + if (!$this->analysedFilesResolver->isInAnalyzedFiles($fileName)) { continue; } $adaptations = []; @@ -6394,7 +6394,7 @@ private function processCalledMethod(MethodReflection $methodReflection): ?Mutat $this->calledMethodStack[$stackName] = true; $fileName = $this->fileHelper->normalizePath($declaringClass->getFileName()); - if (!isset($this->analysedFiles[$fileName])) { + if (!$this->analysedFilesResolver->isInAnalyzedFiles($fileName)) { return null; } $parserNodes = $this->parser->parseFile($fileName); diff --git a/src/Command/AnalyseApplication.php b/src/Command/AnalyseApplication.php index 7a0820cc46..cd554006d4 100644 --- a/src/Command/AnalyseApplication.php +++ b/src/Command/AnalyseApplication.php @@ -2,6 +2,7 @@ namespace PHPStan\Command; +use PHPStan\Analyser\AnalysedFilesResolver; use PHPStan\Analyser\AnalyserResult; use PHPStan\Analyser\AnalyserResultFinalizer; use PHPStan\Analyser\Ignore\IgnoredErrorHelper; @@ -151,7 +152,7 @@ public function analyse( } } - $ignoredErrorHelperProcessedResult = $ignoredErrorHelperResult->process($errors, $onlyFiles, $files, $hasInternalErrors); + $ignoredErrorHelperProcessedResult = $ignoredErrorHelperResult->process($errors, $onlyFiles, new AnalysedFilesResolver($files), $hasInternalErrors); $fileSpecificErrors = $ignoredErrorHelperProcessedResult->getNotIgnoredErrors(); $notFileSpecificErrors = $ignoredErrorHelperProcessedResult->getOtherIgnoreMessages(); $collectedData = $analyserResult->getCollectedData(); diff --git a/src/Command/FixerWorkerCommand.php b/src/Command/FixerWorkerCommand.php index 54e1da4c41..28573d0a8b 100644 --- a/src/Command/FixerWorkerCommand.php +++ b/src/Command/FixerWorkerCommand.php @@ -3,6 +3,7 @@ namespace PHPStan\Command; use Clue\React\NDJson\Encoder; +use PHPStan\Analyser\AnalysedFilesResolver; use PHPStan\Analyser\AnalyserResult; use PHPStan\Analyser\AnalyserResultFinalizer; use PHPStan\Analyser\Error; @@ -302,7 +303,7 @@ function (array $errors, array $locallyIgnoredErrors, array $analysedFiles) use $ignoredErrorHelperProcessedResult = $ignoredErrorHelperResult->process( $finalizerResult->getErrors(), $isOnlyFiles, - $inceptionFiles, + new AnalysedFilesResolver($inceptionFiles), $hasInternalErrors, ); $ignoreFileErrors = []; @@ -357,7 +358,7 @@ private function transformErrorIntoInternalError(Error $error): InternalError */ private function filterErrors(array $errors, IgnoredErrorHelperResult $ignoredErrorHelperResult, bool $onlyFiles, array $inceptionFiles, bool $hasInternalErrors): array { - $ignoredErrorHelperProcessedResult = $ignoredErrorHelperResult->process($errors, $onlyFiles, $inceptionFiles, $hasInternalErrors); + $ignoredErrorHelperProcessedResult = $ignoredErrorHelperResult->process($errors, $onlyFiles, new AnalysedFilesResolver($inceptionFiles), $hasInternalErrors); $finalErrors = []; foreach ($ignoredErrorHelperProcessedResult->getNotIgnoredErrors() as $error) { if ($error->getIdentifier() === null) { diff --git a/src/Command/WorkerCommand.php b/src/Command/WorkerCommand.php index 0fa30e1755..e812003a26 100644 --- a/src/Command/WorkerCommand.php +++ b/src/Command/WorkerCommand.php @@ -4,6 +4,7 @@ use Clue\React\NDJson\Decoder; use Clue\React\NDJson\Encoder; +use PHPStan\Analyser\AnalysedFilesResolver; use PHPStan\Analyser\FileAnalyser; use PHPStan\Analyser\InternalError; use PHPStan\Analyser\NodeScopeResolver; @@ -23,7 +24,6 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Throwable; -use function array_fill_keys; use function array_filter; use function array_merge; use function array_unshift; @@ -136,17 +136,17 @@ protected function execute(InputInterface $input, OutputInterface $output): int $nodeScopeResolver = $container->getByType(NodeScopeResolver::class); $nodeScopeResolver->setAnalysedFiles($analysedFiles); - $analysedFiles = array_fill_keys($analysedFiles, true); + $analyzedFilesResolver = new AnalysedFilesResolver($analysedFiles); $tcpConnector = new TcpConnector($loop); - $tcpConnector->connect(sprintf('127.0.0.1:%d', $port))->then(function (ConnectionInterface $connection) use ($container, $identifier, $output, $analysedFiles, $tmpFile, $insteadOfFile): void { + $tcpConnector->connect(sprintf('127.0.0.1:%d', $port))->then(function (ConnectionInterface $connection) use ($container, $identifier, $output, $analyzedFilesResolver, $tmpFile, $insteadOfFile): void { // phpcs:disable SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly $jsonInvalidUtf8Ignore = defined('JSON_INVALID_UTF8_IGNORE') ? JSON_INVALID_UTF8_IGNORE : 0; // phpcs:enable $out = new Encoder($connection, $jsonInvalidUtf8Ignore); $in = new Decoder($connection, true, 512, $jsonInvalidUtf8Ignore, $container->getParameter('parallel')['buffer']); $out->write(['action' => 'hello', 'identifier' => $identifier]); - $this->runWorker($container, $out, $in, $output, $analysedFiles, $tmpFile, $insteadOfFile); + $this->runWorker($container, $out, $in, $output, $analyzedFilesResolver, $tmpFile, $insteadOfFile); }); $loop->run(); @@ -158,15 +158,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 0; } - /** - * @param array $analysedFiles - */ private function runWorker( Container $container, WritableStreamInterface $out, ReadableStreamInterface $in, OutputInterface $output, - array $analysedFiles, + AnalysedFilesResolver $analysedFilesResolver, ?string $tmpFile, ?string $insteadOfFile, ): void @@ -206,7 +203,7 @@ private function runWorker( $fileAnalyser = $container->getByType(FileAnalyser::class); $ruleRegistry = $container->getByType(RuleRegistry::class); $collectorRegistry = $container->getByType(CollectorRegistry::class); - $in->on('data', static function (array $json) use ($fileAnalyser, $ruleRegistry, $collectorRegistry, $out, $analysedFiles, $tmpFile, $insteadOfFile): void { + $in->on('data', static function (array $json) use ($fileAnalyser, $ruleRegistry, $collectorRegistry, $out, $analysedFilesResolver, $tmpFile, $insteadOfFile): void { $action = $json['action']; if ($action !== 'analyse') { return; @@ -230,7 +227,7 @@ private function runWorker( if ($file === $insteadOfFile) { $file = $tmpFile; } - $fileAnalyserResult = $fileAnalyser->analyseFile($file, $analysedFiles, $ruleRegistry, $collectorRegistry, null); + $fileAnalyserResult = $fileAnalyser->analyseFile($file, $analysedFilesResolver, $ruleRegistry, $collectorRegistry, null); $fileErrors = $fileAnalyserResult->getErrors(); $filteredPhpErrors = array_merge($filteredPhpErrors, $fileAnalyserResult->getFilteredPhpErrors()); $allPhpErrors = array_merge($allPhpErrors, $fileAnalyserResult->getAllPhpErrors()); diff --git a/src/Dependency/NodeDependencies.php b/src/Dependency/NodeDependencies.php index ac30175b35..05353f2a66 100644 --- a/src/Dependency/NodeDependencies.php +++ b/src/Dependency/NodeDependencies.php @@ -2,6 +2,7 @@ namespace PHPStan\Dependency; +use PHPStan\Analyser\AnalysedFilesResolver; use PHPStan\File\FileHelper; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\FunctionReflection; @@ -22,10 +23,9 @@ public function __construct( } /** - * @param array $analysedFiles * @return string[] */ - public function getFileDependencies(string $currentFile, array $analysedFiles): array + public function getFileDependencies(string $currentFile, AnalysedFilesResolver $analyzedFilesResolver): array { $dependencies = []; @@ -40,7 +40,7 @@ public function getFileDependencies(string $currentFile, array $analysedFiles): continue; } - if (!isset($analysedFiles[$dependencyFile])) { + if (!$analyzedFilesResolver->isInAnalyzedFiles($dependencyFile)) { continue; } diff --git a/src/File/FilesystemHelper.php b/src/File/FilesystemHelper.php new file mode 100644 index 0000000000..c8e27b668d --- /dev/null +++ b/src/File/FilesystemHelper.php @@ -0,0 +1,21 @@ + bool(true) */ - private array $analysedFiles = []; + private AnalysedFilesResolver $analysedFilesResolver; public function __construct( private FileHelper $fileHelper, @@ -30,6 +29,7 @@ public function __construct( ) { $this->singleReflectionFile = $singleReflectionFile !== null ? $fileHelper->normalizePath($singleReflectionFile) : null; + $this->analysedFilesResolver = new AnalysedFilesResolver(); } /** @@ -37,7 +37,7 @@ public function __construct( */ public function setAnalysedFiles(array $files): void { - $this->analysedFiles = array_fill_keys($files, true); + $this->analysedFilesResolver->setAnalysedFiles($files); } public function parseFile(string $file): array @@ -51,7 +51,7 @@ public function parseFile(string $file): array } $file = $this->fileHelper->normalizePath($file); - if (!isset($this->analysedFiles[$file]) && $file !== $this->singleReflectionFile) { + if (!$this->analysedFilesResolver->isInAnalyzedFiles($file) && $file !== $this->singleReflectionFile) { // check symlinked file that still might be in analysedFiles $pathParts = explode(DIRECTORY_SEPARATOR, $file); for ($i = count($pathParts); $i > 1; $i--) { @@ -63,7 +63,7 @@ public function parseFile(string $file): array $realFilePath = realpath($file); if ($realFilePath !== false) { $normalizedRealFilePath = $this->fileHelper->normalizePath($realFilePath); - if (isset($this->analysedFiles[$normalizedRealFilePath])) { + if ($this->analysedFilesResolver->isInAnalyzedFiles($normalizedRealFilePath)) { return $this->currentPhpVersionRichParser->parseFile($file); } } diff --git a/src/PhpDoc/StubValidator.php b/src/PhpDoc/StubValidator.php index b0737cbcc9..dade6a296b 100644 --- a/src/PhpDoc/StubValidator.php +++ b/src/PhpDoc/StubValidator.php @@ -2,6 +2,7 @@ namespace PHPStan\PhpDoc; +use PHPStan\Analyser\AnalysedFilesResolver; use PHPStan\Analyser\Error; use PHPStan\Analyser\FileAnalyser; use PHPStan\Analyser\InternalError; @@ -97,7 +98,6 @@ use PHPStan\Type\FileTypeMapper; use PHPStan\Type\ObjectType; use Throwable; -use function array_fill_keys; use function count; use function sprintf; @@ -137,14 +137,14 @@ public function validate(array $stubFiles, bool $debug): array $pathRoutingParser = $container->getService('pathRoutingParser'); $pathRoutingParser->setAnalysedFiles($stubFiles); - $analysedFiles = array_fill_keys($stubFiles, true); + $analyzedFilesResolver = new AnalysedFilesResolver($stubFiles); $errors = []; foreach ($stubFiles as $stubFile) { try { $tmpErrors = $fileAnalyser->analyseFile( $stubFile, - $analysedFiles, + $analyzedFilesResolver, $ruleRegistry, $collectorRegistry, static function (): void { diff --git a/tests/PHPStan/Analyser/AnalyserTest.php b/tests/PHPStan/Analyser/AnalyserTest.php index 9877e01b77..c04eb111a8 100644 --- a/tests/PHPStan/Analyser/AnalyserTest.php +++ b/tests/PHPStan/Analyser/AnalyserTest.php @@ -680,7 +680,7 @@ private function runAnalyser( ); $analyserResult = $finalizer->finalize($analyserResult, $onlyFiles, false)->getAnalyserResult(); - $ignoredErrorHelperProcessedResult = $ignoredErrorHelperResult->process($analyserResult->getErrors(), $onlyFiles, $normalizedFilePaths, $analyserResult->hasReachedInternalErrorsCountLimit()); + $ignoredErrorHelperProcessedResult = $ignoredErrorHelperResult->process($analyserResult->getErrors(), $onlyFiles, new AnalysedFilesResolver($normalizedFilePaths), $analyserResult->hasReachedInternalErrorsCountLimit()); $errors = $ignoredErrorHelperProcessedResult->getNotIgnoredErrors(); $errors = array_merge($errors, $ignoredErrorHelperProcessedResult->getOtherIgnoreMessages()); if ($analyserResult->hasReachedInternalErrorsCountLimit()) {