Skip to content

Commit

Permalink
[Core] Handle parent return/assign from FuncCall with No Scope (#2525)
Browse files Browse the repository at this point in the history
  • Loading branch information
samsonasik committed Jun 19, 2022
1 parent 3e6c9cf commit 372e030
Show file tree
Hide file tree
Showing 23 changed files with 295 additions and 201 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ jobs:
- 'e2e/use-rector-configurator'
- 'e2e/applied-rule-removed-node'
- 'e2e/parallel with space'
- 'e2e/parent-arg-from-func-call'
- 'e2e/parent-binaryop-from-func-call'
- 'e2e/parent-assign-from-func-call'

name: End to end test - ${{ matrix.directory }}

Expand Down
1 change: 0 additions & 1 deletion e2e/parent-arg-from-func-call/.gitignore

This file was deleted.

5 changes: 0 additions & 5 deletions e2e/parent-arg-from-func-call/composer.json

This file was deleted.

16 changes: 0 additions & 16 deletions e2e/parent-arg-from-func-call/rector.php

This file was deleted.

1 change: 0 additions & 1 deletion e2e/parent-assign-from-func-call/.gitignore

This file was deleted.

5 changes: 0 additions & 5 deletions e2e/parent-assign-from-func-call/composer.json

This file was deleted.

38 changes: 0 additions & 38 deletions e2e/parent-assign-from-func-call/expected-output.diff

This file was deleted.

16 changes: 0 additions & 16 deletions e2e/parent-assign-from-func-call/rector.php

This file was deleted.

20 changes: 0 additions & 20 deletions e2e/parent-assign-from-func-call/src/Loop.php

This file was deleted.

1 change: 0 additions & 1 deletion e2e/parent-binaryop-from-func-call/.gitignore

This file was deleted.

5 changes: 0 additions & 5 deletions e2e/parent-binaryop-from-func-call/composer.json

This file was deleted.

16 changes: 0 additions & 16 deletions e2e/parent-binaryop-from-func-call/rector.php

This file was deleted.

7 changes: 7 additions & 0 deletions full_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ rm -rf vendor
composer clear-cache

composer install --ansi

# ensure clear cache
bin/rector --version --clear-cache

# ensure remove cache directory
php -r 'shell_exec("rm -rf " . sys_get_temp_dir() . "/rector_cached_files");';

composer install --no-dev --ansi

# early downgrade individual functions
Expand Down
101 changes: 77 additions & 24 deletions packages/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\AssignOp;
use PhpParser\Node\Expr\BinaryOp;
use PhpParser\Node\Expr\Ternary;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Class_;
Expand Down Expand Up @@ -101,6 +104,18 @@ public function processNodes(
$isScopeRefreshing,
$smartFileInfo
): void {
if ($node instanceof Ternary) {
$this->processTernary($node, $mutatingScope);
}

if ($node instanceof AssignOp) {
$node->expr->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}

if ($node instanceof BinaryOp) {
$this->processBinaryOp($node, $mutatingScope);
}

if ($node instanceof Arg) {
$node->value->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}
Expand All @@ -111,13 +126,7 @@ public function processNodes(
}

if ($node instanceof Property) {
foreach ($node->props as $propertyProperty) {
$propertyProperty->setAttribute(AttributeKey::SCOPE, $mutatingScope);

if ($propertyProperty->default instanceof Expr) {
$propertyProperty->default->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}
}
$this->processProperty($node, $mutatingScope);
}

if ($node instanceof Switch_) {
Expand All @@ -127,8 +136,14 @@ public function processNodes(
}
}

if ($node instanceof TryCatch && $node->finally instanceof Finally_) {
$node->finally->setAttribute(AttributeKey::SCOPE, $mutatingScope);
if ($node instanceof TryCatch) {
foreach ($node->catches as $catch) {
$this->processNodes($catch->stmts, $smartFileInfo, $mutatingScope);
}

if ($node->finally instanceof Finally_) {
$node->finally->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}
}

if ($node instanceof Assign) {
Expand All @@ -142,16 +157,6 @@ public function processNodes(
$node->expr->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}

// scope is missing on attributes
// @todo decorate parent nodes too
if ($node instanceof Property) {
foreach ($node->attrGroups as $attrGroup) {
foreach ($attrGroup->attrs as $attribute) {
$attribute->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}
}
}

if ($node instanceof Trait_) {
$traitName = $this->resolveClassName($node);

Expand Down Expand Up @@ -196,11 +201,7 @@ public function processNodes(

// special case for unreachable nodes
if ($node instanceof UnreachableStatementNode) {
$originalStmt = $node->getOriginalStatement();
$originalStmt->setAttribute(AttributeKey::IS_UNREACHABLE, true);
$originalStmt->setAttribute(AttributeKey::SCOPE, $mutatingScope);

$this->processNodes([$originalStmt], $smartFileInfo, $mutatingScope);
$this->processUnreachableStatementNode($node, $smartFileInfo, $mutatingScope);
} else {
$node->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}
Expand All @@ -211,6 +212,58 @@ public function processNodes(
return $this->processNodesWithDependentFiles($smartFileInfo, $stmts, $scope, $nodeCallback);
}

private function processUnreachableStatementNode(
UnreachableStatementNode $unreachableStatementNode,
SmartFileInfo $smartFileInfo,
MutatingScope $mutatingScope
): void {
$originalStmt = $unreachableStatementNode->getOriginalStatement();
$originalStmt->setAttribute(AttributeKey::IS_UNREACHABLE, true);
$originalStmt->setAttribute(AttributeKey::SCOPE, $mutatingScope);

$this->processNodes([$originalStmt], $smartFileInfo, $mutatingScope);

$next = $originalStmt->getAttribute(AttributeKey::NEXT_NODE);
while ($next instanceof Stmt) {
$next->setAttribute(AttributeKey::IS_UNREACHABLE, true);

$this->processNodes([$next], $smartFileInfo, $mutatingScope);
$next = $next->getAttribute(AttributeKey::NEXT_NODE);
}
}

private function processProperty(Property $property, MutatingScope $mutatingScope): void
{
foreach ($property->props as $propertyProperty) {
$propertyProperty->setAttribute(AttributeKey::SCOPE, $mutatingScope);

if ($propertyProperty->default instanceof Expr) {
$propertyProperty->default->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}
}

foreach ($property->attrGroups as $attrGroup) {
foreach ($attrGroup->attrs as $attribute) {
$attribute->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}
}
}

private function processBinaryOp(BinaryOp $binaryOp, MutatingScope $mutatingScope): void
{
$binaryOp->left->setAttribute(AttributeKey::SCOPE, $mutatingScope);
$binaryOp->right->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}

private function processTernary(Ternary $ternary, MutatingScope $mutatingScope): void
{
if ($ternary->if instanceof Expr) {
$ternary->if->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}

$ternary->else->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}

/**
* @param Stmt[] $stmts
* @param callable(Node $node, MutatingScope $scope): void $nodeCallback
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

namespace Rector\Tests\DowngradePhp81\Rector\FuncCall\DowngradeArrayIsListRector\Fixture;

final class Loop
{
/**
* @var LoopInterface
*/
private static $instance;

public static function get()
{
if (self::$instance instanceof LoopInterface) {
return self::$instance;
}

register_shutdown_function(function () {
$test = array_is_list([]);
});
}
}

?>
-----
<?php

namespace Rector\Tests\DowngradePhp81\Rector\FuncCall\DowngradeArrayIsListRector\Fixture;

final class Loop
{
/**
* @var LoopInterface
*/
private static $instance;

public static function get()
{
if (self::$instance instanceof LoopInterface) {
return self::$instance;
}

register_shutdown_function(function () {
$arrayIsList = function (array $array) : bool {
if (function_exists('array_is_list')) {
return array_is_list($array);
}
if ($array === []) {
return true;
}
$current_key = 0;
foreach ($array as $key => $noop) {
if ($key !== $current_key) {
return false;
}
++$current_key;
}
return true;
};
$test = $arrayIsList([]);
});
}
}

?>

0 comments on commit 372e030

Please sign in to comment.