Skip to content

Commit

Permalink
Use statement result of analysed anonymous class to inform about thro…
Browse files Browse the repository at this point in the history
…w points and impure points
  • Loading branch information
ondrejmirtes committed Apr 19, 2024
1 parent 00bad36 commit 70a75f6
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 12 deletions.
35 changes: 33 additions & 2 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -749,8 +749,15 @@ private function processStmtNode(
} elseif ($stmt instanceof Node\Stmt\Expression) {
$earlyTerminationExpr = $this->findEarlyTerminatingExpr($stmt->expr, $scope);
$hasAssign = false;
$result = $this->processExprNode($stmt, $stmt->expr, $scope, static function (Node $node, Scope $scope) use ($nodeCallback, &$hasAssign): void {
$currentScope = $scope;
$result = $this->processExprNode($stmt, $stmt->expr, $scope, static function (Node $node, Scope $scope) use ($nodeCallback, $currentScope, &$hasAssign): void {
$nodeCallback($node, $scope);
if ($scope->getAnonymousFunctionReflection() !== $currentScope->getAnonymousFunctionReflection()) {
return;
}
if ($scope->getFunction() !== $currentScope->getFunction()) {
return;
}
if (!$node instanceof VariableAssignNode && !$node instanceof PropertyAssignNode) {
return;
}
Expand Down Expand Up @@ -3152,7 +3159,31 @@ static function (): void {

} else {
$classReflection = $this->reflectionProvider->getAnonymousClassReflection($expr->class, $scope); // populates $expr->class->name
$this->processStmtNode($expr->class, $scope, $nodeCallback, StatementContext::createTopLevel());
$constructorResult = null;
$this->processStmtNode($expr->class, $scope, static function (Node $node, Scope $scope) use ($nodeCallback, $classReflection, &$constructorResult): void {
$nodeCallback($node, $scope);
if (!$node instanceof MethodReturnStatementsNode) {
return;
}
if ($constructorResult !== null) {
return;
}
$currentClassReflection = $node->getClassReflection();
if ($currentClassReflection->getName() !== $classReflection->getName()) {
return;
}
if (!$currentClassReflection->hasConstructor()) {
return;
}
if ($currentClassReflection->getConstructor()->getName() !== $node->getMethodReflection()->getName()) {
return;
}
$constructorResult = $node;
}, StatementContext::createTopLevel());
if ($constructorResult !== null) {
$throwPoints = array_merge($throwPoints, $constructorResult->getStatementResult()->getThrowPoints());
$impurePoints = array_merge($impurePoints, $constructorResult->getImpurePoints());
}
if ($classReflection->hasConstructor()) {
$constructorReflection = $classReflection->getConstructor();
$parametersAcceptor = ParametersAcceptorSelector::selectFromArgs(
Expand Down
6 changes: 5 additions & 1 deletion src/Rules/DeadCode/BetterNoopRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,14 @@ public function processNode(Node $node, Scope $scope): array
}
}

if ($expr instanceof Node\Expr\New_ && $expr->class instanceof Node\Name) {
// handled by CallToConstructorStatementWithoutSideEffectsRule
return [];
}

if (
$expr instanceof Node\Expr\NullsafeMethodCall
|| $expr instanceof Node\Expr\MethodCall
|| $expr instanceof Node\Expr\New_
|| $expr instanceof Node\Expr\StaticCall
) {
// handled by *WithoutSideEffectsRule rules
Expand Down
8 changes: 3 additions & 5 deletions tests/PHPStan/Analyser/data/AnonymousClassesWithComments.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php

// Test comment
new class () {
$a = new class () {

public function doFoo(): void
{
Expand All @@ -10,8 +10,7 @@ public function doFoo(): void

};

/* Test comment */
new class () {
$a = /* Test comment */ new class () {

public function doFoo(): void
{
Expand All @@ -20,8 +19,7 @@ public function doFoo(): void

};

/** Test comment */
new class () {
$a = /** Test comment */ new class () {

public function doFoo(): void
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public function __construct(int $i, int $j)
}

function () {
new class (1, 2) extends Foo
$a = new class (1, 2) extends Foo
{

};
Expand All @@ -30,7 +30,7 @@ final public function __construct(int $i, int $j)
}

function () {
new class (1, 2) extends Bar
$a = new class (1, 2) extends Bar
{

};
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/data/bug-6442.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class B extends A
use T;
}

new class() extends B
$a = new class() extends B
{
use T;
};
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/traits/AnonymousClassUsingTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace AnonymousTraitClass;

new class implements FooInterface {
$a = new class implements FooInterface {

use TraitWithTypeSpecification;

Expand Down
8 changes: 8 additions & 0 deletions tests/PHPStan/Rules/DeadCode/BetterNoopRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,14 @@ public function testRuleImpurePoints(): void
'Expression "$b()" on a separate line does not do anything.',
59,
],
[
'Expression "new class…" on a separate line does not do anything.',
98,
],
[
'Expression "new class…" on a separate line does not do anything.',
104,
],
]);
}

Expand Down
31 changes: 31 additions & 0 deletions tests/PHPStan/Rules/DeadCode/data/noop-impure-points.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,35 @@ public function doFunctionWithByRef(bool $b, array $a): void
$func($a, 1);
}

public function anonymousClassWithSideEffect(): void
{
new class () {
public function __construct()
{
echo '1';
}
};
}

public function anonymousClassWithoutConstructor(): void
{
new class () {
};
}

public function anonymousClassWithPureConstructor(): void
{
new class () {

/** @var int */
private $i;

public function __construct()
{
$this->i = 1;
}

};
}

}

0 comments on commit 70a75f6

Please sign in to comment.