Skip to content

Commit 04d83e1

Browse files
committed
Use a node visitor to flag the deprecated interpolated strings
1 parent f059229 commit 04d83e1

15 files changed

+91
-139
lines changed

UPGRADING.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,5 +336,3 @@ Remove `Type::isSuperTypeOfWithReason()`, `Type:isSuperTypeOf()` return type cha
336336
* `ClassPropertyNode::getNativeType()` return type changed from AST node to `Type|null`
337337
* Class `PHPStan\Node\ClassMethod` (accessible from `ClassMethodsNode`) is no longer an AST node
338338
* Call `PHPStan\Node\ClassMethod::getNode()` to access the original AST node
339-
* Interface `PHPStan\Analyser\Scope` introduces a new `getTokens()` method which returns the tokens for the current file.
340-
* Interface `PHPStan\Parser\Parser` introduces a new `getTokens()` method which returns the tokens for the parsed file.

src/Analyser/FileAnalyser.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ public function analyseFile(
9999
try {
100100
$this->collectErrors($analysedFiles);
101101
$parserNodes = $this->parser->parseFile($file);
102-
$parserTokens = $this->parser->getTokens();
103102
$processedFiles[] = $file;
104103

105104
$nodeCallback = new FileAnalyserCallback(
@@ -115,7 +114,7 @@ public function analyseFile(
115114
$this->ruleErrorTransformer,
116115
$processedFiles,
117116
);
118-
$scope = $this->scopeFactory->create(ScopeContext::create($file, $parserTokens), $nodeCallback);
117+
$scope = $this->scopeFactory->create(ScopeContext::create($file), $nodeCallback);
119118
$nodeCallback(new FileNode($parserNodes), $scope);
120119
$this->nodeScopeResolver->processNodes(
121120
$parserNodes,

src/Analyser/MutatingScope.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -300,12 +300,6 @@ public function getFile(): string
300300
return $this->context->getFile();
301301
}
302302

303-
/** @api */
304-
public function getTokens(): array
305-
{
306-
return $this->context->getTokens();
307-
}
308-
309303
/** @api */
310304
public function getFileDescription(): string
311305
{

src/Analyser/Scope.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
use PhpParser\Node\Expr;
77
use PhpParser\Node\Name;
88
use PhpParser\Node\Param;
9-
use PhpParser\Token;
109
use PHPStan\Php\PhpVersions;
1110
use PHPStan\Reflection\ClassConstantReflection;
1211
use PHPStan\Reflection\ClassMemberAccessAnswerer;
@@ -66,11 +65,6 @@ interface Scope extends ClassMemberAccessAnswerer, NamespaceAnswerer
6665
*/
6766
public function getFile(): string;
6867

69-
/**
70-
* @return Token[]
71-
*/
72-
public function getTokens(): array;
73-
7468
/**
7569
* For traits, returns the trait file path with the using class context,
7670
* e.g. "TraitFile.php (in context of class MyClass)".

src/Analyser/ScopeContext.php

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,44 +2,29 @@
22

33
namespace PHPStan\Analyser;
44

5-
use PhpParser\Token;
65
use PHPStan\Reflection\ClassReflection;
76
use PHPStan\ShouldNotHappenException;
87

98
final class ScopeContext
109
{
1110

12-
/**
13-
* @param string $file
14-
* @param \PHPStan\Reflection\ClassReflection|null $classReflection
15-
* @param \PHPStan\Reflection\ClassReflection|null $traitReflection
16-
* @param Token[] $tokens
17-
*/
1811
private function __construct(
1912
private string $file,
2013
private ?ClassReflection $classReflection,
2114
private ?ClassReflection $traitReflection,
22-
private array $tokens,
2315
)
2416
{
2517
}
2618

27-
/**
28-
* @param string $file
29-
* @param Token[] $tokens
30-
*
31-
* @return self
32-
*
33-
* @api
34-
*/
35-
public static function create(string $file, array $tokens = []): self
19+
/** @api */
20+
public static function create(string $file): self
3621
{
37-
return new self($file, classReflection: null, traitReflection: null, tokens: $tokens);
22+
return new self($file, classReflection: null, traitReflection: null);
3823
}
3924

4025
public function beginFile(): self
4126
{
42-
return new self($this->file, classReflection: null, traitReflection: null, tokens: $this->tokens);
27+
return new self($this->file, classReflection: null, traitReflection: null);
4328
}
4429

4530
public function enterClass(ClassReflection $classReflection): self
@@ -50,7 +35,7 @@ public function enterClass(ClassReflection $classReflection): self
5035
if ($classReflection->isTrait()) {
5136
throw new ShouldNotHappenException();
5237
}
53-
return new self($this->file, $classReflection, traitReflection: null, tokens: $this->tokens);
38+
return new self($this->file, $classReflection, traitReflection: null);
5439
}
5540

5641
public function enterTrait(ClassReflection $traitReflection): self
@@ -62,7 +47,7 @@ public function enterTrait(ClassReflection $traitReflection): self
6247
throw new ShouldNotHappenException();
6348
}
6449

65-
return new self($this->file, $this->classReflection, $traitReflection, $this->tokens);
50+
return new self($this->file, $this->classReflection, $traitReflection);
6651
}
6752

6853
public function equals(self $otherContext): bool
@@ -105,12 +90,4 @@ public function getTraitReflection(): ?ClassReflection
10590
return $this->traitReflection;
10691
}
10792

