Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ecs-after-rector.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ services:

# add spaces between class elements
PhpCsFixer\Fixer\ClassNotation\ClassAttributesSeparationFixer: ~

# add declare strict types to start of the file
PhpCsFixer\Fixer\Strict\DeclareStrictTypesFixer: ~
1 change: 1 addition & 0 deletions ecs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ services:
- 'PhpParser\NodeVisitor\NameResolver'
- 'PhpParser\Node\*'
- 'PhpParser\Comment'
- 'PhpParser\Lexer'
- 'PhpParser\Comment\Doc'
- 'PhpParser\NodeTraverser'
- 'Rector\Reporting\FileDiff'
Expand Down
10 changes: 3 additions & 7 deletions packages/CodingStyle/src/Rector/Use_/RemoveUnusedAliasRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -254,14 +254,10 @@ private function resolveUsedNames(Node $searchNode): void

private function resolveUsedClassNames(Node $searchNode): void
{
/** @var ClassLike[] $classLikeNodes */
$classLikeNodes = $this->betterNodeFinder->findInstanceOf($searchNode, ClassLike::class);

foreach ($classLikeNodes as $classLikeNode) {
if ($classLikeNode->name === null) { // skip anonymous classes
continue;
}
/** @var ClassLike[] $classLikes */
$classLikes = $this->betterNodeFinder->findClassLikes([$searchNode]);

foreach ($classLikes as $classLikeNode) {
$name = $this->getName($classLikeNode->name);
$this->resolvedNodeNames[$name][] = [$classLikeNode->name, $classLikeNode];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@

namespace Rector\FileSystemRector\Rector;

use Nette\Utils\Strings;
use PhpParser\Lexer;
use PhpParser\Node;
use PhpParser\ParserFactory;
use Rector\Application\FileSystem\RemovedAndAddedFilesCollector;
use Rector\Configuration\Configuration;
use Rector\FileSystemRector\Contract\FileSystemRectorInterface;
use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator;
use Rector\PhpParser\Parser\Parser;
use Rector\PhpParser\Printer\BetterStandardPrinter;
use Rector\PhpParser\Printer\FormatPerservingPrinter;
use Rector\Rector\AbstractRectorTrait;
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
use TypeError;

abstract class AbstractFileSystemRector implements FileSystemRectorInterface
{
Expand Down Expand Up @@ -52,23 +56,32 @@ abstract class AbstractFileSystemRector implements FileSystemRectorInterface
*/
private $removedAndAddedFilesCollector;

/**
* @var ParserFactory
*/
private $parserFactory;

/**
* @required
*/
public function setAbstractFileSystemRectorDependencies(
Parser $parser,
ParserFactory $parserFactory,
Lexer $lexer,
FormatPerservingPrinter $formatPerservingPrinter,
NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator,
RemovedAndAddedFilesCollector $removedAndAddedFilesCollector,
Configuration $configuration
Configuration $configuration,
BetterStandardPrinter $betterStandardPrinter
): void {
$this->parser = $parser;
$this->parserFactory = $parserFactory;
$this->lexer = $lexer;
$this->formatPerservingPrinter = $formatPerservingPrinter;
$this->nodeScopeAndMetadataDecorator = $nodeScopeAndMetadataDecorator;
$this->removedAndAddedFilesCollector = $removedAndAddedFilesCollector;
$this->configuration = $configuration;
$this->betterStandardPrinter = $betterStandardPrinter;
}

/**
Expand Down Expand Up @@ -99,6 +112,46 @@ protected function printNodesToFilePath(array $nodes, string $fileDestination):
$this->addFile($fileDestination, $fileContent);
}

/**
* @param Node[] $nodes
*/
protected function printNewNodesToFilePath(array $nodes, string $fileDestination): void
{
// 1. if nodes are the same, prefer format preserving printer
try {
$dummyLexer = new Lexer();
$dummyParser = $this->parserFactory->create(ParserFactory::PREFER_PHP7, $dummyLexer);
$dummyParser->parse('<?php ' . $this->print($nodes));

$dummyTokenCount = count($dummyLexer->getTokens());
$modelTokenCount = count($this->lexer->getTokens());

if ($dummyTokenCount > $modelTokenCount) {
// nothing we can do - this would end by "Undefined offset in TokenStream.php on line X" error
$formatPreservingContent = '';
} else {
$formatPreservingContent = $this->formatPerservingPrinter->printToString(
$nodes,
$this->oldStmts,
$this->lexer->getTokens()
);
}
} catch (TypeError $typeError) {
// incompatible tokens, nothing we can do to preserve format
$formatPreservingContent = '';
}

$prettyPrintContent = '<?php' . PHP_EOL . $this->betterStandardPrinter->prettyPrint($nodes);

if ($this->areStringsSameWithoutSpaces($formatPreservingContent, $prettyPrintContent)) {
$fileContent = $formatPreservingContent;
} else {
$fileContent = $prettyPrintContent;
}

$this->addFile($fileDestination, $fileContent);
}

protected function removeFile(SmartFileInfo $smartFileInfo): void
{
$this->removedAndAddedFilesCollector->removeFile($smartFileInfo);
Expand All @@ -108,4 +161,32 @@ protected function addFile(string $filePath, string $content): void
{
$this->removedAndAddedFilesCollector->addFileWithContent($filePath, $content);
}

/**
* Also without FQN "\" that are added by basic printer
*/
private function areStringsSameWithoutSpaces(string $firstString, string $secondString): bool
{
// remove all comments

// remove all spaces
$firstString = Strings::replace($firstString, '#\s+#', '');
$secondString = Strings::replace($secondString, '#\s+#', '');

$firstString = $this->removeComments($firstString);
$secondString = $this->removeComments($secondString);

// remove FQN "\" that are added by basic printer
$firstString = Strings::replace($firstString, '#\\\\#', '');
$secondString = Strings::replace($secondString, '#\\\\#', '');

return $firstString === $secondString;
}

private function removeComments(string $string): string
{
$string = Strings::replace($string, '#/\*.*?\*/#s', '');

return Strings::replace($string, '#\n\s*\n#', "\n");
}
}
3 changes: 3 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,6 @@ parameters:
- '#Cannot call method getRealPath\(\) on Symplify\\PackageBuilder\\FileSystem\\SmartFileInfo\|null#'
# cascade irelevant
- '#Parameter (.*?) expects array<PhpParser\\Node\\Stmt\>, array<PhpParser\\Node\> given#'

# known value
- '#Parameter \#1 \$node of method Rector\\Rector\\AbstractRector\:\:getName\(\) expects PhpParser\\Node, PhpParser\\Node\\Identifier\|null given#'
2 changes: 1 addition & 1 deletion rector.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ parameters:
php_version_features: '7.1'

services:
# Rector\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector: ~
Rector\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector: ~
23 changes: 23 additions & 0 deletions src/PhpParser/Node/BetterNodeFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Expression;
use PhpParser\NodeFinder;
use Rector\NodeTypeResolver\Node\AttributeKey;
Expand Down Expand Up @@ -112,6 +114,27 @@ public function find($nodes, callable $filter): array
return $this->nodeFinder->find($nodes, $filter);
}

/**
* Excludes anonymous classes!
*
* @param Node[] $nodes
* @return ClassLike[]
*/
public function findClassLikes(array $nodes): array
{
return $this->find($nodes, function (Node $node): bool {
if (! $node instanceof ClassLike) {
return false;
}

if ($node instanceof Class_ && $node->isAnonymous()) {
return false;
}

return true;
});
}

/**
* @param Node|Node[] $nodes
*/
Expand Down
24 changes: 0 additions & 24 deletions src/Rector/AbstractRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
use Rector\Contract\Rector\PhpRectorInterface;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Php\PhpVersionProvider;
use Rector\PhpParser\Node\Value\ValueResolver;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;

Expand All @@ -36,11 +35,6 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
*/
private $removedAndAddedFilesCollector;

/**
* @var ValueResolver
*/
private $valueResolver;

/**
* @var PhpVersionProvider
*/
Expand All @@ -58,13 +52,11 @@ protected function tearDown(): void
*/
public function setAbstractRectorDependencies(
SymfonyStyle $symfonyStyle,
ValueResolver $valueResolver,
RemovedAndAddedFilesCollector $removedAndAddedFilesCollector,
PhpVersionProvider $phpVersionProvider,
BuilderFactory $builderFactory
): void {
$this->symfonyStyle = $symfonyStyle;
$this->valueResolver = $valueResolver;
$this->removedAndAddedFilesCollector = $removedAndAddedFilesCollector;
$this->phpVersionProvider = $phpVersionProvider;
$this->builderFactory = $builderFactory;
Expand Down Expand Up @@ -153,22 +145,6 @@ protected function addFileWithContent(string $filePath, string $content): void
$this->removedAndAddedFilesCollector->addFileWithContent($filePath, $content);
}

/**
* @return mixed
*/
protected function getValue(Expr $expr)
{
return $this->valueResolver->resolve($expr);
}

/**
* @param mixed $expectedValue
*/
protected function isValue(Expr $expr, $expectedValue): bool
{
return $this->getValue($expr) === $expectedValue;
}

/**
* @param Expr[]|null[] $nodes
* @param mixed[] $expectedValues
Expand Down
1 change: 1 addition & 0 deletions src/Rector/AbstractRectorTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ trait AbstractRectorTrait
use NodeCommandersTrait;
use NodeFactoryTrait;
use VisibilityTrait;
use ValueResolverTrait;
}
Loading