handle Symplify 7.3 deprecations in CS

This commit is contained in:
TomasVotruba 2020-05-03 16:16:10 +02:00
parent d89b92f9f7
commit 8e0deaa2b4
19 changed files with 280 additions and 266 deletions

View File

@ -8,6 +8,7 @@ services:
exclude:
- '../src/Rector/**/*Rector.php'
- '../src/Testing/PHPUnit/*'
- '../src/Testing/Dumper/*'
- '../src/RectorDefinition/*'
- '../src/Exception/*'
- '../src/DependencyInjection/CompilerPass/*'

View File

@ -1,10 +1,4 @@
services:
Symplify\CodingStandard\Sniffs\CleanCode\ClassCognitiveComplexitySniff:
max_class_cognitive_complexity: 50
Symplify\CodingStandard\Sniffs\CleanCode\CognitiveComplexitySniff:
max_cognitive_complexity: 9
Symplify\CodingStandard\Fixer\Order\MethodOrderByTypeFixer:
method_order_by_type:
Rector\Contract\Rector\PhpRectorInterface:
@ -12,15 +6,6 @@ services:
- 'getNodeTypes'
- 'refactor'
Symplify\CodingStandard\Fixer\Naming\PropertyNameMatchingTypeFixer:
extra_skipped_classes:
- 'PhpParser\PrettyPrinter\Standard'
- '?string' # bug probably
Symplify\CodingStandard\Sniffs\Naming\ClassNameSuffixByParentSniff:
extra_parent_types_to_suffixes:
- 'Rector'
parameters:
paths:
- "bin"
@ -88,33 +73,6 @@ parameters:
- 'src/Rector/AbstractRector.php'
- 'packages/post-rector/src/Rector/AbstractPostRector.php'
Symplify\CodingStandard\Sniffs\CleanCode\ClassCognitiveComplexitySniff:
# complex case
- 'packages/better-php-doc-parser/src/PhpDocInfo/PhpDocInfo.php'
# node printing
- 'utils/documentation-generator/src/Command/DumpNodesCommand.php'
# 3rd party code
- 'rules/php70/src/EregToPcreTransformer.php'
Symplify\CodingStandard\Sniffs\CleanCode\CognitiveComplexitySniff:
# todo
- "packages/better-php-doc-parser/src/Printer/WhitespaceDetector.php"
- "packages/node-type-resolver/src/NodeTypeResolver.php"
- "packages/better-php-doc-parser/src/Printer/OriginalSpacingRestorer.php"
# @todo split to multiple rectors
- "rules/php-spec-to-phpunit/src/Rector/MethodCall/PhpSpecPromisesToPHPUnitAssertRector.php"
- 'packages/better-php-doc-parser/src/PhpDocNode/**/*TagValueNode.php'
- "rules/coding-style/src/Rector/ClassMethod/NewlineBeforeNewAssignSetRector.php"
# per node logic
- 'utils/documentation-generator/src/Command/DumpNodesCommand.php'
# copied 3rd party logic
- 'rules/php70/src/EregToPcreTransformer.php'
# dev
- 'packages/type-declaration/src/Rector/FunctionLike/*TypeDeclarationRector.php'
- 'rules/php70/src/Rector/If_/IfToSpaceshipRector.php'
PHP_CodeSniffer\Standards\Generic\Sniffs\CodeAnalysis\AssignmentInConditionSniff.FoundInWhileCondition: null
SlevomatCodingStandard\Sniffs\TypeHints\TypeHintDeclarationSniff.MissingParameterTypeHint:

View File

