mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-17 13:28:18 +01:00
Refactor file processors towards universal collector (#6085)
Co-authored-by: kaizen-ci <info@kaizen-ci.org>
This commit is contained in:
parent
faca7e2763
commit
06f85e4a68
@ -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 = [];
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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()]);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\ChangesReporting\ValueObjectFactory;
|
||||
|
||||
use Rector\ChangesReporting\Collector\RectorChangeCollector;
|
||||
use Rector\Core\Differ\DefaultDiffer;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\Core\ValueObject\Reporting\FileDiff;
|
||||
use Symplify\ConsoleColorDiff\Console\Output\ConsoleDiffer;
|
||||
|
||||
final class FileDiffFactory
|
||||
{
|
||||
/**
|
||||
* @var RectorChangeCollector
|
||||
*/
|
||||
private $rectorChangeCollector;
|
||||
|
||||
/**
|
||||
* @var DefaultDiffer
|
||||
*/
|
||||
private $defaultDiffer;
|
||||
|
||||
/**
|
||||
* @var ConsoleDiffer
|
||||
*/
|
||||
private $consoleDiffer;
|
||||
|
||||
public function __construct(
|
||||
RectorChangeCollector $rectorChangeCollector,
|
||||
DefaultDiffer $defaultDiffer,
|
||||
ConsoleDiffer $consoleDiffer
|
||||
) {
|
||||
$this->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
|
||||
);
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
@ -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, [
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -1,13 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\PhpAttribute\ValueObject;
|
||||
|
||||
final class TagName
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const API = 'api';
|
||||
}
|
@ -17,6 +17,7 @@ use Rector\ChangesReporting\Collector\AffectedFilesCollector;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\PhpParser\Comparing\NodeComparator;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\NodeRemoval\BreakingRemovalGuard;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\PostRector\Contract\Collector\NodeCollectorInterface;
|
||||
@ -82,7 +83,7 @@ final class NodesToRemoveCollector implements NodeCollectorInterface
|
||||
/** @var SmartFileInfo|null $fileInfo */
|
||||
$fileInfo = $node->getAttribute(AttributeKey::FILE_INFO);
|
||||
if ($fileInfo !== null) {
|
||||
$this->affectedFilesCollector->addFile($fileInfo);
|
||||
$this->affectedFilesCollector->addFile(new File($fileInfo, $fileInfo->getContents()));
|
||||
}
|
||||
|
||||
/** @var Stmt $node */
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
10
phpstan.neon
10
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
|
||||
|
@ -7,6 +7,5 @@ use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigura
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
|
||||
$services->set(FormControlToControllerAndFormTypeRector::class);
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -7,6 +7,5 @@ use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigura
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
|
||||
$services->set(MultipleClassFileToPsr4ClassesRector::class);
|
||||
};
|
||||
|
@ -7,6 +7,5 @@ use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigura
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
|
||||
$services->set(PrivatizeLocalPropertyToPrivatePropertyRector::class);
|
||||
};
|
||||
|
@ -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']);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
101
src/Application/ApplicationFileProcessor.php
Normal file
101
src/Application/ApplicationFileProcessor.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\Application;
|
||||
|
||||
use Rector\Core\Application\FileDecorator\FileDiffFileDecorator;
|
||||
use Rector\Core\Configuration\Configuration;
|
||||
use Rector\Core\Contract\Processor\FileProcessorInterface;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Symplify\SmartFileSystem\SmartFileSystem;
|
||||
|
||||
final class ApplicationFileProcessor
|
||||
{
|
||||
/**
|
||||
* @var FileProcessorInterface[]
|
||||
*/
|
||||
private $fileProcessors = [];
|
||||
|
||||
/**
|
||||
* @var SmartFileSystem
|
||||
*/
|
||||
private $smartFileSystem;
|
||||
|
||||
/**
|
||||
* @var Configuration
|
||||
*/
|
||||
private $configuration;
|
||||
|
||||
/**
|
||||
* @var FileDiffFileDecorator
|
||||
*/
|
||||
private $fileDiffFileDecorator;
|
||||
|
||||
/**
|
||||
* @param FileProcessorInterface[] $fileProcessors
|
||||
*/
|
||||
public function __construct(
|
||||
Configuration $configuration,
|
||||
SmartFileSystem $smartFileSystem,
|
||||
FileDiffFileDecorator $fileDiffFileDecorator,
|
||||
array $fileProcessors = []
|
||||
) {
|
||||
$this->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());
|
||||
}
|
||||
}
|
41
src/Application/FileDecorator/FileDiffFileDecorator.php
Normal file
41
src/Application/FileDecorator/FileDiffFileDecorator.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\Application\FileDecorator;
|
||||
|
||||
use Rector\ChangesReporting\ValueObjectFactory\FileDiffFactory;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
|
||||
final class FileDiffFileDecorator
|
||||
{
|
||||
/**
|
||||
* @var FileDiffFactory
|
||||
*/
|
||||
private $fileDiffFactory;
|
||||
|
||||
public function __construct(FileDiffFactory $fileDiffFactory)
|
||||
{
|
||||
$this->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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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()) {
|
53
src/Autoloading/BootstrapFilesIncluder.php
Normal file
53
src/Autoloading/BootstrapFilesIncluder.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\Autoloading;
|
||||
|
||||
use Rector\Core\Configuration\Option;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Symplify\PackageBuilder\Parameter\ParameterProvider;
|
||||
use Throwable;
|
||||
|
||||
final class BootstrapFilesIncluder
|
||||
{
|
||||
/**
|
||||
* @var ParameterProvider
|
||||
*/
|
||||
private $parameterProvider;
|
||||
|
||||
public function __construct(ParameterProvider $parameterProvider)
|
||||
{
|
||||
$this->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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\Contract;
|
||||
|
||||
interface PostRunnerInterface
|
||||
{
|
||||
public function run(): void;
|
||||
}
|
@ -3,14 +3,16 @@ declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\Contract\Processor;
|
||||
|
||||
use Rector\Core\ValueObject\NonPhpFile\NonPhpFileChange;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
|
||||
interface FileProcessorInterface
|
||||
{
|
||||
public function process(SmartFileInfo $smartFileInfo): ?NonPhpFileChange;
|
||||
public function supports(File $file): bool;
|
||||
|
||||
public function supports(SmartFileInfo $smartFileInfo): bool;
|
||||
/**
|
||||
* @param File[] $files
|
||||
*/
|
||||
public function process(array $files): void;
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
|
@ -6,10 +6,9 @@ namespace Rector\Core\NonPhpFile;
|
||||
|
||||
use Rector\Core\Configuration\RenamedClassesDataCollector;
|
||||
use Rector\Core\Contract\Processor\FileProcessorInterface;
|
||||
use Rector\Core\ValueObject\NonPhpFile\NonPhpFileChange;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\Core\ValueObject\StaticNonPhpFileSuffixes;
|
||||
use Rector\PSR4\Collector\RenamedClassesCollector;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
/**
|
||||
* @see \Rector\Tests\Renaming\Rector\Name\RenameClassRector\RenameNonPhpTest
|
||||
@ -41,32 +40,38 @@ final class NonPhpFileProcessor implements FileProcessorInterface
|
||||
$this->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);
|
||||
}
|
||||
}
|
||||
|
@ -1,124 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\NonPhpFile;
|
||||
|
||||
use Rector\ChangesReporting\Application\ErrorAndDiffCollector;
|
||||
use Rector\Core\Configuration\Configuration;
|
||||
use Rector\Core\Contract\Processor\FileProcessorInterface;
|
||||
use Rector\Core\FileSystem\FilesFinder;
|
||||
use Rector\Core\ValueObject\NonPhpFile\NonPhpFileChange;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
use Symplify\SmartFileSystem\SmartFileSystem;
|
||||
|
||||
final class NonPhpFileProcessorService
|
||||
{
|
||||
/**
|
||||
* @var FileProcessorInterface[]
|
||||
*/
|
||||
private $nonPhpFileProcessors = [];
|
||||
|
||||
/**
|
||||
* @var SmartFileSystem
|
||||
*/
|
||||
private $smartFileSystem;
|
||||
|
||||
/**
|
||||
* @var Configuration
|
||||
*/
|
||||
private $configuration;
|
||||
|
||||
/**
|
||||
* @var ErrorAndDiffCollector
|
||||
*/
|
||||
private $errorAndDiffCollector;
|
||||
|
||||
/**
|
||||
* @var FilesFinder
|
||||
*/
|
||||
private $filesFinder;
|
||||
|
||||
/**
|
||||
* @param FileProcessorInterface[] $nonPhpFileProcessors
|
||||
*/
|
||||
public function __construct(
|
||||
FilesFinder $filesFinder,
|
||||
ErrorAndDiffCollector $errorAndDiffCollector,
|
||||
Configuration $configuration,
|
||||
SmartFileSystem $smartFileSystem,
|
||||
array $nonPhpFileProcessors = []
|
||||
) {
|
||||
$this->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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
74
src/Reflection/FunctionLikeReflectionParser.php
Normal file
74
src/Reflection/FunctionLikeReflectionParser.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\Reflection;
|
||||
|
||||
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;
|
||||
|
||||
class 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 ($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());
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
86
src/ValueObject/Application/File.php
Normal file
86
src/ValueObject/Application/File.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\ValueObject\Application;
|
||||
|
||||
use Rector\Core\ValueObject\Reporting\FileDiff;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
/**
|
||||
* @see \Rector\Core\ValueObjectFactory\Application\FileFactory
|
||||
*/
|
||||
final class File
|
||||
{
|
||||
/**
|
||||
* @var SmartFileInfo
|
||||
*/
|
||||
private $smartFileInfo;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $fileContent;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $hasChanged = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $originalFileContent;
|
||||
|
||||
/**
|
||||
* @var FileDiff|null
|
||||
*/
|
||||
private $fileDiff;
|
||||
|
||||
public function __construct(SmartFileInfo $smartFileInfo, string $fileContent)
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\ValueObject\NonPhpFile;
|
||||
|
||||
final class NonPhpFileChange
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $oldContent;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $newContent;
|
||||
|
||||
public function __construct(string $oldContent, string $newContent)
|
||||
{
|
||||
$this->oldContent = $oldContent;
|
||||
$this->newContent = $newContent;
|
||||
}
|
||||
|
||||
public function getOldContent(): string
|
||||
{
|
||||
return $this->oldContent;
|
||||
}
|
||||
|
||||
public function getNewContent(): string
|
||||
{
|
||||
return $this->newContent;
|
||||
}
|
||||
}
|
111
src/ValueObject/ProcessResult.php
Normal file
111
src/ValueObject/ProcessResult.php
Normal file
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\ValueObject;
|
||||
|
||||
use Rector\Core\ValueObject\Application\RectorError;
|
||||
use Rector\Core\ValueObject\Reporting\FileDiff;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
/**
|
||||
* @see \Rector\Core\ValueObjectFactory\ProcessResultFactory
|
||||
*/
|
||||
final class ProcessResult
|
||||
{
|
||||
/**
|
||||
* @var FileDiff[]
|
||||
*/
|
||||
private $fileDiffs = [];
|
||||
|
||||
/**
|
||||
* @var RectorError[]
|
||||
*/
|
||||
private $errors = [];
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $addedFilesCount;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $removedFilesCount;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $removedNodeCount;
|
||||
|
||||
/**
|
||||
* @param FileDiff[] $fileDiffs
|
||||
* @param RectorError[] $errors
|
||||
*/
|
||||
public function __construct(
|
||||
array $fileDiffs,
|
||||
array $errors,
|
||||
int $addedFilesCount,
|
||||
int $removedFilesCount,
|
||||
int $removedNodeCount
|
||||
) {
|
||||
Assert::allIsAOf($fileDiffs, FileDiff::class);
|
||||
Assert::allIsAOf($errors, RectorError::class);
|
||||
|
||||
$this->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);
|
||||
}
|
||||
}
|
68
src/ValueObjectFactory/Application/FileFactory.php
Normal file
68
src/ValueObjectFactory/Application/FileFactory.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\ValueObjectFactory\Application;
|
||||
|
||||
use Rector\Core\Contract\Processor\FileProcessorInterface;
|
||||
use Rector\Core\FileSystem\FilesFinder;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
|
||||
/**
|
||||
* @see \Rector\Core\ValueObject\Application\File
|
||||
*/
|
||||
final class FileFactory
|
||||
{
|
||||
/**
|
||||
* @var FileProcessorInterface[]
|
||||
*/
|
||||
private $fileProcessors = [];
|
||||
|
||||
/**
|
||||
* @var FilesFinder
|
||||
*/
|
||||
private $filesFinder;
|
||||
|
||||
/**
|
||||
* @param FileProcessorInterface[] $fileProcessors
|
||||
*/
|
||||
public function __construct(FilesFinder $filesFinder, array $fileProcessors)
|
||||
{
|
||||
$this->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);
|
||||
}
|
||||
}
|
45
src/ValueObjectFactory/ProcessResultFactory.php
Normal file
45
src/ValueObjectFactory/ProcessResultFactory.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\ValueObjectFactory;
|
||||
|
||||
use Rector\ChangesReporting\Application\ErrorAndDiffCollector;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\Core\ValueObject\ProcessResult;
|
||||
|
||||
final class ProcessResultFactory
|
||||
{
|
||||
/**
|
||||
* @var ErrorAndDiffCollector
|
||||
*/
|
||||
private $errorAndDiffCollector;
|
||||
|
||||
public function __construct(ErrorAndDiffCollector $errorAndDiffCollector)
|
||||
{
|
||||
$this->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(),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\Tests\Application\ApplicationFileProcessor;
|
||||
|
||||
use Rector\Core\Application\ApplicationFileProcessor;
|
||||
use Rector\Core\Configuration\Configuration;
|
||||
use Rector\Core\HttpKernel\RectorKernel;
|
||||
use Rector\Core\ValueObjectFactory\Application\FileFactory;
|
||||
use Rector\Core\ValueObjectFactory\ProcessResultFactory;
|
||||
use Symplify\PackageBuilder\Testing\AbstractKernelTestCase;
|
||||
|
||||
final class ApplicationFileProcessorTest extends AbstractKernelTestCase
|
||||
{
|
||||
/**
|
||||
* @var ApplicationFileProcessor
|
||||
*/
|
||||
private $applicationFileProcessor;
|
||||
|
||||
/**
|
||||
* @var FileFactory
|
||||
*/
|
||||
private $fileFactory;
|
||||
|
||||
/**
|
||||
* @var ProcessResultFactory
|
||||
*/
|
||||
private $processResultFactory;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->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());
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\Tests\Application\ApplicationFileProcessor\Source;
|
||||
|
||||
use Rector\Core\Contract\Processor\FileProcessorInterface;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
|
||||
final class TextFileProcessor implements FileProcessorInterface
|
||||
{
|
||||
/**
|
||||
* @param File[] $files
|
||||
*/
|
||||
public function process(array $files): void
|
||||
{
|
||||
foreach ($files as $file) {
|
||||
$this->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);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Core\Tests\Application\ApplicationFileProcessor\Source\TextFileProcessor;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(TextFileProcessor::class);
|
||||
};
|
@ -1,46 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\Tests\NonPhpFile;
|
||||
|
||||
use Rector\ChangesReporting\Application\ErrorAndDiffCollector;
|
||||
use Rector\Core\Configuration\Configuration;
|
||||
use Rector\Core\Configuration\Option;
|
||||
use Rector\Core\NonPhpFile\NonPhpFileProcessorService;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
final class NonPhpFileProcessorServiceTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @var NonPhpFileProcessorService
|
||||
*/
|
||||
private $nonPhpFileProcessorService;
|
||||
|
||||
/**
|
||||
* @var ErrorAndDiffCollector
|
||||
*/
|
||||
private $errorAndDiffCollector;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
/** @var Configuration $configuration */
|
||||
$configuration = $this->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';
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace Rector\Core\Tests\NonPhpFile\Source;
|
||||
|
||||
|
||||
use Rector\Core\Contract\Processor\FileProcessorInterface;
|
||||
use Rector\Core\ValueObject\NonPhpFile\NonPhpFileChange;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class TextNonPhpFileProcessor implements FileProcessorInterface
|
||||
{
|
||||
|
||||
public function process(SmartFileInfo $smartFileInfo): ?NonPhpFileChange
|
||||
{
|
||||
$oldContent = $smartFileInfo->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'];
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Core\Configuration\Option;
|
||||
use Rector\Core\Tests\NonPhpFile\Source\TextNonPhpFileProcessor;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(TextNonPhpFileProcessor::class);
|
||||
|
||||
$parameters = $containerConfigurator->parameters();
|
||||
$parameters->set(Option::PATHS, [__DIR__ . '/../Fixture/']);
|
||||
};
|
@ -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<class-string>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPStanExtensions\Tests\Rule\NoInstanceOfStaticReflectionRule\Fixture;
|
||||
|
||||
use Symfony\Component\Console\Helper\ProgressBar;
|
||||
|
||||
final class SkipSymfony
|
||||
{
|
||||
public function find($node)
|
||||
{
|
||||
return $node instanceof ProgressBar;
|
||||
}
|
||||
}
|
@ -37,6 +37,7 @@ final class NoInstanceOfStaticReflectionRuleTest extends AbstractServiceAwareRul
|
||||
yield [__DIR__ . '/Fixture/SkipReflection.php', []];
|
||||
yield [__DIR__ . '/Fixture/SkipDateTime.php', []];
|
||||
yield [__DIR__ . '/Fixture/SkipTypesArray.php', []];
|
||||
yield [__DIR__ . '/Fixture/SkipSymfony.php', []];
|
||||
}
|
||||
|
||||
protected function getRule(): Rule
|
||||
|
Loading…
x
Reference in New Issue
Block a user