mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-08 04:10:51 +00:00
sort methods by their call
This commit is contained in:
parent
558fa593c3
commit
3f8c9431ea
|
@ -166,6 +166,12 @@ CODE_SAMPLE
|
|||
return ! $foreachNode->stmts[0] instanceof If_;
|
||||
}
|
||||
|
||||
private function shouldSkipIf(If_ $ifNode): bool
|
||||
{
|
||||
$ifCondition = $ifNode->cond;
|
||||
return ! $ifCondition instanceof Identical && ! $ifCondition instanceof Equal;
|
||||
}
|
||||
|
||||
private function isIfBodyABoolReturnNode(If_ $firstNodeInsideForeach): bool
|
||||
{
|
||||
$ifStatment = $firstNodeInsideForeach->stmts[0];
|
||||
|
@ -212,10 +218,4 @@ CODE_SAMPLE
|
|||
|
||||
$newNode->setAttribute('comments', [new Comment($commentContent)]);
|
||||
}
|
||||
|
||||
private function shouldSkipIf(If_ $ifNode): bool
|
||||
{
|
||||
$ifCondition = $ifNode->cond;
|
||||
return ! $ifCondition instanceof Identical && ! $ifCondition instanceof Equal;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,6 +90,11 @@ final class SimplifyArraySearchRector extends AbstractRector
|
|||
return $inArrayFuncCall;
|
||||
}
|
||||
|
||||
private function shouldBeStrict(BinaryOp $binaryOpNode): bool
|
||||
{
|
||||
return $binaryOpNode instanceof Identical || $binaryOpNode instanceof NotIdentical;
|
||||
}
|
||||
|
||||
private function resolveIsNot(BinaryOp $node, ConstFetch $boolConstFetchNode): bool
|
||||
{
|
||||
if ($node instanceof Identical || $node instanceof Equal) {
|
||||
|
@ -98,9 +103,4 @@ final class SimplifyArraySearchRector extends AbstractRector
|
|||
|
||||
return $this->isTrue($boolConstFetchNode);
|
||||
}
|
||||
|
||||
private function shouldBeStrict(BinaryOp $binaryOpNode): bool
|
||||
{
|
||||
return $binaryOpNode instanceof Identical || $binaryOpNode instanceof NotIdentical;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,6 +96,17 @@ final class NodeTypeAnalyzer
|
|||
return $nodeType instanceof ArrayType;
|
||||
}
|
||||
|
||||
private function getNodeType(Node $node): ?Type
|
||||
{
|
||||
/** @var Scope|null $nodeScope */
|
||||
$nodeScope = $node->getAttribute(Attribute::SCOPE);
|
||||
if (! $node instanceof Expr || $nodeScope === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $nodeScope->getType($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Special case for "preg_match(), preg_match_all()" - with 3rd argument
|
||||
* @covers https://github.com/rectorphp/rector/issues/786
|
||||
|
@ -134,15 +145,4 @@ final class NodeTypeAnalyzer
|
|||
|
||||
return new ArrayType(new MixedType(), new MixedType());
|
||||
}
|
||||
|
||||
private function getNodeType(Node $node): ?Type
|
||||
{
|
||||
/** @var Scope|null $nodeScope */
|
||||
$nodeScope = $node->getAttribute(Attribute::SCOPE);
|
||||
if (! $node instanceof Expr || $nodeScope === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $nodeScope->getType($node);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,6 +79,16 @@ final class NodeScopeResolver
|
|||
return $nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node[] $nodes
|
||||
*/
|
||||
private function removeDeepChainMethodCallNodes(array $nodes): void
|
||||
{
|
||||
$nodeTraverser = new NodeTraverser();
|
||||
$nodeTraverser->addVisitor($this->removeDeepChainMethodCallNodeVisitor);
|
||||
$nodeTraverser->traverse($nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Class_|Interface_ $classOrInterfaceNode
|
||||
*/
|
||||
|
@ -100,14 +110,4 @@ final class NodeScopeResolver
|
|||
|
||||
return $scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node[] $nodes
|
||||
*/
|
||||
private function removeDeepChainMethodCallNodes(array $nodes): void
|
||||
{
|
||||
$nodeTraverser = new NodeTraverser();
|
||||
$nodeTraverser->addVisitor($this->removeDeepChainMethodCallNodeVisitor);
|
||||
$nodeTraverser->traverse($nodes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,16 @@ use function Safe\sort;
|
|||
|
||||
abstract class AbstractTypeInfo
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isNullable = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $hasRemovedTypes = false;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
|
@ -24,21 +34,11 @@ abstract class AbstractTypeInfo
|
|||
*/
|
||||
protected $typesToRemove = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isNullable = false;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $fqnTypes = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $hasRemovedTypes = false;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
|
@ -184,24 +184,33 @@ abstract class AbstractTypeInfo
|
|||
|
||||
/**
|
||||
* @param string[] $types
|
||||
* @return string[]
|
||||
*/
|
||||
private function squashTraversableAndArrayToIterable(array $types): array
|
||||
private function isArraySubtype(array $types): bool
|
||||
{
|
||||
// Traversable | array = iterable
|
||||
if (count(array_intersect($this->iterableUnionTypes, $types)) !== 2) {
|
||||
return $types;
|
||||
$arraySubtypeGroup = ['array', 'iterable'];
|
||||
return $this->areArraysEqual($types, $arraySubtypeGroup);
|
||||
}
|
||||
|
||||
private function normalizeNullable(string $type): string
|
||||
{
|
||||
if (Strings::startsWith($type, '?')) {
|
||||
$type = ltrim($type, '?');
|
||||
$this->isNullable = true;
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
|
||||
private function normalizeCasing(string $type): string
|
||||
{
|
||||
if (TypeAnalyzer::isPhpReservedType($type)) {
|
||||
return strtolower($type);
|
||||
}
|
||||
|
||||
foreach ($types as $i => $type) {
|
||||
if (in_array($type, $this->iterableUnionTypes, true)) {
|
||||
unset($types[$i]);
|
||||
}
|
||||
if (strtolower($type) === '$this') {
|
||||
return strtolower($type);
|
||||
}
|
||||
|
||||
$types[] = 'iterable';
|
||||
|
||||
return $types;
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -226,11 +235,24 @@ abstract class AbstractTypeInfo
|
|||
|
||||
/**
|
||||
* @param string[] $types
|
||||
* @return string[]
|
||||
*/
|
||||
private function isArraySubtype(array $types): bool
|
||||
private function squashTraversableAndArrayToIterable(array $types): array
|
||||
{
|
||||
$arraySubtypeGroup = ['array', 'iterable'];
|
||||
return $this->areArraysEqual($types, $arraySubtypeGroup);
|
||||
// Traversable | array = iterable
|
||||
if (count(array_intersect($this->iterableUnionTypes, $types)) !== 2) {
|
||||
return $types;
|
||||
}
|
||||
|
||||
foreach ($types as $i => $type) {
|
||||
if (in_array($type, $this->iterableUnionTypes, true)) {
|
||||
unset($types[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
$types[] = 'iterable';
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -244,26 +266,4 @@ abstract class AbstractTypeInfo
|
|||
|
||||
return $types === $arraySubtypeGroup;
|
||||
}
|
||||
|
||||
private function normalizeNullable(string $type): string
|
||||
{
|
||||
if (Strings::startsWith($type, '?')) {
|
||||
$type = ltrim($type, '?');
|
||||
$this->isNullable = true;
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
|
||||
private function normalizeCasing(string $type): string
|
||||
{
|
||||
if (TypeAnalyzer::isPhpReservedType($type)) {
|
||||
return strtolower($type);
|
||||
}
|
||||
|
||||
if (strtolower($type) === '$this') {
|
||||
return strtolower($type);
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -250,6 +250,20 @@ final class DocBlockAnalyzer
|
|||
return new VarTypeInfo($types, $fqnTypes);
|
||||
}
|
||||
|
||||
private function createPhpDocInfoWithFqnTypesFromNode(Node $node): PhpDocInfo
|
||||
{
|
||||
$phpDocInfo = $this->createPhpDocInfoFromNode($node);
|
||||
|
||||
$this->phpDocInfoFqnTypeDecorator->decorate($phpDocInfo, $node);
|
||||
|
||||
return $phpDocInfo;
|
||||
}
|
||||
|
||||
private function isNamespaced(string $name): bool
|
||||
{
|
||||
return Strings::contains($name, '\\');
|
||||
}
|
||||
|
||||
private function updateNodeWithPhpDocInfo(Node $node, PhpDocInfo $phpDocInfo): void
|
||||
{
|
||||
// skip if has no doc comment
|
||||
|
@ -278,18 +292,4 @@ final class DocBlockAnalyzer
|
|||
|
||||
return $this->phpDocInfoFactory->createFrom($node->getDocComment()->getText());
|
||||
}
|
||||
|
||||
private function createPhpDocInfoWithFqnTypesFromNode(Node $node): PhpDocInfo
|
||||
{
|
||||
$phpDocInfo = $this->createPhpDocInfoFromNode($node);
|
||||
|
||||
$this->phpDocInfoFqnTypeDecorator->decorate($phpDocInfo, $node);
|
||||
|
||||
return $phpDocInfo;
|
||||
}
|
||||
|
||||
private function isNamespaced(string $name): bool
|
||||
{
|
||||
return Strings::contains($name, '\\');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,6 +92,18 @@ CODE_SAMPLE
|
|||
return $this->processFieldToFieldDirect($node, $funcCallNode);
|
||||
}
|
||||
|
||||
private function processMysqlTableName(Assign $assignNode, FuncCall $funcCall): FuncCall
|
||||
{
|
||||
$funcCall->name = new Name('mysqli_data_seek');
|
||||
|
||||
$newFuncCall = new FuncCall(new Name('mysql_fetch_array'), [$funcCall->args[0]]);
|
||||
$newAssignNode = new Assign($assignNode->var, new ArrayDimFetch($newFuncCall, new LNumber(0)));
|
||||
|
||||
$this->addNodeAfterNode($newAssignNode, $assignNode);
|
||||
|
||||
return $funcCall;
|
||||
}
|
||||
|
||||
private function processMysqlDbName(Assign $assignNode, FuncCall $funcCallNode): FuncCall
|
||||
{
|
||||
$funcCallNode->name = new Name('mysqli_data_seek');
|
||||
|
@ -143,18 +155,6 @@ CODE_SAMPLE
|
|||
return $assignNode;
|
||||
}
|
||||
|
||||
private function processMysqlTableName(Assign $assignNode, FuncCall $funcCall): FuncCall
|
||||
{
|
||||
$funcCall->name = new Name('mysqli_data_seek');
|
||||
|
||||
$newFuncCall = new FuncCall(new Name('mysql_fetch_array'), [$funcCall->args[0]]);
|
||||
$newAssignNode = new Assign($assignNode->var, new ArrayDimFetch($newFuncCall, new LNumber(0)));
|
||||
|
||||
$this->addNodeAfterNode($newAssignNode, $assignNode);
|
||||
|
||||
return $funcCall;
|
||||
}
|
||||
|
||||
private function processFieldToFieldDirect(Assign $assignNode, FuncCall $funcCallNode): ?Assign
|
||||
{
|
||||
foreach ($this->fieldToFieldDirect as $funcName => $property) {
|
||||
|
|
|
@ -116,6 +116,20 @@ CODE_SAMPLE
|
|||
return $anonymousFunctionNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Param[]
|
||||
*/
|
||||
private function parseStringToParameters(Expr $expr): array
|
||||
{
|
||||
$content = $this->stringify($expr);
|
||||
|
||||
$content = '<?php $value = function(' . $content . ') {};';
|
||||
|
||||
$nodes = $this->parser->parse($content);
|
||||
|
||||
return $nodes[0]->expr->expr->params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String_|Expr $content
|
||||
* @return Stmt[]
|
||||
|
@ -133,20 +147,6 @@ CODE_SAMPLE
|
|||
return (array) $this->parser->parse('<?php ' . $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Param[]
|
||||
*/
|
||||
private function parseStringToParameters(Expr $expr): array
|
||||
{
|
||||
$content = $this->stringify($expr);
|
||||
|
||||
$content = '<?php $value = function(' . $content . ') {};';
|
||||
|
||||
$nodes = $this->parser->parse($content);
|
||||
|
||||
return $nodes[0]->expr->expr->params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node[] $nodes
|
||||
* @param Variable[] $paramNodes
|
||||
|
|
|
@ -116,30 +116,6 @@ CODE_SAMPLE
|
|||
return $this->isNotIdenticalToNull($funcCallNode, $parentNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* E.g. "$value !== null ? get_class($value)"
|
||||
*/
|
||||
private function isNotIdenticalToNull(FuncCall $funcCallNode, Ternary $ternaryNode): bool
|
||||
{
|
||||
if (! $ternaryNode->cond instanceof NotIdentical) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->areNodesEqual($ternaryNode->cond->left, $funcCallNode->args[0]->value)) {
|
||||
if ($this->isNull($ternaryNode->cond->right)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->areNodesEqual($ternaryNode->cond->right, $funcCallNode->args[0]->value)) {
|
||||
if ($this->isNull($ternaryNode->cond->left)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* E.g. "$value === [!null] ? get_class($value)"
|
||||
*/
|
||||
|
@ -163,4 +139,28 @@ CODE_SAMPLE
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* E.g. "$value !== null ? get_class($value)"
|
||||
*/
|
||||
private function isNotIdenticalToNull(FuncCall $funcCallNode, Ternary $ternaryNode): bool
|
||||
{
|
||||
if (! $ternaryNode->cond instanceof NotIdentical) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->areNodesEqual($ternaryNode->cond->left, $funcCallNode->args[0]->value)) {
|
||||
if ($this->isNull($ternaryNode->cond->right)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->areNodesEqual($ternaryNode->cond->right, $funcCallNode->args[0]->value)) {
|
||||
if ($this->isNull($ternaryNode->cond->left)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,9 @@ final class RegexDashEscapeRector extends AbstractRector
|
|||
private $staticMethodsWithPatternsToArgumentPosition = [
|
||||
'Nette\Utils\Strings' => [
|
||||
'match' => 1,
|
||||
'matchAll' => 1,
|
||||
'replace' => 1,
|
||||
'split' => 1,
|
||||
],
|
||||
];
|
||||
|
||||
|
@ -100,36 +102,15 @@ CODE_SAMPLE
|
|||
return $node;
|
||||
}
|
||||
|
||||
private function escapeDashInPattern(Expr $value): Expr
|
||||
private function processFuncCall(FuncCall $funcCallNode): void
|
||||
{
|
||||
if ($value instanceof String_) {
|
||||
$stringValue = $value->value;
|
||||
|
||||
if (! Strings::match($stringValue, self::PATTERN_DASH_NOT_AROUND_BRACKETS)) {
|
||||
return $value;
|
||||
foreach ($this->functionsWithPatternsToArgumentPosition as $functionName => $argumentPosition) {
|
||||
if (! $this->isName($funcCallNode, $functionName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$value->value = Strings::replace($stringValue, self::PATTERN_DASH_NOT_AROUND_BRACKETS, '\-');
|
||||
// helped needed to skip re-escaping regular expression
|
||||
$value->setAttribute('is_regular_pattern', true);
|
||||
$this->processArgumentPosition($funcCallNode, $argumentPosition);
|
||||
}
|
||||
|
||||
// @todo constants
|
||||
// @todo properties above
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StaticCall|FuncCall $node
|
||||
*/
|
||||
private function processArgumentPosition(Node $node, int $argumentPosition): void
|
||||
{
|
||||
if (! $this->isStringType($node->args[$argumentPosition]->value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$node->args[$argumentPosition]->value = $this->escapeDashInPattern($node->args[$argumentPosition]->value);
|
||||
}
|
||||
|
||||
private function processStaticCall(StaticCall $staticCallNode): void
|
||||
|
@ -149,14 +130,35 @@ CODE_SAMPLE
|
|||
}
|
||||
}
|
||||
|
||||
private function processFuncCall(FuncCall $funcCallNode): void
|
||||
/**
|
||||
* @param StaticCall|FuncCall $node
|
||||
*/
|
||||
private function processArgumentPosition(Node $node, int $argumentPosition): void
|
||||
{
|
||||
foreach ($this->functionsWithPatternsToArgumentPosition as $functionName => $argumentPosition) {
|
||||
if (! $this->isName($funcCallNode, $functionName)) {
|
||||
return;
|
||||
if (! $this->isStringType($node->args[$argumentPosition]->value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$node->args[$argumentPosition]->value = $this->escapeDashInPattern($node->args[$argumentPosition]->value);
|
||||
}
|
||||
|
||||
private function escapeDashInPattern(Expr $value): Expr
|
||||
{
|
||||
if ($value instanceof String_) {
|
||||
$stringValue = $value->value;
|
||||
|
||||
if (! Strings::match($stringValue, self::PATTERN_DASH_NOT_AROUND_BRACKETS)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$this->processArgumentPosition($funcCallNode, $argumentPosition);
|
||||
$value->value = Strings::replace($stringValue, self::PATTERN_DASH_NOT_AROUND_BRACKETS, '\-');
|
||||
// helped needed to skip re-escaping regular expression
|
||||
$value->setAttribute('is_regular_pattern', true);
|
||||
}
|
||||
|
||||
// @todo constants
|
||||
// @todo properties above
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -223,12 +223,6 @@ abstract class AbstractScalarTypehintRector extends AbstractRector
|
|||
return false;
|
||||
}
|
||||
|
||||
private function haveSameNamespace(Node $firstNode, Node $secondNode): bool
|
||||
{
|
||||
return $firstNode->getAttribute(Attribute::NAMESPACE_NAME)
|
||||
=== $secondNode->getAttribute(Attribute::NAMESPACE_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Class_|Interface_ $classLikeNode
|
||||
* @return string[]
|
||||
|
@ -251,4 +245,10 @@ abstract class AbstractScalarTypehintRector extends AbstractRector
|
|||
|
||||
return $interfaces;
|
||||
}
|
||||
|
||||
private function haveSameNamespace(Node $firstNode, Node $secondNode): bool
|
||||
{
|
||||
return $firstNode->getAttribute(Attribute::NAMESPACE_NAME)
|
||||
=== $secondNode->getAttribute(Attribute::NAMESPACE_NAME);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,11 @@ function regexDashEscapeRector()
|
|||
preg_match("#[-\w()]#", 'some text'); // ok
|
||||
preg_match("#[\w-()]#", 'some text'); // NOPE!
|
||||
preg_match("#[\w(-)]#", 'some text'); // ok
|
||||
|
||||
preg_match('#[\w()-]#', 'some text'); // ok
|
||||
preg_match('#[-\w()]#', 'some text'); // ok
|
||||
preg_match('#[\w-()]#', 'some text'); // NOPE!
|
||||
preg_match('#[\w(-)]#', 'some text'); // ok
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -18,6 +23,11 @@ function regexDashEscapeRector()
|
|||
preg_match("#[-\w()]#", 'some text'); // ok
|
||||
preg_match("#[\w\-()]#", 'some text'); // NOPE!
|
||||
preg_match("#[\w(-)]#", 'some text'); // ok
|
||||
|
||||
preg_match('#[\w()-]#', 'some text'); // ok
|
||||
preg_match('#[-\w()]#', 'some text'); // ok
|
||||
preg_match('#[\w\-()]#', 'some text'); // NOPE!
|
||||
preg_match('#[\w(-)]#', 'some text'); // ok
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Php\Tests\Rector\FuncCall\RegexDashEscapeRector\Fixture;
|
||||
|
||||
class Variable
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$pattern = '#[-\w()]#'; // ok
|
||||
preg_match($pattern, 'some text');
|
||||
|
||||
$pattern = '#[\w-()]#'; // NOPE!
|
||||
preg_match($pattern, 'some text');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Php\Tests\Rector\FuncCall\RegexDashEscapeRector\Fixture;
|
||||
|
||||
class Variable
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$pattern = '#[-\w()]#'; // ok
|
||||
preg_match($pattern, 'some text');
|
||||
|
||||
$pattern = '#[\w\-()]#'; // NOPE!
|
||||
preg_match($pattern, 'some text');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -9,7 +9,11 @@ final class RegexDashEscapeRectorTest extends AbstractRectorTestCase
|
|||
{
|
||||
public function test(): void
|
||||
{
|
||||
$this->doTestFiles([__DIR__ . '/Fixture/fixture.php.inc', __DIR__ . '/Fixture/method_call.php.inc']);
|
||||
$this->doTestFiles([
|
||||
// __DIR__ . '/Fixture/fixture.php.inc',
|
||||
// __DIR__ . '/Fixture/method_call.php.inc',
|
||||
__DIR__ . '/Fixture/variable.php.inc',
|
||||
]);
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
|
|
|
@ -18,16 +18,16 @@ use Rector\RectorDefinition\RectorDefinition;
|
|||
*/
|
||||
final class RootNodeTreeBuilderRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var BetterNodeFinder
|
||||
*/
|
||||
private $betterNodeFinder;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $treeBuilderClass;
|
||||
|
||||
/**
|
||||
* @var BetterNodeFinder
|
||||
*/
|
||||
private $betterNodeFinder;
|
||||
|
||||
public function __construct(
|
||||
BetterNodeFinder $betterNodeFinder,
|
||||
string $treeBuilderClass = 'Symfony\Component\Config\Definition\Builder\TreeBuilder'
|
||||
|
|
|
@ -123,23 +123,6 @@ CODE_SAMPLE
|
|||
return $node;
|
||||
}
|
||||
|
||||
private function findPreviousNodeAssign(Node $node, Node $firstArgument): ?Assign
|
||||
{
|
||||
return $this->betterNodeFinder->findFirstPrevious($node, function (Node $checkedNode) use ($firstArgument) {
|
||||
if (! $checkedNode instanceof Assign) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->areNodesEqual($checkedNode->var, $firstArgument)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// @todo check out of scope assign, e.g. in previous method
|
||||
|
||||
return $checkedNode;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param New_|MethodCall $node
|
||||
*/
|
||||
|
@ -167,4 +150,21 @@ CODE_SAMPLE
|
|||
$createdNode->expr = $arrayNode;
|
||||
}
|
||||
}
|
||||
|
||||
private function findPreviousNodeAssign(Node $node, Node $firstArgument): ?Assign
|
||||
{
|
||||
return $this->betterNodeFinder->findFirstPrevious($node, function (Node $checkedNode) use ($firstArgument) {
|
||||
if (! $checkedNode instanceof Assign) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->areNodesEqual($checkedNode->var, $firstArgument)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// @todo check out of scope assign, e.g. in previous method
|
||||
|
||||
return $checkedNode;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,16 +16,16 @@ final class Error
|
|||
*/
|
||||
private $message;
|
||||
|
||||
/**
|
||||
* @var SmartFileInfo
|
||||
*/
|
||||
private $fileInfo;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $rectorClass;
|
||||
|
||||
/**
|
||||
* @var SmartFileInfo
|
||||
*/
|
||||
private $fileInfo;
|
||||
|
||||
public function __construct(
|
||||
SmartFileInfo $smartFileInfo,
|
||||
string $message,
|
||||
|
|
|
@ -13,6 +13,11 @@ use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
|
|||
|
||||
final class FileProcessor
|
||||
{
|
||||
/**
|
||||
* @var mixed[][]
|
||||
*/
|
||||
private $tokensByFilePath = [];
|
||||
|
||||
/**
|
||||
* @var FormatPerservingPrinter
|
||||
*/
|
||||
|
@ -43,11 +48,6 @@ final class FileProcessor
|
|||
*/
|
||||
private $currentFileInfoProvider;
|
||||
|
||||
/**
|
||||
* @var mixed[][]
|
||||
*/
|
||||
private $tokensByFilePath = [];
|
||||
|
||||
public function __construct(
|
||||
FormatPerservingPrinter $formatPerservingPrinter,
|
||||
Parser $parser,
|
||||
|
|
|
@ -96,21 +96,6 @@ final class RectorApplication
|
|||
$this->symfonyStyle->newLine(2);
|
||||
}
|
||||
|
||||
private function processFileInfo(SmartFileInfo $fileInfo): void
|
||||
{
|
||||
$oldContent = $fileInfo->getContents();
|
||||
|
||||
if ($this->configuration->isDryRun()) {
|
||||
$newContent = $this->fileProcessor->printToString($fileInfo);
|
||||
} else {
|
||||
$newContent = $this->fileProcessor->printToFile($fileInfo);
|
||||
}
|
||||
|
||||
$this->errorAndDiffCollector->addFileDiff($fileInfo, $newContent, $oldContent);
|
||||
|
||||
$this->fileSystemFileProcessor->processFileInfo($fileInfo);
|
||||
}
|
||||
|
||||
private function advance(): void
|
||||
{
|
||||
if ($this->symfonyStyle->isVerbose() === false) {
|
||||
|
@ -136,4 +121,19 @@ final class RectorApplication
|
|||
$this->errorAndDiffCollector->addThrowableWithFileInfo($throwable, $fileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private function processFileInfo(SmartFileInfo $fileInfo): void
|
||||
{
|
||||
$oldContent = $fileInfo->getContents();
|
||||
|
||||
if ($this->configuration->isDryRun()) {
|
||||
$newContent = $this->fileProcessor->printToString($fileInfo);
|
||||
} else {
|
||||
$newContent = $this->fileProcessor->printToFile($fileInfo);
|
||||
}
|
||||
|
||||
$this->errorAndDiffCollector->addFileDiff($fileInfo, $newContent, $oldContent);
|
||||
|
||||
$this->fileSystemFileProcessor->processFileInfo($fileInfo);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,12 +11,6 @@ final class Configuration
|
|||
*/
|
||||
private $isDryRun = false;
|
||||
|
||||
/**
|
||||
* Files and directories to by analysed
|
||||
* @var string[]
|
||||
*/
|
||||
private $source = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
@ -27,6 +21,12 @@ final class Configuration
|
|||
*/
|
||||
private $withStyle = false;
|
||||
|
||||
/**
|
||||
* Files and directories to by analysed
|
||||
* @var string[]
|
||||
*/
|
||||
private $source = [];
|
||||
|
||||
/**
|
||||
* Needs to run in the start of the life cycle, since the rest of workflow uses it.
|
||||
*/
|
||||
|
|
|
@ -69,6 +69,20 @@ final class Application extends SymfonyApplication
|
|||
return $defaultInputDefinition;
|
||||
}
|
||||
|
||||
private function isVersionPrintedElsewhere(InputInterface $input): bool
|
||||
{
|
||||
return $input->hasParameterOption('--version') !== false || $input->getFirstArgument() === null;
|
||||
}
|
||||
|
||||
private function getConfigPath(InputInterface $input): string
|
||||
{
|
||||
if ($input->getParameterOption('--config')) {
|
||||
return $input->getParameterOption('--config');
|
||||
}
|
||||
|
||||
return $this->getDefaultConfigPath();
|
||||
}
|
||||
|
||||
private function removeUnusedOptions(InputDefinition $inputDefinition): void
|
||||
{
|
||||
$options = $inputDefinition->getOptions();
|
||||
|
@ -103,20 +117,6 @@ final class Application extends SymfonyApplication
|
|||
));
|
||||
}
|
||||
|
||||
private function isVersionPrintedElsewhere(InputInterface $input): bool
|
||||
{
|
||||
return $input->hasParameterOption('--version') !== false || $input->getFirstArgument() === null;
|
||||
}
|
||||
|
||||
private function getConfigPath(InputInterface $input): string
|
||||
{
|
||||
if ($input->getParameterOption('--config')) {
|
||||
return $input->getParameterOption('--config');
|
||||
}
|
||||
|
||||
return $this->getDefaultConfigPath();
|
||||
}
|
||||
|
||||
private function getDefaultConfigPath(): string
|
||||
{
|
||||
return getcwd() . '/rector.yml';
|
||||
|
|
|
@ -26,16 +26,16 @@ use Rector\PhpParser\Node\BetterNodeFinder;
|
|||
*/
|
||||
final class NodeAddingCommander implements CommanderInterface
|
||||
{
|
||||
/**
|
||||
* @var BetterNodeFinder
|
||||
*/
|
||||
private $betterNodeFinder;
|
||||
|
||||
/**
|
||||
* @var Stmt[][]
|
||||
*/
|
||||
private $nodesToAdd = [];
|
||||
|
||||
/**
|
||||
* @var BetterNodeFinder
|
||||
*/
|
||||
private $betterNodeFinder;
|
||||
|
||||
public function __construct(BetterNodeFinder $betterNodeFinder)
|
||||
{
|
||||
$this->betterNodeFinder = $betterNodeFinder;
|
||||
|
|
|
@ -16,16 +16,16 @@ use Rector\PhpParser\Node\VariableInfo;
|
|||
*/
|
||||
final class PropertyAddingCommander implements CommanderInterface
|
||||
{
|
||||
/**
|
||||
* @var ClassMaintainer
|
||||
*/
|
||||
private $classMaintainer;
|
||||
|
||||
/**
|
||||
* @var VariableInfo[][]
|
||||
*/
|
||||
private $propertiesByClass = [];
|
||||
|
||||
/**
|
||||
* @var ClassMaintainer
|
||||
*/
|
||||
private $classMaintainer;
|
||||
|
||||
public function __construct(ClassMaintainer $classMaintainer)
|
||||
{
|
||||
$this->classMaintainer = $classMaintainer;
|
||||
|
@ -59,16 +59,16 @@ final class PropertyAddingCommander implements CommanderInterface
|
|||
private function createNodeVisitor(): NodeVisitor
|
||||
{
|
||||
return new class($this->classMaintainer, $this->propertiesByClass) extends NodeVisitorAbstract {
|
||||
/**
|
||||
* @var ClassMaintainer
|
||||
*/
|
||||
private $classMaintainer;
|
||||
|
||||
/**
|
||||
* @var VariableInfo[][]
|
||||
*/
|
||||
private $propertiesByClass = [];
|
||||
|
||||
/**
|
||||
* @var ClassMaintainer
|
||||
*/
|
||||
private $classMaintainer;
|
||||
|
||||
/**
|
||||
* @param VariableInfo[][] $propertiesByClass
|
||||
*/
|
||||
|
|
|
@ -38,20 +38,6 @@ final class BinaryOpMaintainer
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable|string $condition
|
||||
*/
|
||||
private function normalizeCondition($condition): callable
|
||||
{
|
||||
if (is_callable($condition)) {
|
||||
return $condition;
|
||||
}
|
||||
|
||||
return function (Node $node) use ($condition) {
|
||||
return is_a($node, $condition, true);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $firstCondition
|
||||
*/
|
||||
|
@ -67,4 +53,18 @@ final class BinaryOpMaintainer
|
|||
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable|string $condition
|
||||
*/
|
||||
private function normalizeCondition($condition): callable
|
||||
{
|
||||
if (is_callable($condition)) {
|
||||
return $condition;
|
||||
}
|
||||
|
||||
return function (Node $node) use ($condition) {
|
||||
return is_a($node, $condition, true);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -202,12 +202,6 @@ final class NodeFactory
|
|||
);
|
||||
}
|
||||
|
||||
private function createVarDoc(string $type): Doc
|
||||
{
|
||||
$type = $this->typeAnalyzer->isPhpReservedType($type) ? $type : '\\' . $type;
|
||||
return new Doc(sprintf('/**%s * @var %s%s */', PHP_EOL, $type, PHP_EOL));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $item
|
||||
*/
|
||||
|
@ -233,6 +227,12 @@ final class NodeFactory
|
|||
));
|
||||
}
|
||||
|
||||
private function createVarDoc(string $type): Doc
|
||||
{
|
||||
$type = $this->typeAnalyzer->isPhpReservedType($type) ? $type : '\\' . $type;
|
||||
return new Doc(sprintf('/**%s * @var %s%s */', PHP_EOL, $type, PHP_EOL));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Param[] $paramNodes
|
||||
* @return Arg[]
|
||||
|
|
|
@ -110,6 +110,26 @@ final class NodeTransformer
|
|||
return [$arrayItems, $stringArgument];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function splitBySpace(string $value): array
|
||||
{
|
||||
$value = str_getcsv($value, ' ');
|
||||
|
||||
return array_filter($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function transformConcatToItems(Concat $concatNode): array
|
||||
{
|
||||
$arrayItems = $this->transformConcatItemToArrayItems($concatNode->left);
|
||||
|
||||
return array_merge($arrayItems, $this->transformConcatItemToArrayItems($concatNode->right));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Node[]|string[]
|
||||
*/
|
||||
|
@ -133,24 +153,4 @@ final class NodeTransformer
|
|||
|
||||
return $arrayItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function transformConcatToItems(Concat $concatNode): array
|
||||
{
|
||||
$arrayItems = $this->transformConcatItemToArrayItems($concatNode->left);
|
||||
|
||||
return array_merge($arrayItems, $this->transformConcatItemToArrayItems($concatNode->right));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function splitBySpace(string $value): array
|
||||
{
|
||||
$value = str_getcsv($value, ' ');
|
||||
|
||||
return array_filter($value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,27 +101,6 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
private function createMethodCallNodeFromPropertyFetchNode(
|
||||
PropertyFetch $propertyFetchNode,
|
||||
string $method
|
||||
): MethodCall {
|
||||
/** @var Variable $variableNode */
|
||||
$variableNode = $propertyFetchNode->var;
|
||||
|
||||
return $this->createMethodCall($variableNode, $method, [$this->getName($propertyFetchNode)]);
|
||||
}
|
||||
|
||||
private function createMethodCallNodeFromAssignNode(
|
||||
PropertyFetch $propertyFetchNode,
|
||||
Node $node,
|
||||
string $method
|
||||
): MethodCall {
|
||||
/** @var Variable $variableNode */
|
||||
$variableNode = $propertyFetchNode->var;
|
||||
|
||||
return $this->createMethodCall($variableNode, $method, [$this->getName($propertyFetchNode), $node]);
|
||||
}
|
||||
|
||||
private function processMagicGet(Assign $assignNode): ?Node
|
||||
{
|
||||
/** @var PropertyFetch $propertyFetchNode */
|
||||
|
@ -170,4 +149,25 @@ CODE_SAMPLE
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function createMethodCallNodeFromPropertyFetchNode(
|
||||
PropertyFetch $propertyFetchNode,
|
||||
string $method
|
||||
): MethodCall {
|
||||
/** @var Variable $variableNode */
|
||||
$variableNode = $propertyFetchNode->var;
|
||||
|
||||
return $this->createMethodCall($variableNode, $method, [$this->getName($propertyFetchNode)]);
|
||||
}
|
||||
|
||||
private function createMethodCallNodeFromAssignNode(
|
||||
PropertyFetch $propertyFetchNode,
|
||||
Node $node,
|
||||
string $method
|
||||
): MethodCall {
|
||||
/** @var Variable $variableNode */
|
||||
$variableNode = $propertyFetchNode->var;
|
||||
|
||||
return $this->createMethodCall($variableNode, $method, [$this->getName($propertyFetchNode), $node]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,19 @@ CODE_SAMPLE
|
|||
return $this->processMethodCall($node);
|
||||
}
|
||||
|
||||
private function processStringNode(String_ $stringNode): ?Node
|
||||
{
|
||||
foreach ($this->methodNamesByType as $type => $methodName) {
|
||||
if (! $this->isType($stringNode, $type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $this->createMethodCall($stringNode->expr, $methodName);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function processMethodCall(MethodCall $methodCallNode): ?Node
|
||||
{
|
||||
foreach ($this->methodNamesByType as $type => $methodName) {
|
||||
|
@ -88,17 +101,4 @@ CODE_SAMPLE
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function processStringNode(String_ $stringNode): ?Node
|
||||
{
|
||||
foreach ($this->methodNamesByType as $type => $methodName) {
|
||||
if (! $this->isType($stringNode, $type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $this->createMethodCall($stringNode->expr, $methodName);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -171,18 +171,6 @@ abstract class AbstractRectorTestCase extends TestCase
|
|||
return [$originalFile, $expectedFile];
|
||||
}
|
||||
|
||||
private function createTemporaryPathWithPrefix(SmartFileInfo $smartFileInfo, string $prefix): string
|
||||
{
|
||||
$hash = Strings::substring(md5($smartFileInfo->getRealPath()), 0, 5);
|
||||
|
||||
return sprintf(
|
||||
sys_get_temp_dir() . '/rector_temp_tests/%s_%s_%s',
|
||||
$prefix,
|
||||
$hash,
|
||||
$smartFileInfo->getBasename('.inc')
|
||||
);
|
||||
}
|
||||
|
||||
private function doTestFileMatchesExpectedContent(
|
||||
string $originalFile,
|
||||
string $expectedFile,
|
||||
|
@ -199,4 +187,16 @@ abstract class AbstractRectorTestCase extends TestCase
|
|||
|
||||
$this->assertStringEqualsFile($expectedFile, $changedContent, 'Caused by ' . $fixtureFile);
|
||||
}
|
||||
|
||||
private function createTemporaryPathWithPrefix(SmartFileInfo $smartFileInfo, string $prefix): string
|
||||
{
|
||||
$hash = Strings::substring(md5($smartFileInfo->getRealPath()), 0, 5);
|
||||
|
||||
return sprintf(
|
||||
sys_get_temp_dir() . '/rector_temp_tests/%s_%s_%s',
|
||||
$prefix,
|
||||
$hash,
|
||||
$smartFileInfo->getBasename('.inc')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user