1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Trigger dispatch even when only legacy hooks (#4962)

This commit is contained in:
Adrien LUCAS 2021-01-09 01:51:26 +01:00 committed by Daniil Gentili
parent 7b43d321ad
commit fe71e8d16b
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
6 changed files with 104 additions and 8 deletions

View File

@ -370,7 +370,7 @@ class ExistingAtomicMethodCallAnalyzer extends CallAnalyzer
} }
} }
if ($config->eventDispatcher->after_method_checks) { if ($config->eventDispatcher->hasAfterMethodCallAnalysisHandlers()) {
$file_manipulations = []; $file_manipulations = [];
$appearing_method_id = $codebase->methods->getAppearingMethodId($method_id); $appearing_method_id = $codebase->methods->getAppearingMethodId($method_id);

View File

@ -469,7 +469,7 @@ class ExistingAtomicStaticCallAnalyzer
} }
} }
if ($config->eventDispatcher->after_method_checks) { if ($config->eventDispatcher->hasAfterMethodCallAnalysisHandlers()) {
$file_manipulations = []; $file_manipulations = [];
$appearing_method_id = $codebase->methods->getAppearingMethodId($method_id); $appearing_method_id = $codebase->methods->getAppearingMethodId($method_id);

View File

@ -6,6 +6,7 @@ use Psalm\Plugin\Hook;
use Psalm\Plugin\EventHandler; use Psalm\Plugin\EventHandler;
use Psalm\Plugin\EventHandler\Event; use Psalm\Plugin\EventHandler\Event;
use Psalm\Type\Atomic\TLiteralString; use Psalm\Type\Atomic\TLiteralString;
use function count;
use function is_subclass_of; use function is_subclass_of;
@ -16,9 +17,9 @@ class EventDispatcher
* *
* @var list<class-string<EventHandler\AfterMethodCallAnalysisInterface>> * @var list<class-string<EventHandler\AfterMethodCallAnalysisInterface>>
*/ */
public $after_method_checks = []; private $after_method_checks = [];
/** @var list<class-string<Hook\AfterMethodCallAnalysisInterface>> */ /** @var list<class-string<Hook\AfterMethodCallAnalysisInterface>> */
public $legacy_after_method_checks = []; private $legacy_after_method_checks = [];
/** /**
* Static methods to be called after project function checks have completed * Static methods to be called after project function checks have completed
@ -96,9 +97,9 @@ class EventDispatcher
* *
* @var list<class-string<EventHandler\AfterClassLikeVisitInterface>> * @var list<class-string<EventHandler\AfterClassLikeVisitInterface>>
*/ */
public $after_visit_classlikes = []; private $after_visit_classlikes = [];
/** @var list<class-string<Hook\AfterClassLikeVisitInterface>> */ /** @var list<class-string<Hook\AfterClassLikeVisitInterface>> */
public $legacy_after_visit_classlikes = []; private $legacy_after_visit_classlikes = [];
/** /**
* Static methods to be called after codebase has been populated * Static methods to be called after codebase has been populated
@ -235,6 +236,11 @@ class EventDispatcher
} }
} }
public function hasAfterMethodCallAnalysisHandlers(): bool
{
return count($this->after_method_checks) || count($this->legacy_after_method_checks);
}
public function dispatchAfterMethodCallAnalysis(Event\AfterMethodCallAnalysisEvent $event): void public function dispatchAfterMethodCallAnalysis(Event\AfterMethodCallAnalysisEvent $event): void
{ {
foreach ($this->after_method_checks as $handler) { foreach ($this->after_method_checks as $handler) {
@ -409,6 +415,11 @@ class EventDispatcher
return null; return null;
} }
public function hasAfterClassLikeVisitHandlers(): bool
{
return count($this->after_visit_classlikes) || count($this->legacy_after_visit_classlikes);
}
public function dispatchAfterClassLikeVisit(Event\AfterClassLikeVisitEvent $event): void public function dispatchAfterClassLikeVisit(Event\AfterClassLikeVisitEvent $event): void
{ {
foreach ($this->after_visit_classlikes as $handler) { foreach ($this->after_visit_classlikes as $handler) {

View File

@ -51,7 +51,7 @@ class ClassLikeStorageCacheProvider
$storage_dir . 'MethodStorage.php', $storage_dir . 'MethodStorage.php',
]; ];
if ($config->eventDispatcher->after_visit_classlikes) { if ($config->eventDispatcher->hasAfterClassLikeVisitHandlers()) {
$dependent_files = array_merge($dependent_files, $config->plugin_paths); $dependent_files = array_merge($dependent_files, $config->plugin_paths);
} }

View File

@ -52,7 +52,7 @@ class FileStorageCacheProvider
$storage_dir . 'FunctionLikeParameter.php', $storage_dir . 'FunctionLikeParameter.php',
]; ];
if ($config->eventDispatcher->after_visit_classlikes) { if ($config->eventDispatcher->hasAfterClassLikeVisitHandlers()) {
$dependent_files = array_merge($dependent_files, $config->plugin_paths); $dependent_files = array_merge($dependent_files, $config->plugin_paths);
} }

View File

@ -1,10 +1,19 @@
<?php <?php
namespace Psalm\Tests\Config; namespace Psalm\Tests\Config;
use PhpParser\Node\Expr;
use PhpParser\Node\Stmt\ClassLike;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use Psalm\Codebase;
use Psalm\FileSource;
use Psalm\Plugin\EventHandler\AfterEveryFunctionCallAnalysisInterface; use Psalm\Plugin\EventHandler\AfterEveryFunctionCallAnalysisInterface;
use Psalm\Plugin\EventHandler\Event\AfterCodebasePopulatedEvent; use Psalm\Plugin\EventHandler\Event\AfterCodebasePopulatedEvent;
use Psalm\Plugin\EventHandler\Event\AfterEveryFunctionCallAnalysisEvent; use Psalm\Plugin\EventHandler\Event\AfterEveryFunctionCallAnalysisEvent;
use Psalm\Plugin\Hook\AfterClassLikeVisitInterface;
use Psalm\Plugin\Hook\AfterMethodCallAnalysisInterface;
use Psalm\StatementsSource;
use Psalm\Storage\ClassLikeStorage;
use Psalm\Type\Union;
use function define; use function define;
use function defined; use function defined;
use const DIRECTORY_SEPARATOR; use const DIRECTORY_SEPARATOR;
@ -549,6 +558,82 @@ class PluginTest extends \Psalm\Tests\TestCase
); );
} }
public function testAfterMethodCallAnalysisLegacyHookIsLoaded(): void
{
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__, 2) . DIRECTORY_SEPARATOR,
'<?xml version="1.0"?>
<psalm
errorLevel="1"
>
<projectFiles>
<directory name="src" />
</projectFiles>
</psalm>'
)
);
$hook = new class implements AfterMethodCallAnalysisInterface {
public static function afterMethodCallAnalysis(
Expr $expr,
string $method_id,
string $appearing_method_id,
string $declaring_method_id,
Context $context,
StatementsSource $statements_source,
Codebase $codebase,
array &$file_replacements = [],
Union &$return_type_candidate = null
): void {
}
};
$codebase = $this->project_analyzer->getCodebase();
$config = $codebase->config;
(new PluginRegistrationSocket($config, $codebase))->registerHooksFromClass(get_class($hook));
$this->assertTrue($this->project_analyzer->getCodebase()->config->eventDispatcher->hasAfterMethodCallAnalysisHandlers());
}
public function testAfterClassLikeAnalysisLegacyHookIsLoaded(): void
{
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__, 2) . DIRECTORY_SEPARATOR,
'<?xml version="1.0"?>
<psalm
errorLevel="1"
>
<projectFiles>
<directory name="src" />
</projectFiles>
</psalm>'
)
);
$hook = new class implements AfterClassLikeVisitInterface {
public static function afterClassLikeVisit(
ClassLike $stmt,
ClassLikeStorage $storage,
FileSource $statements_source,
Codebase $codebase,
array &$file_replacements = []
): void {
}
};
$codebase = $this->project_analyzer->getCodebase();
$config = $codebase->config;
(new PluginRegistrationSocket($config, $codebase))->registerHooksFromClass(get_class($hook));
$this->assertTrue($this->project_analyzer->getCodebase()->config->eventDispatcher->hasAfterClassLikeVisitHandlers());
}
public function testPropertyProviderHooks(): void public function testPropertyProviderHooks(): void
{ {
require_once __DIR__ . '/Plugin/PropertyPlugin.php'; require_once __DIR__ . '/Plugin/PropertyPlugin.php';