Skip to content

Commit ace34fb

Browse files
committed
introduce FileNode to handle file-level changes; deprecate IncreaseDeclareStrictTypesRector
1 parent 3e0d7e1 commit ace34fb

File tree

16 files changed

+175
-61
lines changed

16 files changed

+175
-61
lines changed

rules/Naming/Naming/UseImportsResolver.php

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use PhpParser\Node\Stmt\Namespace_;
1111
use PhpParser\Node\Stmt\Use_;
1212
use Rector\Application\Provider\CurrentFileProvider;
13-
use Rector\PhpParser\Node\CustomNode\FileWithoutNamespace;
13+
use Rector\PhpParser\Node\FileNode;
1414
use Rector\ValueObject\Application\File;
1515

1616
final readonly class UseImportsResolver
@@ -57,7 +57,7 @@ public function resolvePrefix(Use_|GroupUse $use): string
5757
: '';
5858
}
5959

60-
private function resolveNamespace(): Namespace_|FileWithoutNamespace|null
60+
private function resolveNamespace(): Namespace_|FileNode|null
6161
{
6262
/** @var File|null $file */
6363
$file = $this->currentFileProvider->getFile();
@@ -66,22 +66,15 @@ private function resolveNamespace(): Namespace_|FileWithoutNamespace|null
6666
}
6767

6868
$newStmts = $file->getNewStmts();
69-
7069
if ($newStmts === []) {
7170
return null;
7271
}
7372

74-
/** @var Namespace_[]|FileWithoutNamespace[] $namespaces */
75-
$namespaces = array_filter(
76-
$newStmts,
77-
static fn (Stmt $stmt): bool => $stmt instanceof Namespace_ || $stmt instanceof FileWithoutNamespace
78-
);
79-
80-
// multiple namespaces is not supported
81-
if (count($namespaces) !== 1) {
82-
return null;
73+
if ($newStmts[0] instanceof FileNode) {
74+
$fileNode = $newStmts[0];
75+
return $fileNode->getNamespace();
8376
}
8477

85-
return current($namespaces);
78+
return null;
8679
}
8780
}

rules/TypeDeclaration/NodeAnalyzer/DeclareStrictTypeFinder.php

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,24 @@
44

55
namespace Rector\TypeDeclaration\NodeAnalyzer;
66

7-
use PhpParser\Node;
87
use PhpParser\Node\Stmt\Declare_;
8+
use Rector\PhpParser\Node\FileNode;
99

