diff --git a/conf/config.neon b/conf/config.neon index af1c6c18f2..94d96fb648 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -6,6 +6,7 @@ parameters: - ../stubs/runtime/ReflectionUnionType.php - ../stubs/runtime/Attribute.php excludes_analyse: [] + excludePaths: null autoload_directories: [] autoload_files: [] level: null @@ -139,6 +140,19 @@ parametersSchema: bootstrap: schema(string(), nullable()) bootstrapFiles: listOf(string()) excludes_analyse: listOf(string()) + excludePaths: schema(anyOf( + listOf(string()), + structure([ + analyse: listOf(string()), + ]), + structure([ + analyseAndScan: listOf(string()), + ]) + structure([ + analyse: listOf(string()), + analyseAndScan: listOf(string()) + ]) + ), nullable()) autoload_directories: listOf(string()) autoload_files: listOf(string()) level: schema(anyOf(int(), string()), nullable()) @@ -425,6 +439,8 @@ services: - class: PHPStan\Dependency\DependencyDumper + arguments: + fileFinder: @fileFinderAnalyse - class: PHPStan\Dependency\DependencyResolver @@ -479,18 +495,44 @@ services: workingDirectory: %currentWorkingDirectory% - - class: PHPStan\File\FileExcluder + class: PHPStan\File\FileExcluderFactory arguments: - analyseExcludes: %excludes_analyse% - stubFiles: %stubFiles% + obsoleteExcludesAnalyse: %excludes_analyse% + excludePaths: %excludePaths% - + implement: PHPStan\File\FileExcluderRawFactory + arguments: + stubFiles: %stubFiles% + + fileExcluderAnalyse: + class: PHPStan\File\FileExcluder + factory: @PHPStan\File\FileExcluderFactory::createAnalyseFileExcluder() + autowired: false + + fileExcluderScan: + class: PHPStan\File\FileExcluder + factory: @PHPStan\File\FileExcluderFactory::createAnalyseFileExcluder() + autowired: false + + fileFinderAnalyse: + class: PHPStan\File\FileFinder + arguments: + fileExcluder: @fileExcluderAnalyse + fileExtensions: %fileExtensions% + autowired: false + + fileFinderScan: class: PHPStan\File\FileFinder arguments: + fileExcluder: @fileExcluderScan fileExtensions: %fileExtensions% + autowired: false - class: PHPStan\File\FileMonitor + arguments: + fileFinder: @fileFinderAnalyse - class: PHPStan\NodeVisitor\StatementOrderVisitor @@ -544,6 +586,8 @@ services: - implement: PHPStan\Reflection\BetterReflection\SourceLocator\OptimizedDirectorySourceLocatorFactory + arguments: + fileFinder: @fileFinderScan - class: PHPStan\Reflection\BetterReflection\SourceLocator\OptimizedDirectorySourceLocatorRepository diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index dcd5a2481d..1c9ca868ed 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -75,6 +75,16 @@ parameters: count: 1 path: src/DependencyInjection/ParametersSchemaExtension.php + - + message: "#^Parameter \\#1 \\$analyseExcludes of method PHPStan\\\\File\\\\FileExcluderRawFactory\\:\\:create\\(\\) expects array\\, array\\\\|string\\> given\\.$#" + count: 2 + path: src/File/FileExcluderFactory.php + + - + message: "#^Parameter \\#1 \\$input of function array_unique expects array, array\\\\|string given\\.$#" + count: 2 + path: src/File/FileExcluderFactory.php + - message: "#^Variable method call on PHPStan\\\\Reflection\\\\ClassReflection\\.$#" count: 2 diff --git a/src/Command/CommandHelper.php b/src/Command/CommandHelper.php index 738c19ac31..d2f577c066 100644 --- a/src/Command/CommandHelper.php +++ b/src/Command/CommandHelper.php @@ -393,11 +393,22 @@ public static function begin( throw new \PHPStan\Command\InceptionNotSuccessfulException(); } + $excludesAnalyse = $container->getParameter('excludes_analyse'); + $excludePaths = $container->getParameter('excludePaths'); + if (count($excludesAnalyse) > 0 && $excludePaths !== null) { + $errorOutput->writeLineFormatted(sprintf('Configuration parameters excludes_analyse and excludePaths cannot be used at the same time.')); + $errorOutput->writeLineFormatted(''); + $errorOutput->writeLineFormatted(sprintf('Parameter excludes_analyse has been deprecated so use excludePaths only from now on.')); + $errorOutput->writeLineFormatted(''); + + throw new \PHPStan\Command\InceptionNotSuccessfulException(); + } + $tempResultCachePath = $container->getParameter('tempResultCachePath'); $createDir($tempResultCachePath); /** @var FileFinder $fileFinder */ - $fileFinder = $container->getByType(FileFinder::class); + $fileFinder = $container->getService('fileFinderAnalyse'); /** @var \Closure(): (array{string[], bool}) $filesCallback */ $filesCallback = static function () use ($fileFinder, $paths): array { diff --git a/src/DependencyInjection/NeonAdapter.php b/src/DependencyInjection/NeonAdapter.php index ad55395031..6d868d7bf2 100644 --- a/src/DependencyInjection/NeonAdapter.php +++ b/src/DependencyInjection/NeonAdapter.php @@ -14,7 +14,7 @@ class NeonAdapter implements Adapter { - public const CACHE_KEY = 'v10'; + public const CACHE_KEY = 'v11-excludePaths'; private const PREVENT_MERGING_SUFFIX = '!'; @@ -92,6 +92,9 @@ public function process(array $arr, string $fileKey, string $file): array '[parameters][autoload_directories][]', '[parameters][paths][]', '[parameters][excludes_analyse][]', + '[parameters][excludePaths][]', + '[parameters][excludePaths][analyse][]', + '[parameters][excludePaths][analyseAndScan][]', '[parameters][ignoreErrors][][paths][]', '[parameters][ignoreErrors][][path]', '[parameters][bootstrap]', diff --git a/src/File/FileExcluderFactory.php b/src/File/FileExcluderFactory.php new file mode 100644 index 0000000000..700c177347 --- /dev/null +++ b/src/File/FileExcluderFactory.php @@ -0,0 +1,71 @@ +|array{analyse?: array, analyseAndScan?: array}|null */ + private ?array $excludePaths; + + /** + * @param FileExcluderRawFactory $fileExcluderRawFactory + * @param string[] $obsoleteExcludesAnalyse + * @param array|array{analyse?: array, analyseAndScan?: array}|null $excludePaths + */ + public function __construct( + FileExcluderRawFactory $fileExcluderRawFactory, + array $obsoleteExcludesAnalyse, + ?array $excludePaths + ) + { + $this->fileExcluderRawFactory = $fileExcluderRawFactory; + $this->obsoleteExcludesAnalyse = $obsoleteExcludesAnalyse; + $this->excludePaths = $excludePaths; + } + + public function createAnalyseFileExcluder(): FileExcluder + { + if ($this->excludePaths === null) { + return $this->fileExcluderRawFactory->create($this->obsoleteExcludesAnalyse); + } + + if (!array_key_exists('analyse', $this->excludePaths) && !array_key_exists('analyseAndScan', $this->excludePaths)) { + return $this->fileExcluderRawFactory->create($this->excludePaths); + } + + $paths = []; + if (array_key_exists('analyse', $this->excludePaths)) { + $paths = $this->excludePaths['analyse']; + } + if (array_key_exists('analyseAndScan', $this->excludePaths)) { + $paths = $this->excludePaths['analyseAndScan']; + } + + return $this->fileExcluderRawFactory->create(array_values(array_unique($paths))); + } + + public function createScanFileExcluder(): FileExcluder + { + if ($this->excludePaths === null) { + return $this->fileExcluderRawFactory->create($this->obsoleteExcludesAnalyse); + } + + if (!array_key_exists('analyse', $this->excludePaths) && !array_key_exists('analyseAndScan', $this->excludePaths)) { + return $this->fileExcluderRawFactory->create($this->excludePaths); + } + + $paths = []; + if (array_key_exists('analyseAndScan', $this->excludePaths)) { + $paths = $this->excludePaths['analyseAndScan']; + } + + return $this->fileExcluderRawFactory->create(array_values(array_unique($paths))); + } + +} diff --git a/src/File/FileExcluderRawFactory.php b/src/File/FileExcluderRawFactory.php new file mode 100644 index 0000000000..b2f7e4ee77 --- /dev/null +++ b/src/File/FileExcluderRawFactory.php @@ -0,0 +1,16 @@ +