diff --git a/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php b/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php index 4e99005e19e..44cec8c4246 100644 --- a/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php @@ -397,6 +397,7 @@ public static function getFileReportOptions(array $report_file_paths, bool $show '.pylint' => Report::TYPE_PYLINT, '.console' => Report::TYPE_CONSOLE, '.sarif' => Report::TYPE_SARIF, + 'count.txt' => Report::TYPE_COUNT, ]; foreach ($report_file_paths as $report_file_path) { diff --git a/src/Psalm/IssueBuffer.php b/src/Psalm/IssueBuffer.php index 0fea8f035fc..47bde92fccd 100644 --- a/src/Psalm/IssueBuffer.php +++ b/src/Psalm/IssueBuffer.php @@ -16,11 +16,11 @@ use Psalm\Issue\TaintedInput; use Psalm\Issue\UnusedPsalmSuppress; use Psalm\Plugin\EventHandler\Event\AfterAnalysisEvent; -use Psalm\Report; use Psalm\Report\CheckstyleReport; use Psalm\Report\CodeClimateReport; use Psalm\Report\CompactReport; use Psalm\Report\ConsoleReport; +use Psalm\Report\CountReport; use Psalm\Report\EmacsReport; use Psalm\Report\GithubActionsReport; use Psalm\Report\JsonReport; @@ -908,6 +908,13 @@ public static function getOutput( case Report::TYPE_CODECLIMATE: $output = new CodeClimateReport($normalized_data, self::$fixable_issue_counts, $report_options); break; + + case Report::TYPE_COUNT: + $output = new CountReport($normalized_data, self::$fixable_issue_counts, $report_options); + break; + + default: + throw new RuntimeException('Unexpected report format: ' . $report_options->format); } return $output->create(); diff --git a/src/Psalm/Report.php b/src/Psalm/Report.php index 6ad69c849fc..97604a799dd 100644 --- a/src/Psalm/Report.php +++ b/src/Psalm/Report.php @@ -28,24 +28,7 @@ abstract class Report public const TYPE_PHP_STORM = 'phpstorm'; public const TYPE_SARIF = 'sarif'; public const TYPE_CODECLIMATE = 'codeclimate'; - - public const SUPPORTED_OUTPUT_TYPES = [ - self::TYPE_COMPACT, - self::TYPE_CONSOLE, - self::TYPE_PYLINT, - self::TYPE_JSON, - self::TYPE_JSON_SUMMARY, - self::TYPE_SONARQUBE, - self::TYPE_EMACS, - self::TYPE_XML, - self::TYPE_JUNIT, - self::TYPE_CHECKSTYLE, - self::TYPE_TEXT, - self::TYPE_GITHUB_ACTIONS, - self::TYPE_PHP_STORM, - self::TYPE_SARIF, - self::TYPE_CODECLIMATE, - ]; + public const TYPE_COUNT = 'count'; /** * @var array diff --git a/src/Psalm/Report/CountReport.php b/src/Psalm/Report/CountReport.php new file mode 100644 index 00000000000..b044d851651 --- /dev/null +++ b/src/Psalm/Report/CountReport.php @@ -0,0 +1,39 @@ +issues_data as $issue_data) { + if (array_key_exists($issue_data->type, $issue_type_counts)) { + $issue_type_counts[$issue_data->type]++; + } else { + $issue_type_counts[$issue_data->type] = 1; + } + } + uksort($issue_type_counts, function (string $a, string $b) use ($issue_type_counts): int { + $cmp_result = $issue_type_counts[$a] <=> $issue_type_counts[$b]; + if ($cmp_result === 0) { + return $a <=> $b; + } else { + return $cmp_result; + } + }); + + $output = ''; + foreach ($issue_type_counts as $issue_type => $count) { + $output .= "{$issue_type}: {$count}\n"; + } + return $output; + } +} diff --git a/src/Psalm/Report/ReportOptions.php b/src/Psalm/Report/ReportOptions.php index 3ade03bd083..3f9143536b2 100644 --- a/src/Psalm/Report/ReportOptions.php +++ b/src/Psalm/Report/ReportOptions.php @@ -22,7 +22,7 @@ class ReportOptions public $show_info = true; /** - * @var value-of + * @var Report::TYPE_* */ public $format = Report::TYPE_CONSOLE; diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index 5fd7b59bc47..895aef8271d 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -1269,6 +1269,26 @@ public function testGithubActionsOutput(): void ); } + public function testCountOutput(): void + { + $this->analyzeFileForReport(); + + $report_options = new ReportOptions(); + $report_options->format = Report::TYPE_COUNT; + $expected_output = <<<'EOF' +MixedInferredReturnType: 1 +MixedReturnStatement: 1 +PossiblyUndefinedGlobalVariable: 1 +UndefinedConstant: 1 +UndefinedVariable: 1 + +EOF; + $this->assertSame( + $expected_output, + IssueBuffer::getOutput(IssueBuffer::getIssuesData(), $report_options) + ); + } + public function testEmptyReportIfNotError(): void { $this->addFile(