Skip to content

Commit a48c334

Browse files
committed
Fix CleaningParserTest for generators and variadics
1 parent c650ed3 commit a48c334

File tree

6 files changed

+181
-5
lines changed

6 files changed

+181
-5
lines changed

src/Parser/CleaningVisitor.php

+44-3
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,70 @@
33
namespace PHPStan\Parser;
44

55
use PhpParser\Node;
6+
use PhpParser\NodeFinder;
67
use PhpParser\NodeVisitorAbstract;
8+
use PHPStan\Reflection\ParametersAcceptor;
79

810
class CleaningVisitor extends NodeVisitorAbstract
911
{
1012

13+
private NodeFinder $nodeFinder;
14+
15+
public function __construct()
16+
{
17+
$this->nodeFinder = new NodeFinder();
18+
}
19+
1120
public function enterNode(Node $node): ?Node
1221
{
1322
if ($node instanceof Node\Stmt\Function_) {
14-
$node->stmts = [];
23+
$node->stmts = $this->keepVariadicsAndYields($node->stmts);
1524
return $node;
1625
}
1726

1827
if ($node instanceof Node\Stmt\ClassMethod && $node->stmts !== null) {
19-
$node->stmts = [];
28+
$node->stmts = $this->keepVariadicsAndYields($node->stmts);
2029
return $node;
2130
}
2231

2332
if ($node instanceof Node\Expr\Closure) {
24-
$node->stmts = [];
33+
$node->stmts = $this->keepVariadicsAndYields($node->stmts);
2534
return $node;
2635
}
2736

2837
return null;
2938
}
3039

40+
/**
41+
* @param Node\Stmt[] $stmts
42+
* @return Node\Stmt[]
43+
*/
44+
private function keepVariadicsAndYields(array $stmts): array
45+
{
46+
$results = $this->nodeFinder->find($stmts, static function (Node $node): bool {
47+
if ($node instanceof Node\Expr\YieldFrom || $node instanceof Node\Expr\Yield_) {
48+
return true;
49+
}
50+
if ($node instanceof Node\Expr\FuncCall && $node->name instanceof Node\Name) {
51+
return in_array($node->name->toLowerString(), ParametersAcceptor::VARIADIC_FUNCTIONS, true);
52+
}
53+
54+
return false;
55+
});
56+
$newStmts = [];
57+
foreach ($results as $result) {
58+
if ($result instanceof Node\Expr\Yield_ || $result instanceof Node\Expr\YieldFrom) {
59+
$newStmts[] = new Node\Stmt\Expression($result);
60+
continue;
61+
}
62+
if (!$result instanceof Node\Expr\FuncCall) {
63+
continue;
64+
}
65+
66+
$newStmts[] = new Node\Stmt\Expression(new Node\Expr\FuncCall(new Node\Name\FullyQualified('func_get_args')));
67+
}
68+
69+
return $newStmts;
70+
}
71+
3172
}

src/Reflection/Php/PhpFunctionReflection.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ private function isVariadic(): bool
170170
if ($modifiedTime === false) {
171171
$modifiedTime = time();
172172
}
173-
$variableCacheKey = sprintf('%d-v2', $modifiedTime);
173+
$variableCacheKey = sprintf('%d-v3', $modifiedTime);
174174
$key = sprintf('variadic-function-%s-%s', $functionName, $fileName);
175175
$cachedResult = $this->cache->load($key, $variableCacheKey);
176176
if ($cachedResult === null) {

src/Reflection/Php/PhpMethodReflection.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ private function isVariadic(): bool
274274
$modifiedTime = time();
275275
}
276276
$key = sprintf('variadic-method-%s-%s-%s', $declaringClass->getName(), $this->reflection->getName(), $filename);
277-
$variableCacheKey = sprintf('%d-v3', $modifiedTime);
277+
$variableCacheKey = sprintf('%d-v4', $modifiedTime);
278278
$cachedResult = $this->cache->load($key, $variableCacheKey);
279279
if ($cachedResult === null || !is_bool($cachedResult)) {
280280
$nodes = $this->parser->parseFile($filename);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Parser;
4+
5+
use PhpParser\Lexer\Emulative;
6+
use PhpParser\NodeVisitor\NameResolver;
7+
use PhpParser\Parser\Php7;
8+
use PhpParser\PrettyPrinter\Standard;
9+
use PHPStan\File\FileReader;
10+
use PHPStan\Testing\PHPStanTestCase;
11+
12+
class CleaningParserTest extends PHPStanTestCase
13+
{
14+
15+
public function dataParse(): iterable
16+
{
17+
return [
18+
[
19+
__DIR__ . '/data/cleaning-1-before.php',
20+
__DIR__ . '/data/cleaning-1-after.php',
21+
],
22+
];
23+
}
24+
25+
/**
26+
* @dataProvider dataParse
27+
* @param string $beforeFile
28+
* @param string $afterFile
29+
*/
30+
public function testParse(
31+
string $beforeFile,
32+
string $afterFile
33+
): void
34+
{
35+
$parser = new CleaningParser(
36+
new SimpleParser(
37+
new Php7(new Emulative()),
38+
new NameResolver()
39+
)
40+
);
41+
$printer = new Standard();
42+
$ast = $parser->parseFile($beforeFile);
43+
$this->assertSame(FileReader::read($afterFile), "<?php\n" . $printer->prettyPrint($ast) . "\n");
44+
}
45+
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
namespace Test;
3+
4+
class Foo
5+
{
6+
public function doFoo()
7+
{
8+
}
9+
}
10+
interface Bar
11+
{
12+
public function doBar();
13+
}
14+
class Baz
15+
{
16+
public function someGenerator()
17+
{
18+
yield;
19+
}
20+
public function someGenerator2()
21+
{
22+
yield from [1, 2, 3];
23+
}
24+
public function someVariadics()
25+
{
26+
\func_get_args();
27+
}
28+
public function both()
29+
{
30+
yield;
31+
\func_get_args();
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
namespace Test;
4+
5+
class Foo
6+
{
7+
8+
public function doFoo()
9+
{
10+
test();
11+
}
12+
13+
}
14+
15+
interface Bar
16+
{
17+
18+
public function doBar();
19+
20+
}
21+
22+
class Baz
23+
{
24+
25+
public function someGenerator()
26+
{
27+
if (rand(0, 1)) {
28+
yield;
29+
}
30+
}
31+
32+
public function someGenerator2()
33+
{
34+
if (rand(0, 1)) {
35+
yield from [1, 2, 3];
36+
}
37+
}
38+
39+
public function someVariadics()
40+
{
41+
if (rand(0, 1)) {
42+
func_get_args();
43+
}
44+
}
45+
46+
public function both()
47+
{
48+
if (rand(0, 1)) {
49+
yield;
50+
}
51+
if (rand(0, 1)) {
52+
func_get_args();
53+
}
54+
}
55+
56+
}

0 commit comments

Comments
 (0)