Skip to content

Commit 9f59673

Browse files
committed
add rule and enable it
1 parent 01ef160 commit 9f59673

8 files changed

Lines changed: 181 additions & 17 deletions

File tree

.github/workflows/code_analysis.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ jobs:
2121
name: 'Run with Space in Directory'
2222
run: bin/rector process tests-paths/path/with\ space/SomeFile.php --clear-cache
2323

24-
-
25-
name: 'Preload php-parser Order'
26-
run: php preload.php
24+
# -
25+
# name: 'Preload php-parser Order'
26+
# run: php preload.php
2727

2828
-
2929
name: 'PHPStan'
@@ -42,7 +42,7 @@ jobs:
4242
-
4343
name: 'Active Classes'
4444
run: |
45-
vendor/bin/class-leak check bin config src rules utils --skip-suffix "Rector" --skip-type="Rector\\Utils\\Compiler\\Unprefixer" --skip-type="Rector\\NodeCollector\\BinaryOpConditionsCollector" --skip-type="Rector\\Set\\Contract\\SetListInterface"
45+
vendor/bin/class-leak check bin config src rules utils --skip-suffix "Rector" --skip-type="Rector\\Utils\\Compiler\\Unprefixer" --skip-type="Rector\\NodeCollector\\BinaryOpConditionsCollector" --skip-type="Rector\\Set\\Contract\\SetListInterface" --skip-type="Rector\\Contract\\PhpParser\\Node\\StmtsAwareInterface"
4646
4747
-
4848
name: 'Compatible PHPStan versions'

build/build-preload.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -362,11 +362,6 @@ private function findPhpParserFilesAndSortThem(string $vendorDir): array
362362
}
363363

364364
return array_values($fileInfos);
365-
366-
// $ContainsStmts = new SplFileInfo(__DIR__ . '/../src/Contract/PhpParser/Node/ContainsStmts.php');
367-
// array_splice($fileInfos, 1, 0, [$ContainsStmts]);
368-
369-
return $fileInfos;
370365
}
371366

372367
/**

phpstan.neon

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ parameters:
332332

333333
-
334334
identifier: symplify.seeAnnotationToTest
335-
path: utils/PHPStan/Rule/PreferDirectIsNameRule.php
335+
path: utils/
336336

337337
-
338338
identifier: arrayValues.list
@@ -356,3 +356,7 @@ parameters:
356356
-
357357
identifier: offsetAccess.invalidOffset
358358
path: src/CustomRules/SimpleNodeDumper.php
359+
360+
-
361+
message: '#Method Rector\\Utils\\Rector\\MakeUseOfContaintsStmtsRector\:\:refactor\(\) should return 4\|PhpParser\\Node\\Expr\\BinaryOp\\Identical\|PhpParser\\Node\\Expr\\MethodCall\|null but returns int\|null#'
362+
path: utils/Rector/MakeUseOfContaintsStmtsRector.php

preload.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ function isPHPStanTestPreloaded(): bool
2626
}
2727

2828
require_once __DIR__ . '/vendor/nikic/php-parser/lib/PhpParser/Node.php';
29-
//require_once __DIR__ . '/src/Contract/PhpParser/Node/ContainsStmts.php';
29+
require_once __DIR__ . '/vendor/nikic/php-parser/lib/PhpParser/Node/ContainsStmts.php';
3030
require_once __DIR__ . '/vendor/nikic/php-parser/lib/PhpParser/NodeAbstract.php';
3131
require_once __DIR__ . '/vendor/nikic/php-parser/lib/PhpParser/Node/Expr.php';
3232
require_once __DIR__ . '/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor.php';

rector.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Rector\Config\RectorConfig;
77
use Rector\DeadCode\Rector\ConstFetch\RemovePhpVersionIdCheckRector;
88
use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector;
9+
use Rector\Utils\Rector\MakeUseOfContaintsStmtsRector;
910

1011
return RectorConfig::configure()
1112
->withPreparedSets(
@@ -35,6 +36,7 @@
3536
__DIR__ . '/config',
3637
__DIR__ . '/build/build-preload.php',
3738
])
39+
->withRules([MakeUseOfContaintsStmtsRector::class])
3840
->withRootFiles()
3941
->withImportNames(removeUnusedImports: true)
4042
->withSkip([

src/Contract/PhpParser/Node/StmtsAwareInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010
/**
1111
* @property Stmt[]|null $stmts
1212
*/
13-
interface ContainsStmts extends Node
13+
interface StmtsAwareInterface extends Node\ContainsStmts
1414
{
1515
}

tests/BetterPhpDocParser/PhpDoc/ArrayItemNode/ArrayItemNodeTest.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,7 @@ public function testUpdateNestedClassAnnotation(): void
5555
continue;
5656
}
5757