@ -284,14 +284,9 @@ final class NodeTypeResolver
private function resolveFirstType(Node $node): Type
{
foreach ($this->nodeTypeResolvers as $nodeTypeResolver) {
foreach ($nodeTypeResolver->getNodeClasses() as $nodeClass) {
if (! is_a($node, $nodeClass)) {
continue;
}
return $nodeTypeResolver->resolve($node);
}
$type = $this->resolveByNodeTypeResolvers($node);
if ($type !== null) {
return $type;
}
/** @var Scope|null $nodeScope */
@ -346,4 +341,17 @@ final class NodeTypeResolver
return $className === null || Strings::contains($className, 'AnonymousClass');
}
private function resolveByNodeTypeResolvers(Node $node): ?Type
{
foreach ($this->nodeTypeResolvers as $nodeClass => $nodeTypeResolver) {
if (! is_a($node, $nodeClass)) {
continue;
}
return $nodeTypeResolver->resolve($node);
}
return null;
}
}

View File

@ -44,7 +44,7 @@ final class FunctionMethodAndClassNodeVisitorTest extends AbstractNodeVisitorTes
/**
* @param Node[] $nodes
*/
protected function visitNodes(array $nodes): void
protected function traverseNodes(array $nodes): void
{
$nodeTraverser = new NodeTraverser();
$nodeTraverser->addVisitor(new NameResolver());

View File

@ -4,9 +4,18 @@ includes:
- vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon
- vendor/slam/phpstan-extensions/conf/slam-rules.neon
# see https://github.com/symplify/coding-standard
- vendor/symplify/coding-standard/config/symplify-rules.neon
parameters:
level: max
# see https://github.com/symplify/coding-standard
symplify:
max_cognitive_complexity: 9 # default: 8
parent_classes:
- Rector
# to allow installing with various phsptan versions without reporting old errors here
reportUnmatchedIgnoredErrors: false
@ -27,10 +36,8 @@ parameters:
- 'packages/doctrine-annotation-generated/src/ConstantPreservingDocParser.php'
- 'packages/doctrine-annotation-generated/src/ConstantPreservingAnnotationReader.php'
- ci/check_services_in_yaml_configs.php
- "*/Expected/*"
# complex printer
- "utils/phpstan/generate-paths.php"
- '*tests/Rector/MethodCall/RenameMethodRector/**/SomeClass.php'
# tests files
- '*tests/*/Fixture/*'
@ -38,8 +45,6 @@ parameters:
- '*tests/Source/*'
# part of composer
- '*/tests/Rector/Psr4/MultipleClassFileToPsr4ClassesRector/Expected/Just*ExceptionWithoutNamespace.php'
# stubs
- 'stubs/*'
ignoreErrors:
# false positive
@ -257,3 +262,42 @@ parameters:
message: "#^Class \"Rector\\\\PSR4\\\\Rector\\\\Namespace_\\\\NormalizeNamespaceByPSR4ComposerAutoloadRector\" is missing @see annotation with test case class reference$#"
count: 1
path: rules/psr4/src/Rector/Namespace_/NormalizeNamespaceByPSR4ComposerAutoloadRector.php
- '#Method Rector\\Core\\Testing\\Finder\\RectorsFinder\:\:findInDirectories\(\) should return array<Rector\\Core\\Contract\\Rector\\RectorInterface\> but returns array<object\>#'
-
message: "#^Class cognitive complexity for \"PhpDocInfo\" is 53, keep it under 50$#"
count: 1
path: packages/better-php-doc-parser/src/PhpDocInfo/PhpDocInfo.php
-
message: "#^Cognitive complexity for \"Rector\\\\BetterPhpDocParser\\\\Printer\\\\WhitespaceDetector\\:\\:detectOldWhitespaces\\(\\)\" is 18, keep it under 9$#"
count: 1
path: packages/better-php-doc-parser/src/Printer/WhitespaceDetector.php
-
message: "#^Parameter \\#1 \\$input of function array_splice expects array, array\\<PhpParser\\\\Node\\\\Stmt\\>\\|null given\\.$#"
count: 1
path: rules/coding-style/src/Rector/ClassMethod/NewlineBeforeNewAssignSetRector.php
-
message: "#^Cognitive complexity for \"Rector\\\\PhpSpecToPHPUnit\\\\Rector\\\\MethodCall\\\\PhpSpecPromisesToPHPUnitAssertRector\\:\\:refactor\\(\\)\" is 13, keep it under 9$#"
count: 1
path: rules/php-spec-to-phpunit/src/Rector/MethodCall/PhpSpecPromisesToPHPUnitAssertRector.php
-
message: "#^Class cognitive complexity for \"EregToPcreTransformer\" is 77, keep it under 50$#"
count: 1
path: rules/php70/src/EregToPcreTransformer.php
-
message: "#^Cognitive complexity for \"Rector\\\\Php70\\\\EregToPcreTransformer\\:\\:(.*?)\" is (.*?), keep it under 9$#"
path: rules/php70/src/EregToPcreTransformer.php
-
message: "#^Cognitive complexity for \"Rector\\\\Core\\\\Testing\\\\Dumper\\\\AttributeFilteringNodeDumper\\:\\:dumpSubNodes\\(\\)\" is 16, keep it under 9$#"
count: 1
path: src/Testing/Dumper/AttributeFilteringNodeDumper.php
- '#Use explicit return value over magic &reference#'

View File

@ -82,16 +82,10 @@ PHP
$hasChanged = false;
if ($node->stmts === null) {
return null;
}
foreach ($node->stmts as $key => $stmt) {
foreach ((array) $node->stmts as $key => $stmt) {
$currentStmtVariableName = null;
if ($stmt instanceof Expression) {
$stmt = $stmt->expr;
}
$stmt = $this->unwrapExpression($stmt);
if ($stmt instanceof Assign || $stmt instanceof MethodCall) {
if ($this->shouldSkipLeftVariable($stmt)) {
@ -111,11 +105,7 @@ PHP
$this->previousStmtVariableName = $currentStmtVariableName;
}
if (! $hasChanged) {
return null;
}
return $node;
return $hasChanged ? $node : null;
}
private function reset(): void
@ -180,4 +170,13 @@ PHP
return abs($currentNode->getLine() - $previousNode->getLine()) >= 2;
}
private function unwrapExpression(Node $node): Node
{
if ($node instanceof Expression) {
return $node->expr;
}
return $node;
}
}

View File

@ -13,6 +13,7 @@ use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\BinaryOp\Smaller;
use PhpParser\Node\Expr\BinaryOp\Spaceship;
use PhpParser\Node\Expr\Ternary;
use PhpParser\Node\Stmt\Else_;
use PhpParser\Node\Stmt\If_;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\Rector\AbstractRector;
@ -24,6 +25,7 @@ use Rector\NodeTypeResolver\Node\AttributeKey;
/**
* @see https://wiki.php.net/rfc/combined-comparison-operator
* @see https://3v4l.org/LPbA0
*
* @see \Rector\Php70\Tests\Rector\If_\IfToSpaceshipRector\IfToSpaceshipRectorTest
*/
final class IfToSpaceshipRector extends AbstractRector
@ -53,6 +55,11 @@ final class IfToSpaceshipRector extends AbstractRector
*/
private $secondValue;
/**
* @var Node|null
*/
private $nextNode;
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Changes if/else to spaceship <=> where useful', [
@ -105,38 +112,13 @@ PHP
return null;
}
$this->reset();
if ($node->cond instanceof Equal || $node->cond instanceof Identical) {
if ($node->stmts[0] instanceof Return_) {
if ($node->stmts[0]->expr === null) {
return null;
}
$this->onEqual = $this->getValue($node->stmts[0]->expr);
}
} else {
if (! $node->cond instanceof Equal && ! $node->cond instanceof Identical) {
return null;
}
if ($node->else !== null) {
if (count($node->else->stmts) !== 1) {
return null;
}
$this->reset();
if ($node->else->stmts[0] instanceof Return_) {
/** @var Return_ $returnNode */
$returnNode = $node->else->stmts[0];
if ($returnNode->expr instanceof Ternary) {
$this->processTernary($returnNode->expr);
}
}
} else {
$nextNode = $node->getAttribute(AttributeKey::NEXT_NODE);
if ($nextNode instanceof Return_ && $nextNode->expr instanceof Ternary) {
$this->processTernary($nextNode->expr);
}
}
$this->matchOnEqualFirstValueAndSecondValue($node);
if ($this->firstValue === null || $this->secondValue === null) {
return null;
@ -146,13 +128,13 @@ PHP
return null;
}
// is spaceship retun values?
// is spaceship return values?
if ([$this->onGreater, $this->onEqual, $this->onSmaller] !== [-1, 0, 1]) {
return null;
}
if (isset($nextNode)) {
$this->removeNode($nextNode);
if ($this->nextNode !== null) {
$this->removeNode($this->nextNode);
}
// spaceship ready!
@ -211,4 +193,54 @@ PHP
$secondValue
);
}
private function matchOnEqualFirstValueAndSecondValue(If_ $if): void
{
$this->matchOnEqual($if);
if ($if->else !== null) {
$this->processElse($if->else);
} else {
$this->nextNode = $if->getAttribute(AttributeKey::NEXT_NODE);
if ($this->nextNode instanceof Return_ && $this->nextNode->expr instanceof Ternary) {
/** @var Ternary $ternary */
$ternary = $this->nextNode->expr;
$this->processTernary($ternary);
}
}
}
private function matchOnEqual(If_ $if): void
{
if (count($if->stmts) !== 1) {
return;
}
$onlyIfStmt = $if->stmts[0];
if ($onlyIfStmt instanceof Return_) {
if ($onlyIfStmt->expr === null) {
return;
}
$this->onEqual = $this->getValue($onlyIfStmt->expr);
}
}
private function processElse(Else_ $else): void
{
if (count($else->stmts) !== 1) {
return;
}
if (! $else->stmts[0] instanceof Return_) {
return;
}
/** @var Return_ $returnNode */
$returnNode = $else->stmts[0];
if ($returnNode->expr instanceof Ternary) {
$this->processTernary($returnNode->expr);
}
}
}

