Skip to content

Commit df39688

Browse files
authored
Add function PHPStan\dumpPhpDocType()
1 parent ce3ffbd commit df39688

File tree

6 files changed

+221
-0
lines changed

6 files changed

+221
-0
lines changed

conf/config.neon

+4
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ extensions:
282282

283283
rules:
284284
- PHPStan\Rules\Debug\DebugScopeRule
285+
- PHPStan\Rules\Debug\DumpPhpDocTypeRule
285286
- PHPStan\Rules\Debug\DumpTypeRule
286287
- PHPStan\Rules\Debug\FileAssertRule
287288

@@ -433,6 +434,9 @@ services:
433434
usedAttributes:
434435
lines: %featureToggles.phpDocParserIncludeLines%
435436

437+
-
438+
class: PHPStan\PhpDocParser\Printer\Printer
439+
436440
-
437441
class: PHPStan\PhpDoc\ConstExprParserFactory
438442
arguments:
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Debug;
4+
5+
use PhpParser\Node;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\PhpDocParser\Printer\Printer;
8+
use PHPStan\Reflection\ReflectionProvider;
9+
use PHPStan\Rules\Rule;
10+
use PHPStan\Rules\RuleErrorBuilder;
11+
use function count;
12+
use function sprintf;
13+
use function strtolower;
14+
15+
/**
16+
* @implements Rule<Node\Expr\FuncCall>
17+
*/
18+
final class DumpPhpDocTypeRule implements Rule
19+
{
20+
21+
public function __construct(private ReflectionProvider $reflectionProvider, private Printer $printer)
22+
{
23+
}
24+
25+
public function getNodeType(): string
26+
{
27+
return Node\Expr\FuncCall::class;
28+
}
29+
30+
public function processNode(Node $node, Scope $scope): array
31+
{
32+
if (!$node->name instanceof Node\Name) {
33+
return [];
34+
}
35+
36+
$functionName = $this->reflectionProvider->resolveFunctionName($node->name, $scope);
37+
if ($functionName === null) {
38+
return [];
39+
}
40+
41+
if (strtolower($functionName) !== 'phpstan\dumpphpdoctype') {
42+
return [];
43+
}
44+
45+
if (count($node->getArgs()) === 0) {
46+
return [];
47+
}
48+
49+
return [
50+
RuleErrorBuilder::message(
51+
sprintf(
52+
'Dumped type: %s',
53+
$this->printer->print($scope->getType($node->getArgs()[0]->value)->toPhpDocNode()),
54+
),
55+
)->nonIgnorable()->identifier('phpstan.dumpPhpDocType')->build(),
56+
];
57+
}
58+
59+
}

src/Rules/Functions/CallToFunctionStatementWithoutSideEffectsRule.php

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ final class CallToFunctionStatementWithoutSideEffectsRule implements Rule
2929

