Skip to content

Commit b10fb30

Browse files
committed
Support for collectors in RuleTestCase
1 parent eb3d205 commit b10fb30

File tree

5 files changed

+159
-0
lines changed

5 files changed

+159
-0
lines changed

Diff for: src/Testing/RuleTestCase.php

+20
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88
use PHPStan\Analyser\FileAnalyser;
99
use PHPStan\Analyser\NodeScopeResolver;
1010
use PHPStan\Analyser\RuleErrorTransformer;
11+
use PHPStan\Analyser\ScopeContext;
1112
use PHPStan\Analyser\TypeSpecifier;
1213
use PHPStan\Collectors\Collector;
1314
use PHPStan\Collectors\Registry as CollectorRegistry;
1415
use PHPStan\Dependency\DependencyResolver;
1516
use PHPStan\DependencyInjection\Type\DynamicThrowTypeExtensionProvider;
1617
use PHPStan\File\FileHelper;
18+
use PHPStan\Node\CollectedDataNode;
1719
use PHPStan\Php\PhpVersion;
1820
use PHPStan\PhpDoc\PhpDocInheritanceResolver;
1921
use PHPStan\PhpDoc\StubPhpDocProvider;
@@ -118,7 +120,25 @@ public function analyse(array $files, array $expectedErrors): void
118120
if (count($analyserResult->getInternalErrors()) > 0) {
119121
$this->fail(implode("\n", $analyserResult->getInternalErrors()));
120122
}
123+
121124
$actualErrors = $analyserResult->getUnorderedErrors();
125+
$ruleErrorTransformer = new RuleErrorTransformer();
126+
if (count($analyserResult->getCollectedData()) > 0) {
127+
$ruleRegistry = new RuleRegistry([
128+
$this->getRule(),
129+
]);
130+
131+
$nodeType = CollectedDataNode::class;
132+
$node = new CollectedDataNode($analyserResult->getCollectedData());
133+
$scopeFactory = $this->createScopeFactory($this->createReflectionProvider(), $this->getTypeSpecifier());
134+
$scope = $scopeFactory->create(ScopeContext::create('irrelevant'));
135+
foreach ($ruleRegistry->getRules($nodeType) as $rule) {
136+
$ruleErrors = $rule->processNode($node, $scope);
137+
foreach ($ruleErrors as $ruleError) {
138+
$actualErrors[] = $ruleErrorTransformer->transform($ruleError, $scope, $nodeType, $node->getLine());
139+
}
140+
}
141+
}
122142

123143
$strictlyTypedSprintf = static function (int $line, string $message, ?string $tip): string {
124144
$message = sprintf('%02d: %s', $line, $message);

Diff for: tests/PHPStan/Rules/DummyCollector.php

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules;
4+
5+
use PhpParser\Node;
6+
use PhpParser\Node\Expr\MethodCall;
7+
use PHPStan\Analyser\Scope;
8+
use PHPStan\Collectors\Collector;
9+
10+
/**
11+
* @implements Collector<MethodCall, string>
12+
*/
13+
class DummyCollector implements Collector
14+
{
15+
16+
public function getNodeType(): string
17+
{
18+
return MethodCall::class;
19+
}
20+
21+
public function processNode(Node $node, Scope $scope)
22+
{
23+
if (!$node->name instanceof Node\Identifier) {
24+
return null;
25+
}
26+
27+
return $node->name->toString();
28+
}
29+
30+
}

Diff for: tests/PHPStan/Rules/DummyCollectorRule.php

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules;
4+
5+
use PhpParser\Node;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Node\CollectedDataNode;
8+
use function implode;
9+
use function sprintf;
10+
11+
/**
12+
* @implements Rule<CollectedDataNode>
13+
*/
14+
class DummyCollectorRule implements Rule
15+
{
16+
17+
public function getNodeType(): string
18+
{
19+
return CollectedDataNode::class;
20+
}
21+
22+
public function processNode(Node $node, Scope $scope): array
23+
{
24+
$data = $node->get(DummyCollector::class);
25+
$methods = [];
26+
foreach ($data as $methodNames) {
27+
foreach ($methodNames as $methodName) {
28+
if (!isset($methods[$methodName])) {
29+
$methods[$methodName] = 0;
30+
}
31+
32+
$methods[$methodName]++;
33+
}
34+
}
35+
36+
$parts = [];
37+
foreach ($methods as $methodName => $count) {
38+
$parts[] = sprintf('%d× %s', $count, $methodName);
39+
}
40+
41+
return [
42+
RuleErrorBuilder::message(implode(', ', $parts))
43+
->file(__DIR__ . '/data/dummy-collector.php')
44+
->line(5)
45+
->build(),
46+
];
47+
}
48+
49+
}

Diff for: tests/PHPStan/Rules/DummyCollectorRuleTest.php

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules;
4+
5+
use PHPStan\Testing\RuleTestCase;
6+
7+
/**
8+
* @extends RuleTestCase<DummyCollectorRule>
9+
*/
10+
class DummyCollectorRuleTest extends RuleTestCase
11+
{
12+
13+
protected function getRule(): Rule
14+
{
15+
return new DummyCollectorRule();
16+
}
17+
18+
protected function getCollectors(): array
19+
{
20+
return [
21+
new DummyCollector(),
22+
];
23+
}
24+
25+
public function testRule(): void
26+
{
27+
$this->analyse([__DIR__ . '/data/dummy-collector.php'], [
28+
[
29+
'2× doFoo, 2× doBar',
30+
5,
31+
],
32+
]);
33+
}
34+
35+
}

Diff for: tests/PHPStan/Rules/data/dummy-collector.php

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace DummyCollector;
4+
5+
class Foo
6+
{
7+
8+
public function doFoo()
9+
{
10+
$this->doFoo();
11+
$this->doBar();
12+
}
13+
14+
}
15+
16+
class Bar
17+
{
18+
19+
public function doBar()
20+
{
21+
$this->doFoo();
22+
$this->doBar();
23+
}
24+
25+
}

0 commit comments

Comments
 (0)