-
Notifications
You must be signed in to change notification settings - Fork 497
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Collector interface and infrastructure
- Loading branch information
1 parent
78016fe
commit deda4bd
Showing
8 changed files
with
249 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace PHPStan\Collectors; | ||
|
||
use PhpParser\Node; | ||
use PHPStan\Analyser\Scope; | ||
|
||
/** | ||
* @phpstan-template TNodeType of Node | ||
*/ | ||
interface Collector | ||
{ | ||
|
||
/** | ||
* @phpstan-return class-string<TNodeType> | ||
*/ | ||
public function getNodeType(): string; | ||
|
||
/** | ||
* @phpstan-param TNodeType $node | ||
* @return mixed Collected data | ||
*/ | ||
public function processNode(Node $node, Scope $scope); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace PHPStan\Collectors; | ||
|
||
use PhpParser\Node; | ||
use function class_implements; | ||
use function class_parents; | ||
|
||
class Registry | ||
{ | ||
|
||
/** @var Collector[][] */ | ||
private array $collectors = []; | ||
|
||
/** @var Collector[][] */ | ||
private array $cache = []; | ||
|
||
/** | ||
* @param Collector[] $collectors | ||
*/ | ||
public function __construct(array $collectors) | ||
{ | ||
foreach ($collectors as $collector) { | ||
$this->collectors[$collector->getNodeType()][] = $collector; | ||
} | ||
} | ||
|
||
/** | ||
* @template TNodeType of Node | ||
* @phpstan-param class-string<TNodeType> $nodeType | ||
* @param Node $nodeType | ||
* @phpstan-return array<Collector<TNodeType>> | ||
* @return Collector[] | ||
*/ | ||
public function getCollectors(string $nodeType): array | ||
{ | ||
if (!isset($this->cache[$nodeType])) { | ||
$parentNodeTypes = [$nodeType] + class_parents($nodeType) + class_implements($nodeType); | ||
|
||
$collectors = []; | ||
foreach ($parentNodeTypes as $parentNodeType) { | ||
foreach ($this->collectors[$parentNodeType] ?? [] as $collector) { | ||
$collectors[] = $collector; | ||
} | ||
} | ||
|
||
$this->cache[$nodeType] = $collectors; | ||
} | ||
|
||
/** | ||
* @phpstan-var array<Collector<TNodeType>> $selectedCollectors | ||
* @var Collector[] $selectedCollectors | ||
*/ | ||
$selectedCollectors = $this->cache[$nodeType]; | ||
|
||
return $selectedCollectors; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace PHPStan\Collectors; | ||
|
||
use PHPStan\DependencyInjection\Container; | ||
|
||
class RegistryFactory | ||
{ | ||
|
||
public const COLLECTOR_TAG = 'phpstan.collector'; | ||
|
||
public function __construct(private Container $container) | ||
{ | ||
} | ||
|
||
public function create(): Registry | ||
{ | ||
return new Registry( | ||
$this->container->getServicesByTag(self::COLLECTOR_TAG), | ||
); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace PHPStan\Collectors; | ||
|
||
use PhpParser\Node; | ||
use PHPStan\Analyser\Scope; | ||
|
||
/** | ||
* @implements Collector<Node\Expr\FuncCall> | ||
*/ | ||
class DummyCollector implements Collector | ||
{ | ||
|
||
public function getNodeType(): string | ||
{ | ||
return 'PhpParser\Node\Expr\FuncCall'; | ||
} | ||
|
||
public function processNode(Node $node, Scope $scope) | ||
{ | ||
return []; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace PHPStan\Collectors; | ||
|
||
use PhpParser\Node; | ||
use PHPStan\Analyser\Scope; | ||
use PHPStan\Testing\PHPStanTestCase; | ||
|
||
class RegistryTest extends PHPStanTestCase | ||
{ | ||
|
||
public function testGetCollectors(): void | ||
{ | ||
$collector = new DummyCollector(); | ||
|
||
$registry = new Registry([ | ||
$collector, | ||
]); | ||
|
||
$collectors = $registry->getCollectors(Node\Expr\FuncCall::class); | ||
$this->assertCount(1, $collectors); | ||
$this->assertSame($collector, $collectors[0]); | ||
|
||
$this->assertCount(0, $registry->getCollectors(Node\Expr\MethodCall::class)); | ||
} | ||
|
||
public function testGetCollectorsWithTwoDifferentInstances(): void | ||
{ | ||
$fooCollector = new UniversalCollector(Node\Expr\FuncCall::class, static fn (Node\Expr\FuncCall $node, Scope $scope): array => ['Foo error']); | ||
$barCollector = new UniversalCollector(Node\Expr\FuncCall::class, static fn (Node\Expr\FuncCall $node, Scope $scope): array => ['Bar error']); | ||
|
||
$registry = new Registry([ | ||
$fooCollector, | ||
$barCollector, | ||
]); | ||
|
||
$collectors = $registry->getCollectors(Node\Expr\FuncCall::class); | ||
$this->assertCount(2, $collectors); | ||
$this->assertSame($fooCollector, $collectors[0]); | ||
$this->assertSame($barCollector, $collectors[1]); | ||
|
||
$this->assertCount(0, $registry->getCollectors(Node\Expr\MethodCall::class)); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace PHPStan\Collectors; | ||
|
||
use PhpParser\Node; | ||
use PHPStan\Analyser\Scope; | ||
|
||
/** | ||
* @template TNodeType of Node | ||
* @implements Collector<TNodeType> | ||
*/ | ||
class UniversalCollector implements Collector | ||
{ | ||
|
||
/** @phpstan-var class-string<TNodeType> */ | ||
private $nodeType; | ||
|
||
/** @var (callable(TNodeType, Scope): mixed) */ | ||
private $processNodeCallback; | ||
|
||
/** | ||
* @param class-string<TNodeType> $nodeType | ||
* @param (callable(TNodeType, Scope): mixed) $processNodeCallback | ||
*/ | ||
public function __construct(string $nodeType, callable $processNodeCallback) | ||
{ | ||
$this->nodeType = $nodeType; | ||
$this->processNodeCallback = $processNodeCallback; | ||
} | ||
|
||
public function getNodeType(): string | ||
{ | ||
return $this->nodeType; | ||
} | ||
|
||
/** | ||
* @param TNodeType $node | ||
* @return mixed | ||
*/ | ||
public function processNode(Node $node, Scope $scope) | ||
{ | ||
$callback = $this->processNodeCallback; | ||
return $callback($node, $scope); | ||
} | ||
|
||
} |