3030
public const PHPSTAN_TESTING_FUNCTIONS = [
3131
'PHPStan\\dumpType',
32+
'PHPStan\\dumpPhpDocType',
3233
'PHPStan\\debugScope',
3334
'PHPStan\\Testing\\assertType',
3435
'PHPStan\\Testing\\assertNativeType',

src/dumpType.php

+12
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,15 @@ function dumpType($value) // phpcs:ignore Squiz.Functions.GlobalFunction.Found
1313
{
1414
return null;
1515
}
16+
17+
/**
18+
* @phpstan-pure
19+
* @param mixed $value
20+
* @return mixed
21+
*
22+
* @throws void
23+
*/
24+
function dumpPhpDocType($value) // phpcs:ignore Squiz.Functions.GlobalFunction.Found
25+
{
26+
return null;
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Debug;
4+
5+
use PHPStan\PhpDocParser\Printer\Printer;
6+
use PHPStan\Rules\Rule;
7+
use PHPStan\Testing\RuleTestCase;
8+
9+
/**
10+
* @extends RuleTestCase<DumpPhpDocTypeRule>
11+
*/
12+
class DumpPhpDocTypeRuleTest extends RuleTestCase
13+
{
14+
15+
protected function getRule(): Rule
16+
{
17+
return new DumpPhpDocTypeRule($this->createReflectionProvider(), new Printer());
18+
}
19+
20+
public function testRuleSymbols(): void
21+
{
22+
$this->analyse([__DIR__ . '/data/dump-phpdoc-type.php'], [
23+
[
24+
"Dumped type: array{'': ''}",
25+
5,
26+
],
27+
[
28+
"Dumped type: array{'\0': 'NUL', NUL: '\0'}",
29+
6,
30+
],
31+
[
32+
"Dumped type: array{'\001': 'SOH', SOH: '\001'}",
33+
7,
34+
],
35+
[
36+
"Dumped type: array{'\t': 'HT', HT: '\t'}",
37+
8,
38+
],
39+
[
40+
"Dumped type: array{' ': 'SP', SP: ' '}",
41+
11,
42+
],
43+
[
44+
"Dumped type: array{'foo ': 'ends with SP', ' foo': 'starts with SP', ' foo ': 'surrounded by SP', foo: 'no SP'}",
45+
12,
46+
],
47+
[
48+
"Dumped type: array{'foo?': 'foo?'}",
49+
15,
50+
],
51+
[
52+
"Dumped type: array{shallwedance: 'yes'}",
53+
16,
54+
],
55+
[
56+
"Dumped type: array{'shallwedance?': 'yes'}",
57+
17,
58+
],
59+
[
60+
"Dumped type: array{'Shall we dance': 'yes'}",
61+
18,
62+
],
63+
[
64+
"Dumped type: array{'Shall we dance?': 'yes'}",
65+
19,
66+
],
67+
[
68+
"Dumped type: array{shall_we_dance: 'yes'}",
69+
20,
70+
],
71+
[
72+
"Dumped type: array{'shall_we_dance?': 'yes'}",
73+
21,
74+
],
75+
[
76+
"Dumped type: array{shall-we-dance: 'yes'}",
77+
22,
78+
],
79+
[
80+
"Dumped type: array{'shall-we-dance?': 'yes'}",
81+
23,
82+
],
83+
[
84+
"Dumped type: array{'Let\'s go': 'Let\'s go'}",
85+
24,
86+
],
87+
[
88+
"Dumped type: array{Foo\\Bar: 'Foo\\\\Bar'}",
89+
25,
90+
],
91+
[
92+
"Dumped type: array{'3.14': 3.14}",
93+
26,
94+
],
95+
[
96+
'Dumped type: array{1: true, 0: false}',
97+
27,
98+
],
99+
[
100+
'Dumped type: T',
101+
36,
102+
],
103+
]);
104+
}
105+
106+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace PHPStan;
4+
5+
dumpPhpDocType(['' => '']);
6+
dumpPhpDocType(["\0" => 'NUL', 'NUL' => "\0"]);
7+
dumpPhpDocType(["\x01" => 'SOH', 'SOH' => "\x01"]);
8+
dumpPhpDocType(["\t" => 'HT', 'HT' => "\t"]);
9+
10+
// Space
11+
dumpPhpDocType([" " => 'SP', 'SP' => ' ']);
12+
dumpPhpDocType(["foo " => 'ends with SP', " foo" => 'starts with SP', " foo " => 'surrounded by SP', 'foo' => 'no SP']);
13+
14+
// Punctuation marks
15+
dumpPhpDocType(["foo?" => 'foo?']);
16+
dumpPhpDocType(["shallwedance" => 'yes']);
17+
dumpPhpDocType(["shallwedance?" => 'yes']);
18+
dumpPhpDocType(["Shall we dance" => 'yes']);
19+
dumpPhpDocType(["Shall we dance?" => 'yes']);
20+
dumpPhpDocType(["shall_we_dance" => 'yes']);
21+
dumpPhpDocType(["shall_we_dance?" => 'yes']);
22+
dumpPhpDocType(["shall-we-dance" => 'yes']);
23+
dumpPhpDocType(["shall-we-dance?" => 'yes']);
24+
dumpPhpDocType(['Let\'s go' => "Let's go"]);
25+
dumpPhpDocType(['Foo\\Bar' => 'Foo\\Bar']);
26+
dumpPhpDocType(['3.14' => 3.14]);
27+
dumpPhpDocType([true => true, false => false]);
28+
29+
/**
30+
* @template T
31+
* @param T $value
32+
* @return T
33+
*/
34+
function id(mixed $value): mixed
35+
{
36+
dumpPhpDocType($value);
37+
38+
return $value;
39+
}

0 commit comments

Comments
 (0)