From adc64b4ae32ab3c9ebc29d8a5e856eca6115a1ed Mon Sep 17 00:00:00 2001 From: Carlos Granados Date: Fri, 4 Oct 2024 11:02:14 +0000 Subject: [PATCH] Updated Rector to commit c20f5ede4af5310a23ca8baffd2b5f74ae77d622 https://github.com/carlos-granados/rector-src/commit/c20f5ede4af5310a23ca8baffd2b5f74ae77d622 Build rector for this repository (#6) --- config/config.php | 2 +- .../Application/UseImportsAdder.php | 162 +++++++++++++----- src/Application/ApplicationFileProcessor.php | 57 +++++- src/Application/FileProcessor.php | 49 +++++- src/Application/VersionResolver.php | 4 +- src/Caching/Detector/ChangedFilesDetector.php | 13 +- src/Caching/Enum/CacheKey.php | 8 + src/Caching/FileDependenciesCache.php | 63 +++++++ src/Config/RectorConfig.php | 3 +- src/Configuration/Option.php | 5 + src/Configuration/RectorConfigBuilder.php | 9 +- src/Console/Command/WorkerCommand.php | 2 +- .../LazyContainerFactory.php | 3 +- src/FileSystem/FilesFinder.php | 11 +- .../Command/WorkerCommandLineFactory.php | 9 +- .../Rector/UnusedImportRemovingPostRector.php | 10 +- src/PostRector/Rector/UseAddingPostRector.php | 4 +- src/Skipper/Skipper/CommentSkipper.php | 22 +++ src/Skipper/Skipper/SkipSkipper.php | 48 +++++- src/Skipper/Skipper/Skipper.php | 13 +- .../PHPUnit/AbstractRectorTestCase.php | 3 +- src/Util/FileHasher.php | 9 + vendor/composer/autoload_classmap.php | 2 + vendor/composer/autoload_static.php | 2 + 24 files changed, 425 insertions(+), 88 deletions(-) create mode 100644 src/Caching/FileDependenciesCache.php create mode 100644 src/Skipper/Skipper/CommentSkipper.php diff --git a/config/config.php b/config/config.php index 461dffe997ba..d18cc7076f60 100644 --- a/config/config.php +++ b/config/config.php @@ -14,7 +14,7 @@ $rectorConfig->bootstrapFiles([]); $rectorConfig->parallel(); // to avoid autoimporting out of the box - $rectorConfig->importNames(\false, \false); + $rectorConfig->importNames(\false, \false, \false); $rectorConfig->removeUnusedImports(\false); $rectorConfig->importShortClasses(); $rectorConfig->indent(' ', 4); diff --git a/rules/CodingStyle/Application/UseImportsAdder.php b/rules/CodingStyle/Application/UseImportsAdder.php index 8d0142c10906..d4c5948251b1 100644 --- a/rules/CodingStyle/Application/UseImportsAdder.php +++ b/rules/CodingStyle/Application/UseImportsAdder.php @@ -4,6 +4,7 @@ namespace Rector\CodingStyle\Application; use RectorPrefix202410\Nette\Utils\Strings; +use PhpParser\Comment; use PhpParser\Node\Name; use PhpParser\Node\Stmt; use PhpParser\Node\Stmt\Declare_; @@ -13,6 +14,8 @@ use PhpParser\Node\Stmt\Use_; use PHPStan\Type\ObjectType; use Rector\CodingStyle\ClassNameImport\UsedImportsResolver; +use Rector\Configuration\Option; +use Rector\Configuration\Parameter\SimpleParameterProvider; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory; use Rector\PhpParser\Node\CustomNode\FileWithoutNamespace; @@ -38,20 +41,20 @@ public function __construct(UsedImportsResolver $usedImportsResolver, TypeFactor /** * @param Stmt[] $stmts * @param array $useImportTypes - * @param array $constantUseImportTypes * @param array $functionUseImportTypes + * @param array $constantUseImportTypes * @return Stmt[] */ - public function addImportsToStmts(FileWithoutNamespace $fileWithoutNamespace, array $stmts, array $useImportTypes, array $constantUseImportTypes, array $functionUseImportTypes) : array + public function addImportsToStmts(FileWithoutNamespace $fileWithoutNamespace, array $stmts, array $useImportTypes, array $functionUseImportTypes, array $constantUseImportTypes) : array { $usedImports = $this->usedImportsResolver->resolveForStmts($stmts); $existingUseImportTypes = $usedImports->getUseImports(); - $existingConstantUseImports = $usedImports->getConstantImports(); - $existingFunctionUseImports = $usedImports->getFunctionImports(); - $useImportTypes = $this->diffFullyQualifiedObjectTypes($useImportTypes, $existingUseImportTypes); - $constantUseImportTypes = $this->diffFullyQualifiedObjectTypes($constantUseImportTypes, $existingConstantUseImports); - $functionUseImportTypes = $this->diffFullyQualifiedObjectTypes($functionUseImportTypes, $existingFunctionUseImports); - $newUses = $this->createUses($useImportTypes, $constantUseImportTypes, $functionUseImportTypes, null); + $existingFunctionUseImportTypes = $usedImports->getFunctionImports(); + $existingConstantUseImportTypes = $usedImports->getConstantImports(); + $newUseImportTypes = $this->diffFullyQualifiedObjectTypes($useImportTypes, $existingUseImportTypes); + $newFunctionUseImportTypes = $this->diffFullyQualifiedObjectTypes($functionUseImportTypes, $existingFunctionUseImportTypes); + $newConstantUseImportTypes = $this->diffFullyQualifiedObjectTypes($constantUseImportTypes, $existingConstantUseImportTypes); + $newUses = $this->createUses($newUseImportTypes, $newFunctionUseImportTypes, $newConstantUseImportTypes, null); if ($newUses === []) { return [$fileWithoutNamespace]; } @@ -65,29 +68,33 @@ public function addImportsToStmts(FileWithoutNamespace $fileWithoutNamespace, ar if (!$stmt instanceof Declare_) { break; } - $nodesToAdd = \array_merge([new Nop()], $newUses); - $this->mirrorUseComments($stmts, $newUses, $key + 1); + $position = $key + 1; + $useComments = $this->getAndRemoveExistingUseComments($stmts, $position); // remove space before next use tweak - if (isset($stmts[$key + 1]) && ($stmts[$key + 1] instanceof Use_ || $stmts[$key + 1] instanceof GroupUse)) { - $stmts[$key + 1]->setAttribute(AttributeKey::ORIGINAL_NODE, null); + if (isset($stmts[$position]) && ($stmts[$position] instanceof Use_ || $stmts[$position] instanceof GroupUse)) { + $stmts[$position]->setAttribute(AttributeKey::ORIGINAL_NODE, null); + } + \array_splice($stmts, $position, 0, [new Nop()]); + ++$position; + $fileWithoutNamespace->stmts = $this->insertUseNodesInStatements($stmts, $newUses, $position, \false); + if ($useComments !== []) { + $this->reapplyUseComments($useComments, $fileWithoutNamespace->stmts, $position); } - \array_splice($stmts, $key + 1, 0, $nodesToAdd); - $fileWithoutNamespace->stmts = $stmts; - $fileWithoutNamespace->stmts = \array_values($fileWithoutNamespace->stmts); return [$fileWithoutNamespace]; } - $this->mirrorUseComments($stmts, $newUses); - // make use stmts first - $fileWithoutNamespace->stmts = \array_merge($newUses, $this->resolveInsertNop($fileWithoutNamespace), $stmts); - $fileWithoutNamespace->stmts = \array_values($fileWithoutNamespace->stmts); + $useComments = $this->getAndRemoveExistingUseComments($stmts); + $fileWithoutNamespace->stmts = $this->insertUseNodesInStatements($fileWithoutNamespace->stmts, $newUses); + if ($useComments !== []) { + $this->reapplyUseComments($useComments, $fileWithoutNamespace->stmts); + } return [$fileWithoutNamespace]; } /** * @param FullyQualifiedObjectType[] $useImportTypes - * @param FullyQualifiedObjectType[] $constantUseImportTypes * @param FullyQualifiedObjectType[] $functionUseImportTypes + * @param FullyQualifiedObjectType[] $constantUseImportTypes */ - public function addImportsToNamespace(Namespace_ $namespace, array $useImportTypes, array $constantUseImportTypes, array $functionUseImportTypes) : void + public function addImportsToNamespace(Namespace_ $namespace, array $useImportTypes, array $functionUseImportTypes, array $constantUseImportTypes) : void { $namespaceName = $this->getNamespaceName($namespace); $existingUsedImports = $this->usedImportsResolver->resolveForStmts($namespace->stmts); @@ -95,24 +102,26 @@ public function addImportsToNamespace(Namespace_ $namespace, array $useImportTyp $existingConstantUseImportTypes = $existingUsedImports->getConstantImports(); $existingFunctionUseImportTypes = $existingUsedImports->getFunctionImports(); $existingUseImportTypes = $this->typeFactory->uniquateTypes($existingUseImportTypes); - $useImportTypes = $this->diffFullyQualifiedObjectTypes($useImportTypes, $existingUseImportTypes); - $constantUseImportTypes = $this->diffFullyQualifiedObjectTypes($constantUseImportTypes, $existingConstantUseImportTypes); - $functionUseImportTypes = $this->diffFullyQualifiedObjectTypes($functionUseImportTypes, $existingFunctionUseImportTypes); - $newUses = $this->createUses($useImportTypes, $constantUseImportTypes, $functionUseImportTypes, $namespaceName); + $newUseImportTypes = $this->diffFullyQualifiedObjectTypes($useImportTypes, $existingUseImportTypes); + $newFunctionUseImportTypes = $this->diffFullyQualifiedObjectTypes($functionUseImportTypes, $existingFunctionUseImportTypes); + $newConstantUseImportTypes = $this->diffFullyQualifiedObjectTypes($constantUseImportTypes, $existingConstantUseImportTypes); + $newUses = $this->createUses($newUseImportTypes, $newFunctionUseImportTypes, $newConstantUseImportTypes, $namespaceName); if ($newUses === []) { return; } - $this->mirrorUseComments($namespace->stmts, $newUses); - $namespace->stmts = \array_merge($newUses, $this->resolveInsertNop($namespace), $namespace->stmts); - $namespace->stmts = \array_values($namespace->stmts); + $useComments = $this->getAndRemoveExistingUseComments($namespace->stmts); + $namespace->stmts = $this->insertUseNodesInStatements($namespace->stmts, $newUses); + if ($useComments !== []) { + $this->reapplyUseComments($useComments, $namespace->stmts); + } } /** + * @param Stmt[] $stmts * @return Nop[] - * @param \Rector\PhpParser\Node\CustomNode\FileWithoutNamespace|\PhpParser\Node\Stmt\Namespace_ $namespace */ - private function resolveInsertNop($namespace) : array + private function resolveInsertNop(array $stmts, int $position) : array { - $currentStmt = $namespace->stmts[0] ?? null; + $currentStmt = $stmts[$position] ?? null; if (!$currentStmt instanceof Stmt || $currentStmt instanceof Use_ || $currentStmt instanceof GroupUse) { return []; } @@ -120,20 +129,31 @@ private function resolveInsertNop($namespace) : array } /** * @param Stmt[] $stmts - * @param Use_[] $newUses + * @return Comment[] */ - private function mirrorUseComments(array $stmts, array $newUses, int $indexStmt = 0) : void + private function getAndRemoveExistingUseComments(array $stmts, int $indexStmt = 0) : array { + $comments = []; if ($stmts === []) { - return; + return $comments; } if (isset($stmts[$indexStmt]) && $stmts[$indexStmt] instanceof Use_) { $comments = (array) $stmts[$indexStmt]->getAttribute(AttributeKey::COMMENTS); if ($comments !== []) { - $newUses[0]->setAttribute(AttributeKey::COMMENTS, $stmts[$indexStmt]->getAttribute(AttributeKey::COMMENTS)); $stmts[$indexStmt]->setAttribute(AttributeKey::COMMENTS, []); } } + return $comments; + } + /** + * @param Comment[] $comments + * @param Stmt[] $stmts + */ + private function reapplyUseComments(array $comments, array $stmts, int $indexStmt = 0) : void + { + if (isset($stmts[$indexStmt])) { + $stmts[$indexStmt]->setAttribute(AttributeKey::COMMENTS, $comments); + } } /** * @param array $mainTypes @@ -153,24 +173,33 @@ private function diffFullyQualifiedObjectTypes(array $mainTypes, array $typesToR } /** * @param array $useImportTypes - * @param array $constantUseImportTypes * @param array $functionUseImportTypes + * @param array $constantUseImportTypes * @return Use_[] */ - private function createUses(array $useImportTypes, array $constantUseImportTypes, array $functionUseImportTypes, ?string $namespaceName) : array + private function createUses(array $useImportTypes, array $functionUseImportTypes, array $constantUseImportTypes, ?string $namespaceName) : array { $newUses = []; /** @var array> $importsMapping */ - $importsMapping = [Use_::TYPE_NORMAL => $useImportTypes, Use_::TYPE_CONSTANT => $constantUseImportTypes, Use_::TYPE_FUNCTION => $functionUseImportTypes]; + $importsMapping = [Use_::TYPE_NORMAL => $useImportTypes, Use_::TYPE_FUNCTION => $functionUseImportTypes, Use_::TYPE_CONSTANT => $constantUseImportTypes]; foreach ($importsMapping as $type => $importTypes) { - /** @var AliasedObjectType|FullyQualifiedObjectType $importType */ + $newUsesPerType = []; foreach ($importTypes as $importType) { if ($namespaceName !== null && $this->isCurrentNamespace($namespaceName, $importType)) { continue; } // already imported in previous cycle - $newUses[] = $importType->getUseNode($type); + $newUsesPerType[] = $importType->getUseNode($type); + } + if (SimpleParameterProvider::provideBoolParameter(Option::IMPORT_INSERT_SORTED)) { + //sort uses by name in ascending order + \usort($newUsesPerType, function (Use_ $use1, Use_ $use2) : int { + $name1 = $use1->uses[0]->name->toString(); + $name2 = $use2->uses[0]->name->toString(); + return \strcmp($name1, $name2); + }); } + $newUses = \array_merge($newUses, $newUsesPerType); } return $newUses; } @@ -189,4 +218,57 @@ private function isCurrentNamespace(string $namespaceName, ObjectType $objectTyp } return \strpos($afterCurrentNamespace, '\\') === \false; } + /** + * @param Stmt[] $stmts + * @param Use_[] $newUses + * @return Stmt[] + */ + private function insertUseNodesInStatements(array $stmts, array $newUses, int $position = 0, bool $addSpace = \true) : array + { + $importInsertSorted = SimpleParameterProvider::provideBoolParameter(Option::IMPORT_INSERT_SORTED); + if ($importInsertSorted && isset($stmts[$position]) && ($stmts[$position] instanceof Use_ || $stmts[$position] instanceof GroupUse)) { + foreach ($newUses as $newUse) { + do { + $useListPosition = 0; + $prefix = ''; + if (!isset($stmts[$position]) || !$stmts[$position] instanceof Use_ && !$stmts[$position] instanceof GroupUse) { + break; + } + if ($stmts[$position] instanceof GroupUse) { + $prefix = $stmts[$position]->prefix->toString() . '\\'; + } + $parentUseType = $stmts[$position]->type; + $newUseType = $newUse->type; + foreach ($stmts[$position]->uses as $use) { + $currentUseType = $parentUseType === Use_::TYPE_UNKNOWN ? $use->type : $parentUseType; + if ($newUseType < $currentUseType) { + break 2; + } + if ($newUseType === $currentUseType && $prefix . $use->name->toString() > $newUse->uses[0]->name->toString()) { + break 2; + } + ++$useListPosition; + } + ++$position; + } while (\true); + if ($useListPosition === 0) { + \array_splice($stmts, $position, 0, [$newUse]); + ++$position; + } else { + \assert($stmts[$position] instanceof Use_ || $stmts[$position] instanceof GroupUse); + if ($prefix !== '') { + $newUse->uses[0]->name = new Name(\substr($newUse->uses[0]->name->toString(), \strlen($prefix))); + $newUse->uses[0]->type = $newUse->type; + } + \array_splice($stmts[$position]->uses, $useListPosition, 0, [$newUse->uses[0]]); + } + } + } else { + if ($addSpace) { + $newUses = \array_merge($newUses, $this->resolveInsertNop($stmts, $position)); + } + \array_splice($stmts, $position, 0, $newUses); + } + return \array_values($stmts); + } } diff --git a/src/Application/ApplicationFileProcessor.php b/src/Application/ApplicationFileProcessor.php index ce95b3bdd9b7..eb7f4c296b19 100644 --- a/src/Application/ApplicationFileProcessor.php +++ b/src/Application/ApplicationFileProcessor.php @@ -7,6 +7,7 @@ use PHPStan\Parser\ParserErrorsException; use Rector\Application\Provider\CurrentFileProvider; use Rector\Caching\Detector\ChangedFilesDetector; +use Rector\Caching\FileDependenciesCache; use Rector\Configuration\Option; use Rector\Configuration\Parameter\SimpleParameterProvider; use Rector\FileSystem\FilesFinder; @@ -79,6 +80,11 @@ final class ApplicationFileProcessor * @var \Rector\Reporting\MissConfigurationReporter */ private $missConfigurationReporter; + /** + * @readonly + * @var \Rector\Caching\FileDependenciesCache + */ + private $fileDependenciesCache; /** * @var string */ @@ -87,7 +93,7 @@ final class ApplicationFileProcessor * @var SystemError[] */ private $systemErrors = []; - public function __construct(SymfonyStyle $symfonyStyle, FilesFinder $filesFinder, ParallelFileProcessor $parallelFileProcessor, ScheduleFactory $scheduleFactory, CpuCoreCountProvider $cpuCoreCountProvider, ChangedFilesDetector $changedFilesDetector, CurrentFileProvider $currentFileProvider, \Rector\Application\FileProcessor $fileProcessor, ArrayParametersMerger $arrayParametersMerger, MissConfigurationReporter $missConfigurationReporter) + public function __construct(SymfonyStyle $symfonyStyle, FilesFinder $filesFinder, ParallelFileProcessor $parallelFileProcessor, ScheduleFactory $scheduleFactory, CpuCoreCountProvider $cpuCoreCountProvider, ChangedFilesDetector $changedFilesDetector, CurrentFileProvider $currentFileProvider, \Rector\Application\FileProcessor $fileProcessor, ArrayParametersMerger $arrayParametersMerger, MissConfigurationReporter $missConfigurationReporter, FileDependenciesCache $fileDependenciesCache) { $this->symfonyStyle = $symfonyStyle; $this->filesFinder = $filesFinder; @@ -99,10 +105,13 @@ public function __construct(SymfonyStyle $symfonyStyle, FilesFinder $filesFinder $this->fileProcessor = $fileProcessor; $this->arrayParametersMerger = $arrayParametersMerger; $this->missConfigurationReporter = $missConfigurationReporter; + $this->fileDependenciesCache = $fileDependenciesCache; } public function run(Configuration $configuration, InputInterface $input) : ProcessResult { - $filePaths = $this->filesFinder->findFilesInPaths($configuration->getPaths(), $configuration); + $allFiles = $this->filesFinder->findFilesInPaths($configuration->getPaths(), $configuration); + $filePaths = $this->filesFinder->filterUnchangedFiles($allFiles); + $filePaths = \array_merge($filePaths, $this->findDependentFiles($allFiles, $filePaths)); $this->missConfigurationReporter->reportVendorInPaths($filePaths); $this->missConfigurationReporter->reportStartWithShortOpenTag(); // no files found @@ -133,9 +142,10 @@ public function run(Configuration $configuration, InputInterface $input) : Proce $preFileCallback = null; } if ($configuration->isParallel()) { + $this->fileDependenciesCache->cacheAllFiles($allFiles); $processResult = $this->runParallel($filePaths, $input, $postFileCallback); } else { - $processResult = $this->processFiles($filePaths, $configuration, $preFileCallback, $postFileCallback); + $processResult = $this->processFiles($filePaths, $configuration, $allFiles, $preFileCallback, $postFileCallback); } $processResult->addSystemErrors($this->systemErrors); $this->restoreErrorHandler(); @@ -143,22 +153,27 @@ public function run(Configuration $configuration, InputInterface $input) : Proce } /** * @param string[] $filePaths + * @param string[] $allFiles * @param callable(string $file): void|null $preFileCallback * @param callable(int $fileCount): void|null $postFileCallback */ - public function processFiles(array $filePaths, Configuration $configuration, ?callable $preFileCallback = null, ?callable $postFileCallback = null) : ProcessResult + public function processFiles(array $filePaths, Configuration $configuration, ?array $allFiles = null, ?callable $preFileCallback = null, ?callable $postFileCallback = null) : ProcessResult { /** @var SystemError[] $systemErrors */ $systemErrors = []; /** @var FileDiff[] $fileDiffs */ $fileDiffs = []; + if ($allFiles === null) { + $allFiles = $this->fileDependenciesCache->getAllFiles(); + } + $allFiles = \array_fill_keys($allFiles, \true); foreach ($filePaths as $filePath) { if ($preFileCallback !== null) { $preFileCallback($filePath); } $file = new File($filePath, UtilsFileSystem::read($filePath)); try { - $fileProcessResult = $this->processFile($file, $configuration); + $fileProcessResult = $this->processFile($file, $allFiles, $configuration); $systemErrors = $this->arrayParametersMerger->merge($systemErrors, $fileProcessResult->getSystemErrors()); $currentFileDiff = $fileProcessResult->getFileDiff(); if ($currentFileDiff instanceof FileDiff) { @@ -178,10 +193,38 @@ public function processFiles(array $filePaths, Configuration $configuration, ?ca } return new ProcessResult($systemErrors, $fileDiffs); } - private function processFile(File $file, Configuration $configuration) : FileProcessResult + /** + * @param string[] $possibleDependentFiles + * @param string[] $filePaths + * @return string[] + */ + private function findDependentFiles(array $possibleDependentFiles, array $filePaths) : array + { + $filesToAnalise = \array_flip($filePaths); + $dependentFiles = []; + foreach ($possibleDependentFiles as $possibleDependentFile) { + if (!isset($filesToAnalise[$possibleDependentFile])) { + $fileDependencies = $this->fileDependenciesCache->getFileDependencies($possibleDependentFile); + if ($fileDependencies !== null) { + foreach ($fileDependencies as $fileDependency) { + if (isset($filesToAnalise[$fileDependency])) { + $dependentFiles[] = $possibleDependentFile; + $this->changedFilesDetector->invalidateFile($possibleDependentFile); + break; + } + } + } + } + } + return $dependentFiles; + } + /** + * @param array $allFiles + */ + private function processFile(File $file, array $allFiles, Configuration $configuration) : FileProcessResult { $this->currentFileProvider->setFile($file); - $fileProcessResult = $this->fileProcessor->processFile($file, $configuration); + $fileProcessResult = $this->fileProcessor->processFile($file, $allFiles, $configuration); if ($fileProcessResult->getSystemErrors() !== []) { $this->changedFilesDetector->invalidateFile($file->getFilePath()); } elseif (!$configuration->isDryRun() || !$fileProcessResult->getFileDiff() instanceof FileDiff) { diff --git a/src/Application/FileProcessor.php b/src/Application/FileProcessor.php index ec6028a42a05..066c680a54d9 100644 --- a/src/Application/FileProcessor.php +++ b/src/Application/FileProcessor.php @@ -5,14 +5,19 @@ use RectorPrefix202410\Nette\Utils\FileSystem; use RectorPrefix202410\Nette\Utils\Strings; +use PhpParser\Node; use PHPStan\AnalysedCodeException; +use PHPStan\Dependency\DependencyResolver; use PHPStan\Parser\ParserErrorsException; use Rector\Caching\Detector\ChangedFilesDetector; +use Rector\Caching\FileDependenciesCache; use Rector\ChangesReporting\ValueObjectFactory\ErrorFactory; use Rector\ChangesReporting\ValueObjectFactory\FileDiffFactory; use Rector\Exception\ShouldNotHappenException; use Rector\FileSystem\FilePathHelper; +use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator; +use Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser; use Rector\PhpParser\NodeTraverser\RectorNodeTraverser; use Rector\PhpParser\Parser\ParserErrors; use Rector\PhpParser\Parser\RectorParser; @@ -78,12 +83,27 @@ final class FileProcessor * @var \Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator */ private $nodeScopeAndMetadataDecorator; + /** + * @readonly + * @var \PHPStan\Dependency\DependencyResolver + */ + private $dependencyResolver; + /** + * @readonly + * @var \Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser + */ + private $simpleCallableNodeTraverser; + /** + * @readonly + * @var \Rector\Caching\FileDependenciesCache + */ + private $fileDependenciesCache; /** * @var string * @see https://regex101.com/r/llm7XZ/1 */ private const OPEN_TAG_SPACED_REGEX = '#^[ \\t]+<\\?php#m'; - public function __construct(BetterStandardPrinter $betterStandardPrinter, RectorNodeTraverser $rectorNodeTraverser, SymfonyStyle $symfonyStyle, FileDiffFactory $fileDiffFactory, ChangedFilesDetector $changedFilesDetector, ErrorFactory $errorFactory, FilePathHelper $filePathHelper, PostFileProcessor $postFileProcessor, RectorParser $rectorParser, NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator) + public function __construct(BetterStandardPrinter $betterStandardPrinter, RectorNodeTraverser $rectorNodeTraverser, SymfonyStyle $symfonyStyle, FileDiffFactory $fileDiffFactory, ChangedFilesDetector $changedFilesDetector, ErrorFactory $errorFactory, FilePathHelper $filePathHelper, PostFileProcessor $postFileProcessor, RectorParser $rectorParser, NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator, DependencyResolver $dependencyResolver, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, FileDependenciesCache $fileDependenciesCache) { $this->betterStandardPrinter = $betterStandardPrinter; $this->rectorNodeTraverser = $rectorNodeTraverser; @@ -95,8 +115,14 @@ public function __construct(BetterStandardPrinter $betterStandardPrinter, Rector $this->postFileProcessor = $postFileProcessor; $this->rectorParser = $rectorParser; $this->nodeScopeAndMetadataDecorator = $nodeScopeAndMetadataDecorator; + $this->dependencyResolver = $dependencyResolver; + $this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser; + $this->fileDependenciesCache = $fileDependenciesCache; } - public function processFile(File $file, Configuration $configuration) : FileProcessResult + /** + * @param array $allFiles + */ + public function processFile(File $file, array $allFiles, Configuration $configuration) : FileProcessResult { // 1. parse files to nodes $parsingSystemError = $this->parseFileAndDecorateNodes($file); @@ -104,6 +130,7 @@ public function processFile(File $file, Configuration $configuration) : FileProc // we cannot process this file as the parsing and type resolving itself went wrong return new FileProcessResult([$parsingSystemError], null); } + $this->cacheFileDependencies($file, $allFiles); $fileHasChanged = \false; $filePath = $file->getFilePath(); // 2. change nodes with Rectors @@ -159,6 +186,24 @@ private function parseFileAndDecorateNodes(File $file) : ?SystemError } return null; } + /** + * @param array $allFiles + */ + private function cacheFileDependencies(File $file, array $allFiles) : void + { + $fileDependencies = []; + $dependencyResolver = $this->dependencyResolver; + $this->simpleCallableNodeTraverser->traverseNodesWithCallable($file->getOldStmts(), static function (Node $node) use($dependencyResolver, $allFiles, $file, &$fileDependencies) : Node { + $currentScope = $node->getAttribute(AttributeKey::SCOPE); + if ($currentScope !== null) { + $dependencies = $dependencyResolver->resolveDependencies($node, $currentScope); + $fileDependencies = \array_merge($fileDependencies, $dependencies->getFileDependencies($file->getFilePath(), $allFiles)); + } + return $node; + }); + $fileDependencies = \array_values(\array_unique($fileDependencies)); + $this->fileDependenciesCache->cacheFileDependencies($file->getFilePath(), $fileDependencies); + } private function printFile(File $file, Configuration $configuration, string $filePath) : void { // only save to string first, no need to print to file when not needed diff --git a/src/Application/VersionResolver.php b/src/Application/VersionResolver.php index f31f55ad6da1..444b217f5663 100644 --- a/src/Application/VersionResolver.php +++ b/src/Application/VersionResolver.php @@ -19,12 +19,12 @@ final class VersionResolver * @api * @var string */ - public const PACKAGE_VERSION = '447afc1b482cfa80e455d723dd1cf687d0b4c8a1'; + public const PACKAGE_VERSION = 'c20f5ede4af5310a23ca8baffd2b5f74ae77d622'; /** * @api * @var string */ - public const RELEASE_DATE = '2024-10-04 15:10:15'; + public const RELEASE_DATE = '2024-10-04 12:45:50'; /** * @var int */ diff --git a/src/Caching/Detector/ChangedFilesDetector.php b/src/Caching/Detector/ChangedFilesDetector.php index 1246e2fc84d9..9e1ae79d731d 100644 --- a/src/Caching/Detector/ChangedFilesDetector.php +++ b/src/Caching/Detector/ChangedFilesDetector.php @@ -83,22 +83,13 @@ public function setFirstResolvedConfigFileInfo(string $filePath) : void $configHash = $this->fileHashComputer->compute($filePath); $this->storeConfigurationDataHash($filePath, $configHash); } - private function resolvePath(string $filePath) : string - { - /** @var string|false $realPath */ - $realPath = \realpath($filePath); - if ($realPath === \false) { - return $filePath; - } - return $realPath; - } private function getFilePathCacheKey(string $filePath) : string { - return $this->fileHasher->hash($this->resolvePath($filePath)); + return $this->fileHasher->hash($this->fileHasher->resolvePath($filePath)); } private function hashFile(string $filePath) : string { - return $this->fileHasher->hashFiles([$this->resolvePath($filePath)]); + return $this->fileHasher->hashFiles([$this->fileHasher->resolvePath($filePath)]); } private function storeConfigurationDataHash(string $filePath, string $configurationHash) : void { diff --git a/src/Caching/Enum/CacheKey.php b/src/Caching/Enum/CacheKey.php index de575b84fbb4..62d67350bd5a 100644 --- a/src/Caching/Enum/CacheKey.php +++ b/src/Caching/Enum/CacheKey.php @@ -16,4 +16,12 @@ final class CacheKey * @var string */ public const FILE_HASH_KEY = 'file_hash'; + /** + * @var string + */ + public const FILE_DEPENDENCIES_KEY = 'file_dependencies'; + /** + * @var string + */ + public const ALL_FILES_KEY = 'all_files'; } diff --git a/src/Caching/FileDependenciesCache.php b/src/Caching/FileDependenciesCache.php new file mode 100644 index 000000000000..aa0f9a27947a --- /dev/null +++ b/src/Caching/FileDependenciesCache.php @@ -0,0 +1,63 @@ +cache = $cache; + $this->fileHasher = $fileHasher; + } + /** + * @param string[] $dependencies + */ + public function cacheFileDependencies(string $filePath, array $dependencies) : void + { + $filePathCacheKey = $this->getFilePathCacheKey($filePath); + $this->cache->save($filePathCacheKey, CacheKey::FILE_DEPENDENCIES_KEY, \json_encode($dependencies)); + } + /** + * @return string[]|null + */ + public function getFileDependencies(string $filePath) : ?array + { + $fileInfoCacheKey = $this->getFilePathCacheKey($filePath); + $cachedValue = $this->cache->load($fileInfoCacheKey, CacheKey::FILE_DEPENDENCIES_KEY); + return \is_string($cachedValue) ? \json_decode($cachedValue) : null; + } + /** + * @param string[] $allFiles + */ + public function cacheAllFiles(array $allFiles) : void + { + $cacheKey = $this->fileHasher->hash(CacheKey::ALL_FILES_KEY); + $this->cache->save($cacheKey, CacheKey::ALL_FILES_KEY, \json_encode(\array_values($allFiles))); + } + /** + * @return string[] + */ + public function getAllFiles() : array + { + $cacheKey = $this->fileHasher->hash(CacheKey::ALL_FILES_KEY); + $cachedValue = $this->cache->load($cacheKey, CacheKey::ALL_FILES_KEY); + return \is_string($cachedValue) ? \json_decode($cachedValue) : []; + } + private function getFilePathCacheKey(string $filePath) : string + { + return $this->fileHasher->hash($this->fileHasher->resolvePath($filePath) . 'file_dependencies'); + } +} diff --git a/src/Config/RectorConfig.php b/src/Config/RectorConfig.php index f52e772b6ef8..d3c88b0b85d7 100644 --- a/src/Config/RectorConfig.php +++ b/src/Config/RectorConfig.php @@ -114,10 +114,11 @@ public function removeUnusedImports(bool $removeUnusedImports = \true) : void { SimpleParameterProvider::setParameter(Option::REMOVE_UNUSED_IMPORTS, $removeUnusedImports); } - public function importNames(bool $importNames = \true, bool $importDocBlockNames = \true) : void + public function importNames(bool $importNames = \true, bool $importDocBlockNames = \true, bool $importInsertSorted = \false) : void { SimpleParameterProvider::setParameter(Option::AUTO_IMPORT_NAMES, $importNames); SimpleParameterProvider::setParameter(Option::AUTO_IMPORT_DOC_BLOCK_NAMES, $importDocBlockNames); + SimpleParameterProvider::setParameter(Option::IMPORT_INSERT_SORTED, $importInsertSorted); } public function importShortClasses(bool $importShortClasses = \true) : void { diff --git a/src/Configuration/Option.php b/src/Configuration/Option.php index 2047e8d704b8..a63a8b422c11 100644 --- a/src/Configuration/Option.php +++ b/src/Configuration/Option.php @@ -61,6 +61,11 @@ final class Option * @var string */ public const IMPORT_SHORT_CLASSES = 'import_short_classes'; + /** + * @internal Use @see \Rector\Config\RectorConfig::importNames() instead + * @var string + */ + public const IMPORT_INSERT_SORTED = 'import_insert_sorted'; /** * @internal Use @see \Rector\Config\RectorConfig::symfonyContainerXml() instead * @var string diff --git a/src/Configuration/RectorConfigBuilder.php b/src/Configuration/RectorConfigBuilder.php index f595a48a8f51..4e6ee439e3a9 100644 --- a/src/Configuration/RectorConfigBuilder.php +++ b/src/Configuration/RectorConfigBuilder.php @@ -103,6 +103,10 @@ final class RectorConfigBuilder * @var bool */ private $removeUnusedImports = \false; + /** + * @var bool + */ + private $importInsertSorted = \false; /** * @var bool */ @@ -242,7 +246,7 @@ public function __invoke(RectorConfig $rectorConfig) : void $rectorConfig->containerCacheDirectory($this->containerCacheDirectory); } if ($this->importNames || $this->importDocBlockNames) { - $rectorConfig->importNames($this->importNames, $this->importDocBlockNames); + $rectorConfig->importNames($this->importNames, $this->importDocBlockNames, $this->importInsertSorted); $rectorConfig->importShortClasses($this->importShortClasses); } if ($this->removeUnusedImports) { @@ -666,12 +670,13 @@ public function withoutParallel() : self $this->parallel = \false; return $this; } - public function withImportNames(bool $importNames = \true, bool $importDocBlockNames = \true, bool $importShortClasses = \true, bool $removeUnusedImports = \false) : self + public function withImportNames(bool $importNames = \true, bool $importDocBlockNames = \true, bool $importShortClasses = \true, bool $removeUnusedImports = \false, bool $importInsertSorted = \false) : self { $this->importNames = $importNames; $this->importDocBlockNames = $importDocBlockNames; $this->importShortClasses = $importShortClasses; $this->removeUnusedImports = $removeUnusedImports; + $this->importInsertSorted = $importInsertSorted; return $this; } public function withNoDiffs() : self diff --git a/src/Console/Command/WorkerCommand.php b/src/Console/Command/WorkerCommand.php index f68632c931fa..d95f0f356a5d 100644 --- a/src/Console/Command/WorkerCommand.php +++ b/src/Console/Command/WorkerCommand.php @@ -115,7 +115,7 @@ private function runWorker(Encoder $encoder, Decoder $decoder, Configuration $co /** @var string[] $filePaths */ $filePaths = $json[Bridge::FILES] ?? []; Assert::notEmpty($filePaths); - $processResult = $this->applicationFileProcessor->processFiles($filePaths, $configuration, $preFileCallback); + $processResult = $this->applicationFileProcessor->processFiles($filePaths, $configuration, null, $preFileCallback); /** * this invokes all listeners listening $decoder->on(...) @see \Symplify\EasyParallel\Enum\ReactEvent::DATA */ diff --git a/src/DependencyInjection/LazyContainerFactory.php b/src/DependencyInjection/LazyContainerFactory.php index 5cdc61f24d04..4db12d71cc36 100644 --- a/src/DependencyInjection/LazyContainerFactory.php +++ b/src/DependencyInjection/LazyContainerFactory.php @@ -9,6 +9,7 @@ use PhpParser\Lexer; use PHPStan\Analyser\NodeScopeResolver; use PHPStan\Analyser\ScopeFactory; +use PHPStan\Dependency\DependencyResolver; use PHPStan\Parser\Parser; use PHPStan\PhpDoc\TypeNodeResolver; use PHPStan\PhpDocParser\Parser\ConstExprParser; @@ -216,7 +217,7 @@ final class LazyContainerFactory /** * @var array */ - private const PUBLIC_PHPSTAN_SERVICE_TYPES = [ScopeFactory::class, TypeNodeResolver::class, NodeScopeResolver::class, ReflectionProvider::class, CachingVisitor::class]; + private const PUBLIC_PHPSTAN_SERVICE_TYPES = [ScopeFactory::class, TypeNodeResolver::class, NodeScopeResolver::class, ReflectionProvider::class, CachingVisitor::class, DependencyResolver::class]; /** * @var array> */ diff --git a/src/FileSystem/FilesFinder.php b/src/FileSystem/FilesFinder.php index 750919ab0df9..5ba06d0bab5e 100644 --- a/src/FileSystem/FilesFinder.php +++ b/src/FileSystem/FilesFinder.php @@ -88,8 +88,15 @@ public function findInDirectoriesAndFiles(array $source, array $suffixes = [], b // filtering files in directories collection $directories = $this->fileAndDirectoryFilter->filterDirectories($filesAndDirectories); $filteredFilePathsInDirectories = $this->findInDirectories($directories, $suffixes, $sortByName); - $filePaths = \array_merge($filteredFilePaths, $filteredFilePathsInDirectories); - return $this->unchangedFilesFilter->filterFilePaths($filePaths); + return \array_merge($filteredFilePaths, $filteredFilePathsInDirectories); + } + /** + * @param string[] $allFiles + * @return string[] + */ + public function filterUnchangedFiles(array $allFiles) : array + { + return $this->unchangedFilesFilter->filterFilePaths($allFiles); } /** * @param string[] $paths diff --git a/src/Parallel/Command/WorkerCommandLineFactory.php b/src/Parallel/Command/WorkerCommandLineFactory.php index a5b4e284a0db..478dc1a2e545 100644 --- a/src/Parallel/Command/WorkerCommandLineFactory.php +++ b/src/Parallel/Command/WorkerCommandLineFactory.php @@ -146,13 +146,8 @@ private function mirrorCommandOptions(InputInterface $input, array $mainCommandO } continue; } - if ($mainCommandOptionName === 'memory-limit') { - // symfony/console does not accept -1 as value without assign - $workerCommandOptions[] = self::OPTION_DASHES . $mainCommandOptionName . '=' . \escapeshellarg($optionValue); - } else { - $workerCommandOptions[] = self::OPTION_DASHES . $mainCommandOptionName; - $workerCommandOptions[] = \escapeshellarg($optionValue); - } + $workerCommandOptions[] = self::OPTION_DASHES . $mainCommandOptionName; + $workerCommandOptions[] = \escapeshellarg($optionValue); } return $workerCommandOptions; } diff --git a/src/PostRector/Rector/UnusedImportRemovingPostRector.php b/src/PostRector/Rector/UnusedImportRemovingPostRector.php index 2e266816ef32..c63025953e5e 100644 --- a/src/PostRector/Rector/UnusedImportRemovingPostRector.php +++ b/src/PostRector/Rector/UnusedImportRemovingPostRector.php @@ -137,14 +137,14 @@ private function resolveUsedPhpAndDocNames($namespace) : array $phpNames = $this->findNonUseImportNames($namespace); $docBlockNames = $this->findNamesInDocBlocks($namespace); $names = \array_merge($phpNames, $docBlockNames); - return \array_unique(\array_map(\Closure::fromCallable('strtolower'), $names)); + return \array_unique($names); } /** - * @param string[] $names + * @param string[] $names */ private function isUseImportUsed(UseUse $useUse, array $names, ?Name $namespaceName) : bool { - $comparedName = \strtolower($useUse->alias instanceof Identifier ? $useUse->alias->toString() : $useUse->name->toString()); + $comparedName = $useUse->alias instanceof Identifier ? $useUse->alias->toString() : $useUse->name->toString(); if (\in_array($comparedName, $names, \true)) { return \true; } @@ -152,8 +152,8 @@ private function isUseImportUsed(UseUse $useUse, array $names, ?Name $namespaceN if ($namespacedPrefix === '\\') { $namespacedPrefix = $comparedName . '\\'; } - $lastName = \strtolower($useUse->name->getLast()); - $namespaceName = $namespaceName instanceof Name ? \strtolower($namespaceName->toString()) : null; + $lastName = $useUse->name->getLast(); + $namespaceName = $namespaceName instanceof Name ? $namespaceName->toString() : null; // match partial import foreach ($names as $name) { if ($this->isSubNamespace($name, $comparedName, $namespacedPrefix)) { diff --git a/src/PostRector/Rector/UseAddingPostRector.php b/src/PostRector/Rector/UseAddingPostRector.php index e7e6974f0c88..add54d5c9561 100644 --- a/src/PostRector/Rector/UseAddingPostRector.php +++ b/src/PostRector/Rector/UseAddingPostRector.php @@ -87,13 +87,13 @@ private function resolveNodesWithImportedUses(array $nodes, array $useImportType // A. has namespace? add under it if ($namespace instanceof Namespace_) { // then add, to prevent adding + removing false positive of same short use - $this->useImportsAdder->addImportsToNamespace($namespace, $useImportTypes, $constantUseImportTypes, $functionUseImportTypes); + $this->useImportsAdder->addImportsToNamespace($namespace, $useImportTypes, $functionUseImportTypes, $constantUseImportTypes); return $nodes; } // B. no namespace? add in the top $useImportTypes = $this->filterOutNonNamespacedNames($useImportTypes); // then add, to prevent adding + removing false positive of same short use - return $this->useImportsAdder->addImportsToStmts($namespace, $nodes, $useImportTypes, $constantUseImportTypes, $functionUseImportTypes); + return $this->useImportsAdder->addImportsToStmts($namespace, $nodes, $useImportTypes, $functionUseImportTypes, $constantUseImportTypes); } /** * Prevents diff --git a/src/Skipper/Skipper/CommentSkipper.php b/src/Skipper/Skipper/CommentSkipper.php new file mode 100644 index 000000000000..739541398f87 --- /dev/null +++ b/src/Skipper/Skipper/CommentSkipper.php @@ -0,0 +1,22 @@ +skipSkipper = $skipSkipper; + } + public function shouldSkip(string $rectorClass, Node $node) : bool + { + return $this->skipSkipper->doesMatchComments($rectorClass, $node); + } +} diff --git a/src/Skipper/Skipper/SkipSkipper.php b/src/Skipper/Skipper/SkipSkipper.php index 27358b2e30de..d76785e2b17b 100644 --- a/src/Skipper/Skipper/SkipSkipper.php +++ b/src/Skipper/Skipper/SkipSkipper.php @@ -3,7 +3,10 @@ declare (strict_types=1); namespace Rector\Skipper\Skipper; +use PhpParser\Node; +use Rector\BetterPhpDocParser\PhpDocParser\ClassAnnotationMatcher; use Rector\Skipper\Matcher\FileInfoMatcher; +use Rector\Util\NewLineSplitter; final class SkipSkipper { /** @@ -11,9 +14,17 @@ final class SkipSkipper * @var \Rector\Skipper\Matcher\FileInfoMatcher */ private $fileInfoMatcher; - public function __construct(FileInfoMatcher $fileInfoMatcher) + /** + * @readonly + * @var \Rector\BetterPhpDocParser\PhpDocParser\ClassAnnotationMatcher + */ + private $classAnnotationMatcher; + private const RECTOR_IGNORE_NEXT_LINE_TAG = '@rector-ignore-next-line'; + private const RECTOR_IGNORE_TAG = '@rector-ignore'; + public function __construct(FileInfoMatcher $fileInfoMatcher, ClassAnnotationMatcher $classAnnotationMatcher) { $this->fileInfoMatcher = $fileInfoMatcher; + $this->classAnnotationMatcher = $classAnnotationMatcher; } /** * @param array $skippedClasses @@ -35,4 +46,39 @@ public function doesMatchSkip($checker, string $filePath, array $skippedClasses) } return \false; } + public function doesMatchComments(string $rectorClass, Node $node) : bool + { + $comments = $node->getComments(); + if ($comments === []) { + return \false; + } + foreach ($comments as $comment) { + $commentLines = NewLineSplitter::split($comment->getText()); + foreach ($commentLines as $commentLine) { + if (\strpos($commentLine, self::RECTOR_IGNORE_NEXT_LINE_TAG) !== \false) { + return \true; + } + if ($this->isCurrentRuleInExcludedRulesInCommentLine($rectorClass, $commentLine, $node)) { + return \true; + } + } + } + return \false; + } + private function isCurrentRuleInExcludedRulesInCommentLine(string $currentRuleName, string $commentLine, Node $node) : bool + { + $ignorePosition = \strpos($commentLine, self::RECTOR_IGNORE_TAG); + if ($ignorePosition !== \false) { + $restOfLine = \substr($commentLine, $ignorePosition + \strlen(self::RECTOR_IGNORE_TAG)); + $restOfLine = \str_replace('*/', '', $restOfLine); + $excludedRules = \explode(',', $restOfLine); + foreach ($excludedRules as $excludedRule) { + $excludedRuleFullName = $this->classAnnotationMatcher->resolveTagFullyQualifiedName(\trim($excludedRule), $node); + if ($excludedRuleFullName === $currentRuleName) { + return \true; + } + } + } + return \false; + } } diff --git a/src/Skipper/Skipper/Skipper.php b/src/Skipper/Skipper/Skipper.php index 58a4d66c2970..4e99ce648017 100644 --- a/src/Skipper/Skipper/Skipper.php +++ b/src/Skipper/Skipper/Skipper.php @@ -28,11 +28,17 @@ final class Skipper * @var \Rector\Skipper\SkipVoter\ClassSkipVoter */ private $classSkipVoter; - public function __construct(RectifiedAnalyzer $rectifiedAnalyzer, \Rector\Skipper\Skipper\PathSkipper $pathSkipper, ClassSkipVoter $classSkipVoter) + /** + * @readonly + * @var \Rector\Skipper\Skipper\CommentSkipper + */ + private $commentSkipper; + public function __construct(RectifiedAnalyzer $rectifiedAnalyzer, \Rector\Skipper\Skipper\PathSkipper $pathSkipper, ClassSkipVoter $classSkipVoter, \Rector\Skipper\Skipper\CommentSkipper $commentSkipper) { $this->rectifiedAnalyzer = $rectifiedAnalyzer; $this->pathSkipper = $pathSkipper; $this->classSkipVoter = $classSkipVoter; + $this->commentSkipper = $commentSkipper; } /** * @param string|object $element @@ -64,6 +70,9 @@ public function shouldSkipCurrentNode($element, string $filePath, string $rector if ($this->shouldSkipElementAndFilePath($element, $filePath)) { return \true; } - return $this->rectifiedAnalyzer->hasRectified($rectorClass, $node); + if ($this->rectifiedAnalyzer->hasRectified($rectorClass, $node)) { + return \true; + } + return $this->commentSkipper->shouldSkip($rectorClass, $node); } } diff --git a/src/Testing/PHPUnit/AbstractRectorTestCase.php b/src/Testing/PHPUnit/AbstractRectorTestCase.php index cffb3bcff04f..03c4a3da8fd9 100644 --- a/src/Testing/PHPUnit/AbstractRectorTestCase.php +++ b/src/Testing/PHPUnit/AbstractRectorTestCase.php @@ -57,6 +57,7 @@ public static function tearDownAfterClass() : void SimpleParameterProvider::setParameter(Option::AUTO_IMPORT_DOC_BLOCK_NAMES, \false); SimpleParameterProvider::setParameter(Option::REMOVE_UNUSED_IMPORTS, \false); SimpleParameterProvider::setParameter(Option::IMPORT_SHORT_CLASSES, \true); + SimpleParameterProvider::setParameter(Option::IMPORT_INSERT_SORTED, \false); SimpleParameterProvider::setParameter(Option::INDENT_CHAR, ' '); SimpleParameterProvider::setParameter(Option::INDENT_SIZE, 4); SimpleParameterProvider::setParameter(Option::POLYFILL_PACKAGES, []); @@ -200,7 +201,7 @@ private function processFilePath(string $filePath) : RectorTestResult /** @var ConfigurationFactory $configurationFactory */ $configurationFactory = $this->make(ConfigurationFactory::class); $configuration = $configurationFactory->createForTests([$filePath]); - $processResult = $this->applicationFileProcessor->processFiles([$filePath], $configuration); + $processResult = $this->applicationFileProcessor->processFiles([$filePath], $configuration, []); // return changed file contents $changedFileContents = FileSystem::read($filePath); return new RectorTestResult($changedFileContents, $processResult); diff --git a/src/Util/FileHasher.php b/src/Util/FileHasher.php index 27de016e0b46..dacea1cc14a8 100644 --- a/src/Util/FileHasher.php +++ b/src/Util/FileHasher.php @@ -34,6 +34,15 @@ public function hashFiles(array $files) : string } return $configHash; } + public function resolvePath(string $filePath) : string + { + /** @var string|false $realPath */ + $realPath = \realpath($filePath); + if ($realPath === \false) { + return $filePath; + } + return $realPath; + } private function getAlgo() : string { //see https://php.watch/articles/php-hash-benchmark diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 58070aae4ab7..96e3b5e8371e 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -1070,6 +1070,7 @@ 'Rector\\Caching\\Contract\\ValueObject\\Storage\\CacheStorageInterface' => $baseDir . '/src/Caching/Contract/ValueObject/Storage/CacheStorageInterface.php', 'Rector\\Caching\\Detector\\ChangedFilesDetector' => $baseDir . '/src/Caching/Detector/ChangedFilesDetector.php', 'Rector\\Caching\\Enum\\CacheKey' => $baseDir . '/src/Caching/Enum/CacheKey.php', + 'Rector\\Caching\\FileDependenciesCache' => $baseDir . '/src/Caching/FileDependenciesCache.php', 'Rector\\Caching\\UnchangedFilesFilter' => $baseDir . '/src/Caching/UnchangedFilesFilter.php', 'Rector\\Caching\\ValueObject\\CacheFilePaths' => $baseDir . '/src/Caching/ValueObject/CacheFilePaths.php', 'Rector\\Caching\\ValueObject\\CacheItem' => $baseDir . '/src/Caching/ValueObject/CacheItem.php', @@ -2126,6 +2127,7 @@ 'Rector\\Skipper\\SkipCriteriaResolver\\SkippedClassResolver' => $baseDir . '/src/Skipper/SkipCriteriaResolver/SkippedClassResolver.php', 'Rector\\Skipper\\SkipCriteriaResolver\\SkippedPathsResolver' => $baseDir . '/src/Skipper/SkipCriteriaResolver/SkippedPathsResolver.php', 'Rector\\Skipper\\SkipVoter\\ClassSkipVoter' => $baseDir . '/src/Skipper/SkipVoter/ClassSkipVoter.php', + 'Rector\\Skipper\\Skipper\\CommentSkipper' => $baseDir . '/src/Skipper/Skipper/CommentSkipper.php', 'Rector\\Skipper\\Skipper\\PathSkipper' => $baseDir . '/src/Skipper/Skipper/PathSkipper.php', 'Rector\\Skipper\\Skipper\\SkipSkipper' => $baseDir . '/src/Skipper/Skipper/SkipSkipper.php', 'Rector\\Skipper\\Skipper\\Skipper' => $baseDir . '/src/Skipper/Skipper/Skipper.php', diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 7dee7315d06a..a287e6da9318 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -1289,6 +1289,7 @@ class ComposerStaticInit7c12491db1a700dd78980ecb6595c088 'Rector\\Caching\\Contract\\ValueObject\\Storage\\CacheStorageInterface' => __DIR__ . '/../..' . '/src/Caching/Contract/ValueObject/Storage/CacheStorageInterface.php', 'Rector\\Caching\\Detector\\ChangedFilesDetector' => __DIR__ . '/../..' . '/src/Caching/Detector/ChangedFilesDetector.php', 'Rector\\Caching\\Enum\\CacheKey' => __DIR__ . '/../..' . '/src/Caching/Enum/CacheKey.php', + 'Rector\\Caching\\FileDependenciesCache' => __DIR__ . '/../..' . '/src/Caching/FileDependenciesCache.php', 'Rector\\Caching\\UnchangedFilesFilter' => __DIR__ . '/../..' . '/src/Caching/UnchangedFilesFilter.php', 'Rector\\Caching\\ValueObject\\CacheFilePaths' => __DIR__ . '/../..' . '/src/Caching/ValueObject/CacheFilePaths.php', 'Rector\\Caching\\ValueObject\\CacheItem' => __DIR__ . '/../..' . '/src/Caching/ValueObject/CacheItem.php', @@ -2345,6 +2346,7 @@ class ComposerStaticInit7c12491db1a700dd78980ecb6595c088 'Rector\\Skipper\\SkipCriteriaResolver\\SkippedClassResolver' => __DIR__ . '/../..' . '/src/Skipper/SkipCriteriaResolver/SkippedClassResolver.php', 'Rector\\Skipper\\SkipCriteriaResolver\\SkippedPathsResolver' => __DIR__ . '/../..' . '/src/Skipper/SkipCriteriaResolver/SkippedPathsResolver.php', 'Rector\\Skipper\\SkipVoter\\ClassSkipVoter' => __DIR__ . '/../..' . '/src/Skipper/SkipVoter/ClassSkipVoter.php', + 'Rector\\Skipper\\Skipper\\CommentSkipper' => __DIR__ . '/../..' . '/src/Skipper/Skipper/CommentSkipper.php', 'Rector\\Skipper\\Skipper\\PathSkipper' => __DIR__ . '/../..' . '/src/Skipper/Skipper/PathSkipper.php', 'Rector\\Skipper\\Skipper\\SkipSkipper' => __DIR__ . '/../..' . '/src/Skipper/Skipper/SkipSkipper.php', 'Rector\\Skipper\\Skipper\\Skipper' => __DIR__ . '/../..' . '/src/Skipper/Skipper/Skipper.php',