From bcaf7aaf80d4878108be38b21341693341e4c5f5 Mon Sep 17 00:00:00 2001 From: Oliver Hader Date: Mon, 1 Feb 2021 17:00:07 +0100 Subject: [PATCH] [FEATURE] Allow to intercept adding issue in IssueBuffer This change introduces new `BeforeAddIssueEvent` which is invoked from `IssueBuffer::add`, which allows to collect and intercept code issue in a generic way. Resolves: #7528 --- src/Psalm/Internal/EventDispatcher.php | 22 ++++++++++++ src/Psalm/IssueBuffer.php | 6 ++++ .../EventHandler/BeforeAddIssueInterface.php | 21 +++++++++++ .../Event/BeforeAddIssueEvent.php | 36 +++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 src/Psalm/Plugin/EventHandler/BeforeAddIssueInterface.php create mode 100644 src/Psalm/Plugin/EventHandler/Event/BeforeAddIssueEvent.php diff --git a/src/Psalm/Internal/EventDispatcher.php b/src/Psalm/Internal/EventDispatcher.php index 29e8067490d..64f8859488f 100644 --- a/src/Psalm/Internal/EventDispatcher.php +++ b/src/Psalm/Internal/EventDispatcher.php @@ -15,6 +15,7 @@ use Psalm\Plugin\EventHandler\AfterFunctionLikeAnalysisInterface; use Psalm\Plugin\EventHandler\AfterMethodCallAnalysisInterface; use Psalm\Plugin\EventHandler\AfterStatementAnalysisInterface; +use Psalm\Plugin\EventHandler\BeforeAddIssueInterface; use Psalm\Plugin\EventHandler\BeforeFileAnalysisInterface; use Psalm\Plugin\EventHandler\Event\AddRemoveTaintsEvent; use Psalm\Plugin\EventHandler\Event\AfterAnalysisEvent; @@ -29,6 +30,7 @@ use Psalm\Plugin\EventHandler\Event\AfterFunctionLikeAnalysisEvent; use Psalm\Plugin\EventHandler\Event\AfterMethodCallAnalysisEvent; use Psalm\Plugin\EventHandler\Event\AfterStatementAnalysisEvent; +use Psalm\Plugin\EventHandler\Event\BeforeAddIssueEvent; use Psalm\Plugin\EventHandler\Event\BeforeFileAnalysisEvent; use Psalm\Plugin\EventHandler\Event\StringInterpreterEvent; use Psalm\Plugin\EventHandler\RemoveTaintsInterface; @@ -122,6 +124,11 @@ class EventDispatcher */ public $after_codebase_populated = []; + /** + * @var list> + */ + private array $before_add_issue = []; + /** * Static methods to be called after codebase has been populated * @@ -209,6 +216,10 @@ public function registerClass(string $class): void $this->after_codebase_populated[] = $class; } + if (is_subclass_of($class, EventHandler\BeforeAddIssueInterface::class)) { + $this->before_add_issue[] = $class; + } + if (is_subclass_of($class, AfterAnalysisInterface::class)) { $this->after_analysis[] = $class; } @@ -330,6 +341,17 @@ public function dispatchAfterCodebasePopulated(AfterCodebasePopulatedEvent $even } } + public function dispatchBeforeAddIssue(BeforeAddIssueEvent $event): ?bool + { + foreach ($this->before_add_issue as $handler) { + $result = $handler::beforeAddIssue($event); + if (is_bool($result)) { + return $result; + } + } + return null; + } + public function dispatchAfterAnalysis(AfterAnalysisEvent $event): void { foreach ($this->after_analysis as $handler) { diff --git a/src/Psalm/IssueBuffer.php b/src/Psalm/IssueBuffer.php index 8377ff11db2..a9fe2423c1a 100644 --- a/src/Psalm/IssueBuffer.php +++ b/src/Psalm/IssueBuffer.php @@ -16,6 +16,7 @@ use Psalm\Issue\TaintedInput; use Psalm\Issue\UnusedPsalmSuppress; use Psalm\Plugin\EventHandler\Event\AfterAnalysisEvent; +use Psalm\Plugin\EventHandler\Event\BeforeAddIssueEvent; use Psalm\Report\CheckstyleReport; use Psalm\Report\CodeClimateReport; use Psalm\Report\CompactReport; @@ -250,6 +251,11 @@ public static function add(CodeIssue $e, bool $is_fixable = false): bool { $config = Config::getInstance(); + $event = new BeforeAddIssueEvent($e, $is_fixable); + if ($config->eventDispatcher->dispatchBeforeAddIssue($event) === false) { + return false; + }; + $fqcn_parts = explode('\\', get_class($e)); $issue_type = array_pop($fqcn_parts); diff --git a/src/Psalm/Plugin/EventHandler/BeforeAddIssueInterface.php b/src/Psalm/Plugin/EventHandler/BeforeAddIssueInterface.php new file mode 100644 index 00000000000..c52262bc5ae --- /dev/null +++ b/src/Psalm/Plugin/EventHandler/BeforeAddIssueInterface.php @@ -0,0 +1,21 @@ +issue = $issue; + $this->fixable = $fixable; + } + + public function getIssue(): CodeIssue + { + return $this->issue; + } + + public function isFixable(): bool + { + return $this->fixable; + } +}