mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-01 08:50:50 +00:00
[static] Fix mixed type on property fetches and method calls (#1769)
This commit is contained in:
parent
fd7667b5aa
commit
dae413184b
|
@ -8,6 +8,7 @@ use Nette\Utils\Json;
|
|||
use Rector\ChangesReporting\Annotation\RectorsChangelogResolver;
|
||||
use Rector\ChangesReporting\Contract\Output\OutputFormatterInterface;
|
||||
use Rector\Core\ValueObject\Configuration;
|
||||
use Rector\Core\ValueObject\Error\SystemError;
|
||||
use Rector\Core\ValueObject\ProcessResult;
|
||||
use Rector\Parallel\ValueObject\Bridge;
|
||||
|
||||
|
@ -69,7 +70,7 @@ final class JsonOutputFormatter implements OutputFormatterInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $errors
|
||||
* @param SystemError[] $errors
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function createErrorsData(array $errors): array
|
||||
|
@ -82,7 +83,7 @@ final class JsonOutputFormatter implements OutputFormatterInterface
|
|||
'file' => $error->getRelativeFilePath(),
|
||||
];
|
||||
|
||||
if ($error->getRectorClass()) {
|
||||
if ($error->getRectorClass() !== null) {
|
||||
$errorDataJson['caused_by'] = $error->getRectorClass();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,12 +9,8 @@ use PhpParser\Node\Expr;
|
|||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Name;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
|
||||
|
||||
/**
|
||||
* Utils for chain of MethodCall Node:
|
||||
|
@ -24,7 +20,6 @@ final class FluentChainMethodCallNodeAnalyzer
|
|||
{
|
||||
public function __construct(
|
||||
private readonly NodeNameResolver $nodeNameResolver,
|
||||
private readonly NodeTypeResolver $nodeTypeResolver,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -74,47 +69,6 @@ final class FluentChainMethodCallNodeAnalyzer
|
|||
return $chainMethodCalls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks "$this->someMethod()->anotherMethod()"
|
||||
*
|
||||
* @param string[] $methods
|
||||
*/
|
||||
public function isTypeAndChainCalls(Node $node, Type $type, array $methods): bool
|
||||
{
|
||||
if (! $node instanceof MethodCall) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$rootMethodCall = $this->resolveRootMethodCall($node);
|
||||
if (! $rootMethodCall instanceof MethodCall) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$rootMethodCallVarType = $this->nodeTypeResolver->getType($rootMethodCall->var);
|
||||
if (! $rootMethodCallVarType instanceof FullyQualifiedObjectType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// node chaining is in reverse order than code
|
||||
$methods = array_reverse($methods);
|
||||
|
||||
foreach ($methods as $method) {
|
||||
if (! $this->nodeNameResolver->isName($node->name, $method)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$node = $node->var;
|
||||
}
|
||||
|
||||
$variableType = $this->nodeTypeResolver->getType($node);
|
||||
if ($variableType instanceof MixedType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $variableType->isSuperTypeOf($type)
|
||||
->yes();
|
||||
}
|
||||
|
||||
public function resolveRootExpr(MethodCall $methodCall): Expr | Name
|
||||
{
|
||||
$callerNode = $methodCall->var;
|
||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\FileFormatter\EditorConfig;
|
||||
|
||||
use Idiosyncratic\EditorConfig\Declaration\Declaration;
|
||||
use Idiosyncratic\EditorConfig\EditorConfig;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\FileFormatter\ValueObject\EditorConfigConfiguration;
|
||||
|
@ -25,6 +26,8 @@ final class EditorConfigParser
|
|||
EditorConfigConfigurationBuilder $editorConfigConfigurationBuilder
|
||||
): EditorConfigConfiguration {
|
||||
$smartFileInfo = $file->getSmartFileInfo();
|
||||
|
||||
/** @var Declaration[] $configuration */
|
||||
$configuration = $this->editorConfig->getConfigForPath($smartFileInfo->getRealPath());
|
||||
|
||||
if (array_key_exists(EditorConfigOption::INDENT_STYLE, $configuration)) {
|
||||
|
|
|
@ -25,7 +25,7 @@ final class BinaryOpTreeRootLocator
|
|||
public function findOperationRoot(Expr $expr, string $binaryOpClass): Expr
|
||||
{
|
||||
$parentNode = $expr->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if ($parentNode === null) {
|
||||
if (! $parentNode instanceof Node) {
|
||||
// No more parents so the Expr node must be root.
|
||||
return $expr;
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ final class BinaryOpTreeRootLocator
|
|||
return $expr;
|
||||
}
|
||||
|
||||
/** @var BinaryOp $parentNode */
|
||||
$isParentARightAssociativeTree = $parentNode->right === $expr && $expr::class === $binaryOpClass;
|
||||
if ($isParentARightAssociativeTree) {
|
||||
// The Expr node is the right child of its parent but it is the desired operation (BinaryOp b c).
|
||||
|
|
|
@ -40,6 +40,7 @@ final class StatementNodeVisitor extends NodeVisitorAbstract
|
|||
if (property_exists($node, 'stmts')) {
|
||||
$previous = $node;
|
||||
foreach ((array) $node->stmts as $stmt) {
|
||||
/** @var Stmt $stmt */
|
||||
$stmt->setAttribute(AttributeKey::PREVIOUS_STATEMENT, $previous);
|
||||
$stmt->setAttribute(AttributeKey::CURRENT_STATEMENT, $stmt);
|
||||
$previous = $stmt;
|
||||
|
|
|
@ -607,8 +607,9 @@ parameters:
|
|||
- '#Parameter \#2 \$key of class PhpParser\\Node\\Expr\\ArrayItem constructor expects PhpParser\\Node\\Expr\|null, array<PhpParser\\Node\\Expr\>\|PhpParser\\Node\\Expr\|string\|null given#'
|
||||
|
||||
# broken on CI
|
||||
- '#Anonymous variables in a method call can lead to false dead methods\. Make sure the variable type is known#'
|
||||
- '#Anonymous variables in a property fetch can lead to false dead property\. Make sure the variable type is known#'
|
||||
-
|
||||
message: '#Anonymous variables in a method call can lead to false dead methods\. Make sure the variable type is known#'
|
||||
path: packages/NodeNestingScope/FlowOfControlLocator.php
|
||||
|
||||
-
|
||||
message: '#This property type might be inlined to PHP\. Do you have confidence it is correct\? Put it here#'
|
||||
|
|
|
@ -111,6 +111,10 @@ CODE_SAMPLE
|
|||
if ($node instanceof FunctionLike) {
|
||||
return $node->returnsByRef();
|
||||
}
|
||||
|
||||
if (! $node instanceof Node) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\CodingStyle\Rector\Stmt;
|
||||
|
||||
use PhpParser\Comment\Doc;
|
||||
use PhpParser\Comment;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\Catch_;
|
||||
|
@ -127,6 +127,10 @@ CODE_SAMPLE
|
|||
}
|
||||
|
||||
$nextNode = $node->getAttribute(AttributeKey::NEXT_NODE);
|
||||
if (! $nextNode instanceof Node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->shouldSkip($nextNode)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -136,6 +140,7 @@ CODE_SAMPLE
|
|||
$rangeLine = $line - $endLine;
|
||||
|
||||
if ($rangeLine > 1) {
|
||||
/** @var Comment[]|null $comments */
|
||||
$comments = $nextNode->getAttribute(AttributeKey::COMMENTS);
|
||||
|
||||
if ($this->hasNoComment($comments)) {
|
||||
|
@ -147,6 +152,7 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
/** @var Comment[] $comments */
|
||||
$line = $comments[0]->getLine();
|
||||
$rangeLine = $line - $endLine;
|
||||
|
||||
|
@ -171,7 +177,7 @@ CODE_SAMPLE
|
|||
}
|
||||
|
||||
/**
|
||||
* @param null|Doc[] $comments
|
||||
* @param Comment[]|null $comments
|
||||
*/
|
||||
private function hasNoComment(?array $comments): bool
|
||||
{
|
||||
|
|
|
@ -192,6 +192,9 @@ CODE_SAMPLE
|
|||
private function refactorUsedVariable(Assign $assign): ?Assign
|
||||
{
|
||||
$parentNode = $assign->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if (! $parentNode instanceof Node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$if = $parentNode->getAttribute(AttributeKey::NEXT_NODE);
|
||||
|
||||
|
|
|
@ -12,7 +12,9 @@ use PhpParser\Node\Expr\MethodCall;
|
|||
use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Naming\Naming\VariableNaming;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
@ -87,6 +89,10 @@ CODE_SAMPLE
|
|||
private function createVariable(Node $node): Variable
|
||||
{
|
||||
$currentStmt = $node->getAttribute(AttributeKey::CURRENT_STATEMENT);
|
||||
if (! $currentStmt instanceof Stmt) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$scope = $currentStmt->getAttribute(AttributeKey::SCOPE);
|
||||
|
||||
return new Variable($this->variableNaming->createCountedValueName('object', $scope));
|
||||
|
|
|
@ -10,6 +10,7 @@ use PhpParser\Node\Expr\List_;
|
|||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Foreach_;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Naming\Naming\VariableNaming;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
@ -79,6 +80,10 @@ CODE_SAMPLE
|
|||
private function createVariable(Foreach_ $foreach): Variable
|
||||
{
|
||||
$currentStmt = $foreach->getAttribute(AttributeKey::CURRENT_STATEMENT);
|
||||
if (! $currentStmt instanceof Node) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$scope = $currentStmt->getAttribute(AttributeKey::SCOPE);
|
||||
|
||||
return new Variable($this->variableNaming->createCountedValueName('arrayItem', $scope));
|
||||
|
|
|
@ -20,6 +20,7 @@ use PhpParser\Node\Scalar\LNumber;
|
|||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use PhpParser\Node\Stmt\While_;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Naming\Naming\VariableNaming;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
@ -128,6 +129,10 @@ CODE_SAMPLE
|
|||
private function refactorForVariableLevels(FuncCall $funcCall): FuncCall
|
||||
{
|
||||
$currentStmt = $funcCall->getAttribute(AttributeKey::CURRENT_STATEMENT);
|
||||
if (! $currentStmt instanceof Node) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$scope = $currentStmt->getAttribute(AttributeKey::SCOPE);
|
||||
|
||||
$funcVariable = new Variable($this->variableNaming->createCountedValueName('dirnameFunc', $scope));
|
||||
|
|
|
@ -11,6 +11,8 @@ use PhpParser\Node\Expr\Instanceof_;
|
|||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PhpParser\Node\Stmt;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Naming\Naming\VariableNaming;
|
||||
use Rector\NodeCollector\BinaryOpConditionsCollector;
|
||||
|
@ -90,6 +92,10 @@ CODE_SAMPLE
|
|||
private function createVariable(Instanceof_ $instanceof): Variable
|
||||
{
|
||||
$currentStmt = $instanceof->getAttribute(AttributeKey::CURRENT_STATEMENT);
|
||||
if (! $currentStmt instanceof Stmt) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$scope = $currentStmt->getAttribute(AttributeKey::SCOPE);
|
||||
|
||||
return new Variable($this->variableNaming->createCountedValueName('throwable', $scope));
|
||||
|
|
|
@ -18,6 +18,7 @@ use PhpParser\Node\Param;
|
|||
use PhpParser\Node\Scalar\LNumber;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\NodeManipulator\IfManipulator;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Naming\Naming\VariableNaming;
|
||||
|
@ -94,6 +95,10 @@ CODE_SAMPLE
|
|||
$anonymousFunction->stmts[1] = new Return_($ternary);
|
||||
|
||||
$currentStatement = $node->getAttribute(AttributeKey::CURRENT_STATEMENT);
|
||||
if (! $currentStatement instanceof Node) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$scope = $currentStatement->getAttribute(AttributeKey::SCOPE);
|
||||
|
||||
$variableAssignName = $this->variableNaming->createCountedValueName('battleShipcompare', $scope);
|
||||
|
|
|
@ -143,6 +143,7 @@ CODE_SAMPLE
|
|||
|
||||
$comments = $param->getAttribute(AttributeKey::COMMENTS);
|
||||
if (is_array($comments)) {
|
||||
/** @var Comment[] $comments */
|
||||
foreach ($comments as $comment) {
|
||||
$attrGroupsPrint = str_replace($comment->getText(), '', $attrGroupsPrint);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ use PhpParser\Node\Expr\New_;
|
|||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\StaticPropertyFetch;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Naming\Naming\VariableNaming;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
@ -93,6 +94,10 @@ CODE_SAMPLE
|
|||
$variable = $assign->var;
|
||||
} else {
|
||||
$currentStmt = $node->getAttribute(AttributeKey::CURRENT_STATEMENT);
|
||||
if (! $currentStmt instanceof Node) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$scope = $currentStmt->getAttribute(AttributeKey::SCOPE);
|
||||
$variable = new Variable($this->variableNaming->createCountedValueName('className', $scope));
|
||||
$assign = new Assign($variable, $node->class);
|
||||
|
|
|
@ -128,7 +128,7 @@ CODE_SAMPLE
|
|||
|
||||
$callNodeClass = $callNode::class;
|
||||
|
||||
while ($parentNode) {
|
||||
while ($parentNode instanceof Node) {
|
||||
$usedNodes = $this->betterNodeFinder->find($parentNode, function (Node $node) use (
|
||||
$callNodeClass,
|
||||
$callNode
|
||||
|
|
|
@ -91,7 +91,7 @@ final class NonVariableToVariableOnFunctionCallRector extends AbstractRector imp
|
|||
}
|
||||
|
||||
$currentScope = $scopeNode->getAttribute(AttributeKey::SCOPE);
|
||||
if (! $currentScope instanceof Scope) {
|
||||
if (! $currentScope instanceof MutatingScope) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -105,6 +105,7 @@ final class NonVariableToVariableOnFunctionCallRector extends AbstractRector imp
|
|||
$current = $node->getAttribute(AttributeKey::CURRENT_STATEMENT);
|
||||
|
||||
$currentStatement = $node->getAttribute(AttributeKey::CURRENT_STATEMENT);
|
||||
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(
|
||||
$replacements->getAssign(),
|
||||
$current instanceof Return_ ? $current : $currentStatement
|
||||
|
@ -166,7 +167,7 @@ final class NonVariableToVariableOnFunctionCallRector extends AbstractRector imp
|
|||
|
||||
private function getReplacementsFor(
|
||||
Expr $expr,
|
||||
Scope $scope,
|
||||
MutatingScope $scope,
|
||||
Closure|Class_|ClassMethod|Function_|Namespace_ $scopeNode
|
||||
): VariableAssignPair {
|
||||
if ($this->isAssign($expr)) {
|
||||
|
@ -181,10 +182,8 @@ final class NonVariableToVariableOnFunctionCallRector extends AbstractRector imp
|
|||
$variable = new Variable($variableName);
|
||||
|
||||
// add a new scope with this variable
|
||||
if ($scope instanceof MutatingScope) {
|
||||
$mutatingScope = $scope->assignExpression($variable, new MixedType());
|
||||
$scopeNode->setAttribute(AttributeKey::SCOPE, $mutatingScope);
|
||||
}
|
||||
$mutatingScope = $scope->assignExpression($variable, new MixedType());
|
||||
$scopeNode->setAttribute(AttributeKey::SCOPE, $mutatingScope);
|
||||
|
||||
return new VariableAssignPair($variable, new Assign($variable, $expr));
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ use PhpParser\Node;
|
|||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\ValueObject\PhpVersionFeature;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
@ -72,7 +73,7 @@ CODE_SAMPLE
|
|||
$node->args[1] = new Arg($resultVariable);
|
||||
|
||||
$expression = $node->getAttribute(AttributeKey::CURRENT_STATEMENT);
|
||||
if ($expression === null) {
|
||||
if (! $expression instanceof Stmt) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ final class ComplexNodeRemover
|
|||
{
|
||||
$assign = $expr->getAttribute(AttributeKey::PARENT_NODE);
|
||||
|
||||
while ($assign !== null && ! $assign instanceof Assign) {
|
||||
while ($assign instanceof Node && ! $assign instanceof Assign) {
|
||||
$assign = $assign->getAttribute(AttributeKey::PARENT_NODE);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ use PhpParser\Node\Expr\StaticCall;
|
|||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
|
@ -100,6 +101,9 @@ CODE_SAMPLE
|
|||
}
|
||||
|
||||
$scope = $classMethod->getAttribute(AttributeKey::SCOPE);
|
||||
if (! $scope instanceof Scope) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$classReflection = $scope->getClassReflection();
|
||||
if (! $classReflection instanceof ClassReflection) {
|
||||
|
|
|
@ -10,6 +10,9 @@ use Symfony\Component\Config\FileLocatorInterface;
|
|||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
|
||||
|
||||
/**
|
||||
* @property-read ContainerBuilder $container
|
||||
*/
|
||||
final class ConfigurableCallValuesCollectingPhpFileLoader extends PhpFileLoader
|
||||
{
|
||||
public function __construct(
|
||||
|
@ -51,10 +54,6 @@ final class ConfigurableCallValuesCollectingPhpFileLoader extends PhpFileLoader
|
|||
private function collectConfigureCallsFromJustImportedConfigurableRectorDefinitions(): void
|
||||
{
|
||||
foreach ($this->container->getDefinitions() as $class => $definition) {
|
||||
if (! is_string($class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! is_a($class, ConfigurableRectorInterface::class, true)) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ final class AssignManipulator
|
|||
$previousNode = $node;
|
||||
$parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
|
||||
|
||||
while ($parentNode !== null && ! $parentNode instanceof Expression) {
|
||||
while ($parentNode instanceof Node && ! $parentNode instanceof Expression) {
|
||||
if ($parentNode instanceof Assign && $this->nodeComparator->areNodesEqual(
|
||||
$parentNode->var,
|
||||
$previousNode
|
||||
|
|
|
@ -111,6 +111,7 @@ final class IfManipulator
|
|||
while ($this->isIfWithOnlyStmtIf($currentIf)) {
|
||||
$ifs[] = $currentIf;
|
||||
|
||||
/** @var If_ $currentIf */
|
||||
$currentIf = $currentIf->stmts[0];
|
||||
}
|
||||
|
||||
|
@ -198,6 +199,7 @@ final class IfManipulator
|
|||
while ($this->isIfWithOnlyStmtIf($currentIf)) {
|
||||
$ifs[] = $currentIf;
|
||||
|
||||
/** @var If_ $currentIf */
|
||||
$currentIf = $currentIf->stmts[0];
|
||||
}
|
||||
|
||||
|
|
|
@ -310,24 +310,24 @@ final class BetterNodeFinder
|
|||
public function findFirstPrevious(Node $node, callable $filter): ?Node
|
||||
{
|
||||
$node = $node instanceof Expression ? $node : $node->getAttribute(AttributeKey::CURRENT_STATEMENT);
|
||||
if ($node === null) {
|
||||
if (! $node instanceof Node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$foundNode = $this->findFirst([$node], $filter);
|
||||
// we found what we need
|
||||
if ($foundNode !== null) {
|
||||
if ($foundNode instanceof Node) {
|
||||
return $foundNode;
|
||||
}
|
||||
|
||||
// move to previous expression
|
||||
$previousStatement = $node->getAttribute(AttributeKey::PREVIOUS_STATEMENT);
|
||||
if ($previousStatement !== null) {
|
||||
if ($previousStatement instanceof Node) {
|
||||
return $this->findFirstPrevious($previousStatement, $filter);
|
||||
}
|
||||
|
||||
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if ($parent === null) {
|
||||
if (! $parent instanceof Node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace Rector\Core\PhpParser\Printer;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Comment;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
|
@ -458,6 +459,7 @@ final class BetterStandardPrinter extends Standard
|
|||
return $content;
|
||||
}
|
||||
|
||||
/** @var Comment[] $comments */
|
||||
$comments = $expr->getAttribute(AttributeKey::COMMENTS) ?? [];
|
||||
|
||||
if ($comments === []) {
|
||||
|
|
|
@ -230,6 +230,7 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
|
|||
$this->printDebugApplying();
|
||||
|
||||
$originalAttributes = $node->getAttributes();
|
||||
|
||||
$originalNode ??= clone $node;
|
||||
|
||||
$node = $this->refactor($node);
|
||||
|
@ -239,6 +240,7 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
|
|||
return null;
|
||||
}
|
||||
|
||||
/** @var Node $originalNode */
|
||||
if (is_array($node)) {
|
||||
$this->createdByRule($node, $originalNode);
|
||||
|
||||
|
|
|
@ -37,6 +37,11 @@ final class SystemError implements SerializableInterface
|
|||
return $this->relativeFilePath . ':' . $this->line;
|
||||
}
|
||||
|
||||
public function getRelativeFilePath(): ?string
|
||||
{
|
||||
return $this->relativeFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{message: string, relative_file_path: string|null, line: int|null, rector_class: string|null}
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue
Block a user