add support for override of already checked file

This commit is contained in:
Tomas Votruba 2018-12-07 18:54:24 +01:00
parent 522dc17cdb
commit d60e21c0a0
8 changed files with 122 additions and 28 deletions

View File

@ -10,6 +10,7 @@ use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Interface_;
use Rector\Application\FilesToReprintCollector;
use Rector\NodeTypeResolver\Application\ClassLikeNodeCollector;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockAnalyzer;
@ -41,9 +42,15 @@ abstract class AbstractScalarTypehintRector extends AbstractRector
*/
protected $classLikeNodeCollector;
/**
* @var FilesToReprintCollector
*/
protected $filesToReprintCollector;
public function __construct(
DocBlockAnalyzer $docBlockAnalyzer,
ClassLikeNodeCollector $classLikeNodeCollector,
FilesToReprintCollector $filesToReprintCollector,
bool $enableObjectType = false
) {
$this->docBlockAnalyzer = $docBlockAnalyzer;
@ -52,6 +59,7 @@ abstract class AbstractScalarTypehintRector extends AbstractRector
if ($enableObjectType) {
PhpTypeSupport::enableType('object');
}
$this->filesToReprintCollector = $filesToReprintCollector;
}
/**

View File

@ -11,6 +11,7 @@ use PhpParser\Node\Stmt\Function_;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
final class ReturnScalarTypehintRector extends AbstractScalarTypehintRector
{
@ -134,6 +135,12 @@ CODE_SAMPLE
// let the method now it was changed now
$childrenClassMethod->returnType->setAttribute(self::HAS_NEW_INHERITED_TYPE, true);
// reprint the file
/** @var SmartFileInfo $fileInfo */
$fileInfo = $childrenClassMethod->getAttribute(Attribute::FILE_INFO);
$this->filesToReprintCollector->addFileInfoWithNewTokens($fileInfo);
}
}

View File

@ -20,7 +20,6 @@ final class ParamAndReturnScalarTypehintsRectorTest extends AbstractRectorTestCa
__DIR__ . '/Fixture/external_scope.php.inc',
__DIR__ . '/Fixture/local_and_external_scope.php.inc',
__DIR__ . '/Fixture/local_scope_with_parent_interface.php.inc',
__DIR__ . '/Fixture/local_scope_with_parent_interface2.php.inc',
__DIR__ . '/Fixture/local_scope_with_parent_class.php.inc',
__DIR__ . '/Fixture/local_scope_with_parent_class2.php.inc',
__DIR__ . '/Fixture/complex_array.php.inc',

View File

@ -43,6 +43,11 @@ final class FileProcessor
*/
private $currentFileInfoProvider;
/**
* @var mixed[][]
*/
private $tokensByFilePath = [];
public function __construct(
FormatPerservingPrinter $formatPerservingPrinter,
Parser $parser,
@ -65,6 +70,17 @@ final class FileProcessor
[$newStmts, $oldStmts, $oldTokens] = $this->parseAndTraverseFileInfoToNodes($smartFileInfo);
// store tokens by absolute path, so we don't have to print them right now
$this->tokensByFilePath[$smartFileInfo->getRealPath()] = [$newStmts, $oldStmts, $oldTokens];
return $this->formatPerservingPrinter->printToFile($smartFileInfo, $newStmts, $oldStmts, $oldTokens);
}
public function reprintFile(SmartFileInfo $smartFileInfo): string
{
// restore tokens
[$newStmts, $oldStmts, $oldTokens] = $this->tokensByFilePath[$smartFileInfo->getRealPath()];
return $this->formatPerservingPrinter->printToFile($smartFileInfo, $newStmts, $oldStmts, $oldTokens);
}
@ -77,6 +93,20 @@ final class FileProcessor
[$newStmts, $oldStmts, $oldTokens] = $this->parseAndTraverseFileInfoToNodes($smartFileInfo);
// store tokens by absolute path, so we don't have to print them right now
$this->tokensByFilePath[$smartFileInfo->getRealPath()] = [$newStmts, $oldStmts, $oldTokens];
return $this->formatPerservingPrinter->printToString($newStmts, $oldStmts, $oldTokens);
}
/**
* See https://github.com/nikic/PHP-Parser/issues/344#issuecomment-298162516.
*/
public function reprintToString(SmartFileInfo $smartFileInfo): string
{
// restore tokens
[$newStmts, $oldStmts, $oldTokens] = $this->tokensByFilePath[$smartFileInfo->getRealPath()];
return $this->formatPerservingPrinter->printToString($newStmts, $oldStmts, $oldTokens);
}