58-
if ($newStmt->stmts === null) {
59-
continue;
60-
}
61-
62-
foreach ($newStmt->stmts as $stmt) {
58+
foreach ($newStmt->getStmts() as $stmt) {
6359
if (! $stmt instanceof Class_) {
6460
continue;
6561
}
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Utils\Rector;
6+
7+
// e.g. to move PhpDocInfo to the particular rule itself
8+
use PhpParser\Node;
9+
use PhpParser\Node\ContainsStmts;
10+
use PhpParser\Node\Expr;
11+
use PhpParser\Node\Expr\Array_;
12+
use PhpParser\Node\Expr\ArrayDimFetch;
13+
use PhpParser\Node\Expr\Assign;
14+
use PhpParser\Node\Expr\BinaryOp\Identical;
15+
use PhpParser\Node\Expr\MethodCall;
16+
use PhpParser\Node\Expr\PropertyFetch;
17+
use PhpParser\Node\Stmt\ClassMethod;
18+
use PhpParser\Node\Stmt\Foreach_;
19+
use PhpParser\Node\Stmt\Function_;
20+
use PhpParser\NodeVisitor;
21+
use PHPStan\Type\ObjectType;
22+
use Rector\PhpParser\Node\Value\ValueResolver;
23+
use Rector\Rector\AbstractRector;
24+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
25+
26+
final class MakeUseOfContaintsStmtsRector extends AbstractRector
27+
{
28+
public function __construct(
29+
private readonly ValueResolver $valueResolver
30+
) {
31+
}
32+
33+
public function getRuleDefinition(): RuleDefinition
34+
{
35+
// @see https://github.com/nikic/PHP-Parser/pull/1113
36+
return new RuleDefinition('Move $node->stmts to $node->getStmts() for ContaintsStmts', []);
37+
}
38+
39+
public function getNodeTypes(): array
40+
{
41+
return [
42+
Identical::class,
43+
PropertyFetch::class,
44+
Function_::class,
45+
Assign::class,
46+
Foreach_::class,
47+
ClassMethod::class,
48+
];
49+
}
50+
51+
/**
52+
* @param PropertyFetch|Identical|Function_|Assign|Foreach_|ClassMethod $node
53+
* @return MethodCall|Identical|null|NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN
54+
*/
55+
public function refactor(Node $node): MethodCall|Identical|null|int
56+
{
57+
if ($node instanceof ClassMethod) {
58+
if ($this->isName($node, 'getStmts')) {
59+
// skip getter
60+
return NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
61+
}
62+
63+
return null;
64+
}
65+
66+
if ($node instanceof Foreach_) {
67+
return $this->refactorForeach($node);
68+
}
69+
70+
if ($node instanceof Function_) {
71+
return $this->refactorFunction($node);
72+
}
73+
74+
if ($node instanceof Assign) {
75+
return $this->refactorAssign($node);
76+
}
77+
78+
if ($node instanceof Identical) {
79+
return $this->refactorIdentical($node);
80+
}
81+
82+
if (! $this->isName($node->name, 'stmts')) {
83+
return null;
84+
}
85+
86+
if (! $this->isObjectType($node->var, new ObjectType(ContainsStmts::class))) {
87+
return null;
88+
}
89+
90+
return new MethodCall($node->var, 'getStmts');
91+
}
92+
93+
private function isStmtsPropertyFetch(Expr $expr): bool
94+
{
95+
if (! $expr instanceof PropertyFetch) {
96+
return false;
97+
}
98+
99+
return $this->isName($expr->name, 'stmts');
100+
}
101+
102+
private function refactorIdentical(Identical $identical): ?Identical
103+
{
104+
if (! $this->valueResolver->isNull($identical->right)) {
105+
return null;
106+
}
107+
108+
if ($this->isStmtsPropertyFetch($identical->left)) {
109+
/** @var PropertyFetch $propertyFetch */
110+
$propertyFetch = $identical->left;
111+
112+
$identical->left = new MethodCall($propertyFetch->var, 'getStmts');
113+
$identical->right = new Array_([]);
114+
115+
return $identical;
116+
}
117+
118+
return null;
119+
}
120+
121+
/**
122+
* @return null|NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN
123+
*/
124+
private function refactorForeach(Foreach_ $foreach): ?int
125+
{
126+
if (! $this->isStmtsPropertyFetch($foreach->expr)) {
127+
return null;
128+
}
129+
// skip $node->stmts in foreach with key, as key is probably used on the $node->stmts
130+
if ($foreach->keyVar instanceof Expr) {
131+
return NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
132+
}
133+
134+
return null;
135+
}
136+
137+
private function refactorFunction(Function_ $function): ?int
138+
{
139+
// keep any unset($node->stmts[x])) calls
140+
if ($this->isName($function->name, 'unset')) {
141+
return NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
142+
}
143+
144+
return null;
145+
}
146+
147+
/**
148+
* @return null|NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN
149+
*/
150+
private function refactorAssign(Assign $assign): ?int
151+
{
152+
if ($assign->var instanceof ArrayDimFetch) {
153+
$arrayDimFetch = $assign->var;
154+
if ($this->isStmtsPropertyFetch($arrayDimFetch->var)) {
155+
// keep $node->stmts[x] = ...
156+
return NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
157+
}
158+
}
159+
160+
if (! $this->isStmtsPropertyFetch($assign->var)) {
161+
return null;
162+
}
163+
164+
// keep assign to $node->stmts property
165+
return NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
166+
}
167+
}

0 commit comments

Comments
 (0)