108-
/**
109-
* @return Token[]
110-
*/
111-
public function getTokens(): array
112-
{
113-
return $this->tokens;
114-
}
115-
11693
}

src/Parser/CachedParser.php

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace PHPStan\Parser;
44

55
use PhpParser\Node;
6-
use PhpParser\Token;
76
use PHPStan\File\FileReader;
87
use function array_slice;
98

@@ -13,11 +12,6 @@ final class CachedParser implements Parser
1312
/** @var array<string, Node\Stmt[]>*/
1413
private array $cachedNodesByString = [];
1514

16-
/** @var array<string, Token[]>*/
17-
private array $cachedTokensByString = [];
18-
19-
private ?string $lastParsedSourceCode = null;
20-
2115
private int $cachedNodesByStringCount = 0;
2216

2317
/** @var array<string, true> */
@@ -42,24 +36,17 @@ public function parseFile(string $file): array
4236
1,
4337
preserve_keys: true,
4438
);
45-
$this->cachedTokensByString = array_slice(
46-
$this->cachedTokensByString,
47-
1,
48-
preserve_keys: true,
49-
);
5039

5140
--$this->cachedNodesByStringCount;
5241
}
5342

5443
$sourceCode = FileReader::read($file);
5544
if (!isset($this->cachedNodesByString[$sourceCode]) || isset($this->parsedByString[$sourceCode])) {
5645
$this->cachedNodesByString[$sourceCode] = $this->originalParser->parseFile($file);
57-
$this->cachedTokensByString[$sourceCode] = $this->originalParser->getTokens();
5846
$this->cachedNodesByStringCount++;
5947
unset($this->parsedByString[$sourceCode]);
6048
}
6149

62-
$this->lastParsedSourceCode = $sourceCode;
6350
return $this->cachedNodesByString[$sourceCode];
6451
}
6552

@@ -74,34 +61,19 @@ public function parseString(string $sourceCode): array
7461
1,
7562
preserve_keys: true,
7663
);
77-
$this->cachedTokensByString = array_slice(
78-
$this->cachedTokensByString,
79-
1,
80-
preserve_keys: true,
81-
);
8264

8365
--$this->cachedNodesByStringCount;
8466
}
8567

8668
if (!isset($this->cachedNodesByString[$sourceCode])) {
8769
$this->cachedNodesByString[$sourceCode] = $this->originalParser->parseString($sourceCode);
88-
$this->cachedTokensByString[$sourceCode] = $this->originalParser->getTokens();
8970
$this->cachedNodesByStringCount++;
9071
$this->parsedByString[$sourceCode] = true;
9172
}
9273

93-
$this->lastParsedSourceCode = $sourceCode;
9474
return $this->cachedNodesByString[$sourceCode];
9575
}
9676

97-
public function getTokens(): array
98-
{
99-
if (isset($this->lastParsedSourceCode, $this->cachedTokensByString[$this->lastParsedSourceCode])) {
100-
return $this->cachedTokensByString[$this->lastParsedSourceCode];
101-
}
102-
return [];
103-
}
104-
10577
public function getCachedNodesByStringCount(): int
10678
{
10779
return $this->cachedNodesByStringCount;

src/Parser/CleaningParser.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,6 @@ public function parseString(string $sourceCode): array
2828
return $this->clean($this->wrappedParser->parseString($sourceCode));
2929
}
3030