View File

@ -0,0 +1,31 @@
<?php declare(strict_types=1);
namespace Rector\Application;
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
final class FilesToReprintCollector
{
/**
* @var SmartFileInfo[]
*/
private $fileInfos = [];
public function addFileInfoWithNewTokens(SmartFileInfo $smartFileInfo): void
{
$this->fileInfos[$smartFileInfo->getRealPath()] = $smartFileInfo;
}
/**
* @return SmartFileInfo[]
*/
public function getFileInfos(): array
{
return $this->fileInfos;
}
public function reset(): void
{
$this->fileInfos = [];
}
}

View File

@ -7,6 +7,7 @@ use Rector\Application\AppliedRectorCollector;
use Rector\Application\Error;
use Rector\Application\ErrorCollector;
use Rector\Application\FileProcessor;
use Rector\Application\FilesToReprintCollector;
use Rector\Autoloading\AdditionalAutoloader;
use Rector\CodingStyle\AfterRectorCodingStyle;
use Rector\Configuration\Option;
@ -32,11 +33,6 @@ use function Safe\sprintf;
final class ProcessCommand extends Command
{
/**
* @var string[]
*/
private $changedFiles = [];
/**
* @var FileDiff[]
*/
@ -102,6 +98,11 @@ final class ProcessCommand extends Command
*/
private $appliedRectorCollector;
/**
* @var FilesToReprintCollector
*/
private $filesToReprintCollector;
public function __construct(
FileProcessor $fileProcessor,
SymfonyStyle $symfonyStyle,
@ -114,7 +115,8 @@ final class ProcessCommand extends Command
FileSystemFileProcessor $fileSystemFileProcessor,
ErrorCollector $errorCollector,
AfterRectorCodingStyle $afterRectorCodingStyle,
AppliedRectorCollector $appliedRectorCollector
AppliedRectorCollector $appliedRectorCollector,
FilesToReprintCollector $filesToReprintCollector
) {
parent::__construct();
@ -130,6 +132,7 @@ final class ProcessCommand extends Command
$this->errorCollector = $errorCollector;
$this->afterRectorCodingStyle = $afterRectorCodingStyle;
$this->appliedRectorCollector = $appliedRectorCollector;
$this->filesToReprintCollector = $filesToReprintCollector;
}
protected function configure(): void
@ -178,15 +181,13 @@ final class ProcessCommand extends Command
$this->parameterProvider->changeParameter(Option::OPTION_DRY_RUN, $input->getOption(Option::OPTION_DRY_RUN));
$phpFileInfos = $this->filesFinder->findInDirectoriesAndFiles($source, ['php']);
$yamlFileInfos = $this->filesFinder->findInDirectoriesAndFiles($source, ['yml', 'yaml']);
$allFileInfos = $phpFileInfos + $yamlFileInfos;
$this->additionalAutoloader->autoloadWithInputAndSource($input, $source);
$this->processFileInfos($allFileInfos, (bool) $input->getOption(Option::HIDE_AUTOLOAD_ERRORS));
$this->processFileInfos($phpFileInfos, (bool) $input->getOption(Option::HIDE_AUTOLOAD_ERRORS));
$this->processCommandReporter->reportFileDiffs($this->fileDiffs);
$this->processCommandReporter->reportChangedFiles($this->changedFiles);
$this->processCommandReporter->reportChangedFiles(array_keys($this->fileDiffs));
if ($this->errorCollector->getErrors()) {
$this->processCommandReporter->reportErrors($this->errorCollector->getErrors());
@ -231,7 +232,8 @@ final class ProcessCommand extends Command
private function processFileInfo(SmartFileInfo $fileInfo, bool $shouldHideAutoloadErrors): void
{
try {
$this->processAnyFile($fileInfo);
$this->processFile($fileInfo);
$this->fileSystemFileProcessor->processFileInfo($fileInfo);
} catch (AnalysedCodeException $analysedCodeException) {
if ($shouldHideAutoloadErrors) {
return;
@ -264,19 +266,24 @@ final class ProcessCommand extends Command
if ($this->parameterProvider->provideParameter(Option::OPTION_DRY_RUN)) {
$newContent = $this->fileProcessor->processFileToString($fileInfo);
if ($newContent !== $oldContent) {
$this->fileDiffs[] = new FileDiff(
$fileInfo->getPathname(),
$this->differAndFormatter->diffAndFormat($oldContent, $newContent),
$this->appliedRectorCollector->getRectorClasses()
);
foreach ($this->filesToReprintCollector->getFileInfos() as $fileInfoToReprint) {
$reprintedOldContent = $fileInfoToReprint->getContents();
$reprintedNewContent = $this->fileProcessor->reprintToString($fileInfoToReprint);
$this->recordFileDiff($fileInfoToReprint, $reprintedNewContent, $reprintedOldContent);
}
} else {
$newContent = $this->fileProcessor->processFile($fileInfo);
if ($newContent !== $oldContent) {
$this->changedFiles[] = $fileInfo->getPathname();
foreach ($this->filesToReprintCollector->getFileInfos() as $fileInfoToReprint) {
$reprintedOldContent = $fileInfoToReprint->getContents();
$reprintedNewContent = $this->fileProcessor->reprintFile($fileInfoToReprint);
$this->recordFileDiff($fileInfoToReprint, $reprintedNewContent, $reprintedOldContent);
}
}
$this->recordFileDiff($fileInfo, $newContent, $oldContent);
$this->filesToReprintCollector->reset();
}
private function matchRectorClass(Throwable $throwable): ?string
@ -294,12 +301,17 @@ final class ProcessCommand extends Command
return $class;
}
private function processAnyFile(SmartFileInfo $fileInfo): void
private function recordFileDiff(SmartFileInfo $fileInfo, string $newContent, string $oldContent): void
{
if ($fileInfo->getExtension() === 'php') {
$this->processFile($fileInfo);
if ($newContent === $oldContent) {
return;
}
$this->fileSystemFileProcessor->processFileInfo($fileInfo);
// always keep the most recent diff
$this->fileDiffs[$fileInfo->getRealPath()] = new FileDiff(
$fileInfo->getRealPath(),
$this->differAndFormatter->diffAndFormat($oldContent, $newContent),
$this->appliedRectorCollector->getRectorClasses()
);
}
}

View File

@ -5,6 +5,8 @@ namespace Rector\Console\Output;
use Rector\Application\Error;
use Rector\Reporting\FileDiff;
use Symfony\Component\Console\Style\SymfonyStyle;
use function Safe\ksort;
use function Safe\sort;
use function Safe\sprintf;
final class ProcessCommandReporter
@ -28,6 +30,8 @@ final class ProcessCommandReporter
return;
}
sort($changedFiles);
$this->symfonyStyle->title(
sprintf('%d Changed file%s', count($changedFiles), count($changedFiles) === 1 ? '' : 's')
);
@ -43,6 +47,9 @@ final class ProcessCommandReporter
return;
}
// normalize
ksort($fileDiffs);
$this->symfonyStyle->title(
sprintf('%d file%s with changes', count($fileDiffs), count($fileDiffs) === 1 ? '' : 's')
);

View File

@ -65,16 +65,16 @@ final class NameResolver
return 'empty';
};
$this->nameResolversPerNode[Class_::class] = function (Class_ $classNode): string {
if ($classNode->namespacedName) {
$this->nameResolversPerNode[Class_::class] = function (Class_ $classNode): ?string {
if (isset($classNode->namespacedName)) {
return $classNode->namespacedName->toString();
}
return $this->resolve($classNode->name);
};
$this->nameResolversPerNode[Interface_::class] = function (Interface_ $interfaceNode): string {
if ($interfaceNode->namespacedName) {
$this->nameResolversPerNode[Interface_::class] = function (Interface_ $interfaceNode): ?string {
if (isset($interfaceNode->namespacedName)) {
return $interfaceNode->namespacedName->toString();
}