From ef23056ca0cb7a5029d2586596c70ff3e7918082 Mon Sep 17 00:00:00 2001 From: Tomasz Mlynski Date: Tue, 14 Dec 2021 17:51:31 +0100 Subject: [PATCH 1/4] Use `FilesystemIterator::SKIP_DOTS` flag instead of `DirectoryIterator::isDot()` --- src/Psalm/Internal/Provider/FileProvider.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Psalm/Internal/Provider/FileProvider.php b/src/Psalm/Internal/Provider/FileProvider.php index 5ca384b7fb3..ffbfb14f9de 100644 --- a/src/Psalm/Internal/Provider/FileProvider.php +++ b/src/Psalm/Internal/Provider/FileProvider.php @@ -1,6 +1,7 @@ rewind(); while ($iterator->valid()) { - if (!$iterator->isDot()) { - $extension = $iterator->getExtension(); - if (in_array($extension, $file_extensions, true)) { - $file_paths[] = (string)$iterator->getRealPath(); - } + $extension = $iterator->getExtension(); + if (in_array($extension, $file_extensions, true)) { + $file_paths[] = (string)$iterator->getRealPath(); } $iterator->next(); From 837075a378625153883728a2fbffb75b788ada1b Mon Sep 17 00:00:00 2001 From: Tomasz Mlynski Date: Tue, 14 Dec 2021 17:57:19 +0100 Subject: [PATCH 2/4] Use cached `ProjectAnalyzer::$project_files` to build list of changed files --- .../Internal/Analyzer/ProjectAnalyzer.php | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php b/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php index a32260a7573..401141a14a0 100644 --- a/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php @@ -610,11 +610,7 @@ public function check(string $base_dir, bool $is_diff = false): void && $this->project_cache_provider->canDiffFiles() ) { $deleted_files = $this->file_reference_provider->getDeletedReferencedFiles(); - $diff_files = $deleted_files; - - foreach ($this->config->getProjectDirectories() as $dir_name) { - $diff_files = array_merge($diff_files, $this->getDiffFilesInDir($dir_name, $this->config)); - } + $diff_files = array_merge($deleted_files, $this->getDiffFiles()); } $this->progress->write($this->generatePHPVersionMessage()); @@ -1079,10 +1075,8 @@ public function addExtraFile(string $file_path): void /** * @return list */ - protected function getDiffFilesInDir(string $dir_name, Config $config): array + protected function getDiffFiles(): array { - $file_extensions = $config->getFileExtensions(); - if (!$this->parser_cache_provider || !$this->project_cache_provider) { throw new UnexpectedValueException('Parser cache provider cannot be null here'); } @@ -1091,16 +1085,12 @@ protected function getDiffFilesInDir(string $dir_name, Config $config): array $last_run = $this->project_cache_provider->getLastRun(PSALM_VERSION); - $file_paths = $this->file_provider->getFilesInDir($dir_name, $file_extensions); - - foreach ($file_paths as $file_path) { - if ($config->isInProjectDirs($file_path)) { - if ($this->file_provider->getModifiedTime($file_path) >= $last_run - && $this->parser_cache_provider->loadExistingFileContentsFromCache($file_path) - !== $this->file_provider->getContents($file_path) - ) { - $diff_files[] = $file_path; - } + foreach ($this->project_files as $file_path) { + if ($this->file_provider->getModifiedTime($file_path) >= $last_run + && $this->parser_cache_provider->loadExistingFileContentsFromCache($file_path) + !== $this->file_provider->getContents($file_path) + ) { + $diff_files[] = $file_path; } } From d00c733c1f02fea363e3f638e0f736741a2c6af8 Mon Sep 17 00:00:00 2001 From: Tomasz Mlynski Date: Tue, 14 Dec 2021 18:22:47 +0100 Subject: [PATCH 3/4] Add `callable $directory_filter` to `FileProvider::getFilesInDir()` --- .../Internal/Provider/FakeFileProvider.php | 5 +++-- src/Psalm/Internal/Provider/FileProvider.php | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Psalm/Internal/Provider/FakeFileProvider.php b/src/Psalm/Internal/Provider/FakeFileProvider.php index 7cafa391b6e..d2ffb991080 100644 --- a/src/Psalm/Internal/Provider/FakeFileProvider.php +++ b/src/Psalm/Internal/Provider/FakeFileProvider.php @@ -57,12 +57,13 @@ public function registerFile(string $file_path, string $file_contents): void /** * @param array $file_extensions + * @param null|callable(string):bool $directory_filter * * @return list */ - public function getFilesInDir(string $dir_path, array $file_extensions): array + public function getFilesInDir(string $dir_path, array $file_extensions, callable $directory_filter = null): array { - $file_paths = parent::getFilesInDir($dir_path, $file_extensions); + $file_paths = parent::getFilesInDir($dir_path, $file_extensions, $directory_filter); foreach ($this->fake_files as $file_path => $_) { if (strpos(strtolower($file_path), strtolower($dir_path)) === 0) { diff --git a/src/Psalm/Internal/Provider/FileProvider.php b/src/Psalm/Internal/Provider/FileProvider.php index ffbfb14f9de..3f319ca1370 100644 --- a/src/Psalm/Internal/Provider/FileProvider.php +++ b/src/Psalm/Internal/Provider/FileProvider.php @@ -2,7 +2,9 @@ namespace Psalm\Internal\Provider; use FilesystemIterator; +use RecursiveCallbackFilterIterator; use RecursiveDirectoryIterator; +use RecursiveIterator; use RecursiveIteratorIterator; use UnexpectedValueException; @@ -14,6 +16,8 @@ use function is_dir; use function strtolower; +use const DIRECTORY_SEPARATOR; + class FileProvider { /** @@ -113,10 +117,11 @@ public function fileExists(string $file_path): bool /** * @param array $file_extensions + * @param null|callable(string):bool $directory_filter * * @return list */ - public function getFilesInDir(string $dir_path, array $file_extensions): array + public function getFilesInDir(string $dir_path, array $file_extensions, callable $directory_filter = null): array { $file_paths = []; @@ -125,6 +130,16 @@ public function getFilesInDir(string $dir_path, array $file_extensions): array FilesystemIterator::CURRENT_AS_PATHNAME | FilesystemIterator::SKIP_DOTS ); + if ($directory_filter !== null) { + $iterator = new RecursiveCallbackFilterIterator( + $iterator, + /** @param mixed $_ */ + function (string $current, $_, RecursiveIterator $iterator) use ($directory_filter): bool { + return !$iterator->hasChildren() || $directory_filter($current . DIRECTORY_SEPARATOR); + } + ); + } + /** @var RecursiveDirectoryIterator */ $iterator = new RecursiveIteratorIterator($iterator); $iterator->rewind(); From 4034959c1bc3d3921408375ad04f094fad353787 Mon Sep 17 00:00:00 2001 From: Tomasz Mlynski Date: Tue, 14 Dec 2021 18:25:09 +0100 Subject: [PATCH 4/4] Use `$directory_filter` with `FileProvider::getFilesInDir()` to skip ignored directories --- .../Internal/Analyzer/ProjectAnalyzer.php | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php b/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php index 401141a14a0..b07eeedd0d7 100644 --- a/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php @@ -308,7 +308,11 @@ public function __construct( $file_extensions = $this->config->getFileExtensions(); foreach ($this->config->getProjectDirectories() as $dir_name) { - $file_paths = $this->file_provider->getFilesInDir($dir_name, $file_extensions); + $file_paths = $this->file_provider->getFilesInDir( + $dir_name, + $file_extensions, + [$this->config, 'isInProjectDirs'] + ); foreach ($file_paths as $file_path) { if ($this->config->isInProjectDirs($file_path)) { @@ -318,7 +322,11 @@ public function __construct( } foreach ($this->config->getExtraDirectories() as $dir_name) { - $file_paths = $this->file_provider->getFilesInDir($dir_name, $file_extensions); + $file_paths = $this->file_provider->getFilesInDir( + $dir_name, + $file_extensions, + [$this->config, 'isInExtraDirs'] + ); foreach ($file_paths as $file_path) { if ($this->config->isInExtraDirs($file_path)) { @@ -1048,8 +1056,13 @@ public function checkDir(string $dir_name): void private function checkDirWithConfig(string $dir_name, Config $config, bool $allow_non_project_files = false): void { $file_extensions = $config->getFileExtensions(); + $directory_filter = $allow_non_project_files ? null : [$this->config, 'isInProjectDirs']; - $file_paths = $this->file_provider->getFilesInDir($dir_name, $file_extensions); + $file_paths = $this->file_provider->getFilesInDir( + $dir_name, + $file_extensions, + $directory_filter + ); $files_to_scan = [];