1010
final readonly class DeclareStrictTypeFinder
1111
{
12-
public function hasDeclareStrictTypes(Node $node): bool
12+
public function hasDeclareStrictTypes(FileNode $fileNode): bool
1313
{
14-
// when first node is Declare_, verify if there is strict_types definition already,
15-
// as multiple declare is allowed, with declare(strict_types=1) only allowed on very first node
16-
if (! $node instanceof Declare_) {
17-
return false;
18-
}
14+
// when first fileNode is Declare_, verify if there is strict_types definition already,
15+
// as multiple declare is allowed, with declare(strict_types=1) only allowed on very first fileNode
16+
foreach ($fileNode->stmts as $stmt) {
17+
if (! $stmt instanceof Declare_) {
18+
continue;
19+
}
1920

20-
foreach ($node->declares as $declare) {
21-
if ($declare->key->toString() === 'strict_types') {
22-
return true;
21+
foreach ($stmt->declares as $declare) {
22+
if ($declare->key->toString() === 'strict_types') {
23+
return true;
24+
}
2325
}
2426
}
2527

rules/TypeDeclaration/PHPStan/ObjectTypeSpecifier.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ public function narrowToFullyQualifiedOrAliasedObjectType(
8888
}
8989

9090
$currentTemplateTag = $templateTags[$className] ?? null;
91-
9291
if ($currentTemplateTag === null) {
9392
// invalid type
9493
return $this->resolveNamespacedNonExistingObjectType($namespaceName, $className, $withPreslash);

rules/TypeDeclaration/Rector/StmtsAwareInterface/DeclareStrictTypesRector.php

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@
77
use PhpParser\Node;
88
use PhpParser\Node\Stmt;
99
use PhpParser\Node\Stmt\Nop;
10-
use Rector\ChangesReporting\ValueObject\RectorWithLineChange;
1110
use Rector\Contract\Rector\HTMLAverseRectorInterface;
12-
use Rector\PhpParser\Enum\NodeGroup;
13-
use Rector\PhpParser\Node\CustomNode\FileWithoutNamespace;
11+
use Rector\PhpParser\Node\FileNode;
1412
use Rector\Rector\AbstractRector;
1513
use Rector\TypeDeclaration\NodeAnalyzer\DeclareStrictTypeFinder;
1614
use Rector\ValueObject\Application\File;
@@ -62,52 +60,54 @@ function someFunction(int $number)
6260
}
6361

6462
/**
65-
* @param Stmt[] $nodes
66-
* @return Stmt[]|null
63+
* @param FileNode $node
6764
*/
68-
public function beforeTraverse(array $nodes): ?array
65+
public function refactor(Node $node): ?FileNode
6966
{
70-
parent::beforeTraverse($nodes);
67+
// parent::beforeTraverse($nodes);
7168

72-
if ($this->shouldSkipNodes($nodes, $this->file)) {
69+
if ($this->shouldSkipNodes($node->stmts, $this->file)) {
7370
return null;
7471
}
7572

76-
/** @var Node $rootStmt */
77-
$rootStmt = current($nodes);
78-
if ($rootStmt instanceof FileWithoutNamespace) {
73+
// /** @var Node $rootStmt */
74+
// $rootStmt = current();
75+
if (! $node->isNamespaced()) {
7976
return null;
8077
}
8178

8279
// when first stmt is Declare_, verify if there is strict_types definition already,
8380
// as multiple declare is allowed, with declare(strict_types=1) only allowed on very first stmt
84-
if ($this->declareStrictTypeFinder->hasDeclareStrictTypes($rootStmt)) {
81+
if ($this->declareStrictTypeFinder->hasDeclareStrictTypes($node)) {
8582
return null;
8683
}
8784

88-
$rectorWithLineChange = new RectorWithLineChange(self::class, $rootStmt->getStartLine());
89-
$this->file->addRectorClassWithLine($rectorWithLineChange);
85+
// $rectorWithLineChange = new RectorWithLineChange(self::class, $rootStmt->getStartLine());
86+
// $this->file->addRectorClassWithLine($rectorWithLineChange);
87+
88+
$node->stmts = array_merge([$this->nodeFactory->createDeclaresStrictType(), new Nop()], $node->stmts);
9089

91-
return [$this->nodeFactory->createDeclaresStrictType(), new Nop(), ...$nodes];
90+
return $node;
91+
// return [$this->nodeFactory->createDeclaresStrictType(), new Nop(), ...$nodes];
9292
}
9393

9494
/**
9595
* @return array<class-string<Node>>
9696
*/
9797
public function getNodeTypes(): array
9898
{
99-
return NodeGroup::STMTS_AWARE;
100-
}
101-
102-
/**
103-
* @param StmtsAware $node
104-
*/
105-
public function refactor(Node $node): null
106-
{
107-
// workaround, as Rector now only hooks to specific nodes, not arrays
108-
// avoid traversing, as we already handled in beforeTraverse()
109-
return null;
99+
return [FileNode::class];
110100
}
101+
//
102+
// /**
103+
// * @param StmtsAware $node
104+
// */
105+
// public function refactor(Node $node): null
106+
// {
107+
// // workaround, as Rector now only hooks to specific nodes, not arrays
108+
// // avoid traversing, as we already handled in beforeTraverse()
109+
// return null;
110+
// }
111111

112112
public function provideMinPhpVersion(): int
113113
{
@@ -123,6 +123,7 @@ private function shouldSkipNodes(array $nodes, File $file): bool
123123
return true;
124124
}
125125

126+
// shebang files cannot have declare strict types
126127
if (str_starts_with($file->getFileContent(), '#!')) {
127128
return true;
128129
}

rules/TypeDeclaration/Rector/StmtsAwareInterface/IncreaseDeclareStrictTypesRector.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@
1414
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
1515

1616
/**
17+
<<<<<<< HEAD
1718
* @deprecated As keeps changing files randomly on every run. Not deterministic. Use more reliable @see \Rector\TypeDeclaration\Rector\StmtsAwareInterface\DeclareStrictTypesRector instead on specific paths.
19+
=======
20+
* @deprecated This rule is deprecated as behaves very randomly and keeps adding strict types on new run Cannot be automated.
21+
* Use @see DeclareStrictTypesRector on specific paths instead narrow control.
22+
>>>>>>> 595b685f3e (introduce FileNode to handle file-level changes; deprecate IncreaseDeclareStrictTypesRector)
1823
*/
1924
final class IncreaseDeclareStrictTypesRector extends AbstractRector implements ConfigurableRectorInterface, DeprecatedInterface
2025
{
@@ -62,7 +67,12 @@ public function getNodeTypes(): array
6267
public function refactor(Node $node): ?Node
6368
{
6469
throw new ShouldNotHappenException(sprintf(
70+
<<<<<<< HEAD
6571
'"%s" is deprecated as changes strict types randomly on each run.. Use "%s" Rector on specific paths instead.',
72+
=======
73+
'This rule is deprecated as behaves very randomly and keeps adding strict types on new run Cannot be automated.
74+
* Use %s on specific paths instead narrow control',
75+
>>>>>>> 595b685f3e (introduce FileNode to handle file-level changes; deprecate IncreaseDeclareStrictTypesRector)
6676
self::class,
6777
DeclareStrictTypesRector::class
6878
));
@@ -73,5 +83,10 @@ public function refactor(Node $node): ?Node
7383
*/
7484
public function configure(array $configuration): void
7585
{
86+
<<<<<<< HEAD
87+
=======
88+
Assert::keyExists($configuration, self::LIMIT);
89+
$this->limit = (int) $configuration[self::LIMIT];
90+
>>>>>>> 595b685f3e (introduce FileNode to handle file-level changes; deprecate IncreaseDeclareStrictTypesRector)
7691
}
7792
}

src/Application/FileProcessor.php

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Rector\Exception\ShouldNotHappenException;
1414
use Rector\FileSystem\FilePathHelper;
1515
use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator;
16+
use Rector\PhpParser\Node\FileNode;
1617
use Rector\PhpParser\NodeTraverser\RectorNodeTraverser;
1718
use Rector\PhpParser\Parser\ParserErrors;
1819
use Rector\PhpParser\Parser\RectorParser;
@@ -57,7 +58,6 @@ public function processFile(File $file, Configuration $configuration): FileProce
5758
do {
5859
$file->changeHasChanged(false);
5960

60-
// 1. change nodes with Rector Rules
6161
$newStmts = $this->rectorNodeTraverser->traverse($file->getNewStmts());
6262

6363
// 2. apply post rectors
@@ -140,9 +140,22 @@ private function parseFileAndDecorateNodes(File $file): ?SystemError
140140
private function printFile(File $file, Configuration $configuration, string $filePath): void
141141
{
142142
// only save to string first, no need to print to file when not needed
143+
$newStmts = $file->getNewStmts();
144+
145+
$oldStmts = $file->getOldStmts();
146+
147+
// unwrap FileNode stmts to allow printing
148+
if ($newStmts[0] instanceof FileNode) {
149+
$newStmts = $newStmts[0]->stmts;
150+
}
151+
152+
if ($oldStmts[0] instanceof FileNode) {
153+
$oldStmts = $oldStmts[0]->stmts;
154+
}
155+
143156
$newContent = $this->betterStandardPrinter->printFormatPreserving(
144-
$file->getNewStmts(),
145-
$file->getOldStmts(),
157+
$newStmts,
158+
$oldStmts,
146159
$file->getOldTokens()
147160
);
148161

@@ -168,9 +181,13 @@ private function parseFileNodes(File $file, bool $forNewestSupportedVersion = tr
168181
);
169182

170183
$oldStmts = $stmtsAndTokens->getStmts();
184+
185+
// wrap in FileNode to allow file-level rules
186+
$oldStmts = [new FileNode($oldStmts)];
171187
$oldTokens = $stmtsAndTokens->getTokens();
172188

173189
$newStmts = $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile($file->getFilePath(), $oldStmts);
190+
174191
$file->hydrateStmtsAndTokens($newStmts, $oldStmts, $oldTokens);
175192
}
176193
}

src/BetterPhpDocParser/PhpDocParser/ArrayItemClassNameDecorator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public function decorate(PhpDocNode $phpDocNode, PhpNode $phpNode): void
4949
}
5050

5151
$className = $this->resolveFullyQualifiedClass($splitScopeResolution[0], $phpNode);
52-
$node->setAttribute(PhpDocAttributeKey::RESOLVED_CLASS, $className);
52+
// $node->setAttribute(PhpDocAttributeKey::RESOLVED_CLASS, $className);
5353

5454
return $node;
5555
});

src/BetterPhpDocParser/PhpDocParser/ConstExprClassNameDecorator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public function decorate(PhpDocNode $phpDocNode, PhpNode $phpNode): void
4040
}
4141

4242
$className = $this->resolveFullyQualifiedClass($node, $phpNode);
43-
$node->setAttribute(PhpDocAttributeKey::RESOLVED_CLASS, $className);
43+
// $node->setAttribute(PhpDocAttributeKey::RESOLVED_CLASS, $className);
4444

4545
return $node;
4646
});

src/NodeTypeResolver/NodeScopeAndMetadataDecorator.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use PhpParser\NodeTraverser;
99
use PhpParser\NodeVisitor\CloningVisitor;
1010
use Rector\NodeTypeResolver\PHPStan\Scope\PHPStanNodeScopeResolver;
11-
use Rector\PhpParser\NodeTraverser\FileWithoutNamespaceNodeTraverser;
1211

1312
final readonly class NodeScopeAndMetadataDecorator
1413
{
@@ -17,7 +16,6 @@
1716
public function __construct(
1817
CloningVisitor $cloningVisitor,
1918
private PHPStanNodeScopeResolver $phpStanNodeScopeResolver,
20-
private FileWithoutNamespaceNodeTraverser $fileWithoutNamespaceNodeTraverser
2119
) {
2220
// needed for format preserving printing
2321
$this->nodeTraverser = new NodeTraverser($cloningVisitor);
@@ -29,9 +27,7 @@ public function __construct(
2927
*/
3028
public function decorateNodesFromFile(string $filePath, array $stmts): array
3129
{
32-
$stmts = $this->fileWithoutNamespaceNodeTraverser->traverse($stmts);
3330
$stmts = $this->phpStanNodeScopeResolver->processNodes($stmts, $filePath);
34-
3531
return $this->nodeTraverser->traverse($stmts);
3632
}
3733
}

src/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@
106106
use Rector\NodeAnalyzer\ClassAnalyzer;
107107
use Rector\NodeNameResolver\NodeNameResolver;
108108
use Rector\NodeTypeResolver\Node\AttributeKey;
109-
use Rector\PhpParser\Node\CustomNode\FileWithoutNamespace;
109+
use Rector\PhpParser\Node\FileNode;
110110
use Rector\Util\Reflection\PrivatesAccessor;
111111
use Webmozart\Assert\Assert;
112112

@@ -202,7 +202,8 @@ public function processNodes(
202202
$node->setAttribute(AttributeKey::SCOPE, $mutatingScope);
203203
}
204204

205-
if ($node instanceof FileWithoutNamespace) {
205+
// handle unwrapped stmts
206+
if ($node instanceof FileNode) {
206207
$this->nodeScopeResolverProcessNodes($node->stmts, $mutatingScope, $nodeCallback);
207208
return;
208209
}

0 commit comments

Comments
 (0)