31-
public function getTokens(): array
32-
{
33-
return $this->wrappedParser->getTokens();
34-
}
35-
3631
/**
3732
* @param Stmt[] $ast
3833
* @return Stmt[]
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Parser;
4+
5+
use Override;
6+
use PhpParser\Node;
7+
use PhpParser\Node\Expr\ArrayDimFetch;
8+
use PhpParser\Node\Expr\Variable;
9+
use PhpParser\Node\Scalar\InterpolatedString;
10+
use PhpParser\NodeVisitorAbstract;
11+
use PhpParser\Token;
12+
use PHPStan\DependencyInjection\AutowiredService;
13+
14+
#[AutowiredService]
15+
final class DeprecatedInterpolatedStringVisitor extends NodeVisitorAbstract implements TokenAwareVisitor
16+
{
17+
public const ATTRIBUTE_NAME = 'isDeprecatedInterpolatedString';
18+
19+
/**
20+
* @var Token[]
21+
*/
22+
protected array $tokens = [];
23+
24+
#[Override]
25+
public function setTokens(array $tokens): void
26+
{
27+
$this->tokens = $tokens;
28+
}
29+
30+
#[Override]
31+
public function enterNode(Node $node): ?Node
32+
{
33+
if (!$node instanceof InterpolatedString) {
34+
return null;
35+
}
36+
37+
foreach ($node->parts as $part) {
38+
if (!$part instanceof Variable && !($part instanceof ArrayDimFetch && $part->var instanceof Variable)) {
39+
continue;
40+
}
41+
$startTokenPos = $part->getStartTokenPos();
42+
if (!isset($this->tokens[$startTokenPos])) {
43+
continue;
44+
}
45+
$startToken = (string) $this->tokens[$startTokenPos];
46+
if ($startToken !== '${') {
47+
continue;
48+
}
49+
50+
$node->setAttribute(self::ATTRIBUTE_NAME, true);
51+
}
52+
53+
return null;
54+
}
55+
56+
}

src/Parser/Parser.php

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace PHPStan\Parser;
44

55
use PhpParser\Node;
6-
use PhpParser\Token;
76

87
/** @api */
98
interface Parser
@@ -22,11 +21,4 @@ public function parseFile(string $file): array;
2221
*/
2322
public function parseString(string $sourceCode): array;
2423

25-
/**
26-
* Return tokens for the last parse.
27-
*
28-
* @return Token[]
29-
*/
30-
public function getTokens(): array;
31-
3224
}

src/Parser/PathRoutingParser.php

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ final class PathRoutingParser implements Parser
1818

1919
private ?string $singleReflectionFile;
2020

21-
private ?Parser $usedParser = null;
22-
2321
/** @var array<string, true> filePath(string) => bool(true) */
2422
private array $analysedFiles = [];
2523

@@ -46,11 +44,9 @@ public function parseFile(string $file): array
4644
{
4745
$normalizedPath = $this->fileHelper->normalizePath($file, '/');
4846
if (str_contains($normalizedPath, 'vendor/jetbrains/phpstorm-stubs')) {
49-
$this->usedParser = $this->php8Parser;
5047
return $this->php8Parser->parseFile($file);
5148
}
5249
if (str_contains($normalizedPath, 'vendor/phpstan/php-8-stubs/stubs')) {
53-
$this->usedParser = $this->php8Parser;
5450
return $this->php8Parser->parseFile($file);
5551
}
5652

@@ -68,36 +64,21 @@ public function parseFile(string $file): array
6864
if ($realFilePath !== false) {
6965
$normalizedRealFilePath = $this->fileHelper->normalizePath($realFilePath);
7066
if (isset($this->analysedFiles[$normalizedRealFilePath])) {
71-
$this->usedParser = $this->currentPhpVersionRichParser;
7267
return $this->currentPhpVersionRichParser->parseFile($file);
7368
}
7469
}
7570
break;
7671
}
7772

78-
$this->usedParser = $this->currentPhpVersionSimpleParser;
7973
return $this->currentPhpVersionSimpleParser->parseFile($file);
8074
}
8175

82-
$this->usedParser = $this->currentPhpVersionRichParser;
8376
return $this->currentPhpVersionRichParser->parseFile($file);
8477
}
8578

8679
public function parseString(string $sourceCode): array
8780
{
88-
$this->usedParser = $this->currentPhpVersionSimpleParser;
8981
return $this->currentPhpVersionSimpleParser->parseString($sourceCode);
9082
}
9183

92-
/**
93-
* {@inheritdoc}
94-
*/
95-
public function getTokens(): array
96-
{
97-
if ($this->usedParser !== null) {
98-
return $this->usedParser->getTokens();
99-
}
100-
return [];
101-
}
102-
10384
}

0 commit comments

Comments
 (0)