View File

@ -12,6 +12,7 @@ use PhpParser\Node\Expr\List_;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\Core\ValueObject\PhpVersionFeature;
/**
* @source http://php.net/manual/en/migration70.incompatible.php#migration70.incompatible.variable-handling.list
@ -40,7 +41,7 @@ final class ListSwapArrayOrderRector extends AbstractRector
*/
public function refactor(Node $node): ?Node
{
if (! $this->isAtLeastPhpVersion('7.0')) {
if (! $this->isAtLeastPhpVersion(PhpVersionFeature::LIST_SWAP_ORDER)) {
return null;
}

View File

@ -44,13 +44,17 @@ final class SetsCommand extends AbstractCommand
{
$sets = $this->setProvider->provide();
if ($input->getArgument('name')) {
$sets = $this->filterSetsByName($input, $sets);
$name = (string) $input->getArgument('name');
if ($name) {
$sets = $this->filterSetsByName($name, $sets);
}
$this->symfonyStyle->title(sprintf('%d available sets:', count($sets)));
$this->symfonyStyle->listing($sets);
if ($name === '') {
$this->symfonyStyle->note('Tip: filter sets by name, e.g. "vendor/bin/rector sets symfony"');
}
return ShellCode::SUCCESS;
}
@ -58,10 +62,8 @@ final class SetsCommand extends AbstractCommand
* @param string[] $sets
* @return string[]
*/
private function filterSetsByName(InputInterface $input, array $sets): array
private function filterSetsByName(string $name, array $sets): array
{
$name = (string) $input->getArgument('name');
return array_filter($sets, function (string $set) use ($name): bool {
return (bool) Strings::match($set, sprintf('#%s#', $name));
});

View File

@ -86,17 +86,17 @@ PHP
$implementedInterfaceNames = $this->classManipulator->getImplementedInterfaceNames($node);
foreach (array_keys($usedTraitNames) as $traitName) {
foreach ($this->interfaceByTrait as $seekedTraitName => $interfaceName) {
if ($traitName !== $seekedTraitName) {
continue;
}
if (in_array($interfaceName, $implementedInterfaceNames, true)) {
continue;
}
$node->implements[] = new FullyQualified($interfaceName);
if (! isset($this->interfaceByTrait[$traitName])) {
continue;
}
$interfaceNameToAdd = $this->interfaceByTrait[$traitName];
if (in_array($interfaceNameToAdd, $implementedInterfaceNames, true)) {
continue;
}
$node->implements[] = new FullyQualified($interfaceNameToAdd);
}
return $node;

View File

@ -229,10 +229,12 @@ PHP
$serviceName = $jmsInjectTagValueNode->getServiceName();
if ($serviceName) {
// 1. service class
if (class_exists($serviceName)) {
return new ObjectType($serviceName);
}
// 2. service name
if ($serviceMap->hasService($serviceName)) {
$serviceType = $serviceMap->getServiceType($serviceName);
if ($serviceType !== null) {
@ -241,6 +243,7 @@ PHP
}
}
// 3. service is in @var annotation
/** @var PhpDocInfo $phpDocInfo */
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
@ -250,17 +253,24 @@ PHP
}
// the @var is missing and service name was not found → report it
if ($serviceName) {
/** @var SmartFileInfo $fileInfo */
$fileInfo = $node->getAttribute(AttributeKey::FILE_INFO);
$this->errorAndDiffCollector->addErrorWithRectorClassMessageAndFileInfo(
self::class,
sprintf('Service "%s" was not found in DI Container of your Symfony App.', $serviceName),
$fileInfo
);
}
$this->reportServiceNotFound($serviceName, $node);
return new MixedType();
}
private function reportServiceNotFound(?string $serviceName, Node $node): void
{
if ($serviceName !== null) {
return;
}
/** @var SmartFileInfo $fileInfo */
$fileInfo = $node->getAttribute(AttributeKey::FILE_INFO);
$this->errorAndDiffCollector->addErrorWithRectorClassMessageAndFileInfo(
self::class,
sprintf('Service "%s" was not found in DI Container of your Symfony App.', $serviceName),
$fileInfo
);
}
}

View File

@ -84,17 +84,7 @@ PHP
continue;
}
foreach ($methodNameAndNewArgumentPositions as $methodName => $newArgumentPositions) {
if (! $this->isMethodStaticCallOrClassMethodName($node, $methodName)) {
continue;
}
if ($node instanceof ClassMethod) {
$this->swapParameters($node, $newArgumentPositions);
} else {
$this->swapArguments($node, $newArgumentPositions);
}
}
$this->refactorArgumentPositions($methodNameAndNewArgumentPositions, $node);
}
return $node;
@ -139,6 +129,24 @@ PHP
}
}
/**
* @param StaticCall|MethodCall|ClassMethod $node
*/
private function refactorArgumentPositions(array $methodNameAndNewArgumentPositions, Node $node): void
{
foreach ($methodNameAndNewArgumentPositions as $methodName => $newArgumentPositions) {
if (! $this->isMethodStaticCallOrClassMethodName($node, $methodName)) {
continue;
}
if ($node instanceof ClassMethod) {
$this->swapParameters($node, $newArgumentPositions);
} else {
$this->swapArguments($node, $newArgumentPositions);
}
}
}
/**
* @param MethodCall|StaticCall $node
* @param int[] $newArgumentPositions

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\Core\PhpParser;
namespace Rector\Core\Testing\Dumper;
use InvalidArgumentException;
use PhpParser\Comment;
@ -13,18 +13,8 @@ use PhpParser\Node\Stmt\Use_;
use PhpParser\Node\Stmt\UseUse;
use PhpParser\NodeDumper;
final class BetterNodeDumper extends NodeDumper
final class AttributeFilteringNodeDumper extends NodeDumper
{
/**
* @var bool
*/
private $dumpComments = false;
/**
* @var bool
*/
private $dumpPositions = false;
/**
* @var int[]
*/
@ -38,66 +28,44 @@ final class BetterNodeDumper extends NodeDumper
/**
* @var string[]
*/
private $filterAttributes = [];
private $relevantAttributes = [];
/**
* Constructs a NodeDumper.
*
* Supported options:
* * bool dumpComments: Whether comments should be dumped.
* * bool dumpPositions: Whether line/offset information should be dumped. To dump offset
* information, the code needs to be passed to dump().
*
* @param array $options Options (see description)
* @param string[] $relevantAttributes
*/
public function __construct(array $options = [])
public function __construct(array $relevantAttributes)
{
$this->dumpComments = ! empty($options['dumpComments']);
$this->dumpPositions = ! empty($options['dumpPositions']);
parent::__construct($options);
$this->relevantAttributes = $relevantAttributes;
}
public function dump($node, ?string $code = null): string
{
$this->nodeIds = 0;
$this->printedNodes = [];
return parent::dump($node, $code);
}
/**
* @param string[] $filterAttributes
*/
public function setFilterAttributes(array $filterAttributes): void
{
$this->filterAttributes = $filterAttributes;
return parent::dump($node, $code);
}
protected function dumpRecursive($node)
{
if ($node instanceof Node) {
$r = $this->dumpNode($node);
return $this->dumpNode($node);
} elseif (is_array($node)) {
$r = $this->dumpArray($node);
return $this->dumpArray($node);
} elseif ($node instanceof Comment) {
return $node->getReformattedText();
} else {
throw new InvalidArgumentException('Can only dump nodes and arrays.');
}
return $r;
throw new InvalidArgumentException('Can only dump nodes and arrays.');
}
/**
* @return mixed[]
*/
private function getFilteredAttributes(Node $node) : array
private function getFilteredAttributes(Node $node): array
{
$attributes = $node->getAttributes();
if ($this->filterAttributes !== []) {
$attributes = array_intersect_key($attributes, array_flip($this->filterAttributes));
}
return $attributes;
return array_intersect_key($attributes, array_flip($this->relevantAttributes));
}
private function dumpSubNodes(Node $node): string
@ -134,7 +102,6 @@ final class BetterNodeDumper extends NodeDumper
}
}
return $r;
}
private function dumpNode(Node $node): string
@ -144,20 +111,14 @@ final class BetterNodeDumper extends NodeDumper
if (isset($this->printedNodes[$splObjectHash])) {
return $node->getType() . ' #' . $this->printedNodes[$splObjectHash];
}
$this->printedNodes[$splObjectHash] = $this->nodeIds++;
$r = $node->getType() . ' #' . $this->printedNodes[$splObjectHash];
if ($this->dumpPositions ) {
$r .= $this->dumpPosition($node);
}
$r .= '(';
$r .= $this->dumpSubNodes($node);
$comments = $node->getComments();
if ($this->dumpComments && $comments) {
$r .= "\n comments: " . str_replace("\n", "\n ", $this->dumpRecursive($comments));
}
$attributes = $this->getFilteredAttributes($node);
if ($attributes !== []) {
$r .= "\n attributes: " . str_replace("\n", "\n ", $this->dumpArray($attributes));
@ -177,7 +138,7 @@ final class BetterNodeDumper extends NodeDumper
if ($value === null) {
$r .= 'null';
} elseif (!$value) {
} elseif (! $value) {
$r .= 'false';
} elseif ($value === true) {
$r .= 'true';

View File

@ -48,17 +48,10 @@ final class RectorsFinder
*/
public function findInDirectories(array $directories): array
{
$robotLoader = new RobotLoader();
foreach ($directories as $directory) {
$robotLoader->addDirectory($directory);
}
$robotLoader->setTempDirectory(sys_get_temp_dir() . '/_rector_finder');
$robotLoader->acceptFiles = ['*Rector.php'];
$robotLoader->rebuild();
$foundClasses = $this->findClassesInDirectoriesByName($directories, '*Rector.php');
$rectors = [];
foreach (array_keys($robotLoader->getIndexedClasses()) as $class) {
foreach ($foundClasses as $class) {
// special case, because robot loader is case insensitive
if ($class === ExceptionCorrector::class) {
continue;
@ -86,16 +79,43 @@ final class RectorsFinder
$rectors[] = $rector;
}
return $this->sortObjectsByShortClassName($rectors);
}
/**
* @param string[] $directories
* @return string[]
*/
private function findClassesInDirectoriesByName(array $directories, string $name): array
{
$robotLoader = new RobotLoader();
foreach ($directories as $directory) {
$robotLoader->addDirectory($directory);
}
$robotLoader->setTempDirectory(sys_get_temp_dir() . '/_rector_finder');
$robotLoader->acceptFiles = [$name];
$robotLoader->rebuild();
return array_keys($robotLoader->getIndexedClasses());
}
/**
* @param object[] $objects
* @return object[]
*/
private function sortObjectsByShortClassName(array $objects): array
{
usort(
$rectors,
function (RectorInterface $firstRector, RectorInterface $secondRector): int {
$firstRectorShortClass = Strings::after(get_class($firstRector), '\\', -1);
$secondRectorShortClass = Strings::after(get_class($secondRector), '\\', -1);
$objects,
function (object $firstObject, object $secondObject): int {
$firstRectorShortClass = Strings::after(get_class($firstObject), '\\', -1);
$secondRectorShortClass = Strings::after(get_class($secondObject), '\\', -1);
return $firstRectorShortClass <=> $secondRectorShortClass;
}
);
return $rectors;
return $objects;
}
}

View File

@ -7,10 +7,9 @@ namespace Rector\Core\Testing\PHPUnit;
use Iterator;
use Nette\Utils\FileSystem;
use PhpParser\Node;
use PhpParser\NodeDumper;
use Rector\Core\HttpKernel\RectorKernel;
use Rector\Core\PhpParser\BetterNodeDumper;
use Rector\Core\PhpParser\Parser\Parser;
use Rector\Core\Testing\Dumper\AttributeFilteringNodeDumper;
use Rector\Core\Testing\StaticFixtureProvider;
use Symplify\PackageBuilder\Tests\AbstractKernelTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
@ -23,9 +22,9 @@ use Symplify\SmartFileSystem\SmartFileInfo;
abstract class AbstractNodeVisitorTestCase extends AbstractKernelTestCase
{
/**
* @var NodeDumper
* @var AttributeFilteringNodeDumper
*/
protected $nodeDumper;
protected $attributeFilteringNodeDumper;
/**
* @var Parser
@ -39,19 +38,18 @@ abstract class AbstractNodeVisitorTestCase extends AbstractKernelTestCase
protected function setUp(): void
{
parent::setUp();
$this->bootKernelWithConfigs(RectorKernel::class, []);
$this->fixtureSplitter = new FixtureSplitter($this->getTempPath());
$this->parser = static::$container->get(Parser::class);
$this->nodeDumper = new BetterNodeDumper();
$this->nodeDumper->setFilterAttributes($this->getRelevantAttributes());
$this->attributeFilteringNodeDumper = new AttributeFilteringNodeDumper($this->getRelevantAttributes());
}
/**
* @param Node[] $nodes
*/
abstract protected function visitNodes(array $nodes): void;
abstract protected function traverseNodes(array $nodes): void;
/**
* @return string[]
@ -73,19 +71,19 @@ abstract class AbstractNodeVisitorTestCase extends AbstractKernelTestCase
$smartFileInfo,
true
);
$smartFileInfo2 = new SmartFileInfo($expectedNodesFile);
$originalFileInfo = new SmartFileInfo($originalFile);
$expectedNodesFileInfo = new SmartFileInfo($expectedNodesFile);
$nodes = $this->parser->parseFileInfo($originalFileInfo);
$this->traverseNodes($nodes);
$this->visitNodes($nodes);
$dumpedNodes = $this->nodeDumper->dump($nodes);
$dumpedNodes = $this->attributeFilteringNodeDumper->dump($nodes);
if (getenv('UPDATE_FIXTURE')) {
FileSystem::write($file, FileSystem::read($originalFile) . "-----\n" . $dumpedNodes);
} else {
$this->assertSame(trim($smartFileInfo2->getContents()), $dumpedNodes, 'Caused by ' . $file);
$this->assertSame(trim($expectedNodesFileInfo->getContents()), $dumpedNodes, 'Caused by ' . $file);
}
}

View File

@ -68,17 +68,10 @@ abstract class AbstractRectorTestCase extends AbstractGenericRectorTestCase
$enabledRectorsProvider = static::$container->get(EnabledRectorsProvider::class);
$enabledRectorsProvider->reset();
} else {
// repare contains with all rectors
// prepare container with all rectors
// cache only rector tests - defined in phpunit.xml
if (defined('RECTOR_REPOSITORY')) {
if (self::$allRectorContainer === null) {
$this->createContainerWithAllRectors();
self::$allRectorContainer = self::$container;
} else {
// load from cache
self::$container = self::$allRectorContainer;
}
$this->createRectorRepositoryContainer();
} else {
// 3rd party
$configFileTempPath = $this->getConfigFor3rdPartyTest();
@ -204,10 +197,6 @@ abstract class AbstractRectorTestCase extends AbstractGenericRectorTestCase
private function getConfigFor3rdPartyTest(): string
{
if ($this->provideConfig() !== '') {
return $this->provideConfig();
}
$rectorClassWithConfiguration = $this->getCurrentTestRectorClassesWithConfiguration();
$yamlContent = Yaml::dump([
'services' => $rectorClassWithConfiguration,
@ -265,4 +254,17 @@ abstract class AbstractRectorTestCase extends AbstractGenericRectorTestCase
{
return (new SmartFileInfo($fixtureFile))->getRelativeFilePathFromCwd();
}
private function createRectorRepositoryContainer(): void
{
if (self::$allRectorContainer === null) {
$this->createContainerWithAllRectors();
self::$allRectorContainer = self::$container;
return;
}
// load from cache
self::$container = self::$allRectorContainer;
}
}

View File

@ -36,6 +36,11 @@ final class PhpVersionFeature
*/
public const NULL_COALESCE = '7.0';
/**
* @var string
*/
public const LIST_SWAP_ORDER = '7.0';
/**
* @var string
*/

View File

@ -1,35 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PHPStanExtensions\Tests;
use PHPStan\DependencyInjection\Container;
use PHPStan\DependencyInjection\ContainerFactory;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
/**
* @deprecated
* Waits on https://github.com/symplify/symplify/pull/1908 to be merged + tagged
*/
abstract class AbstractServiceAwareRuleTestCase extends RuleTestCase
{
protected function getRuleFromConfig(string $ruleClass, string $config): Rule
{
$container = $this->createContainer([$config]);
return $container->getByType($ruleClass);
}
/**
* @param string[] $configs
*/
private function createContainer(array $configs): Container
{
$containerFactory = new ContainerFactory(getcwd());
// random for tests cache invalidation in case the container changes
$tempDirectory = sys_get_temp_dir() . '/_phpstan_rector/id_' . random_int(0, 1000);
return $containerFactory->create($tempDirectory, $configs, [], []);
}
}

View File

@ -7,9 +7,9 @@ namespace Rector\PHPStanExtensions\Tests\Rule\SeeAnnotationToTestRule;
use Iterator;
use PHPStan\Rules\Rule;
use Rector\PHPStanExtensions\Rule\SeeAnnotationToTestRule;
use Rector\PHPStanExtensions\Tests\AbstractServiceAwareRuleTestCase;
use Rector\PHPStanExtensions\Tests\Rule\SeeAnnotationToTestRule\Fixture\ClassMissingDocBlockRector;
use Rector\PHPStanExtensions\Tests\Rule\SeeAnnotationToTestRule\Fixture\ClassMissingSeeAnnotationRector;
use Symplify\PHPStanExtensions\Testing\AbstractServiceAwareRuleTestCase;
final class SeeAnnotationToTestRuleTest extends AbstractServiceAwareRuleTestCase
{