From 06f85e4a68acba9ea05d7894e79df5661663e452 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 12 Apr 2021 12:34:04 +0200 Subject: [PATCH] Refactor file processors towards universal collector (#6085) Co-authored-by: kaizen-ci --- .../Caching/FileSystem/DependencyResolver.php | 36 ++-- .../Application/ErrorAndDiffCollector.php | 88 +-------- .../Collector/AffectedFilesCollector.php | 14 +- .../Output/OutputFormatterInterface.php | 4 +- .../Output/ConsoleOutputFormatter.php | 39 ++-- .../Output/JsonOutputFormatter.php | 14 +- .../ValueObjectFactory/FileDiffFactory.php | 53 ++++++ packages/NodeRemoval/NodeRemover.php | 6 +- .../NodeScopeAndMetadataDecorator.php | 2 +- .../NodeTypeResolver/PHPStan/TypeHasher.php | 19 +- .../TypeMapper/UnionTypeMapper.php | 1 - packages/PhpAttribute/ValueObject/TagName.php | 13 -- .../Collector/NodesToRemoveCollector.php | 3 +- .../PHPUnit/AbstractRectorTestCase.php | 81 +++----- phpstan.neon | 10 +- .../config/configured_rule.php | 1 - ...ltipleClassFileToPsr4ClassesRectorTest.php | 5 - .../config/configured_rule.php | 1 - .../config/configured_rule.php | 1 - .../FileProcessor}/ComposerFileProcessor.php | 69 ++++--- .../MethodCallToClassMethodParser.php | 12 +- .../FuncCall/RemoveExtraParametersRector.php | 4 + .../ReturnTypeDeclarationRector.php | 4 - src/Application/ActiveRectorsProvider.php | 19 +- src/Application/ApplicationFileProcessor.php | 101 ++++++++++ .../FileDecorator/FileDiffFileDecorator.php | 41 ++++ src/Application/FileProcessor.php | 17 +- .../PhpFileProcessor.php} | 178 +++++++----------- src/Autoloading/BootstrapFilesIncluder.php | 53 ++++++ src/Configuration/Configuration.php | 21 --- src/Console/Command/ProcessCommand.php | 176 ++++++++--------- src/Contract/PostRunnerInterface.php | 10 - .../Processor/FileProcessorInterface.php | 10 +- src/NonPhpFile/NonPhpFileProcessor.php | 43 +++-- src/NonPhpFile/NonPhpFileProcessorService.php | 124 ------------ .../NodeTraverser/RectorNodeTraverser.php | 9 +- src/PhpParser/Parser/FunctionLikeParser.php | 70 +------ .../FunctionLikeReflectionParser.php | 74 ++++++++ src/Reporting/MissingRectorRulesReporter.php | 26 ++- src/ValueObject/Application/File.php | 86 +++++++++ .../NonPhpFile/NonPhpFileChange.php | 33 ---- src/ValueObject/ProcessResult.php | 111 +++++++++++ .../Application/FileFactory.php | 68 +++++++ .../ProcessResultFactory.php | 45 +++++ .../ApplicationFileProcessorTest.php | 54 ++++++ .../Fixture/bar_stays_bar.txt | 0 .../Fixture/foo_to_bar.txt | 0 .../Source/TextFileProcessor.php | 43 +++++ .../config/configured_rule.php | 11 ++ .../NonPhpFileProcessorServiceTest.php | 46 ----- .../Source/TextNonPhpFileProcessor.php | 32 ---- tests/NonPhpFile/config/configured_rule.php | 15 -- .../AllowedAutoloadedTypeAnalyzer.php | 2 +- .../Fixture/InstanceofWithType.php | 4 +- .../Fixture/IsAWithType.php | 4 +- .../Fixture/SkipSymfony.php | 15 ++ .../NoInstanceOfStaticReflectionRuleTest.php | 1 + 57 files changed, 1163 insertions(+), 859 deletions(-) create mode 100644 packages/ChangesReporting/ValueObjectFactory/FileDiffFactory.php delete mode 100644 packages/PhpAttribute/ValueObject/TagName.php rename rules/Composer/{Processor => Application/FileProcessor}/ComposerFileProcessor.php (58%) create mode 100644 src/Application/ApplicationFileProcessor.php create mode 100644 src/Application/FileDecorator/FileDiffFileDecorator.php rename src/Application/{RectorApplication.php => FileProcessor/PhpFileProcessor.php} (55%) create mode 100644 src/Autoloading/BootstrapFilesIncluder.php delete mode 100644 src/Contract/PostRunnerInterface.php delete mode 100644 src/NonPhpFile/NonPhpFileProcessorService.php create mode 100644 src/Reflection/FunctionLikeReflectionParser.php create mode 100644 src/ValueObject/Application/File.php delete mode 100644 src/ValueObject/NonPhpFile/NonPhpFileChange.php create mode 100644 src/ValueObject/ProcessResult.php create mode 100644 src/ValueObjectFactory/Application/FileFactory.php create mode 100644 src/ValueObjectFactory/ProcessResultFactory.php create mode 100644 tests/Application/ApplicationFileProcessor/ApplicationFileProcessorTest.php rename tests/{NonPhpFile => Application/ApplicationFileProcessor}/Fixture/bar_stays_bar.txt (100%) rename tests/{NonPhpFile => Application/ApplicationFileProcessor}/Fixture/foo_to_bar.txt (100%) create mode 100644 tests/Application/ApplicationFileProcessor/Source/TextFileProcessor.php create mode 100644 tests/Application/ApplicationFileProcessor/config/configured_rule.php delete mode 100644 tests/NonPhpFile/NonPhpFileProcessorServiceTest.php delete mode 100644 tests/NonPhpFile/Source/TextNonPhpFileProcessor.php delete mode 100644 tests/NonPhpFile/config/configured_rule.php create mode 100644 utils/phpstan-extensions/tests/Rule/NoInstanceOfStaticReflectionRule/Fixture/SkipSymfony.php diff --git a/packages/Caching/FileSystem/DependencyResolver.php b/packages/Caching/FileSystem/DependencyResolver.php index 0fe72cdcf8b..448dec8874d 100644 --- a/packages/Caching/FileSystem/DependencyResolver.php +++ b/packages/Caching/FileSystem/DependencyResolver.php @@ -6,9 +6,10 @@ namespace Rector\Caching\FileSystem; use PhpParser\Node; use PHPStan\Analyser\MutatingScope; +use PHPStan\Analyser\NodeScopeResolver; use PHPStan\Dependency\DependencyResolver as PHPStanDependencyResolver; use PHPStan\File\FileHelper; -use Rector\Core\Configuration\Configuration; +use Symplify\PackageBuilder\Reflection\PrivatesAccessor; final class DependencyResolver { @@ -17,24 +18,31 @@ final class DependencyResolver */ private $fileHelper; - /** - * @var Configuration - */ - private $configuration; - /** * @var PHPStanDependencyResolver */ private $phpStanDependencyResolver; + /** + * @var NodeScopeResolver + */ + private $nodeScopeResolver; + + /** + * @var PrivatesAccessor + */ + private $privatesAccessor; + public function __construct( - Configuration $configuration, + NodeScopeResolver $nodeScopeResolver, PHPStanDependencyResolver $phpStanDependencyResolver, - FileHelper $fileHelper + FileHelper $fileHelper, + PrivatesAccessor $privatesAccessor ) { $this->fileHelper = $fileHelper; - $this->configuration = $configuration; $this->phpStanDependencyResolver = $phpStanDependencyResolver; + $this->nodeScopeResolver = $nodeScopeResolver; + $this->privatesAccessor = $privatesAccessor; } /** @@ -42,12 +50,10 @@ final class DependencyResolver */ public function resolveDependencies(Node $node, MutatingScope $mutatingScope): array { - $fileInfos = $this->configuration->getFileInfos(); - - $analysedFileAbsolutesPaths = []; - foreach ($fileInfos as $fileInfo) { - $analysedFileAbsolutesPaths[] = $fileInfo->getRealPath(); - } + $analysedFileAbsolutesPaths = $this->privatesAccessor->getPrivateProperty( + $this->nodeScopeResolver, + 'analysedFiles' + ); $dependencyFiles = []; diff --git a/packages/ChangesReporting/Application/ErrorAndDiffCollector.php b/packages/ChangesReporting/Application/ErrorAndDiffCollector.php index 7e0609edb33..af1df1014e2 100644 --- a/packages/ChangesReporting/Application/ErrorAndDiffCollector.php +++ b/packages/ChangesReporting/Application/ErrorAndDiffCollector.php @@ -5,14 +5,11 @@ declare(strict_types=1); namespace Rector\ChangesReporting\Application; use PHPStan\AnalysedCodeException; -use Rector\ChangesReporting\Collector\RectorChangeCollector; use Rector\Core\Application\FileSystem\RemovedAndAddedFilesCollector; -use Rector\Core\Differ\DefaultDiffer; use Rector\Core\Error\ExceptionCorrector; +use Rector\Core\ValueObject\Application\File; use Rector\Core\ValueObject\Application\RectorError; -use Rector\Core\ValueObject\Reporting\FileDiff; use Rector\PostRector\Collector\NodesToRemoveCollector; -use Symplify\ConsoleColorDiff\Console\Output\ConsoleDiffer; use Symplify\SmartFileSystem\SmartFileInfo; use Throwable; @@ -23,16 +20,6 @@ final class ErrorAndDiffCollector */ private $errors = []; - /** - * @var FileDiff[] - */ - private $fileDiffs = []; - - /** - * @var RectorChangeCollector - */ - private $rectorChangeCollector; - /** * @var ExceptionCorrector */ @@ -48,30 +35,14 @@ final class ErrorAndDiffCollector */ private $nodesToRemoveCollector; - /** - * @var ConsoleDiffer - */ - private $consoleDiffer; - - /** - * @var DefaultDiffer - */ - private $defaultDiffer; - public function __construct( ExceptionCorrector $exceptionCorrector, NodesToRemoveCollector $nodesToRemoveCollector, - RectorChangeCollector $rectorChangeCollector, - RemovedAndAddedFilesCollector $removedAndAddedFilesCollector, - ConsoleDiffer $consoleDiffer, - DefaultDiffer $defaultDiffer + RemovedAndAddedFilesCollector $removedAndAddedFilesCollector ) { - $this->rectorChangeCollector = $rectorChangeCollector; $this->exceptionCorrector = $exceptionCorrector; $this->removedAndAddedFilesCollector = $removedAndAddedFilesCollector; $this->nodesToRemoveCollector = $nodesToRemoveCollector; - $this->consoleDiffer = $consoleDiffer; - $this->defaultDiffer = $defaultDiffer; } /** @@ -87,7 +58,7 @@ final class ErrorAndDiffCollector return $this->removedAndAddedFilesCollector->getAffectedFilesCount(); } - public function getAddFilesCount(): int + public function getAddedFilesCount(): int { return $this->removedAndAddedFilesCollector->getAddedFileCount(); } @@ -102,55 +73,10 @@ final class ErrorAndDiffCollector return $this->nodesToRemoveCollector->getCount(); } - public function addFileDiff(SmartFileInfo $smartFileInfo, string $newContent, string $oldContent): void - { - if ($newContent === $oldContent) { - return; - } - - $rectorChanges = $this->rectorChangeCollector->getRectorChangesByFileInfo($smartFileInfo); - - // always keep the most recent diff - $fileDiff = new FileDiff( - $smartFileInfo, - $this->defaultDiffer->diff($oldContent, $newContent), - $this->consoleDiffer->diff($oldContent, $newContent), - $rectorChanges - ); - $this->fileDiffs[$smartFileInfo->getRealPath()] = $fileDiff; - } - - /** - * @return FileDiff[] - */ - public function getFileDiffs(): array - { - return $this->fileDiffs; - } - - /** - * @return SmartFileInfo[] - */ - public function getAffectedFileInfos(): array - { - $fileInfos = []; - foreach ($this->fileDiffs as $fileDiff) { - $fileInfos[] = $fileDiff->getFileInfo(); - } - - return array_unique($fileInfos); - } - - public function getFileDiffsCount(): int - { - return count($this->fileDiffs); - } - - public function addAutoloadError(AnalysedCodeException $analysedCodeException, SmartFileInfo $fileInfo): void + public function addAutoloadError(AnalysedCodeException $analysedCodeException, File $file): void { $message = $this->exceptionCorrector->getAutoloadExceptionMessageAndAddLocation($analysedCodeException); - - $this->errors[] = new RectorError($fileInfo, $message); + $this->errors[] = new RectorError($file->getSmartFileInfo(), $message); } public function addErrorWithRectorClassMessageAndFileInfo( @@ -171,10 +97,10 @@ final class ErrorAndDiffCollector } } - public function hasErrors(SmartFileInfo $phpFileInfo): bool + public function hasSmartFileErrors(File $file): bool { foreach ($this->errors as $error) { - if ($error->getFileInfo() === $phpFileInfo) { + if ($error->getFileInfo() === $file->getSmartFileInfo()) { return true; } } diff --git a/packages/ChangesReporting/Collector/AffectedFilesCollector.php b/packages/ChangesReporting/Collector/AffectedFilesCollector.php index 2c9be12e611..75accc5a28a 100644 --- a/packages/ChangesReporting/Collector/AffectedFilesCollector.php +++ b/packages/ChangesReporting/Collector/AffectedFilesCollector.php @@ -4,21 +4,22 @@ declare(strict_types=1); namespace Rector\ChangesReporting\Collector; -use Symplify\SmartFileSystem\SmartFileInfo; +use Rector\Core\ValueObject\Application\File; final class AffectedFilesCollector { /** - * @var SmartFileInfo[] + * @var File[] */ private $affectedFiles = []; - public function addFile(SmartFileInfo $fileInfo): void + public function addFile(File $file): void { - $this->affectedFiles[$fileInfo->getRealPath()] = $fileInfo; + $fileInfo = $file->getSmartFileInfo(); + $this->affectedFiles[$fileInfo->getRealPath()] = $file; } - public function getNext(): ?SmartFileInfo + public function getNext(): ?File { if ($this->affectedFiles !== []) { return current($this->affectedFiles); @@ -26,8 +27,9 @@ final class AffectedFilesCollector return null; } - public function removeFromList(SmartFileInfo $fileInfo): void + public function removeFromList(File $file): void { + $fileInfo = $file->getSmartFileInfo(); unset($this->affectedFiles[$fileInfo->getRealPath()]); } } diff --git a/packages/ChangesReporting/Contract/Output/OutputFormatterInterface.php b/packages/ChangesReporting/Contract/Output/OutputFormatterInterface.php index 2ec41a0d549..77c4a375e9e 100644 --- a/packages/ChangesReporting/Contract/Output/OutputFormatterInterface.php +++ b/packages/ChangesReporting/Contract/Output/OutputFormatterInterface.php @@ -4,11 +4,11 @@ declare(strict_types=1); namespace Rector\ChangesReporting\Contract\Output; -use Rector\ChangesReporting\Application\ErrorAndDiffCollector; +use Rector\Core\ValueObject\ProcessResult; interface OutputFormatterInterface { public function getName(): string; - public function report(ErrorAndDiffCollector $errorAndDiffCollector): void; + public function report(ProcessResult $processResult): void; } diff --git a/packages/ChangesReporting/Output/ConsoleOutputFormatter.php b/packages/ChangesReporting/Output/ConsoleOutputFormatter.php index ac452e0ffd3..f2d6d01c301 100644 --- a/packages/ChangesReporting/Output/ConsoleOutputFormatter.php +++ b/packages/ChangesReporting/Output/ConsoleOutputFormatter.php @@ -6,11 +6,11 @@ namespace Rector\ChangesReporting\Output; use Nette\Utils\Strings; use Rector\ChangesReporting\Annotation\RectorsChangelogResolver; -use Rector\ChangesReporting\Application\ErrorAndDiffCollector; use Rector\ChangesReporting\Contract\Output\OutputFormatterInterface; use Rector\Core\Configuration\Configuration; use Rector\Core\Configuration\Option; use Rector\Core\ValueObject\Application\RectorError; +use Rector\Core\ValueObject\ProcessResult; use Rector\Core\ValueObject\Reporting\FileDiff; use Symfony\Component\Console\Style\SymfonyStyle; @@ -52,7 +52,7 @@ final class ConsoleOutputFormatter implements OutputFormatterInterface $this->rectorsChangelogResolver = $rectorsChangelogResolver; } - public function report(ErrorAndDiffCollector $errorAndDiffCollector): void + public function report(ProcessResult $processResult): void { if ($this->configuration->getOutputFile()) { $message = sprintf( @@ -65,17 +65,17 @@ final class ConsoleOutputFormatter implements OutputFormatterInterface } if ($this->configuration->shouldShowDiffs()) { - $this->reportFileDiffs($errorAndDiffCollector->getFileDiffs()); + $this->reportFileDiffs($processResult->getFileDiffs()); } - $this->reportErrors($errorAndDiffCollector->getErrors()); - $this->reportRemovedFilesAndNodes($errorAndDiffCollector); + $this->reportErrors($processResult->getErrors()); + $this->reportRemovedFilesAndNodes($processResult); - if ($errorAndDiffCollector->getErrors() !== []) { + if ($processResult->getErrors() !== []) { return; } - $message = $this->createSuccessMessage($errorAndDiffCollector); + $message = $this->createSuccessMessage($processResult); $this->symfonyStyle->success($message); } @@ -145,19 +145,19 @@ final class ConsoleOutputFormatter implements OutputFormatterInterface } } - private function reportRemovedFilesAndNodes(ErrorAndDiffCollector $errorAndDiffCollector): void + private function reportRemovedFilesAndNodes(ProcessResult $processResult): void { - if ($errorAndDiffCollector->getAddFilesCount() !== 0) { - $message = sprintf('%d files were added', $errorAndDiffCollector->getAddFilesCount()); + if ($processResult->getAddedFilesCount() !== 0) { + $message = sprintf('%d files were added', $processResult->getAddedFilesCount()); $this->symfonyStyle->note($message); } - if ($errorAndDiffCollector->getRemovedFilesCount() !== 0) { - $message = sprintf('%d files were removed', $errorAndDiffCollector->getRemovedFilesCount()); + if ($processResult->getRemovedFilesCount() !== 0) { + $message = sprintf('%d files were removed', $processResult->getRemovedFilesCount()); $this->symfonyStyle->note($message); } - $this->reportRemovedNodes($errorAndDiffCollector); + $this->reportRemovedNodes($processResult); } private function normalizePathsToRelativeWithLine(string $errorMessage): string @@ -167,20 +167,19 @@ final class ConsoleOutputFormatter implements OutputFormatterInterface return Strings::replace($errorMessage, self::ON_LINE_REGEX, ':'); } - private function reportRemovedNodes(ErrorAndDiffCollector $errorAndDiffCollector): void + private function reportRemovedNodes(ProcessResult $processResult): void { - if ($errorAndDiffCollector->getRemovedNodeCount() === 0) { + if ($processResult->getRemovedNodeCount() === 0) { return; } - $message = sprintf('%d nodes were removed', $errorAndDiffCollector->getRemovedNodeCount()); + $message = sprintf('%d nodes were removed', $processResult->getRemovedNodeCount()); $this->symfonyStyle->warning($message); } - private function createSuccessMessage(ErrorAndDiffCollector $errorAndDiffCollector): string + private function createSuccessMessage(ProcessResult $processResult): string { - $changeCount = $errorAndDiffCollector->getFileDiffsCount() - + $errorAndDiffCollector->getRemovedAndAddedFilesCount(); + $changeCount = count($processResult->getFileDiffs()) + $processResult->getRemovedAndAddedFilesCount(); if ($changeCount === 0) { return 'Rector is done!'; @@ -203,7 +202,7 @@ final class ConsoleOutputFormatter implements OutputFormatterInterface $rectorsChangelogsLines = []; foreach ($rectorsChangelogs as $rectorClass => $changelog) { - $rectorsChangelogsLines[] = $changelog === null ? $rectorClass : $rectorClass . ' ' . $changelog; + $rectorsChangelogsLines[] = $changelog === null ? $rectorClass : $rectorClass . ' (' . $changelog . ')'; } return $rectorsChangelogsLines; diff --git a/packages/ChangesReporting/Output/JsonOutputFormatter.php b/packages/ChangesReporting/Output/JsonOutputFormatter.php index 3d4f852b53a..efe4ce173c3 100644 --- a/packages/ChangesReporting/Output/JsonOutputFormatter.php +++ b/packages/ChangesReporting/Output/JsonOutputFormatter.php @@ -6,9 +6,9 @@ namespace Rector\ChangesReporting\Output; use Nette\Utils\Json; use Rector\ChangesReporting\Annotation\RectorsChangelogResolver; -use Rector\ChangesReporting\Application\ErrorAndDiffCollector; use Rector\ChangesReporting\Contract\Output\OutputFormatterInterface; use Rector\Core\Configuration\Configuration; +use Rector\Core\ValueObject\ProcessResult; use Symplify\SmartFileSystem\SmartFileSystem; final class JsonOutputFormatter implements OutputFormatterInterface @@ -48,7 +48,7 @@ final class JsonOutputFormatter implements OutputFormatterInterface return self::NAME; } - public function report(ErrorAndDiffCollector $errorAndDiffCollector): void + public function report(ProcessResult $processResult): void { $errorsArray = [ 'meta' => [ @@ -56,13 +56,13 @@ final class JsonOutputFormatter implements OutputFormatterInterface 'config' => $this->configuration->getMainConfigFilePath(), ], 'totals' => [ - 'changed_files' => $errorAndDiffCollector->getFileDiffsCount(), - 'removed_and_added_files_count' => $errorAndDiffCollector->getRemovedAndAddedFilesCount(), - 'removed_node_count' => $errorAndDiffCollector->getRemovedNodeCount(), + 'changed_files' => count($processResult->getFileDiffs()), + 'removed_and_added_files_count' => $processResult->getRemovedAndAddedFilesCount(), + 'removed_node_count' => $processResult->getRemovedNodeCount(), ], ]; - $fileDiffs = $errorAndDiffCollector->getFileDiffs(); + $fileDiffs = $processResult->getFileDiffs(); ksort($fileDiffs); foreach ($fileDiffs as $fileDiff) { $relativeFilePath = $fileDiff->getRelativeFilePath(); @@ -80,7 +80,7 @@ final class JsonOutputFormatter implements OutputFormatterInterface $errorsArray['changed_files'][] = $relativeFilePath; } - $errors = $errorAndDiffCollector->getErrors(); + $errors = $processResult->getErrors(); $errorsArray['totals']['errors'] = count($errors); $errorsData = $this->createErrorsData($errors); diff --git a/packages/ChangesReporting/ValueObjectFactory/FileDiffFactory.php b/packages/ChangesReporting/ValueObjectFactory/FileDiffFactory.php new file mode 100644 index 00000000000..48ce27714d2 --- /dev/null +++ b/packages/ChangesReporting/ValueObjectFactory/FileDiffFactory.php @@ -0,0 +1,53 @@ +rectorChangeCollector = $rectorChangeCollector; + $this->defaultDiffer = $defaultDiffer; + $this->consoleDiffer = $consoleDiffer; + } + + public function createFileDiff(File $file, string $oldContent, string $newContent): FileDiff + { + $smartFileInfo = $file->getSmartFileInfo(); + $rectorChanges = $this->rectorChangeCollector->getRectorChangesByFileInfo($smartFileInfo); + + // always keep the most recent diff + return new FileDiff( + $smartFileInfo, + $this->defaultDiffer->diff($oldContent, $newContent), + $this->consoleDiffer->diff($oldContent, $newContent), + $rectorChanges + ); + } +} diff --git a/packages/NodeRemoval/NodeRemover.php b/packages/NodeRemoval/NodeRemover.php index 536b45616f2..2bcf0b93752 100644 --- a/packages/NodeRemoval/NodeRemover.php +++ b/packages/NodeRemoval/NodeRemover.php @@ -95,11 +95,7 @@ final class NodeRemover */ public function removeParam(ClassMethod $classMethod, $keyOrParam): void { - if ($keyOrParam instanceof Param) { - $key = $keyOrParam->getAttribute(AttributeKey::PARAMETER_POSITION); - } else { - $key = $keyOrParam; - } + $key = $keyOrParam instanceof Param ? $keyOrParam->getAttribute(AttributeKey::PARAMETER_POSITION) : $keyOrParam; if ($classMethod->params === null) { throw new ShouldNotHappenException(); diff --git a/packages/NodeTypeResolver/NodeScopeAndMetadataDecorator.php b/packages/NodeTypeResolver/NodeScopeAndMetadataDecorator.php index 1d116d7bb20..159d2dfd814 100644 --- a/packages/NodeTypeResolver/NodeScopeAndMetadataDecorator.php +++ b/packages/NodeTypeResolver/NodeScopeAndMetadataDecorator.php @@ -92,7 +92,7 @@ final class NodeScopeAndMetadataDecorator * @param Node[] $nodes * @return Node[] */ - public function decorateNodesFromFile(array $nodes, SmartFileInfo $smartFileInfo, bool $needsScope = false): array + public function decorateNodesFromFile(array $nodes, SmartFileInfo $smartFileInfo): array { $nodeTraverser = new NodeTraverser(); $nodeTraverser->addVisitor(new NameResolver(null, [ diff --git a/packages/NodeTypeResolver/PHPStan/TypeHasher.php b/packages/NodeTypeResolver/PHPStan/TypeHasher.php index c66e609cb99..49e745fd91d 100644 --- a/packages/NodeTypeResolver/PHPStan/TypeHasher.php +++ b/packages/NodeTypeResolver/PHPStan/TypeHasher.php @@ -78,15 +78,20 @@ final class TypeHasher return $booleanType->describe(VerbosityLevel::precise()); } + $normalizedUnionType = clone $sortedUnionType; + // change alias to non-alias - $sortedUnionType = TypeTraverser::map($sortedUnionType, function (Type $type, callable $callable): Type { - if (! $type instanceof AliasedObjectType) { - return $callable($type); + $normalizedUnionType = TypeTraverser::map( + $normalizedUnionType, + function (Type $type, callable $callable): Type { + if (! $type instanceof AliasedObjectType) { + return $callable($type); + } + + return new FullyQualifiedObjectType($type->getFullyQualifiedClass()); } + ); - return new FullyQualifiedObjectType($type->getFullyQualifiedClass()); - }); - - return $sortedUnionType->describe(VerbosityLevel::cache()); + return $normalizedUnionType->describe(VerbosityLevel::cache()); } } diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php index 7b190599df8..7b81cec260c 100644 --- a/packages/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php +++ b/packages/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php @@ -21,7 +21,6 @@ use PHPStan\Type\TypeWithClassName; use PHPStan\Type\UnionType; use PHPStan\Type\VoidType; use Rector\BetterPhpDocParser\ValueObject\Type\BracketsAwareUnionTypeNode; -use Rector\CodeQuality\Tests\Rector\If_\ExplicitBoolCompareRector\Fixture\Nullable; use Rector\Core\Exception\ShouldNotHappenException; use Rector\Core\Php\PhpVersionProvider; use Rector\Core\Rector\AbstractRector; diff --git a/packages/PhpAttribute/ValueObject/TagName.php b/packages/PhpAttribute/ValueObject/TagName.php deleted file mode 100644 index fd0803bcb4a..00000000000 --- a/packages/PhpAttribute/ValueObject/TagName.php +++ /dev/null @@ -1,13 +0,0 @@ -getAttribute(AttributeKey::FILE_INFO); if ($fileInfo !== null) { - $this->affectedFilesCollector->addFile($fileInfo); + $this->affectedFilesCollector->addFile(new File($fileInfo, $fileInfo->getContents())); } /** @var Stmt $node */ diff --git a/packages/Testing/PHPUnit/AbstractRectorTestCase.php b/packages/Testing/PHPUnit/AbstractRectorTestCase.php index a57be64ade8..05c57c16521 100644 --- a/packages/Testing/PHPUnit/AbstractRectorTestCase.php +++ b/packages/Testing/PHPUnit/AbstractRectorTestCase.php @@ -5,25 +5,24 @@ declare(strict_types=1); namespace Rector\Testing\PHPUnit; use Iterator; -use Nette\Utils\Json; use Nette\Utils\Strings; use PHPStan\Analyser\NodeScopeResolver; use PHPUnit\Framework\ExpectationFailedException; use Psr\Container\ContainerInterface; -use Rector\Composer\Modifier\ComposerModifier; +use Rector\Core\Application\ApplicationFileProcessor; use Rector\Core\Application\FileProcessor; use Rector\Core\Application\FileSystem\RemovedAndAddedFilesCollector; use Rector\Core\Bootstrap\RectorConfigsResolver; +use Rector\Core\Configuration\Configuration; use Rector\Core\Configuration\Option; use Rector\Core\Exception\ShouldNotHappenException; use Rector\Core\HttpKernel\RectorKernel; use Rector\Core\NonPhpFile\NonPhpFileProcessor; use Rector\Core\PhpParser\Printer\BetterStandardPrinter; -use Rector\Core\ValueObject\StaticNonPhpFileSuffixes; +use Rector\Core\ValueObject\Application\File; use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocatorProvider; use Rector\Testing\Contract\RectorTestInterface; use Rector\Testing\PHPUnit\Behavior\MovingFilesTrait; -use Symplify\ComposerJsonManipulator\ComposerJsonFactory; use Symplify\EasyTesting\DataProvider\StaticFixtureFinder; use Symplify\EasyTesting\DataProvider\StaticFixtureUpdater; use Symplify\EasyTesting\StaticFixtureSplitter; @@ -76,14 +75,9 @@ abstract class AbstractRectorTestCase extends AbstractKernelTestCase implements private $dynamicSourceLocatorProvider; /** - * @var ComposerJsonFactory + * @var ApplicationFileProcessor */ - private $composerJsonFactory; - - /** - * @var ComposerModifier - */ - private $composerModifier; + private $applicationFileProcessor; protected function setUp(): void { @@ -99,15 +93,17 @@ abstract class AbstractRectorTestCase extends AbstractKernelTestCase implements $this->fileProcessor = $this->getService(FileProcessor::class); $this->nonPhpFileProcessor = $this->getService(NonPhpFileProcessor::class); + $this->applicationFileProcessor = $this->getService(ApplicationFileProcessor::class); $this->parameterProvider = $this->getService(ParameterProvider::class); $this->betterStandardPrinter = $this->getService(BetterStandardPrinter::class); $this->dynamicSourceLocatorProvider = $this->getService(DynamicSourceLocatorProvider::class); - $this->composerJsonFactory = $this->getService(ComposerJsonFactory::class); - $this->composerModifier = $this->getService(ComposerModifier::class); - $this->removedAndAddedFilesCollector = $this->getService(RemovedAndAddedFilesCollector::class); $this->removedAndAddedFilesCollector->reset(); + + /** @var Configuration $configuration */ + $configuration = $this->getService(Configuration::class); + $configuration->setIsDryRun(true); } public function provideConfigFilePath(): string @@ -131,29 +127,11 @@ abstract class AbstractRectorTestCase extends AbstractKernelTestCase implements ); $inputFileInfo = $inputFileInfoAndExpectedFileInfo->getInputFileInfo(); - if ($inputFileInfo->getSuffix() === 'json') { - $inputFileInfoAndExpected = StaticFixtureSplitter::splitFileInfoToLocalInputAndExpected($fixtureFileInfo); - $composerJson = $this->composerJsonFactory->createFromFileInfo( - $inputFileInfoAndExpected->getInputFileInfo() - ); - $this->composerModifier->modify($composerJson); + $expectedFileInfo = $inputFileInfoAndExpectedFileInfo->getExpectedFileInfo(); + $this->doTestFileMatchesExpectedContent($inputFileInfo, $expectedFileInfo, $fixtureFileInfo); - $changedComposerJson = Json::encode($composerJson->getJsonArray(), Json::PRETTY); - $this->assertJsonStringEqualsJsonString($inputFileInfoAndExpected->getExpected(), $changedComposerJson); - } else { - // needed for PHPStan, because the analyzed file is just created in /temp - need for trait and similar deps - /** @var NodeScopeResolver $nodeScopeResolver */ - $nodeScopeResolver = $this->getService(NodeScopeResolver::class); - $nodeScopeResolver->setAnalysedFiles([$inputFileInfo->getRealPath()]); - - $this->dynamicSourceLocatorProvider->setFileInfo($inputFileInfo); - - $expectedFileInfo = $inputFileInfoAndExpectedFileInfo->getExpectedFileInfo(); - - $this->doTestFileMatchesExpectedContent($inputFileInfo, $expectedFileInfo, $fixtureFileInfo); - $this->originalTempFileInfo = $inputFileInfo; - } + $this->originalTempFileInfo = $inputFileInfo; } protected function doTestExtraFile(string $expectedExtraFileName, string $expectedExtraContentFilePath): void @@ -206,6 +184,11 @@ abstract class AbstractRectorTestCase extends AbstractKernelTestCase implements $changedContent = $this->processFileInfo($originalFileInfo); + // file is removed, we cannot compare it + if ($this->removedAndAddedFilesCollector->isFileRemoved($originalFileInfo)) { + return; + } + $relativeFilePathFromCwd = $fixtureFileInfo->getRelativeFilePathFromCwd(); try { @@ -227,26 +210,18 @@ abstract class AbstractRectorTestCase extends AbstractKernelTestCase implements return Strings::replace($string, '#\r\n|\r|\n#', "\n"); } - private function processFileInfo(SmartFileInfo $originalFileInfo): string + private function processFileInfo(SmartFileInfo $fileInfo): string { - if (! Strings::endsWith($originalFileInfo->getFilename(), '.blade.php') && in_array( - $originalFileInfo->getSuffix(), - ['php', 'phpt'], - true - )) { - $this->fileProcessor->refactor($originalFileInfo); - $this->fileProcessor->postFileRefactor($originalFileInfo); + $this->dynamicSourceLocatorProvider->setFileInfo($fileInfo); - // mimic post-rectors - $changedContent = $this->fileProcessor->printToString($originalFileInfo); - } elseif (Strings::match($originalFileInfo->getFilename(), StaticNonPhpFileSuffixes::getSuffixRegexPattern())) { - $nonPhpFileChange = $this->nonPhpFileProcessor->process($originalFileInfo); + // needed for PHPStan, because the analyzed file is just created in /temp - need for trait and similar deps + /** @var NodeScopeResolver $nodeScopeResolver */ + $nodeScopeResolver = $this->getService(NodeScopeResolver::class); + $nodeScopeResolver->setAnalysedFiles([$fileInfo->getRealPath()]); - $changedContent = $nonPhpFileChange !== null ? $nonPhpFileChange->getNewContent() : ''; - } else { - $message = sprintf('Suffix "%s" is not supported yet', $originalFileInfo->getSuffix()); - throw new ShouldNotHappenException($message); - } - return $changedContent; + $file = new File($fileInfo, $fileInfo->getContents()); + $this->applicationFileProcessor->run([$file]); + + return $file->getFileContent(); } } diff --git a/phpstan.neon b/phpstan.neon index 01eea32753a..78554a00898 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -443,7 +443,6 @@ parameters: - message: '#Instead of "(.*?)" use ReflectionProvider service (.*?) for static reflection to work#' paths: - - src/Application/RectorApplication.php - src/Console/Command/ProcessCommand.php # mimics original doctrine/annotations parser, improve later when finished @@ -509,3 +508,12 @@ parameters: - '#Cognitive complexity for "Rector\\PHPStanStaticTypeMapper\\TypeMapper\\UnionTypeMapper\:\:mapToPhpParserNode\(\)" is 10, keep it under 9#' - '#Method Rector\\NodeNameResolver\\NodeNameResolver\:\:matchRectorBacktraceCall\(\) return type has no value type specified in iterable type array#' + - + message: '#Do not inherit from abstract class, better use composition#' + paths: + - src/PhpParser/Parser/FunctionLikeParser.php + + - + message: '#Unreachable statement \- code above always terminates#' + paths: + - src/Application/FileProcessor/PhpFileProcessor.php diff --git a/rules-tests/NetteToSymfony/Rector/Class_/FormControlToControllerAndFormTypeRector/config/configured_rule.php b/rules-tests/NetteToSymfony/Rector/Class_/FormControlToControllerAndFormTypeRector/config/configured_rule.php index 39375a2f944..53e9f1d0937 100644 --- a/rules-tests/NetteToSymfony/Rector/Class_/FormControlToControllerAndFormTypeRector/config/configured_rule.php +++ b/rules-tests/NetteToSymfony/Rector/Class_/FormControlToControllerAndFormTypeRector/config/configured_rule.php @@ -7,6 +7,5 @@ use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigura return static function (ContainerConfigurator $containerConfigurator): void { $services = $containerConfigurator->services(); - $services->set(FormControlToControllerAndFormTypeRector::class); }; diff --git a/rules-tests/PSR4/Rector/Namespace_/MultipleClassFileToPsr4ClassesRector/MultipleClassFileToPsr4ClassesRectorTest.php b/rules-tests/PSR4/Rector/Namespace_/MultipleClassFileToPsr4ClassesRector/MultipleClassFileToPsr4ClassesRectorTest.php index 460d17a44bc..2cb0fdf0151 100644 --- a/rules-tests/PSR4/Rector/Namespace_/MultipleClassFileToPsr4ClassesRector/MultipleClassFileToPsr4ClassesRectorTest.php +++ b/rules-tests/PSR4/Rector/Namespace_/MultipleClassFileToPsr4ClassesRector/MultipleClassFileToPsr4ClassesRectorTest.php @@ -5,7 +5,6 @@ declare(strict_types=1); namespace Rector\Tests\PSR4\Rector\Namespace_\MultipleClassFileToPsr4ClassesRector; use Iterator; -use Rector\Core\Application\FileSystem\RemovedAndAddedFilesCollector; use Rector\FileSystemRector\ValueObject\AddedFileWithContent; use Rector\Testing\PHPUnit\AbstractRectorTestCase; use Symplify\SmartFileSystem\SmartFileInfo; @@ -19,10 +18,6 @@ final class MultipleClassFileToPsr4ClassesRectorTest extends AbstractRectorTestC */ public function test(SmartFileInfo $originalFileInfo, array $expectedFilePathsWithContents): void { - /** @var RemovedAndAddedFilesCollector $removedAndAddedFilesCollector */ - $removedAndAddedFilesCollector = $this->getService(RemovedAndAddedFilesCollector::class); - $removedAndAddedFilesCollector->reset(); - $this->doTestFileInfo($originalFileInfo); $this->assertFilesWereAdded($expectedFilePathsWithContents); } diff --git a/rules-tests/PSR4/Rector/Namespace_/MultipleClassFileToPsr4ClassesRector/config/configured_rule.php b/rules-tests/PSR4/Rector/Namespace_/MultipleClassFileToPsr4ClassesRector/config/configured_rule.php index 54bb45ffc6c..82a4a6134d1 100644 --- a/rules-tests/PSR4/Rector/Namespace_/MultipleClassFileToPsr4ClassesRector/config/configured_rule.php +++ b/rules-tests/PSR4/Rector/Namespace_/MultipleClassFileToPsr4ClassesRector/config/configured_rule.php @@ -7,6 +7,5 @@ use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigura return static function (ContainerConfigurator $containerConfigurator): void { $services = $containerConfigurator->services(); - $services->set(MultipleClassFileToPsr4ClassesRector::class); }; diff --git a/rules-tests/Privatization/Rector/Property/PrivatizeLocalPropertyToPrivatePropertyRector/config/configured_rule.php b/rules-tests/Privatization/Rector/Property/PrivatizeLocalPropertyToPrivatePropertyRector/config/configured_rule.php index d4d45a041a6..3240a421cae 100644 --- a/rules-tests/Privatization/Rector/Property/PrivatizeLocalPropertyToPrivatePropertyRector/config/configured_rule.php +++ b/rules-tests/Privatization/Rector/Property/PrivatizeLocalPropertyToPrivatePropertyRector/config/configured_rule.php @@ -7,6 +7,5 @@ use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigura return static function (ContainerConfigurator $containerConfigurator): void { $services = $containerConfigurator->services(); - $services->set(PrivatizeLocalPropertyToPrivatePropertyRector::class); }; diff --git a/rules/Composer/Processor/ComposerFileProcessor.php b/rules/Composer/Application/FileProcessor/ComposerFileProcessor.php similarity index 58% rename from rules/Composer/Processor/ComposerFileProcessor.php rename to rules/Composer/Application/FileProcessor/ComposerFileProcessor.php index 2c344314d0b..19c09d1fc0e 100644 --- a/rules/Composer/Processor/ComposerFileProcessor.php +++ b/rules/Composer/Application/FileProcessor/ComposerFileProcessor.php @@ -2,11 +2,12 @@ declare(strict_types=1); -namespace Rector\Composer\Processor; +namespace Rector\Composer\Application\FileProcessor; use Rector\Composer\Modifier\ComposerModifier; use Rector\Core\Contract\Processor\FileProcessorInterface; -use Rector\Core\ValueObject\NonPhpFile\NonPhpFileChange; +use Rector\Core\ValueObject\Application\File; +use Rector\Testing\PHPUnit\StaticPHPUnitEnvironment; use Symplify\ComposerJsonManipulator\ComposerJsonFactory; use Symplify\ComposerJsonManipulator\Printer\ComposerJsonPrinter; use Symplify\SmartFileSystem\SmartFileInfo; @@ -38,31 +39,25 @@ final class ComposerFileProcessor implements FileProcessorInterface $this->composerModifier = $composerModifier; } - public function process(SmartFileInfo $smartFileInfo): ?NonPhpFileChange + /** + * @param File[] $files + */ + public function process(array $files): void { - // to avoid modification of file - if (! $this->composerModifier->enabled()) { - return null; + foreach ($files as $file) { + $this->processFile($file); } - - $composerJson = $this->composerJsonFactory->createFromFileInfo($smartFileInfo); - $oldComposerJson = clone $composerJson; - $this->composerModifier->modify($composerJson); - - // nothing has changed - if ($oldComposerJson->getJsonArray() === $composerJson->getJsonArray()) { - return null; - } - - $oldContent = $this->composerJsonPrinter->printToString($oldComposerJson); - $newContent = $this->composerJsonPrinter->printToString($composerJson); - - return new NonPhpFileChange($oldContent, $newContent); } - public function supports(SmartFileInfo $smartFileInfo): bool + public function supports(File $file): bool { - return $smartFileInfo->getRealPath() === getcwd() . '/composer.json'; + $fileInfo = $file->getSmartFileInfo(); + + if ($this->isJsonInTests($fileInfo)) { + return true; + } + + return $fileInfo->getRealPath() === getcwd() . '/composer.json'; } /** @@ -72,4 +67,34 @@ final class ComposerFileProcessor implements FileProcessorInterface { return ['json']; } + + private function processFile(File $file): void + { + // to avoid modification of file + if (! $this->composerModifier->enabled()) { + return; + } + + $smartFileInfo = $file->getSmartFileInfo(); + $composerJson = $this->composerJsonFactory->createFromFileInfo($smartFileInfo); + + $oldComposerJson = clone $composerJson; + $this->composerModifier->modify($composerJson); + + // nothing has changed + if ($oldComposerJson->getJsonArray() === $composerJson->getJsonArray()) { + return; + } + + $changeFileContent = $this->composerJsonPrinter->printToString($composerJson); + $file->changeFileContent($changeFileContent); + } + + private function isJsonInTests(SmartFileInfo $fileInfo): bool + { + if (! StaticPHPUnitEnvironment::isPHPUnitRun()) { + return false; + } + return $fileInfo->hasSuffixes(['json']); + } } diff --git a/rules/Defluent/Reflection/MethodCallToClassMethodParser.php b/rules/Defluent/Reflection/MethodCallToClassMethodParser.php index 44cee183d6b..007bce5cde2 100644 --- a/rules/Defluent/Reflection/MethodCallToClassMethodParser.php +++ b/rules/Defluent/Reflection/MethodCallToClassMethodParser.php @@ -8,7 +8,7 @@ use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Stmt\ClassMethod; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\TypeWithClassName; -use Rector\Core\PhpParser\Parser\FunctionLikeParser; +use Rector\Core\Reflection\FunctionLikeReflectionParser; use Rector\NodeNameResolver\NodeNameResolver; use Rector\NodeTypeResolver\NodeTypeResolver; @@ -30,20 +30,20 @@ final class MethodCallToClassMethodParser private $reflectionProvider; /** - * @var FunctionLikeParser + * @var FunctionLikeReflectionParser */ - private $functionLikeParser; + private $functionLikeReflectionParser; public function __construct( NodeTypeResolver $nodeTypeResolver, NodeNameResolver $nodeNameResolver, ReflectionProvider $reflectionProvider, - FunctionLikeParser $functionLikeParser + FunctionLikeReflectionParser $functionLikeReflectionParser ) { $this->nodeTypeResolver = $nodeTypeResolver; $this->nodeNameResolver = $nodeNameResolver; $this->reflectionProvider = $reflectionProvider; - $this->functionLikeParser = $functionLikeParser; + $this->functionLikeReflectionParser = $functionLikeReflectionParser; } public function parseMethodCall(MethodCall $methodCall): ?ClassMethod @@ -61,6 +61,6 @@ final class MethodCallToClassMethodParser $methodReflection = $callerClassReflection->getNativeMethod($methodName); - return $this->functionLikeParser->parseMethodReflection($methodReflection); + return $this->functionLikeReflectionParser->parseMethodReflection($methodReflection); } } diff --git a/rules/Php71/Rector/FuncCall/RemoveExtraParametersRector.php b/rules/Php71/Rector/FuncCall/RemoveExtraParametersRector.php index 63a12f6ea0f..785b1976e0c 100644 --- a/rules/Php71/Rector/FuncCall/RemoveExtraParametersRector.php +++ b/rules/Php71/Rector/FuncCall/RemoveExtraParametersRector.php @@ -73,6 +73,10 @@ final class RemoveExtraParametersRector extends AbstractRector $maximumAllowedParameterCount = $this->resolveMaximumAllowedParameterCount($functionLikeReflection); $numberOfArguments = count($node->args); + if ($numberOfArguments <= $maximumAllowedParameterCount) { + return null; + } + for ($i = $maximumAllowedParameterCount; $i <= $numberOfArguments; ++$i) { unset($node->args[$i]); } diff --git a/rules/TypeDeclaration/Rector/FunctionLike/ReturnTypeDeclarationRector.php b/rules/TypeDeclaration/Rector/FunctionLike/ReturnTypeDeclarationRector.php index c4d6bf27436..5961ad5d79e 100644 --- a/rules/TypeDeclaration/Rector/FunctionLike/ReturnTypeDeclarationRector.php +++ b/rules/TypeDeclaration/Rector/FunctionLike/ReturnTypeDeclarationRector.php @@ -33,9 +33,6 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** * @changelog https://wiki.php.net/rfc/scalar_type_hints_v5 - * @changelog https://github.com/nikic/TypeUtil - * @changelog https://github.com/nette/type-fixer - * @changelog https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues/3258 * * @see \Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\ReturnTypeDeclarationRectorTest */ @@ -266,7 +263,6 @@ CODE_SAMPLE } $isSubtype = $this->phpParserTypeAnalyzer->isCovariantSubtypeOf($inferredReturnNode, $functionLike->returnType); - if ($this->isAtLeastPhpVersion(PhpVersionFeature::COVARIANT_RETURN) && $isSubtype) { $functionLike->returnType = $inferredReturnNode; return; diff --git a/src/Application/ActiveRectorsProvider.php b/src/Application/ActiveRectorsProvider.php index 702aedd1352..5e9ba9bebd8 100644 --- a/src/Application/ActiveRectorsProvider.php +++ b/src/Application/ActiveRectorsProvider.php @@ -49,26 +49,11 @@ final class ActiveRectorsProvider */ public function provide(): array { - return $this->filterOutInternalRectorsAndSort($this->rectors); - } + sort($this->rectors); - /** - * @param RectorInterface[] $rectors - * @return RectorInterface[] - */ - private function filterOutInternalRectorsAndSort(array $rectors): array - { - sort($rectors); - - $rectors = array_filter($rectors, function (RectorInterface $rector): bool { + return array_filter($this->rectors, function (RectorInterface $rector): bool { // skip as internal and always run return ! $rector instanceof PostRectorInterface; }); - - usort($rectors, function (RectorInterface $firstRector, RectorInterface $secondRector): int { - return get_class($firstRector) <=> get_class($secondRector); - }); - - return $rectors; } } diff --git a/src/Application/ApplicationFileProcessor.php b/src/Application/ApplicationFileProcessor.php new file mode 100644 index 00000000000..665cd6ca58e --- /dev/null +++ b/src/Application/ApplicationFileProcessor.php @@ -0,0 +1,101 @@ +fileProcessors = $fileProcessors; + $this->smartFileSystem = $smartFileSystem; + $this->configuration = $configuration; + $this->fileDiffFileDecorator = $fileDiffFileDecorator; + } + + /** + * @param File[] $files + */ + public function run(array $files): void + { + $this->processFiles($files); + + $this->fileDiffFileDecorator->decorate($files); + + $this->printFiles($files); + } + + /** + * @param File[] $files + */ + private function processFiles(array $files): void + { + foreach ($this->fileProcessors as $fileProcessor) { + $supportedFiles = array_filter($files, function (File $file) use ($fileProcessor): bool { + return $fileProcessor->supports($file); + }); + + $fileProcessor->process($supportedFiles); + } + } + + /** + * @param File[] $files + */ + private function printFiles(array $files): void + { + if ($this->configuration->isDryRun()) { + return; + } + + foreach ($files as $file) { + if (! $file->hasChanged()) { + continue; + } + + $this->printFile($file); + } + } + + private function printFile(File $file): void + { + $smartFileInfo = $file->getSmartFileInfo(); + + $this->smartFileSystem->dumpFile($smartFileInfo->getPathname(), $file->getFileContent()); + $this->smartFileSystem->chmod($smartFileInfo->getRealPath(), $smartFileInfo->getPerms()); + } +} diff --git a/src/Application/FileDecorator/FileDiffFileDecorator.php b/src/Application/FileDecorator/FileDiffFileDecorator.php new file mode 100644 index 00000000000..c63d32e3b08 --- /dev/null +++ b/src/Application/FileDecorator/FileDiffFileDecorator.php @@ -0,0 +1,41 @@ +fileDiffFactory = $fileDiffFactory; + } + + /** + * @param File[] $files + */ + public function decorate(array $files): void + { + foreach ($files as $file) { + if (! $file->hasChanged()) { + continue; + } + + $fileDiff = $this->fileDiffFactory->createFileDiff( + $file, + $file->getOriginalFileContent(), + $file->getFileContent() + ); + + $file->setFileDiff($fileDiff); + } + } +} diff --git a/src/Application/FileProcessor.php b/src/Application/FileProcessor.php index 00ad0f9754d..4645e1d7cf2 100644 --- a/src/Application/FileProcessor.php +++ b/src/Application/FileProcessor.php @@ -10,6 +10,7 @@ use Rector\Core\PhpParser\Node\CustomNode\FileNode; use Rector\Core\PhpParser\NodeTraverser\RectorNodeTraverser; use Rector\Core\PhpParser\Parser\Parser; use Rector\Core\PhpParser\Printer\FormatPerservingPrinter; +use Rector\Core\ValueObject\Application\File; use Rector\Core\ValueObject\Application\ParsedStmtsAndTokens; use Rector\NodeTypeResolver\FileSystem\CurrentFileInfoProvider; use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator; @@ -85,8 +86,9 @@ final class FileProcessor $this->tokensByFilePathStorage = $tokensByFilePathStorage; } - public function parseFileInfoToLocalCache(SmartFileInfo $smartFileInfo): void + public function parseFileInfoToLocalCache(File $file): void { + $smartFileInfo = $file->getSmartFileInfo(); if ($this->tokensByFilePathStorage->hasForFileInfo($smartFileInfo)) { return; } @@ -113,10 +115,11 @@ final class FileProcessor return $this->formatPerservingPrinter->printParsedStmstAndTokensToString($parsedStmtsAndTokens); } - public function refactor(SmartFileInfo $smartFileInfo): void + public function refactor(File $file): void { - $this->parseFileInfoToLocalCache($smartFileInfo); + $this->parseFileInfoToLocalCache($file); + $smartFileInfo = $file->getSmartFileInfo(); $parsedStmtsAndTokens = $this->tokensByFilePathStorage->getForFileInfo($smartFileInfo); $this->currentFileInfoProvider->setCurrentStmts($parsedStmtsAndTokens->getNewStmts()); @@ -130,16 +133,18 @@ final class FileProcessor // this is needed for new tokens added in "afterTraverse()" $parsedStmtsAndTokens->updateNewStmts($newStmts); - $this->affectedFilesCollector->removeFromList($smartFileInfo); + $this->affectedFilesCollector->removeFromList($file); while ($otherTouchedFile = $this->affectedFilesCollector->getNext()) { $this->refactor($otherTouchedFile); } } - public function postFileRefactor(SmartFileInfo $smartFileInfo): void + public function postFileRefactor(File $file): void { + $smartFileInfo = $file->getSmartFileInfo(); + if (! $this->tokensByFilePathStorage->hasForFileInfo($smartFileInfo)) { - $this->parseFileInfoToLocalCache($smartFileInfo); + $this->parseFileInfoToLocalCache($file); } $parsedStmtsAndTokens = $this->tokensByFilePathStorage->getForFileInfo($smartFileInfo); diff --git a/src/Application/RectorApplication.php b/src/Application/FileProcessor/PhpFileProcessor.php similarity index 55% rename from src/Application/RectorApplication.php rename to src/Application/FileProcessor/PhpFileProcessor.php index 85215628861..00e32ffb73f 100644 --- a/src/Application/RectorApplication.php +++ b/src/Application/FileProcessor/PhpFileProcessor.php @@ -2,34 +2,24 @@ declare(strict_types=1); -namespace Rector\Core\Application; +namespace Rector\Core\Application\FileProcessor; use PHPStan\AnalysedCodeException; -use PHPStan\Analyser\NodeScopeResolver; use Rector\ChangesReporting\Application\ErrorAndDiffCollector; +use Rector\Core\Application\FileDecorator\FileDiffFileDecorator; +use Rector\Core\Application\FileProcessor; use Rector\Core\Application\FileSystem\RemovedAndAddedFilesCollector; use Rector\Core\Application\FileSystem\RemovedAndAddedFilesProcessor; use Rector\Core\Configuration\Configuration; -use Rector\Core\Contract\PostRunnerInterface; +use Rector\Core\Contract\Processor\FileProcessorInterface; use Rector\Core\Exception\ShouldNotHappenException; -use Rector\Core\FileSystem\PhpFilesFinder; -use Rector\Core\StaticReflection\DynamicSourceLocatorDecorator; +use Rector\Core\ValueObject\Application\File; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Style\SymfonyStyle; use Symplify\PackageBuilder\Reflection\PrivatesAccessor; -use Symplify\SmartFileSystem\SmartFileInfo; use Throwable; -/** - * Rector cycle has 3 steps: - * - * 1. parse all files to nodes - * - * 2. run Rectors on all files and their nodes - * - * 3. print changed content to file or to string diff with "--dry-run" - */ -final class RectorApplication +final class PhpFileProcessor implements FileProcessorInterface { /** * Why 4? One for each cycle, so user sees some activity all the time: @@ -44,14 +34,14 @@ final class RectorApplication private const PROGRESS_BAR_STEP_MULTIPLIER = 4; /** - * @var SmartFileInfo[] + * @var Configuration */ - private $notParsedFiles = []; + private $configuration; /** - * @var PostRunnerInterface[] + * @var File[] */ - private $postRunners = []; + private $notParsedFiles = []; /** * @var SymfonyStyle @@ -63,11 +53,6 @@ final class RectorApplication */ private $errorAndDiffCollector; - /** - * @var Configuration - */ - private $configuration; - /** * @var FileProcessor */ @@ -83,41 +68,25 @@ final class RectorApplication */ private $removedAndAddedFilesProcessor; - /** - * @var NodeScopeResolver - */ - private $nodeScopeResolver; - /** * @var PrivatesAccessor */ private $privatesAccessor; /** - * @var PhpFilesFinder + * @var FileDiffFileDecorator */ - private $phpFilesFinder; + private $fileDiffFileDecorator; - /** - * @var DynamicSourceLocatorDecorator - */ - private $dynamicSourceLocatorDecorator; - - /** - * @param PostRunnerInterface[] $postRunners - */ public function __construct( Configuration $configuration, ErrorAndDiffCollector $errorAndDiffCollector, FileProcessor $fileProcessor, - NodeScopeResolver $nodeScopeResolver, RemovedAndAddedFilesCollector $removedAndAddedFilesCollector, RemovedAndAddedFilesProcessor $removedAndAddedFilesProcessor, SymfonyStyle $symfonyStyle, PrivatesAccessor $privatesAccessor, - PhpFilesFinder $phpFilesFinder, - DynamicSourceLocatorDecorator $dynamicSourceLocatorDecorator, - array $postRunners + FileDiffFileDecorator $fileDiffFileDecorator ) { $this->symfonyStyle = $symfonyStyle; $this->errorAndDiffCollector = $errorAndDiffCollector; @@ -125,55 +94,46 @@ final class RectorApplication $this->fileProcessor = $fileProcessor; $this->removedAndAddedFilesCollector = $removedAndAddedFilesCollector; $this->removedAndAddedFilesProcessor = $removedAndAddedFilesProcessor; - $this->nodeScopeResolver = $nodeScopeResolver; $this->privatesAccessor = $privatesAccessor; - $this->postRunners = $postRunners; - $this->phpFilesFinder = $phpFilesFinder; - $this->dynamicSourceLocatorDecorator = $dynamicSourceLocatorDecorator; + $this->fileDiffFileDecorator = $fileDiffFileDecorator; + $this->configuration = $configuration; } /** - * @param string[] $paths + * @param File[] $files */ - public function runOnPaths(array $paths): void + public function process(array $files): void { - $phpFileInfos = $this->phpFilesFinder->findInPaths($paths); - $fileCount = count($phpFileInfos); + $fileCount = count($files); if ($fileCount === 0) { return; } $this->prepareProgressBar($fileCount); - // PHPStan has to know about all files! - $this->configurePHPStanNodeScopeResolver($phpFileInfos); - - // 0. add files and directories to static locator - $this->dynamicSourceLocatorDecorator->addPaths($paths); - // 1. parse files to nodes - $this->parseFileInfosToNodes($phpFileInfos); + $this->parseFileInfosToNodes($files); // 2. change nodes with Rectors - $this->refactorNodesWithRectors($phpFileInfos); + $this->refactorNodesWithRectors($files); // 3. apply post rectors - foreach ($phpFileInfos as $phpFileInfo) { - $this->tryCatchWrapper($phpFileInfo, function (SmartFileInfo $smartFileInfo): void { - $this->fileProcessor->postFileRefactor($smartFileInfo); + foreach ($files as $file) { + $this->tryCatchWrapper($file, function (File $file): void { + $this->fileProcessor->postFileRefactor($file); }, 'post rectors'); } // 4. print to file or string - foreach ($phpFileInfos as $phpFileInfo) { - // cannot print file with errors, as print would break everything to orignal nodes - if ($this->errorAndDiffCollector->hasErrors($phpFileInfo)) { - $this->advance($phpFileInfo, 'printing'); + foreach ($files as $file) { + // cannot print file with errors, as print would break everything to original nodes + if ($this->errorAndDiffCollector->hasSmartFileErrors($file)) { + $this->advance($file, 'printing skipped due error'); continue; } - $this->tryCatchWrapper($phpFileInfo, function (SmartFileInfo $smartFileInfo): void { - $this->printFileInfo($smartFileInfo); + $this->tryCatchWrapper($file, function (File $file): void { + $this->printFileInfo($file); }, 'printing'); } @@ -183,11 +143,20 @@ final class RectorApplication // 4. remove and add files $this->removedAndAddedFilesProcessor->run(); + } - // 5. various extensions on finish - foreach ($this->postRunners as $postRunner) { - $postRunner->run(); - } + public function supports(File $file): bool + { + $fileInfo = $file->getSmartFileInfo(); + return $fileInfo->hasSuffixes($this->getSupportedFileExtensions()); + } + + /** + * @return string[] + */ + public function getSupportedFileExtensions(): array + { + return $this->configuration->getFileExtensions(); } private function prepareProgressBar(int $fileCount): void @@ -204,79 +173,67 @@ final class RectorApplication } /** - * @param SmartFileInfo[] $fileInfos + * @param File[] $files */ - private function configurePHPStanNodeScopeResolver(array $fileInfos): void + private function parseFileInfosToNodes(array $files): void { - $filePaths = []; - foreach ($fileInfos as $fileInfo) { - $filePaths[] = $fileInfo->getPathname(); - } - - $this->nodeScopeResolver->setAnalysedFiles($filePaths); - } - - /** - * @param SmartFileInfo[] $phpFileInfos - */ - private function parseFileInfosToNodes(array $phpFileInfos): void - { - foreach ($phpFileInfos as $phpFileInfo) { - $this->tryCatchWrapper($phpFileInfo, function (SmartFileInfo $smartFileInfo): void { - $this->fileProcessor->parseFileInfoToLocalCache($smartFileInfo); + foreach ($files as $file) { + $this->tryCatchWrapper($file, function (File $file): void { + $this->fileProcessor->parseFileInfoToLocalCache($file); }, 'parsing'); } } /** - * @param SmartFileInfo[] $phpFileInfos + * @param File[] $files */ - private function refactorNodesWithRectors(array $phpFileInfos): void + private function refactorNodesWithRectors(array $files): void { - foreach ($phpFileInfos as $phpFileInfo) { - $this->tryCatchWrapper($phpFileInfo, function (SmartFileInfo $smartFileInfo): void { - $this->fileProcessor->refactor($smartFileInfo); + foreach ($files as $file) { + $this->tryCatchWrapper($file, function (File $file): void { + $this->fileProcessor->refactor($file); }, 'refactoring'); } } - private function tryCatchWrapper(SmartFileInfo $smartFileInfo, callable $callback, string $phase): void + private function tryCatchWrapper(File $file, callable $callback, string $phase): void { - $this->advance($smartFileInfo, $phase); + $this->advance($file, $phase); try { - if (in_array($smartFileInfo, $this->notParsedFiles, true)) { + if (in_array($file, $this->notParsedFiles, true)) { // we cannot process this file return; } - $callback($smartFileInfo); + $callback($file); } catch (AnalysedCodeException $analysedCodeException) { - $this->notParsedFiles[] = $smartFileInfo; - - $this->errorAndDiffCollector->addAutoloadError($analysedCodeException, $smartFileInfo); + $this->notParsedFiles[] = $file; + $this->errorAndDiffCollector->addAutoloadError($analysedCodeException, $file); } catch (Throwable $throwable) { if ($this->symfonyStyle->isVerbose()) { throw $throwable; } - $this->errorAndDiffCollector->addThrowableWithFileInfo($throwable, $smartFileInfo); + $fileInfo = $file->getSmartFileInfo(); + $this->errorAndDiffCollector->addThrowableWithFileInfo($throwable, $fileInfo); } } - private function printFileInfo(SmartFileInfo $fileInfo): void + private function printFileInfo(File $file): void { + $fileInfo = $file->getSmartFileInfo(); + if ($this->removedAndAddedFilesCollector->isFileRemoved($fileInfo)) { // skip, because this file exists no more return; } - $oldContents = $fileInfo->getContents(); - $newContent = $this->configuration->isDryRun() ? $this->fileProcessor->printToString($fileInfo) : $this->fileProcessor->printToFile($fileInfo); - $this->errorAndDiffCollector->addFileDiff($fileInfo, $newContent, $oldContents); + $file->changeFileContent($newContent); + $this->fileDiffFileDecorator->decorate([$file]); } /** @@ -299,10 +256,11 @@ final class RectorApplication $progressBar->setRedrawFrequency($redrawFrequency); } - private function advance(SmartFileInfo $smartFileInfo, string $phase): void + private function advance(File $file, string $phase): void { if ($this->symfonyStyle->isVerbose()) { - $relativeFilePath = $smartFileInfo->getRelativeFilePathFromDirectory(getcwd()); + $fileInfo = $file->getSmartFileInfo(); + $relativeFilePath = $fileInfo->getRelativeFilePathFromDirectory(getcwd()); $message = sprintf('[%s] %s', $phase, $relativeFilePath); $this->symfonyStyle->writeln($message); } elseif ($this->configuration->shouldShowProgressBar()) { diff --git a/src/Autoloading/BootstrapFilesIncluder.php b/src/Autoloading/BootstrapFilesIncluder.php new file mode 100644 index 00000000000..2b6752bb660 --- /dev/null +++ b/src/Autoloading/BootstrapFilesIncluder.php @@ -0,0 +1,53 @@ +parameterProvider = $parameterProvider; + } + + /** + * Inspired by + * @see https://github.com/phpstan/phpstan-src/commit/aad1bf888ab7b5808898ee5fe2228bb8bb4e4cf1 + */ + public function includeBootstrapFiles(): void + { + $bootstrapFiles = $this->parameterProvider->provideArrayParameter(Option::BOOTSTRAP_FILES); + + foreach ($bootstrapFiles as $bootstrapFile) { + if (! is_file($bootstrapFile)) { + throw new ShouldNotHappenException('Bootstrap file %s does not exist.', $bootstrapFile); + } + + try { + require_once $bootstrapFile; + } catch (Throwable $throwable) { + $errorMessage = sprintf( + '"%s" thrown in "%s" on line %d while loading bootstrap file %s: %s', + get_class($throwable), + $throwable->getFile(), + $throwable->getLine(), + $bootstrapFile, + $throwable->getMessage() + ); + + throw new ShouldNotHappenException($errorMessage, $throwable->getCode(), $throwable); + } + } + } +} diff --git a/src/Configuration/Configuration.php b/src/Configuration/Configuration.php index 084b7a0b6a7..e95a85161cf 100644 --- a/src/Configuration/Configuration.php +++ b/src/Configuration/Configuration.php @@ -45,11 +45,6 @@ final class Configuration */ private $isCacheEnabled = false; - /** - * @var SmartFileInfo[] - */ - private $fileInfos = []; - /** * @var string[] */ @@ -148,22 +143,6 @@ final class Configuration return $this->outputFile; } - /** - * @param SmartFileInfo[] $fileInfos - */ - public function setFileInfos(array $fileInfos): void - { - $this->fileInfos = $fileInfos; - } - - /** - * @return SmartFileInfo[] - */ - public function getFileInfos(): array - { - return $this->fileInfos; - } - public function shouldClearCache(): bool { return $this->shouldClearCache; diff --git a/src/Console/Command/ProcessCommand.php b/src/Console/Command/ProcessCommand.php index 9e0a8689707..23d935fa779 100644 --- a/src/Console/Command/ProcessCommand.php +++ b/src/Console/Command/ProcessCommand.php @@ -4,28 +4,31 @@ declare(strict_types=1); namespace Rector\Core\Console\Command; +use PHPStan\Analyser\NodeScopeResolver; use Rector\Caching\Detector\ChangedFilesDetector; -use Rector\ChangesReporting\Application\ErrorAndDiffCollector; use Rector\ChangesReporting\Output\ConsoleOutputFormatter; -use Rector\Core\Application\RectorApplication; +use Rector\Core\Application\ApplicationFileProcessor; use Rector\Core\Autoloading\AdditionalAutoloader; +use Rector\Core\Autoloading\BootstrapFilesIncluder; use Rector\Core\Configuration\Configuration; use Rector\Core\Configuration\Option; use Rector\Core\Console\Output\OutputFormatterCollector; use Rector\Core\Exception\ShouldNotHappenException; use Rector\Core\FileSystem\PhpFilesFinder; -use Rector\Core\NonPhpFile\NonPhpFileProcessorService; use Rector\Core\Reporting\MissingRectorRulesReporter; +use Rector\Core\StaticReflection\DynamicSourceLocatorDecorator; +use Rector\Core\ValueObject\ProcessResult; +use Rector\Core\ValueObjectFactory\Application\FileFactory; +use Rector\Core\ValueObjectFactory\ProcessResultFactory; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Style\SymfonyStyle; use Symplify\PackageBuilder\Console\ShellCode; use Symplify\PackageBuilder\Parameter\ParameterProvider; -use Throwable; +use Symplify\SmartFileSystem\SmartFileInfo; final class ProcessCommand extends Command { @@ -34,31 +37,16 @@ final class ProcessCommand extends Command */ private $additionalAutoloader; - /** - * @var ErrorAndDiffCollector - */ - private $errorAndDiffCollector; - /** * @var Configuration */ private $configuration; - /** - * @var RectorApplication - */ - private $rectorApplication; - /** * @var OutputFormatterCollector */ private $outputFormatterCollector; - /** - * @var SymfonyStyle - */ - private $symfonyStyle; - /** * @var PhpFilesFinder */ @@ -74,42 +62,69 @@ final class ProcessCommand extends Command */ private $missingRectorRulesReporter; - /** - * @var ParameterProvider - */ - private $parameterProvider; +// /** +// * @var ParameterProvider +// */ +// private $parameterProvider; /** - * @var NonPhpFileProcessorService + * @var ApplicationFileProcessor */ - private $nonPhpFileProcessorService; + private $applicationFileProcessor; + + /** + * @var FileFactory + */ + private $fileFactory; + + /** + * @var BootstrapFilesIncluder + */ + private $bootstrapFilesIncluder; + + /** + * @var ProcessResultFactory + */ + private $processResultFactory; + + /** + * @var NodeScopeResolver + */ + private $nodeScopeResolver; + + /** + * @var DynamicSourceLocatorDecorator + */ + private $dynamicSourceLocatorDecorator; public function __construct( AdditionalAutoloader $additionalAutoloader, ChangedFilesDetector $changedFilesDetector, Configuration $configuration, - ErrorAndDiffCollector $errorAndDiffCollector, OutputFormatterCollector $outputFormatterCollector, - RectorApplication $rectorApplication, - SymfonyStyle $symfonyStyle, PhpFilesFinder $phpFilesFinder, MissingRectorRulesReporter $missingRectorRulesReporter, - ParameterProvider $parameterProvider, - NonPhpFileProcessorService $nonPhpFileProcessorService + ApplicationFileProcessor $applicationFileProcessor, + FileFactory $fileFactory, + BootstrapFilesIncluder $bootstrapFilesIncluder, + ProcessResultFactory $processResultFactory, + NodeScopeResolver $nodeScopeResolver, + DynamicSourceLocatorDecorator $dynamicSourceLocatorDecorator ) { $this->additionalAutoloader = $additionalAutoloader; - $this->errorAndDiffCollector = $errorAndDiffCollector; $this->configuration = $configuration; - $this->rectorApplication = $rectorApplication; $this->outputFormatterCollector = $outputFormatterCollector; $this->changedFilesDetector = $changedFilesDetector; - $this->symfonyStyle = $symfonyStyle; $this->phpFilesFinder = $phpFilesFinder; $this->missingRectorRulesReporter = $missingRectorRulesReporter; parent::__construct(); - $this->parameterProvider = $parameterProvider; - $this->nonPhpFileProcessorService = $nonPhpFileProcessorService; + $this->applicationFileProcessor = $applicationFileProcessor; + $this->fileFactory = $fileFactory; + $this->bootstrapFilesIncluder = $bootstrapFilesIncluder; + $this->processResultFactory = $processResultFactory; + $this->nodeScopeResolver = $nodeScopeResolver; + $this->dynamicSourceLocatorDecorator = $dynamicSourceLocatorDecorator; } protected function configure(): void @@ -186,40 +201,31 @@ final class ProcessCommand extends Command $phpFileInfos = $this->phpFilesFinder->findInPaths($paths); // register autoloaded and included files - $this->includeBootstrapFiles(); + $this->bootstrapFilesIncluder->includeBootstrapFiles(); $this->additionalAutoloader->autoloadWithInputAndSource($input); - if ($this->configuration->isCacheDebug()) { - $message = sprintf('[cache] %d files after cache filter', count($phpFileInfos)); - $this->symfonyStyle->note($message); - $this->symfonyStyle->listing($phpFileInfos); - } + // PHPStan has to know about all files! + $this->configurePHPStanNodeScopeResolver($phpFileInfos); - $this->configuration->setFileInfos($phpFileInfos); - $this->rectorApplication->runOnPaths($paths); - $this->nonPhpFileProcessorService->runOnPaths($paths); + // 0. add files and directories to static locator + $this->dynamicSourceLocatorDecorator->addPaths($paths); + + $files = $this->fileFactory->createFromPaths($paths); + $this->applicationFileProcessor->run($files); // report diffs and errors $outputFormat = (string) $input->getOption(Option::OPTION_OUTPUT_FORMAT); $outputFormatter = $this->outputFormatterCollector->getByName($outputFormat); - $outputFormatter->report($this->errorAndDiffCollector); + + // here should be value obect factory + $processResult = $this->processResultFactory->create($files); + $outputFormatter->report($processResult); // invalidate affected files - $this->invalidateAffectedCacheFiles(); + $this->invalidateCacheChangedFiles($processResult); - // some errors were found → fail - if ($this->errorAndDiffCollector->getErrors() !== []) { - return ShellCode::ERROR; - } - // inverse error code for CI dry-run - if (! $this->configuration->isDryRun()) { - return ShellCode::SUCCESS; - } - if ($this->errorAndDiffCollector->getFileDiffsCount() === 0) { - return ShellCode::SUCCESS; - } - return ShellCode::ERROR; + return $this->resolveReturnCode($processResult); } protected function initialize(InputInterface $input, OutputInterface $output): void @@ -245,44 +251,42 @@ final class ProcessCommand extends Command } } - private function invalidateAffectedCacheFiles(): void + private function invalidateCacheChangedFiles(ProcessResult $processResult): void { if (! $this->configuration->isCacheEnabled()) { return; } - foreach ($this->errorAndDiffCollector->getAffectedFileInfos() as $affectedFileInfo) { - $this->changedFilesDetector->invalidateFile($affectedFileInfo); + foreach ($processResult->getChangedFileInfos() as $changedFileInfo) { + $this->changedFilesDetector->invalidateFile($changedFileInfo); } } + private function resolveReturnCode(ProcessResult $processResult): int + { + // some errors were found → fail + if ($processResult->getErrors() !== []) { + return ShellCode::ERROR; + } + + // inverse error code for CI dry-run + if (! $this->configuration->isDryRun()) { + return ShellCode::SUCCESS; + } + + return $processResult->getFileDiffs() === [] ? ShellCode::SUCCESS : ShellCode::ERROR; + } + /** - * Inspired by - * @see https://github.com/phpstan/phpstan-src/commit/aad1bf888ab7b5808898ee5fe2228bb8bb4e4cf1 + * @param SmartFileInfo[] $fileInfos */ - private function includeBootstrapFiles(): void + private function configurePHPStanNodeScopeResolver(array $fileInfos): void { - $bootstrapFiles = $this->parameterProvider->provideArrayParameter(Option::BOOTSTRAP_FILES); - - foreach ($bootstrapFiles as $bootstrapFile) { - if (! is_file($bootstrapFile)) { - throw new ShouldNotHappenException('Bootstrap file %s does not exist.', $bootstrapFile); - } - - try { - require_once $bootstrapFile; - } catch (Throwable $throwable) { - $errorMessage = sprintf( - '"%s" thrown in "%s" on line %d while loading bootstrap file %s: %s', - get_class($throwable), - $throwable->getFile(), - $throwable->getLine(), - $bootstrapFile, - $throwable->getMessage() - ); - - throw new ShouldNotHappenException($errorMessage); - } + $filePaths = []; + foreach ($fileInfos as $fileInfo) { + $filePaths[] = $fileInfo->getPathname(); } + + $this->nodeScopeResolver->setAnalysedFiles($filePaths); } } diff --git a/src/Contract/PostRunnerInterface.php b/src/Contract/PostRunnerInterface.php deleted file mode 100644 index d1ac5f2590e..00000000000 --- a/src/Contract/PostRunnerInterface.php +++ /dev/null @@ -1,10 +0,0 @@ -nonPhpFileClassRenamer = $nonPhpFileClassRenamer; } - public function process(SmartFileInfo $smartFileInfo): ?NonPhpFileChange + /** + * @param File[] $files + */ + public function process(array $files): void { - $oldContents = $smartFileInfo->getContents(); - - $classRenames = array_merge( - $this->renamedClassesDataCollector->getOldToNewClasses(), - $this->renamedClassesCollector->getOldToNewClasses() - ); - - $newContents = $this->nonPhpFileClassRenamer->renameClasses($oldContents, $classRenames); - - // nothing has changed - if ($oldContents === $newContents) { - return null; + foreach ($files as $file) { + $this->processFile($file); } - - return new NonPhpFileChange($oldContents, $newContents); } - public function supports(SmartFileInfo $smartFileInfo): bool + public function supports(File $file): bool { - return in_array($smartFileInfo->getExtension(), $this->getSupportedFileExtensions(), true); + $fileInfo = $file->getSmartFileInfo(); + return $fileInfo->hasSuffixes($this->getSupportedFileExtensions()); } public function getSupportedFileExtensions(): array { return StaticNonPhpFileSuffixes::SUFFIXES; } + + private function processFile(File $file): void + { + $fileInfo = $file->getSmartFileInfo(); + $oldFileContents = $fileInfo->getContents(); + + $classRenames = array_merge( + $this->renamedClassesDataCollector->getOldToNewClasses(), + $this->renamedClassesCollector->getOldToNewClasses() + ); + + $changedFileContents = $this->nonPhpFileClassRenamer->renameClasses($oldFileContents, $classRenames); + $file->changeFileContent($changedFileContents); + } } diff --git a/src/NonPhpFile/NonPhpFileProcessorService.php b/src/NonPhpFile/NonPhpFileProcessorService.php deleted file mode 100644 index 6c052bf5341..00000000000 --- a/src/NonPhpFile/NonPhpFileProcessorService.php +++ /dev/null @@ -1,124 +0,0 @@ -nonPhpFileProcessors = $nonPhpFileProcessors; - $this->smartFileSystem = $smartFileSystem; - $this->filesFinder = $filesFinder; - $this->errorAndDiffCollector = $errorAndDiffCollector; - $this->configuration = $configuration; - } - - /** - * @param string[] $paths - */ - public function runOnPaths(array $paths): void - { - $nonPhpFileInfos = $this->collectNonPhpFiles($paths); - $this->runNonPhpFileProcessors($nonPhpFileInfos); - } - - /** - * @param SmartFileInfo[] $nonPhpFileInfos - */ - private function runNonPhpFileProcessors(array $nonPhpFileInfos): void - { - foreach ($nonPhpFileInfos as $nonPhpFileInfo) { - foreach ($this->nonPhpFileProcessors as $nonPhpFileProcessor) { - if (! $nonPhpFileProcessor->supports($nonPhpFileInfo)) { - continue; - } - $nonPhpFileChange = $nonPhpFileProcessor->process($nonPhpFileInfo); - - if (! $nonPhpFileChange instanceof NonPhpFileChange) { - continue; - } - - $this->errorAndDiffCollector->addFileDiff( - $nonPhpFileInfo, - $nonPhpFileChange->getNewContent(), - $nonPhpFileChange->getOldContent() - ); - if (! $this->configuration->isDryRun()) { - $this->smartFileSystem->dumpFile( - $nonPhpFileInfo->getPathname(), - $nonPhpFileChange->getNewContent() - ); - $this->smartFileSystem->chmod($nonPhpFileInfo->getRealPath(), $nonPhpFileInfo->getPerms()); - } - } - } - } - - /** - * @param string[] $paths - * - * @return SmartFileInfo[] - */ - private function collectNonPhpFiles(array $paths): array - { - $nonPhpFileExtensions = []; - foreach ($this->nonPhpFileProcessors as $nonPhpFileProcessor) { - $nonPhpFileExtensions = array_merge( - $nonPhpFileProcessor->getSupportedFileExtensions(), - $nonPhpFileExtensions - ); - } - $nonPhpFileExtensions = array_unique($nonPhpFileExtensions); - - $nonPhpFileInfos = $this->filesFinder->findInDirectoriesAndFiles($paths, $nonPhpFileExtensions); - - $composerJsonFilePath = getcwd() . '/composer.json'; - if ($this->smartFileSystem->exists($composerJsonFilePath)) { - $nonPhpFileInfos[] = new SmartFileInfo($composerJsonFilePath); - } - - return $nonPhpFileInfos; - } -} diff --git a/src/PhpParser/NodeTraverser/RectorNodeTraverser.php b/src/PhpParser/NodeTraverser/RectorNodeTraverser.php index e52d822c186..3d2ec6023f7 100644 --- a/src/PhpParser/NodeTraverser/RectorNodeTraverser.php +++ b/src/PhpParser/NodeTraverser/RectorNodeTraverser.php @@ -21,7 +21,7 @@ final class RectorNodeTraverser extends NodeTraverser /** * @var PhpRectorInterface[] */ - private $allPhpRectors = []; + private $phpRectors = []; /** * @var NodeFinder @@ -46,7 +46,8 @@ final class RectorNodeTraverser extends NodeTraverser /** @var PhpRectorInterface[] $phpRectors */ $phpRectors = $activeRectorsProvider->provideByType(PhpRectorInterface::class); - $this->allPhpRectors = $phpRectors; + $this->phpRectors = $phpRectors; + $this->nodeFinder = $nodeFinder; $this->currentFileInfoProvider = $currentFileInfoProvider; } @@ -125,8 +126,8 @@ final class RectorNodeTraverser extends NodeTraverser return; } - foreach ($this->allPhpRectors as $allPhpRector) { - $this->addVisitor($allPhpRector); + foreach ($this->phpRectors as $phpRector) { + $this->addVisitor($phpRector); } $this->areNodeVisitorsPrepared = true; diff --git a/src/PhpParser/Parser/FunctionLikeParser.php b/src/PhpParser/Parser/FunctionLikeParser.php index 7adafa169ac..2b7d00bad05 100644 --- a/src/PhpParser/Parser/FunctionLikeParser.php +++ b/src/PhpParser/Parser/FunctionLikeParser.php @@ -4,71 +4,11 @@ declare(strict_types=1); namespace Rector\Core\PhpParser\Parser; -use PhpParser\Node\Stmt\Class_; -use PhpParser\Node\Stmt\ClassMethod; -use PhpParser\NodeFinder; -use PhpParser\Parser; -use PHPStan\Reflection\MethodReflection; -use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator; -use Symplify\SmartFileSystem\SmartFileInfo; -use Symplify\SmartFileSystem\SmartFileSystem; +use Rector\Core\Reflection\FunctionLikeReflectionParser; -final class FunctionLikeParser +/** + * @deprecated For BC layer + */ +final class FunctionLikeParser extends FunctionLikeReflectionParser { - /** - * @var Parser - */ - private $parser; - - /** - * @var SmartFileSystem - */ - private $smartFileSystem; - - /** - * @var NodeFinder - */ - private $nodeFinder; - - /** - * @var NodeScopeAndMetadataDecorator - */ - private $nodeScopeAndMetadataDecorator; - - public function __construct( - Parser $parser, - SmartFileSystem $smartFileSystem, - NodeFinder $nodeFinder, - NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator - ) { - $this->parser = $parser; - $this->smartFileSystem = $smartFileSystem; - $this->nodeFinder = $nodeFinder; - $this->nodeScopeAndMetadataDecorator = $nodeScopeAndMetadataDecorator; - } - - public function parseMethodReflection(MethodReflection $methodReflection): ?ClassMethod - { - $classReflection = $methodReflection->getDeclaringClass(); - - $fileName = $classReflection->getFileName(); - if (! is_string($fileName)) { - return null; - } - - $fileContent = $this->smartFileSystem->readFile($fileName); - if (! is_string($fileContent)) { - return null; - } - - $nodes = (array) $this->parser->parse($fileContent); - $nodes = $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile($nodes, new SmartFileInfo($fileName)); - - $class = $this->nodeFinder->findFirstInstanceOf($nodes, Class_::class); - if (! $class instanceof Class_) { - return null; - } - - return $class->getMethod($methodReflection->getName()); - } } diff --git a/src/Reflection/FunctionLikeReflectionParser.php b/src/Reflection/FunctionLikeReflectionParser.php new file mode 100644 index 00000000000..86273cc2e55 --- /dev/null +++ b/src/Reflection/FunctionLikeReflectionParser.php @@ -0,0 +1,74 @@ +parser = $parser; + $this->smartFileSystem = $smartFileSystem; + $this->nodeFinder = $nodeFinder; + $this->nodeScopeAndMetadataDecorator = $nodeScopeAndMetadataDecorator; + } + + public function parseMethodReflection(MethodReflection $methodReflection): ?ClassMethod + { + $classReflection = $methodReflection->getDeclaringClass(); + + $fileName = $classReflection->getFileName(); + if ($fileName === false) { + return null; + } + + $fileContent = $this->smartFileSystem->readFile($fileName); + if (! is_string($fileContent)) { + return null; + } + + $nodes = (array) $this->parser->parse($fileContent); + $nodes = $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile($nodes, new SmartFileInfo($fileName)); + + $class = $this->nodeFinder->findFirstInstanceOf($nodes, Class_::class); + if (! $class instanceof Class_) { + return null; + } + + return $class->getMethod($methodReflection->getName()); + } +} diff --git a/src/Reporting/MissingRectorRulesReporter.php b/src/Reporting/MissingRectorRulesReporter.php index 9dc8cd8053a..59499fa7bc8 100644 --- a/src/Reporting/MissingRectorRulesReporter.php +++ b/src/Reporting/MissingRectorRulesReporter.php @@ -4,31 +4,39 @@ declare(strict_types=1); namespace Rector\Core\Reporting; -use Rector\Core\PhpParser\NodeTraverser\RectorNodeTraverser; +use Rector\Core\Contract\Rector\RectorInterface; +use Rector\PostRector\Contract\Rector\PostRectorInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symplify\PackageBuilder\Console\ShellCode; final class MissingRectorRulesReporter { - /** - * @var RectorNodeTraverser - */ - private $rectorNodeTraverser; - /** * @var SymfonyStyle */ private $symfonyStyle; - public function __construct(RectorNodeTraverser $rectorNodeTraverser, SymfonyStyle $symfonyStyle) + /** + * @var RectorInterface[] + */ + private $rectors = []; + + /** + * @param RectorInterface[] $rectors + */ + public function __construct(array $rectors, SymfonyStyle $symfonyStyle) { - $this->rectorNodeTraverser = $rectorNodeTraverser; $this->symfonyStyle = $symfonyStyle; + $this->rectors = $rectors; } public function reportIfMissing(): ?int { - if ($this->rectorNodeTraverser->getPhpRectorCount() !== 0) { + $activeRectors = array_filter($this->rectors, function (RectorInterface $rector): bool { + return ! $rector instanceof PostRectorInterface; + }); + + if ($activeRectors !== []) { return null; } diff --git a/src/ValueObject/Application/File.php b/src/ValueObject/Application/File.php new file mode 100644 index 00000000000..5738f958f27 --- /dev/null +++ b/src/ValueObject/Application/File.php @@ -0,0 +1,86 @@ +smartFileInfo = $smartFileInfo; + $this->fileContent = $fileContent; + $this->originalFileContent = $fileContent; + } + + public function getSmartFileInfo(): SmartFileInfo + { + return $this->smartFileInfo; + } + + public function getFileContent(): string + { + return $this->fileContent; + } + + public function changeFileContent(string $newFileContent): void + { + if ($this->fileContent === $newFileContent) { + return; + } + + $this->fileContent = $newFileContent; + $this->hasChanged = true; + } + + public function getOriginalFileContent(): string + { + return $this->originalFileContent; + } + + public function hasChanged(): bool + { + return $this->hasChanged; + } + + public function setFileDiff(FileDiff $fileDiff): void + { + $this->fileDiff = $fileDiff; + } + + public function getFileDiff(): ?FileDiff + { + return $this->fileDiff; + } +} diff --git a/src/ValueObject/NonPhpFile/NonPhpFileChange.php b/src/ValueObject/NonPhpFile/NonPhpFileChange.php deleted file mode 100644 index f83f6b19305..00000000000 --- a/src/ValueObject/NonPhpFile/NonPhpFileChange.php +++ /dev/null @@ -1,33 +0,0 @@ -oldContent = $oldContent; - $this->newContent = $newContent; - } - - public function getOldContent(): string - { - return $this->oldContent; - } - - public function getNewContent(): string - { - return $this->newContent; - } -} diff --git a/src/ValueObject/ProcessResult.php b/src/ValueObject/ProcessResult.php new file mode 100644 index 00000000000..3b37eb38311 --- /dev/null +++ b/src/ValueObject/ProcessResult.php @@ -0,0 +1,111 @@ +fileDiffs = $fileDiffs; + $this->errors = $errors; + $this->addedFilesCount = $addedFilesCount; + $this->removedFilesCount = $removedFilesCount; + $this->removedNodeCount = $removedNodeCount; + } + + /** + * @return FileDiff[] + */ + public function getFileDiffs(): array + { + return $this->fileDiffs; + } + + /** + * @return RectorError[] + */ + public function getErrors(): array + { + return $this->errors; + } + + public function getAddedFilesCount(): int + { + return $this->addedFilesCount; + } + + public function getRemovedFilesCount(): int + { + return $this->removedFilesCount; + } + + public function getRemovedAndAddedFilesCount(): int + { + return $this->removedFilesCount + $this->addedFilesCount; + } + + public function getRemovedNodeCount(): int + { + return $this->removedNodeCount; + } + + /** + * @return SmartFileInfo[] + */ + public function getChangedFileInfos(): array + { + $fileInfos = []; + foreach ($this->fileDiffs as $fileDiff) { + $fileInfos[] = $fileDiff->getFileInfo(); + } + + return array_unique($fileInfos); + } +} diff --git a/src/ValueObjectFactory/Application/FileFactory.php b/src/ValueObjectFactory/Application/FileFactory.php new file mode 100644 index 00000000000..a2d3c534c1e --- /dev/null +++ b/src/ValueObjectFactory/Application/FileFactory.php @@ -0,0 +1,68 @@ +fileProcessors = $fileProcessors; + $this->filesFinder = $filesFinder; + } + + /** + * @param string[] $paths + * @return File[] + */ + public function createFromPaths(array $paths): array + { + $supportedFileExtensions = $this->resolveSupportedFileExtensions(); + $fileInfos = $this->filesFinder->findInDirectoriesAndFiles($paths, $supportedFileExtensions); + + $files = []; + foreach ($fileInfos as $fileInfo) { + $files[] = new File($fileInfo, $fileInfo->getContents()); + } + + return $files; + } + + /** + * @return string[] + */ + private function resolveSupportedFileExtensions(): array + { + $supportedFileExtensions = []; + + foreach ($this->fileProcessors as $fileProcessor) { + $supportedFileExtensions = array_merge( + $supportedFileExtensions, + $fileProcessor->getSupportedFileExtensions() + ); + } + + return array_unique($supportedFileExtensions); + } +} diff --git a/src/ValueObjectFactory/ProcessResultFactory.php b/src/ValueObjectFactory/ProcessResultFactory.php new file mode 100644 index 00000000000..f5280c0d8b5 --- /dev/null +++ b/src/ValueObjectFactory/ProcessResultFactory.php @@ -0,0 +1,45 @@ +errorAndDiffCollector = $errorAndDiffCollector; + } + + /** + * @param File[] $files + */ + public function create(array $files): ProcessResult + { + $fileDiffs = []; + foreach ($files as $file) { + if ($file->getFileDiff() === null) { + continue; + } + + $fileDiffs[] = $file->getFileDiff(); + } + + return new ProcessResult( + $fileDiffs, + $this->errorAndDiffCollector->getErrors(), + $this->errorAndDiffCollector->getAddedFilesCount(), + $this->errorAndDiffCollector->getRemovedFilesCount(), + $this->errorAndDiffCollector->getRemovedNodeCount(), + ); + } +} diff --git a/tests/Application/ApplicationFileProcessor/ApplicationFileProcessorTest.php b/tests/Application/ApplicationFileProcessor/ApplicationFileProcessorTest.php new file mode 100644 index 00000000000..f1f271b1e1a --- /dev/null +++ b/tests/Application/ApplicationFileProcessor/ApplicationFileProcessorTest.php @@ -0,0 +1,54 @@ +bootKernelWithConfigs(RectorKernel::class, [__DIR__ . '/config/configured_rule.php']); + + /** @var Configuration $configuration */ + $configuration = $this->getService(Configuration::class); + $configuration->setIsDryRun(true); + + $this->applicationFileProcessor = $this->getService(ApplicationFileProcessor::class); + $this->fileFactory = $this->getService(FileFactory::class); + $this->processResultFactory = $this->getService(ProcessResultFactory::class); + } + + public function test(): void + { + $files = $this->fileFactory->createFromPaths([__DIR__ . '/Fixture']); + $this->assertCount(2, $files); + + $this->applicationFileProcessor->run($files); + + $processResult = $this->processResultFactory->create($files); + $this->assertCount(1, $processResult->getFileDiffs()); + } +} diff --git a/tests/NonPhpFile/Fixture/bar_stays_bar.txt b/tests/Application/ApplicationFileProcessor/Fixture/bar_stays_bar.txt similarity index 100% rename from tests/NonPhpFile/Fixture/bar_stays_bar.txt rename to tests/Application/ApplicationFileProcessor/Fixture/bar_stays_bar.txt diff --git a/tests/NonPhpFile/Fixture/foo_to_bar.txt b/tests/Application/ApplicationFileProcessor/Fixture/foo_to_bar.txt similarity index 100% rename from tests/NonPhpFile/Fixture/foo_to_bar.txt rename to tests/Application/ApplicationFileProcessor/Fixture/foo_to_bar.txt diff --git a/tests/Application/ApplicationFileProcessor/Source/TextFileProcessor.php b/tests/Application/ApplicationFileProcessor/Source/TextFileProcessor.php new file mode 100644 index 00000000000..863d2862bfc --- /dev/null +++ b/tests/Application/ApplicationFileProcessor/Source/TextFileProcessor.php @@ -0,0 +1,43 @@ +processFile($file); + } + } + + public function supports(File $file): bool + { + $fileInfo = $file->getSmartFileInfo(); + return $fileInfo->hasSuffixes($this->getSupportedFileExtensions()); + } + + /** + * @return string[] + */ + public function getSupportedFileExtensions(): array + { + return ['txt']; + } + + private function processFile($file): void + { + $oldFileContent = $file->getFileContent(); + $changedFileContent = str_replace('Foo', 'Bar', $oldFileContent); + + $file->changeFileContent($changedFileContent); + } +} diff --git a/tests/Application/ApplicationFileProcessor/config/configured_rule.php b/tests/Application/ApplicationFileProcessor/config/configured_rule.php new file mode 100644 index 00000000000..6431b80e34a --- /dev/null +++ b/tests/Application/ApplicationFileProcessor/config/configured_rule.php @@ -0,0 +1,11 @@ +services(); + $services->set(TextFileProcessor::class); +}; diff --git a/tests/NonPhpFile/NonPhpFileProcessorServiceTest.php b/tests/NonPhpFile/NonPhpFileProcessorServiceTest.php deleted file mode 100644 index 7e08da2ab29..00000000000 --- a/tests/NonPhpFile/NonPhpFileProcessorServiceTest.php +++ /dev/null @@ -1,46 +0,0 @@ -getService(Configuration::class); - $configuration->setIsDryRun(true); - - $this->nonPhpFileProcessorService = $this->getService(NonPhpFileProcessorService::class); - $this->errorAndDiffCollector = $this->getService(ErrorAndDiffCollector::class); - } - - public function test(): void - { - $this->nonPhpFileProcessorService->runOnPaths($this->parameterProvider->provideParameter(Option::PATHS)); - $fileDiffs = $this->errorAndDiffCollector->getFileDiffs(); - $this->assertCount(1, $fileDiffs); - } - - public function provideConfigFilePath(): string - { - return __DIR__ . '/config/configured_rule.php'; - } -} diff --git a/tests/NonPhpFile/Source/TextNonPhpFileProcessor.php b/tests/NonPhpFile/Source/TextNonPhpFileProcessor.php deleted file mode 100644 index 3651d398dde..00000000000 --- a/tests/NonPhpFile/Source/TextNonPhpFileProcessor.php +++ /dev/null @@ -1,32 +0,0 @@ -getContents(); - $newContent = str_replace('Foo', 'Bar', $oldContent); - - return new NonPhpFileChange($oldContent, $newContent); - } - - public function supports(SmartFileInfo $smartFileInfo): bool - { - return in_array($smartFileInfo->getExtension(), $this->getSupportedFileExtensions()); - } - - public function getSupportedFileExtensions(): array - { - return ['txt']; - } -} diff --git a/tests/NonPhpFile/config/configured_rule.php b/tests/NonPhpFile/config/configured_rule.php deleted file mode 100644 index aefc40712c4..00000000000 --- a/tests/NonPhpFile/config/configured_rule.php +++ /dev/null @@ -1,15 +0,0 @@ -services(); - $services->set(TextNonPhpFileProcessor::class); - - $parameters = $containerConfigurator->parameters(); - $parameters->set(Option::PATHS, [__DIR__ . '/../Fixture/']); -}; diff --git a/utils/phpstan-extensions/src/TypeAnalyzer/AllowedAutoloadedTypeAnalyzer.php b/utils/phpstan-extensions/src/TypeAnalyzer/AllowedAutoloadedTypeAnalyzer.php index fd471d16a15..0ef29ff941d 100644 --- a/utils/phpstan-extensions/src/TypeAnalyzer/AllowedAutoloadedTypeAnalyzer.php +++ b/utils/phpstan-extensions/src/TypeAnalyzer/AllowedAutoloadedTypeAnalyzer.php @@ -18,7 +18,7 @@ final class AllowedAutoloadedTypeAnalyzer * @see https://regex101.com/r/BBm9bf/1 * @var string */ - private const AUTOLOADED_CLASS_PREFIX_REGEX = '#^(PhpParser|PHPStan|Rector|Reflection)#'; + private const AUTOLOADED_CLASS_PREFIX_REGEX = '#^(PhpParser|PHPStan|Rector|Reflection|Symfony\\\\Component\\\\Console)#'; /** * @var array diff --git a/utils/phpstan-extensions/tests/Rule/NoInstanceOfStaticReflectionRule/Fixture/InstanceofWithType.php b/utils/phpstan-extensions/tests/Rule/NoInstanceOfStaticReflectionRule/Fixture/InstanceofWithType.php index 39b4212f2ce..f503eb0549f 100644 --- a/utils/phpstan-extensions/tests/Rule/NoInstanceOfStaticReflectionRule/Fixture/InstanceofWithType.php +++ b/utils/phpstan-extensions/tests/Rule/NoInstanceOfStaticReflectionRule/Fixture/InstanceofWithType.php @@ -4,13 +4,13 @@ declare(strict_types=1); namespace Rector\PHPStanExtensions\Tests\Rule\NoInstanceOfStaticReflectionRule\Fixture; -use Symfony\Component\Console\Command\Command; +use Hoa\Math\Sampler\Random; final class InstanceofWithType { public function check($object) { - if ($object instanceof Command) { + if ($object instanceof Random) { return true; } } diff --git a/utils/phpstan-extensions/tests/Rule/NoInstanceOfStaticReflectionRule/Fixture/IsAWithType.php b/utils/phpstan-extensions/tests/Rule/NoInstanceOfStaticReflectionRule/Fixture/IsAWithType.php index 8393a9540ea..8d14a791ad6 100644 --- a/utils/phpstan-extensions/tests/Rule/NoInstanceOfStaticReflectionRule/Fixture/IsAWithType.php +++ b/utils/phpstan-extensions/tests/Rule/NoInstanceOfStaticReflectionRule/Fixture/IsAWithType.php @@ -4,12 +4,12 @@ declare(strict_types=1); namespace Rector\PHPStanExtensions\Tests\Rule\NoInstanceOfStaticReflectionRule\Fixture; -use Symfony\Component\Console\Command\Command; +use Hoa\Math\Sampler\Random; final class IsAWithType { public function check($object) { - return is_a($object, Command::class); + return is_a($object, Random::class); } } diff --git a/utils/phpstan-extensions/tests/Rule/NoInstanceOfStaticReflectionRule/Fixture/SkipSymfony.php b/utils/phpstan-extensions/tests/Rule/NoInstanceOfStaticReflectionRule/Fixture/SkipSymfony.php new file mode 100644 index 00000000000..94c8fe09661 --- /dev/null +++ b/utils/phpstan-extensions/tests/Rule/NoInstanceOfStaticReflectionRule/Fixture/SkipSymfony.php @@ -0,0 +1,15 @@ +