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
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Attribute;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
Expand All @@ -17,6 +18,7 @@
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\Instanceof_;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\NullsafeMethodCall;
Expand All @@ -28,6 +30,7 @@
use PhpParser\Node\Identifier;
use PhpParser\Node\IntersectionType;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\NullableType;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Class_;
Expand All @@ -38,12 +41,17 @@
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Finally_;
use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\Stmt\GroupUse;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\Stmt\Switch_;
use PhpParser\Node\Stmt\Trait_;
use PhpParser\Node\Stmt\TraitUse;
use PhpParser\Node\Stmt\TraitUseAdaptation\Precedence;
use PhpParser\Node\Stmt\TryCatch;
use PhpParser\Node\Stmt\UseUse;
use PhpParser\Node\UnionType;
use PhpParser\NodeTraverser;
use PHPStan\AnalysedCodeException;
Expand Down Expand Up @@ -132,15 +140,56 @@ public function processNodes(
): void {
if ($node instanceof FileWithoutNamespace) {
$this->nodeScopeResolver->processNodes($node->stmts, $mutatingScope, $nodeCallback);

return;
}

if ($node instanceof Namespace_ && $node->name instanceof Name) {
$node->name->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}

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

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

if ($node instanceof GroupUse) {
$node->prefix->setAttribute(AttributeKey::SCOPE, $mutatingScope);
foreach ($node->uses as $use) {
$use->name->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}
}

if ($node instanceof TraitUse) {
foreach ($node->traits as $traitName) {
$traitName->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}

foreach ($node->adaptations as $precedence) {
if ($precedence instanceof Precedence) {
foreach ($precedence->insteadof as $insteadof) {
$insteadof->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}

if ($precedence->trait instanceof Name) {
$precedence->trait->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}
}
}
}

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

if ((
$node instanceof Expression ||
$node instanceof Return_ ||
$node instanceof Assign ||
$node instanceof EnumCase ||
$node instanceof AssignOp ||
$node instanceof Cast
) && $node->expr instanceof Expr) {
$node->expr->setAttribute(AttributeKey::SCOPE, $mutatingScope);
Expand Down Expand Up @@ -268,6 +317,21 @@ public function processNodes(
if ($node instanceof Class_ || $node instanceof Interface_ || $node instanceof Enum_) {
/** @var MutatingScope $mutatingScope */
$mutatingScope = $this->resolveClassOrInterfaceScope($node, $mutatingScope, $isScopeRefreshing);
if ($node instanceof Class_ && $node->extends instanceof FullyQualified) {
$node->extends->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}

if ($node instanceof Interface_) {
foreach ($node->extends as $extend) {
$extend->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}
}

if ($node instanceof Class_ || $node instanceof Enum_) {
foreach ($node->implements as $implement) {
$implement->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}
}
}

if ($node instanceof Stmt) {
Expand Down Expand Up @@ -322,24 +386,34 @@ private function processArgsForCallike(Expr $expr, MutatingScope $mutatingScope)
if (! $expr->isFirstClassCallable()) {
foreach ($expr->getArgs() as $arg) {
$arg->value->setAttribute(AttributeKey::SCOPE, $mutatingScope);
if ($arg->value instanceof PropertyFetch) {
$arg->value->var->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}
}
}
}

private function processAssign(Assign|AssignOp $assign, MutatingScope $mutatingScope): void
{
if (! $assign->var instanceof Variable || ! $assign->var->name instanceof Variable) {
$assign->var->setAttribute(AttributeKey::SCOPE, $mutatingScope);
return;
$assign->var->setAttribute(AttributeKey::SCOPE, $mutatingScope);
if ($assign->var instanceof Variable && $assign->var->name instanceof Expr) {
$assign->var->name->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}

$assign->expr->setAttribute(AttributeKey::SCOPE, $mutatingScope);

$expr = $assign;

while ($expr instanceof Assign || $expr instanceof AssignOp) {
$this->processArgsForCallike($expr->expr, $mutatingScope);

// decorate value as well
$expr->var->setAttribute(AttributeKey::SCOPE, $mutatingScope);
if ($expr->var instanceof Variable && $expr->var->name instanceof Expr) {
$expr->var->name->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}

$expr->expr->setAttribute(AttributeKey::SCOPE, $mutatingScope);

$expr = $expr->expr;
}
}
Expand Down Expand Up @@ -369,6 +443,7 @@ private function processArray(Array_ $array, MutatingScope $mutatingScope): void
foreach ($array->items as $arrayItem) {
if ($arrayItem instanceof ArrayItem) {
$arrayItem->setAttribute(AttributeKey::SCOPE, $mutatingScope);
$this->processArrayItem($arrayItem, $mutatingScope);
}
}
}
Expand Down
33 changes: 1 addition & 32 deletions src/NodeAnalyzer/ScopeAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\Namespace_;
use PHPStan\Analyser\MutatingScope;
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PHPStan\Scope\ScopeFactory;

Expand Down Expand Up @@ -47,39 +45,10 @@ public function resolveScope(
return $mutatingScope;
}

$parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
if (! $parentNode instanceof Node) {
if ($node->getAttribute(AttributeKey::STATEMENT_DEPTH) === 0) {
return $this->scopeFactory->createFromFile($filePath);
}

if (! $this->hasScope($node)) {
return $this->scopeFactory->createFromFile($filePath);
}

if (! $this->hasScope($parentNode)) {
return $this->scopeFactory->createFromFile($filePath);
}

/** @var MutatingScope|null $parentScope */
$parentScope = $parentNode->getAttribute(AttributeKey::SCOPE);
if ($parentScope instanceof MutatingScope) {
return $parentScope;
}

/**
* There is no higher Node than FileWithoutNamespace
* There is no code that can live outside Namespace_, @see https://3v4l.org/har0k
*/
if ($parentNode instanceof FileWithoutNamespace || $parentNode instanceof Namespace_) {
return $this->scopeFactory->createFromFile($filePath);
}

/**
* Fallback when current Node is FileWithoutNamespace or Namespace_ already
*/
if ($node instanceof FileWithoutNamespace || $node instanceof Namespace_) {
return $this->scopeFactory->createFromFile($filePath);
}

/**
* Node and parent Node doesn't has Scope, and Node Start token pos is < 0,
Expand Down