Skip to content

Commit

Permalink
[FEATURE] Allow to intercept adding issue in IssueBuffer
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ohader committed Jan 30, 2022
1 parent 64d06c6 commit bcaf7aa
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 0 deletions.
22 changes: 22 additions & 0 deletions src/Psalm/Internal/EventDispatcher.php
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -122,6 +124,11 @@ class EventDispatcher
*/
public $after_codebase_populated = [];

/**
* @var list<class-string<BeforeAddIssueInterface>>
*/
private array $before_add_issue = [];

/**
* Static methods to be called after codebase has been populated
*
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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) {
Expand Down
6 changes: 6 additions & 0 deletions src/Psalm/IssueBuffer.php
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down
21 changes: 21 additions & 0 deletions src/Psalm/Plugin/EventHandler/BeforeAddIssueInterface.php
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Psalm\Plugin\EventHandler;

use Psalm\Plugin\EventHandler\Event\BeforeAddIssueEvent;

interface BeforeAddIssueInterface
{
/**
* Called before adding a code issue
*
* @param BeforeAddIssueEvent $event
* @return null|bool $event How and whether to continue
* + `null` continue with next event handler
* + `true` stop event handling, keep issue
* + `false` stop event handling, drop/suppress issue
*/
public static function beforeAddIssue(BeforeAddIssueEvent $event): ?bool;
}
36 changes: 36 additions & 0 deletions src/Psalm/Plugin/EventHandler/Event/BeforeAddIssueEvent.php
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Psalm\Plugin\EventHandler\Event;

use Psalm\Issue\CodeIssue;

class BeforeAddIssueEvent
{
/**
* @var CodeIssue
*/
private CodeIssue $issue;

/**
* @var bool
*/
private bool $fixable;

public function __construct(CodeIssue $issue, bool $fixable)
{
$this->issue = $issue;
$this->fixable = $fixable;
}

public function getIssue(): CodeIssue
{
return $this->issue;
}

public function isFixable(): bool
{
return $this->fixable;
}
}

0 comments on commit bcaf7aa

Please sign in to comment.