From fe71e8d16bc341a201b323d1a0811ad358e54d41 Mon Sep 17 00:00:00 2001 From: Adrien LUCAS Date: Sat, 9 Jan 2021 01:51:26 +0100 Subject: [PATCH] Trigger dispatch even when only legacy hooks (#4962) --- .../ExistingAtomicMethodCallAnalyzer.php | 2 +- .../ExistingAtomicStaticCallAnalyzer.php | 2 +- src/Psalm/Internal/EventDispatcher.php | 19 ++++- .../ClassLikeStorageCacheProvider.php | 2 +- .../Provider/FileStorageCacheProvider.php | 2 +- tests/Config/PluginTest.php | 85 +++++++++++++++++++ 6 files changed, 104 insertions(+), 8 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/ExistingAtomicMethodCallAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/ExistingAtomicMethodCallAnalyzer.php index c379ffa97..ac5a7a430 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/ExistingAtomicMethodCallAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/ExistingAtomicMethodCallAnalyzer.php @@ -370,7 +370,7 @@ class ExistingAtomicMethodCallAnalyzer extends CallAnalyzer } } - if ($config->eventDispatcher->after_method_checks) { + if ($config->eventDispatcher->hasAfterMethodCallAnalysisHandlers()) { $file_manipulations = []; $appearing_method_id = $codebase->methods->getAppearingMethodId($method_id); diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php index d4905ccf0..bfbbcc9fa 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php @@ -469,7 +469,7 @@ class ExistingAtomicStaticCallAnalyzer } } - if ($config->eventDispatcher->after_method_checks) { + if ($config->eventDispatcher->hasAfterMethodCallAnalysisHandlers()) { $file_manipulations = []; $appearing_method_id = $codebase->methods->getAppearingMethodId($method_id); diff --git a/src/Psalm/Internal/EventDispatcher.php b/src/Psalm/Internal/EventDispatcher.php index 89ccdbfdc..2a301d45b 100644 --- a/src/Psalm/Internal/EventDispatcher.php +++ b/src/Psalm/Internal/EventDispatcher.php @@ -6,6 +6,7 @@ use Psalm\Plugin\Hook; use Psalm\Plugin\EventHandler; use Psalm\Plugin\EventHandler\Event; use Psalm\Type\Atomic\TLiteralString; +use function count; use function is_subclass_of; @@ -16,9 +17,9 @@ class EventDispatcher * * @var list> */ - public $after_method_checks = []; + private $after_method_checks = []; /** @var list> */ - public $legacy_after_method_checks = []; + private $legacy_after_method_checks = []; /** * Static methods to be called after project function checks have completed @@ -96,9 +97,9 @@ class EventDispatcher * * @var list> */ - public $after_visit_classlikes = []; + private $after_visit_classlikes = []; /** @var list> */ - public $legacy_after_visit_classlikes = []; + private $legacy_after_visit_classlikes = []; /** * 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 { foreach ($this->after_method_checks as $handler) { @@ -409,6 +415,11 @@ class EventDispatcher 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 { foreach ($this->after_visit_classlikes as $handler) { diff --git a/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php b/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php index 30bde3455..938aaef73 100644 --- a/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php +++ b/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php @@ -51,7 +51,7 @@ class ClassLikeStorageCacheProvider $storage_dir . 'MethodStorage.php', ]; - if ($config->eventDispatcher->after_visit_classlikes) { + if ($config->eventDispatcher->hasAfterClassLikeVisitHandlers()) { $dependent_files = array_merge($dependent_files, $config->plugin_paths); } diff --git a/src/Psalm/Internal/Provider/FileStorageCacheProvider.php b/src/Psalm/Internal/Provider/FileStorageCacheProvider.php index 10ca4c3f6..aa84c72d3 100644 --- a/src/Psalm/Internal/Provider/FileStorageCacheProvider.php +++ b/src/Psalm/Internal/Provider/FileStorageCacheProvider.php @@ -52,7 +52,7 @@ class FileStorageCacheProvider $storage_dir . 'FunctionLikeParameter.php', ]; - if ($config->eventDispatcher->after_visit_classlikes) { + if ($config->eventDispatcher->hasAfterClassLikeVisitHandlers()) { $dependent_files = array_merge($dependent_files, $config->plugin_paths); } diff --git a/tests/Config/PluginTest.php b/tests/Config/PluginTest.php index 926bd988f..f2df38643 100644 --- a/tests/Config/PluginTest.php +++ b/tests/Config/PluginTest.php @@ -1,10 +1,19 @@ project_analyzer = $this->getProjectAnalyzerWithConfig( + TestConfig::loadFromXML( + dirname(__DIR__, 2) . DIRECTORY_SEPARATOR, + ' + + + + + ' + ) + ); + + $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, + ' + + + + + ' + ) + ); + + $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 { require_once __DIR__ . '/Plugin/PropertyPlugin.php';