mirror of
https://github.com/danog/psalm.git
synced 2025-01-21 21:31:13 +01:00
Replace issue data array with object
This commit is contained in:
parent
d3bfb96431
commit
196a0a5c4e
@ -15,6 +15,7 @@ use function min;
|
||||
use const PHP_VERSION;
|
||||
use function phpversion;
|
||||
use function preg_replace_callback;
|
||||
use Psalm\Internal\Analyzer\IssueData;
|
||||
use Psalm\Internal\Provider\FileProvider;
|
||||
use RuntimeException;
|
||||
use function str_replace;
|
||||
@ -53,12 +54,7 @@ class ErrorBaseline
|
||||
/**
|
||||
* @param FileProvider $fileProvider
|
||||
* @param string $baselineFile
|
||||
* @param array<string, list<array{
|
||||
* file_name: string,
|
||||
* type: string,
|
||||
* severity: string,
|
||||
* selected_text: string
|
||||
* }>> $issues
|
||||
* @param array<string, list<IssueData>> $issues
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@ -136,12 +132,7 @@ class ErrorBaseline
|
||||
/**
|
||||
* @param FileProvider $fileProvider
|
||||
* @param string $baselineFile
|
||||
* @param array<string, list<array{
|
||||
* file_name: string,
|
||||
* type: string,
|
||||
* severity: string,
|
||||
* selected_text: string
|
||||
* }>> $issues
|
||||
* @param array<string, list<IssueData>> $issues
|
||||
*
|
||||
* @throws Exception\ConfigException
|
||||
*
|
||||
@ -189,12 +180,7 @@ class ErrorBaseline
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, list<array{
|
||||
* file_name: string,
|
||||
* type: string,
|
||||
* severity: string,
|
||||
* selected_text: string
|
||||
* }>> $issues
|
||||
* @param array<string, list<IssueData>> $issues
|
||||
*
|
||||
* @return array<string,array<string,array{o:int, s:array<int, string>}>>
|
||||
*/
|
||||
@ -207,18 +193,17 @@ class ErrorBaseline
|
||||
array_merge(...array_values($issues)),
|
||||
/**
|
||||
* @param array<string,array<string,array{o:int, s:array<int, string>}>> $carry
|
||||
* @param array{type: string, file_name: string, severity: string, selected_text: string} $issue
|
||||
*
|
||||
* @return array<string,array<string,array{o:int, s:array<int, string>}>>
|
||||
*/
|
||||
function (array $carry, array $issue): array {
|
||||
if ($issue['severity'] !== Config::REPORT_ERROR) {
|
||||
function (array $carry, IssueData $issue): array {
|
||||
if ($issue->severity !== Config::REPORT_ERROR) {
|
||||
return $carry;
|
||||
}
|
||||
|
||||
$fileName = $issue['file_name'];
|
||||
$fileName = $issue->file_name;
|
||||
$fileName = str_replace('\\', '/', $fileName);
|
||||
$issueType = $issue['type'];
|
||||
$issueType = $issue->type;
|
||||
|
||||
if (!isset($carry[$fileName])) {
|
||||
$carry[$fileName] = [];
|
||||
@ -230,8 +215,8 @@ class ErrorBaseline
|
||||
|
||||
++$carry[$fileName][$issueType]['o'];
|
||||
|
||||
if (!strpos($issue['selected_text'], "\n")) {
|
||||
$carry[$fileName][$issueType]['s'][] = $issue['selected_text'];
|
||||
if (!strpos($issue->selected_text, "\n")) {
|
||||
$carry[$fileName][$issueType]['s'][] = $issue->selected_text;
|
||||
}
|
||||
|
||||
return $carry;
|
||||
|
146
src/Psalm/Internal/Analyzer/IssueData.php
Normal file
146
src/Psalm/Internal/Analyzer/IssueData.php
Normal file
@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace Psalm\Internal\Analyzer;
|
||||
|
||||
class IssueData
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $severity;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @readonly
|
||||
*/
|
||||
public $line_from;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @readonly
|
||||
*/
|
||||
public $line_to;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @readonly
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @readonly
|
||||
*/
|
||||
public $message;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @readonly
|
||||
*/
|
||||
public $file_name;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @readonly
|
||||
*/
|
||||
public $file_path;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @readonly
|
||||
*/
|
||||
public $snippet;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @readonly
|
||||
*/
|
||||
public $selected_text;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @readonly
|
||||
*/
|
||||
public $from;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @readonly
|
||||
*/
|
||||
public $to;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @readonly
|
||||
*/
|
||||
public $snippet_from;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @readonly
|
||||
*/
|
||||
public $snippet_to;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @readonly
|
||||
*/
|
||||
public $column_from;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @readonly
|
||||
*/
|
||||
public $column_to;
|
||||
|
||||
/**
|
||||
* @param string $severity
|
||||
* @param int $line_from
|
||||
* @param int $line_to
|
||||
* @param string $type
|
||||
* @param string $message
|
||||
* @param string $file_name
|
||||
* @param string $file_path
|
||||
* @param string $snippet
|
||||
* @param string $selected_text
|
||||
* @param int $from
|
||||
* @param int $to
|
||||
* @param int $snippet_from
|
||||
* @param int $snippet_to
|
||||
* @param int $column_from
|
||||
* @param int $column_to
|
||||
*/
|
||||
public function __construct(
|
||||
$severity,
|
||||
$line_from,
|
||||
$line_to,
|
||||
$type,
|
||||
$message,
|
||||
$file_name,
|
||||
$file_path,
|
||||
$snippet,
|
||||
$selected_text,
|
||||
$from,
|
||||
$to,
|
||||
$snippet_from,
|
||||
$snippet_to,
|
||||
$column_from,
|
||||
$column_to
|
||||
) {
|
||||
$this->severity = $severity;
|
||||
$this->line_from = $line_from;
|
||||
$this->line_to = $line_to;
|
||||
$this->type = $type;
|
||||
$this->message = $message;
|
||||
$this->file_name = $file_name;
|
||||
$this->file_path = $file_path;
|
||||
$this->snippet = $snippet;
|
||||
$this->selected_text = $selected_text;
|
||||
$this->from = $from;
|
||||
$this->to = $to;
|
||||
$this->snippet_from = $snippet_from;
|
||||
$this->snippet_to = $snippet_to;
|
||||
$this->column_from = $column_from;
|
||||
$this->column_to = $column_to;
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ use PhpParser;
|
||||
use function preg_replace;
|
||||
use Psalm\Config;
|
||||
use Psalm\FileManipulation;
|
||||
use Psalm\Internal\Analyzer\IssueData;
|
||||
use Psalm\Internal\Analyzer\FileAnalyzer;
|
||||
use Psalm\Internal\Analyzer\ProjectAnalyzer;
|
||||
use Psalm\Internal\FileManipulation\FileManipulationBuffer;
|
||||
@ -25,24 +26,6 @@ use function substr;
|
||||
use function usort;
|
||||
|
||||
/**
|
||||
* @psalm-type IssueData = array{
|
||||
* severity: string,
|
||||
* line_from: int,
|
||||
* line_to: int,
|
||||
* type: string,
|
||||
* message: string,
|
||||
* file_name: string,
|
||||
* file_path: string,
|
||||
* snippet: string,
|
||||
* from: int,
|
||||
* to: int,
|
||||
* snippet_from: int,
|
||||
* snippet_to: int,
|
||||
* column_from: int,
|
||||
* column_to: int,
|
||||
* selected_text: string
|
||||
* }
|
||||
*
|
||||
* @psalm-type TaggedCodeType = array<int, array{0: int, 1: string}>
|
||||
*
|
||||
* @psalm-type WorkerData = array{
|
||||
@ -349,12 +332,12 @@ class Analyzer
|
||||
$has_info = false;
|
||||
|
||||
foreach ($issues as $issue) {
|
||||
if ($issue['severity'] === 'error') {
|
||||
if ($issue->severity === 'error') {
|
||||
$has_error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ($issue['severity'] === 'info') {
|
||||
if ($issue->severity === 'info') {
|
||||
$has_info = true;
|
||||
}
|
||||
}
|
||||
@ -865,7 +848,7 @@ class Analyzer
|
||||
$last_diff_offset = $file_diff_map[count($file_diff_map) - 1][1];
|
||||
|
||||
foreach ($file_issues as $i => &$issue_data) {
|
||||
if ($issue_data['to'] < $first_diff_offset || $issue_data['from'] > $last_diff_offset) {
|
||||
if ($issue_data->to < $first_diff_offset || $issue_data->from > $last_diff_offset) {
|
||||
unset($file_issues[$i]);
|
||||
continue;
|
||||
}
|
||||
@ -873,16 +856,16 @@ class Analyzer
|
||||
$matched = false;
|
||||
|
||||
foreach ($file_diff_map as list($from, $to, $file_offset, $line_offset)) {
|
||||
if ($issue_data['from'] >= $from
|
||||
&& $issue_data['from'] <= $to
|
||||
if ($issue_data->from >= $from
|
||||
&& $issue_data->from <= $to
|
||||
&& !$matched
|
||||
) {
|
||||
$issue_data['from'] += $file_offset;
|
||||
$issue_data['to'] += $file_offset;
|
||||
$issue_data['snippet_from'] += $file_offset;
|
||||
$issue_data['snippet_to'] += $file_offset;
|
||||
$issue_data['line_from'] += $line_offset;
|
||||
$issue_data['line_to'] += $line_offset;
|
||||
$issue_data->from += $file_offset;
|
||||
$issue_data->to += $file_offset;
|
||||
$issue_data->snippet_from += $file_offset;
|
||||
$issue_data->snippet_to += $file_offset;
|
||||
$issue_data->line_from += $line_offset;
|
||||
$issue_data->line_to += $line_offset;
|
||||
$matched = true;
|
||||
}
|
||||
}
|
||||
@ -1351,8 +1334,8 @@ class Analyzer
|
||||
$applicable_issues = [];
|
||||
|
||||
foreach ($this->existing_issues[$file_path] as $issue_data) {
|
||||
if ($issue_data['from'] >= $start && $issue_data['from'] <= $end) {
|
||||
if ($issue_type === null || $issue_type === $issue_data['type']) {
|
||||
if ($issue_data->from >= $start && $issue_data->from <= $end) {
|
||||
if ($issue_type === null || $issue_type === $issue_data->type) {
|
||||
$applicable_issues[] = $issue_data;
|
||||
}
|
||||
}
|
||||
@ -1372,8 +1355,8 @@ class Analyzer
|
||||
{
|
||||
if (isset($this->existing_issues[$file_path])) {
|
||||
foreach ($this->existing_issues[$file_path] as $i => $issue_data) {
|
||||
if ($issue_data['from'] >= $start && $issue_data['from'] <= $end) {
|
||||
if ($issue_type === null || $issue_type === $issue_data['type']) {
|
||||
if ($issue_data->from >= $start && $issue_data->from <= $end) {
|
||||
if ($issue_type === null || $issue_type === $issue_data->type) {
|
||||
unset($this->existing_issues[$file_path][$i]);
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ use function min;
|
||||
use const PHP_EOL;
|
||||
use Psalm\Codebase;
|
||||
use Psalm\Config;
|
||||
use Psalm\Internal\Analyzer\IssueData;
|
||||
use Psalm\Internal\Provider\FileProvider;
|
||||
use Psalm\Internal\Provider\FileReferenceProvider;
|
||||
use Psalm\Internal\Provider\FileStorageProvider;
|
||||
@ -24,24 +25,6 @@ use function strtolower;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
* @psalm-type IssueData = array{
|
||||
* severity: string,
|
||||
* line_from: int,
|
||||
* line_to: int,
|
||||
* type: string,
|
||||
* message: string,
|
||||
* file_name: string,
|
||||
* file_path: string,
|
||||
* snippet: string,
|
||||
* from: int,
|
||||
* to: int,
|
||||
* snippet_from: int,
|
||||
* snippet_to: int,
|
||||
* column_from: int,
|
||||
* column_to: int,
|
||||
* selected_text: string
|
||||
* }
|
||||
*
|
||||
* @psalm-type PoolData = array{
|
||||
* classlikes_data:array{
|
||||
* 0:array<lowercase-string, bool>,
|
||||
|
@ -29,6 +29,7 @@ use LanguageServerProtocol\TextDocumentSyncKind;
|
||||
use LanguageServerProtocol\TextDocumentSyncOptions;
|
||||
use function max;
|
||||
use function parse_url;
|
||||
use Psalm\Internal\Analyzer\IssueData;
|
||||
use Psalm\Internal\Analyzer\ProjectAnalyzer;
|
||||
use Psalm\Internal\LanguageServer\Server\TextDocument;
|
||||
use function rawurlencode;
|
||||
@ -326,25 +327,15 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher
|
||||
|
||||
foreach ($uris as $file_path => $uri) {
|
||||
$diagnostics = array_map(
|
||||
/**
|
||||
* @param array{
|
||||
* severity: string,
|
||||
* message: string,
|
||||
* line_from: int,
|
||||
* line_to: int,
|
||||
* column_from: int,
|
||||
* column_to: int
|
||||
* } $issue_data
|
||||
*/
|
||||
function (array $issue_data) use ($file_path) : Diagnostic {
|
||||
//$check_name = $issue['check_name'];
|
||||
$description = $issue_data['message'];
|
||||
$severity = $issue_data['severity'];
|
||||
function (IssueData $issue_data) use ($file_path) : Diagnostic {
|
||||
//$check_name = $issue->check_name;
|
||||
$description = $issue_data->message;
|
||||
$severity = $issue_data->severity;
|
||||
|
||||
$start_line = max($issue_data['line_from'], 1);
|
||||
$end_line = $issue_data['line_to'];
|
||||
$start_column = $issue_data['column_from'];
|
||||
$end_column = $issue_data['column_to'];
|
||||
$start_line = max($issue_data->line_from, 1);
|
||||
$end_line = $issue_data->line_to;
|
||||
$start_column = $issue_data->column_from;
|
||||
$end_column = $issue_data->column_to;
|
||||
// Language server has 0 based lines and columns, phan has 1-based lines and columns.
|
||||
$range = new Range(
|
||||
new Position($start_line - 1, $start_column - 1),
|
||||
|
@ -7,28 +7,12 @@ use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function is_array;
|
||||
use function is_readable;
|
||||
use Psalm\Internal\Analyzer\IssueData;
|
||||
use Psalm\Config;
|
||||
use function serialize;
|
||||
use function unserialize;
|
||||
|
||||
/**
|
||||
* @psalm-type IssueData = array{
|
||||
* severity: string,
|
||||
* line_from: int,
|
||||
* line_to: int,
|
||||
* type: string,
|
||||
* message: string,
|
||||
* file_name: string,
|
||||
* file_path: string,
|
||||
* snippet: string,
|
||||
* from: int,
|
||||
* to: int,
|
||||
* snippet_from: int,
|
||||
* snippet_to: int,
|
||||
* column_from: int,
|
||||
* column_to: int
|
||||
* }
|
||||
*
|
||||
* @psalm-type TaggedCodeType = array<int, array{0: int, 1: string}>
|
||||
*/
|
||||
/**
|
||||
|
@ -8,27 +8,10 @@ use function array_unique;
|
||||
use function file_exists;
|
||||
use Psalm\Codebase;
|
||||
use Psalm\CodeLocation;
|
||||
use Psalm\Internal\Analyzer\IssueData;
|
||||
use Psalm\Internal\Analyzer\ClassLikeAnalyzer;
|
||||
|
||||
/**
|
||||
* @psalm-type IssueData = array{
|
||||
* severity: string,
|
||||
* line_from: int,
|
||||
* line_to: int,
|
||||
* type: string,
|
||||
* message: string,
|
||||
* file_name: string,
|
||||
* file_path: string,
|
||||
* snippet: string,
|
||||
* from: int,
|
||||
* to: int,
|
||||
* snippet_from: int,
|
||||
* snippet_to: int,
|
||||
* column_from: int,
|
||||
* column_to: int,
|
||||
* selected_text: string
|
||||
* }
|
||||
*
|
||||
* @psalm-type TaggedCodeType = array<int, array{0: int, 1: string}>
|
||||
*/
|
||||
/**
|
||||
@ -924,10 +907,10 @@ class FileReferenceProvider
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addIssue($file_path, array $issue)
|
||||
public function addIssue($file_path, IssueData $issue)
|
||||
{
|
||||
// don’t save parse errors ever, as they're not responsive to AST diffing
|
||||
if ($issue['type'] === 'ParseError') {
|
||||
if ($issue->type === 'ParseError') {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -93,11 +93,9 @@ abstract class CodeIssue
|
||||
/**
|
||||
* @param string $severity
|
||||
*
|
||||
* @return array{severity: string, line_from: int, line_to: int, type: string, message: string, file_name: string,
|
||||
* file_path: string, snippet: string, selected_text: string, from: int, to: int, snippet_from: int,
|
||||
* snippet_to: int, column_from: int, column_to: int}
|
||||
* @return \Psalm\Internal\Analyzer\IssueData
|
||||
*/
|
||||
public function toArray($severity = Config::REPORT_ERROR)
|
||||
public function toIssueData($severity = Config::REPORT_ERROR)
|
||||
{
|
||||
$location = $this->getLocation();
|
||||
$selection_bounds = $location->getSelectionBounds();
|
||||
@ -106,22 +104,22 @@ abstract class CodeIssue
|
||||
$fqcn_parts = explode('\\', get_called_class());
|
||||
$issue_type = array_pop($fqcn_parts);
|
||||
|
||||
return [
|
||||
'severity' => $severity,
|
||||
'line_from' => $location->getLineNumber(),
|
||||
'line_to' => $location->getEndLineNumber(),
|
||||
'type' => $issue_type,
|
||||
'message' => $this->getMessage(),
|
||||
'file_name' => $location->file_name,
|
||||
'file_path' => $location->file_path,
|
||||
'snippet' => $location->getSnippet(),
|
||||
'selected_text' => $location->getSelectedText(),
|
||||
'from' => $selection_bounds[0],
|
||||
'to' => $selection_bounds[1],
|
||||
'snippet_from' => $snippet_bounds[0],
|
||||
'snippet_to' => $snippet_bounds[1],
|
||||
'column_from' => $location->getColumn(),
|
||||
'column_to' => $location->getEndColumn(),
|
||||
];
|
||||
return new \Psalm\Internal\Analyzer\IssueData(
|
||||
$severity,
|
||||
$location->getLineNumber(),
|
||||
$location->getEndLineNumber(),
|
||||
$issue_type,
|
||||
$this->getMessage(),
|
||||
$location->file_name,
|
||||
$location->file_path,
|
||||
$location->getSnippet(),
|
||||
$location->getSelectedText(),
|
||||
$selection_bounds[0],
|
||||
$selection_bounds[1],
|
||||
$snippet_bounds[0],
|
||||
$snippet_bounds[1],
|
||||
$location->getColumn(),
|
||||
$location->getEndColumn(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ use function get_class;
|
||||
use function memory_get_peak_usage;
|
||||
use function microtime;
|
||||
use function number_format;
|
||||
use Psalm\Internal\Analyzer\IssueData;
|
||||
use Psalm\Internal\Analyzer\ProjectAnalyzer;
|
||||
use Psalm\Issue\CodeIssue;
|
||||
use Psalm\Issue\UnusedPsalmSuppress;
|
||||
@ -36,9 +37,7 @@ use function array_values;
|
||||
class IssueBuffer
|
||||
{
|
||||
/**
|
||||
* @var array<string, list<array{severity: string, line_from: int, line_to: int, type: string, message: string,
|
||||
* file_name: string, file_path: string, snippet: string, from: int, to: int,
|
||||
* snippet_from: int, snippet_to: int, column_from: int, column_to: int, selected_text: string}>>
|
||||
* @var array<string, list<IssueData>>
|
||||
*/
|
||||
protected static $issues_data = [];
|
||||
|
||||
@ -211,7 +210,7 @@ class IssueBuffer
|
||||
|
||||
if ($reporting_level === Config::REPORT_INFO) {
|
||||
if (!self::alreadyEmitted($emitted_key)) {
|
||||
self::$issues_data[$e->getFilePath()][] = $e->toArray(Config::REPORT_INFO);
|
||||
self::$issues_data[$e->getFilePath()][] = $e->toIssueData(Config::REPORT_INFO);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -230,7 +229,7 @@ class IssueBuffer
|
||||
|
||||
if (!self::alreadyEmitted($emitted_key)) {
|
||||
++self::$error_count;
|
||||
self::$issues_data[$e->getFilePath()][] = $e->toArray(Config::REPORT_ERROR);
|
||||
self::$issues_data[$e->getFilePath()][] = $e->toIssueData(Config::REPORT_ERROR);
|
||||
}
|
||||
|
||||
if ($is_fixable) {
|
||||
@ -249,7 +248,7 @@ class IssueBuffer
|
||||
$filtered_issues = [];
|
||||
|
||||
foreach (self::$issues_data[$file_path] as $issue) {
|
||||
if ($issue['type'] !== $issue_type || $issue['from'] !== $file_offset) {
|
||||
if ($issue->type !== $issue_type || $issue->from !== $file_offset) {
|
||||
$filtered_issues[] = $issue;
|
||||
}
|
||||
}
|
||||
@ -267,9 +266,7 @@ class IssueBuffer
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<array{severity: string, line_from: int, line_to: int, type: string, message: string,
|
||||
* file_name: string, file_path: string, snippet: string, from: int, to: int, snippet_from: int, snippet_to: int,
|
||||
* column_from: int, column_to: int, selected_text: string}>>
|
||||
* @return array<string, list<IssueData>>
|
||||
*/
|
||||
public static function getIssuesData()
|
||||
{
|
||||
@ -277,9 +274,7 @@ class IssueBuffer
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array{severity: string, line_from: int, line_to: int, type: string, message: string,
|
||||
* file_name: string, file_path: string, snippet: string, from: int, to: int, snippet_from: int, snippet_to: int,
|
||||
* column_from: int, column_to: int, selected_text: string}>
|
||||
* @return list<IssueData>
|
||||
*/
|
||||
public static function getIssuesDataForFile(string $file_path)
|
||||
{
|
||||
@ -387,9 +382,7 @@ class IssueBuffer
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, list<array{severity: string, line_from: int, line_to: int, type: string, message: string,
|
||||
* file_name: string, file_path: string, snippet: string, from: int, to: int, snippet_from: int,
|
||||
* snippet_to: int, column_from: int, column_to: int, selected_text: string}>> $issues_data
|
||||
* @param array<string, list<IssueData>> $issues_data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@ -397,10 +390,10 @@ class IssueBuffer
|
||||
{
|
||||
foreach ($issues_data as $file_path => $file_issues) {
|
||||
foreach ($file_issues as $issue) {
|
||||
$emitted_key = $issue['type']
|
||||
. '-' . $issue['file_name']
|
||||
. ':' . $issue['line_from']
|
||||
. ':' . $issue['column_from'];
|
||||
$emitted_key = $issue->type
|
||||
. '-' . $issue->file_name
|
||||
. ':' . $issue->line_from
|
||||
. ':' . $issue->column_from;
|
||||
|
||||
if (!self::alreadyEmitted($emitted_key)) {
|
||||
self::$issues_data[$file_path][] = $issue;
|
||||
@ -444,24 +437,20 @@ class IssueBuffer
|
||||
foreach (self::$issues_data as $file_path => $file_issues) {
|
||||
usort(
|
||||
$file_issues,
|
||||
/**
|
||||
* @param array{file_path: string, line_from: int, column_from: int} $d1
|
||||
* @param array{file_path: string, line_from: int, column_from: int} $d2
|
||||
*/
|
||||
function (array $d1, array $d2) : int {
|
||||
if ($d1['file_path'] === $d2['file_path']) {
|
||||
if ($d1['line_from'] === $d2['line_from']) {
|
||||
if ($d1['column_from'] === $d2['column_from']) {
|
||||
function (IssueData $d1, IssueData $d2) : int {
|
||||
if ($d1->file_path === $d2->file_path) {
|
||||
if ($d1->line_from === $d2->line_from) {
|
||||
if ($d1->column_from === $d2->column_from) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $d1['column_from'] > $d2['column_from'] ? 1 : -1;
|
||||
return $d1->column_from > $d2->column_from ? 1 : -1;
|
||||
}
|
||||
|
||||
return $d1['line_from'] > $d2['line_from'] ? 1 : -1;
|
||||
return $d1->line_from > $d2->line_from ? 1 : -1;
|
||||
}
|
||||
|
||||
return $d1['file_path'] > $d2['file_path'] ? 1 : -1;
|
||||
return $d1->file_path > $d2->file_path ? 1 : -1;
|
||||
}
|
||||
);
|
||||
self::$issues_data[$file_path] = $file_issues;
|
||||
@ -471,26 +460,26 @@ class IssueBuffer
|
||||
// Set severity for issues in baseline to INFO
|
||||
foreach (self::$issues_data as $file_path => $file_issues) {
|
||||
foreach ($file_issues as $key => $issue_data) {
|
||||
$file = $issue_data['file_name'];
|
||||
$file = $issue_data->file_name;
|
||||
$file = str_replace('\\', '/', $file);
|
||||
$type = $issue_data['type'];
|
||||
$type = $issue_data->type;
|
||||
|
||||
if (isset($issue_baseline[$file][$type]) && $issue_baseline[$file][$type]['o'] > 0) {
|
||||
if ($issue_baseline[$file][$type]['o'] === count($issue_baseline[$file][$type]['s'])) {
|
||||
$position = array_search(
|
||||
$issue_data['selected_text'],
|
||||
$issue_data->selected_text,
|
||||
$issue_baseline[$file][$type]['s'],
|
||||
true
|
||||
);
|
||||
|
||||
if ($position !== false) {
|
||||
$issue_data['severity'] = Config::REPORT_INFO;
|
||||
$issue_data->severity = Config::REPORT_INFO;
|
||||
array_splice($issue_baseline[$file][$type]['s'], $position, 1);
|
||||
$issue_baseline[$file][$type]['o'] = $issue_baseline[$file][$type]['o'] - 1;
|
||||
}
|
||||
} else {
|
||||
$issue_baseline[$file][$type]['s'] = [];
|
||||
$issue_data['severity'] = Config::REPORT_INFO;
|
||||
$issue_data->severity = Config::REPORT_INFO;
|
||||
$issue_baseline[$file][$type]['o'] = $issue_baseline[$file][$type]['o'] - 1;
|
||||
}
|
||||
}
|
||||
@ -509,7 +498,7 @@ class IssueBuffer
|
||||
|
||||
foreach (self::$issues_data as $file_issues) {
|
||||
foreach ($file_issues as $issue_data) {
|
||||
if ($issue_data['severity'] === Config::REPORT_ERROR) {
|
||||
if ($issue_data->severity === Config::REPORT_ERROR) {
|
||||
++$error_count;
|
||||
} else {
|
||||
++$info_count;
|
||||
@ -735,9 +724,7 @@ class IssueBuffer
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<array{severity: string, line_from: int, line_to: int, type: string, message: string,
|
||||
* file_name: string, file_path: string, snippet: string, from: int, to: int, snippet_from: int, snippet_to: int,
|
||||
* column_from: int, column_to: int}>>
|
||||
* @return array<string, list<IssueData>>
|
||||
*/
|
||||
public static function clear()
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace Psalm\Plugin\Hook;
|
||||
|
||||
use Psalm\Internal\Analyzer\IssueData;
|
||||
use Psalm\Codebase;
|
||||
use Psalm\SourceControl\SourceControlInfo;
|
||||
|
||||
@ -9,9 +10,7 @@ interface AfterAnalysisInterface
|
||||
/**
|
||||
* Called after analysis is complete
|
||||
*
|
||||
* @param array<string, list<array{severity: string, line_from: int, line_to: int, type: string, message: string,
|
||||
* file_name: string, file_path: string, snippet: string, from: int, to: int,
|
||||
* snippet_from: int, snippet_to: int, column_from: int, column_to: int, selected_text: string}>> $issues
|
||||
* @param array<string, list<IssueData>> $issues
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
@ -19,6 +19,7 @@ use function parse_url;
|
||||
use const PHP_EOL;
|
||||
use const PHP_URL_SCHEME;
|
||||
use Psalm\Codebase;
|
||||
use Psalm\Internal\Analyzer\IssueData;
|
||||
use Psalm\SourceControl\SourceControlInfo;
|
||||
use const STDERR;
|
||||
use function strlen;
|
||||
@ -32,9 +33,7 @@ class Shepherd implements \Psalm\Plugin\Hook\AfterAnalysisInterface
|
||||
/**
|
||||
* Called after analysis is complete
|
||||
*
|
||||
* @param array<string, list<array{severity: string, line_from: int, line_to: int, type: string, message: string,
|
||||
* file_name: string, file_path: string, snippet: string, from: int, to: int,
|
||||
* snippet_from: int, snippet_to: int, column_from: int, column_to: int, selected_text: string}>> $issues
|
||||
* @param array<string, list<IssueData>> $issues
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@ -61,11 +60,8 @@ class Shepherd implements \Psalm\Plugin\Hook\AfterAnalysisInterface
|
||||
if ($build_info) {
|
||||
$normalized_data = $issues === [] ? [] : array_filter(
|
||||
array_merge(...array_values($issues)),
|
||||
/**
|
||||
* @param array{severity: string} $i
|
||||
*/
|
||||
static function (array $i) : bool {
|
||||
return $i['severity'] === 'error';
|
||||
static function (IssueData $i) : bool {
|
||||
return $i->severity === 'error';
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
namespace Psalm;
|
||||
|
||||
use function array_filter;
|
||||
use Psalm\Internal\Analyzer\IssueData;
|
||||
|
||||
abstract class Report
|
||||
{
|
||||
@ -34,9 +35,7 @@ abstract class Report
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array<int, array{severity: string, line_from: int, line_to: int, type: string, message: string,
|
||||
* file_name: string, file_path: string, snippet: string, from: int, to: int,
|
||||
* snippet_from: int, snippet_to: int, column_from: int, column_to: int, selected_text: string}>
|
||||
* @var array<int, IssueData>
|
||||
*/
|
||||
protected $issues_data;
|
||||
|
||||
@ -59,9 +58,7 @@ abstract class Report
|
||||
protected $total_expression_count;
|
||||
|
||||
/**
|
||||
* @param array<int, array{severity: string, line_from: int, line_to: int, type: string, message: string,
|
||||
* file_name: string, file_path: string, snippet: string, from: int, to: int,
|
||||
* snippet_from: int, snippet_to: int, column_from: int, column_to: int, selected_text: string}> $issues_data
|
||||
* @param array<int, IssueData> $issues_data
|
||||
* @param array<string, int> $fixable_issue_counts
|
||||
* @param bool $use_color
|
||||
* @param bool $show_snippet
|
||||
@ -77,11 +74,8 @@ abstract class Report
|
||||
if (!$report_options->show_info) {
|
||||
$this->issues_data = array_filter(
|
||||
$issues_data,
|
||||
/**
|
||||
* @param array{severity: string} $issue_data
|
||||
*/
|
||||
function (array $issue_data) : bool {
|
||||
return $issue_data['severity'] !== Config::REPORT_INFO;
|
||||
function ($issue_data) : bool {
|
||||
return $issue_data->severity !== Config::REPORT_INFO;
|
||||
}
|
||||
);
|
||||
} else {
|
||||
|
@ -19,16 +19,16 @@ class CheckstyleReport extends Report
|
||||
foreach ($this->issues_data as $issue_data) {
|
||||
$message = sprintf(
|
||||
'%s: %s',
|
||||
$issue_data['type'],
|
||||
$issue_data['message']
|
||||
$issue_data->type,
|
||||
$issue_data->message
|
||||
);
|
||||
|
||||
$output .= '<file name="' . htmlspecialchars($issue_data['file_name']) . '">' . "\n";
|
||||
$output .= '<file name="' . htmlspecialchars($issue_data->file_name) . '">' . "\n";
|
||||
$output .= ' ';
|
||||
$output .= '<error';
|
||||
$output .= ' line="' . $issue_data['line_from'] . '"';
|
||||
$output .= ' column="' . $issue_data['column_from'] . '"';
|
||||
$output .= ' severity="' . $issue_data['severity'] . '"';
|
||||
$output .= ' line="' . $issue_data->line_from . '"';
|
||||
$output .= ' column="' . $issue_data->column_from . '"';
|
||||
$output .= ' severity="' . $issue_data->severity . '"';
|
||||
$output .= ' message="' . htmlspecialchars($message) . '"';
|
||||
$output .= '/>' . "\n";
|
||||
$output .= '</file>' . "\n";
|
||||
|
@ -32,44 +32,44 @@ class CompactReport extends Report
|
||||
|
||||
$output = [];
|
||||
foreach ($this->issues_data as $i => $issue_data) {
|
||||
if (!$this->show_info && $issue_data['severity'] === Config::REPORT_INFO) {
|
||||
if (!$this->show_info && $issue_data->severity === Config::REPORT_INFO) {
|
||||
continue;
|
||||
} elseif (is_null($current_file) || $current_file !== $issue_data['file_name']) {
|
||||
} elseif (is_null($current_file) || $current_file !== $issue_data->file_name) {
|
||||
// If we're processing a new file, then wrap up the last table and render it out.
|
||||
if ($buffer !== null) {
|
||||
$table->render();
|
||||
$output[] = $buffer->fetch();
|
||||
}
|
||||
|
||||
$output[] = 'FILE: ' . $issue_data['file_name'] . "\n";
|
||||
$output[] = 'FILE: ' . $issue_data->file_name . "\n";
|
||||
|
||||
$buffer = new BufferedOutput();
|
||||
$table = new Table($buffer);
|
||||
$table->setHeaders(['SEVERITY', 'LINE', 'ISSUE', 'DESCRIPTION']);
|
||||
}
|
||||
|
||||
$is_error = $issue_data['severity'] === Config::REPORT_ERROR;
|
||||
$is_error = $issue_data->severity === Config::REPORT_ERROR;
|
||||
if ($is_error) {
|
||||
$severity = ($this->use_color ? "\e[0;31mERROR\e[0m" : 'ERROR');
|
||||
} else {
|
||||
$severity = strtoupper($issue_data['severity']);
|
||||
$severity = strtoupper($issue_data->severity);
|
||||
}
|
||||
|
||||
// Since `Table::setColumnMaxWidth` is only available in symfony/console 4.2+ we need do something similar
|
||||
// so we have clean tables.
|
||||
$message = $issue_data['message'];
|
||||
$message = $issue_data->message;
|
||||
if (strlen($message) > 70) {
|
||||
$message = implode("\n", str_split($message, 70));
|
||||
}
|
||||
|
||||
$table->addRow([
|
||||
$severity,
|
||||
$issue_data['line_from'],
|
||||
$issue_data['type'],
|
||||
$issue_data->line_from,
|
||||
$issue_data->type,
|
||||
$message,
|
||||
]);
|
||||
|
||||
$current_file = $issue_data['file_name'];
|
||||
$current_file = $issue_data->file_name;
|
||||
|
||||
// If we're at the end of the issue sets, then wrap up the last table and render it out.
|
||||
if ($i === count($this->issues_data) - 1) {
|
||||
|
@ -20,18 +20,11 @@ class ConsoleReport extends Report
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{severity: string, line_from: int, line_to: int, type: string, message: string,
|
||||
* file_name: string, file_path: string, snippet: string, from: int, to: int,
|
||||
* snippet_from: int, snippet_to: int, column_from: int, column_to: int} $issue_data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function format(array $issue_data): string
|
||||
private function format(\Psalm\Internal\Analyzer\IssueData $issue_data): string
|
||||
{
|
||||
$issue_string = '';
|
||||
|
||||
$is_error = $issue_data['severity'] === Config::REPORT_ERROR;
|
||||
$is_error = $issue_data->severity === Config::REPORT_ERROR;
|
||||
|
||||
if ($is_error) {
|
||||
$issue_string .= ($this->use_color ? "\e[0;31mERROR\e[0m" : 'ERROR');
|
||||
@ -39,17 +32,17 @@ class ConsoleReport extends Report
|
||||
$issue_string .= 'INFO';
|
||||
}
|
||||
|
||||
$issue_string .= ': ' . $issue_data['type'] . ' - ' . $issue_data['file_name'] . ':' .
|
||||
$issue_data['line_from'] . ':' . $issue_data['column_from'] . ' - ' . $issue_data['message'] . "\n";
|
||||
$issue_string .= ': ' . $issue_data->type . ' - ' . $issue_data->file_name . ':' .
|
||||
$issue_data->line_from . ':' . $issue_data->column_from . ' - ' . $issue_data->message . "\n";
|
||||
|
||||
if ($this->show_snippet) {
|
||||
$snippet = $issue_data['snippet'];
|
||||
$snippet = $issue_data->snippet;
|
||||
|
||||
if (!$this->use_color) {
|
||||
$issue_string .= $snippet;
|
||||
} else {
|
||||
$selection_start = $issue_data['from'] - $issue_data['snippet_from'];
|
||||
$selection_length = $issue_data['to'] - $issue_data['from'];
|
||||
$selection_start = $issue_data->from - $issue_data->snippet_from;
|
||||
$selection_length = $issue_data->to - $issue_data->from;
|
||||
|
||||
$issue_string .= substr($snippet, 0, $selection_start)
|
||||
. ($is_error ? "\e[97;41m" : "\e[30;47m") . substr($snippet, $selection_start, $selection_length)
|
||||
|
@ -16,11 +16,11 @@ class EmacsReport extends Report
|
||||
foreach ($this->issues_data as $issue_data) {
|
||||
$output .= sprintf(
|
||||
'%s:%s:%s:%s - %s',
|
||||
$issue_data['file_path'],
|
||||
$issue_data['line_from'],
|
||||
$issue_data['column_from'],
|
||||
($issue_data['severity'] === Config::REPORT_ERROR ? 'error' : 'warning'),
|
||||
$issue_data['message']
|
||||
$issue_data->file_path,
|
||||
$issue_data->line_from,
|
||||
$issue_data->column_from,
|
||||
($issue_data->severity === Config::REPORT_ERROR ? 'error' : 'warning'),
|
||||
$issue_data->message
|
||||
) . "\n";
|
||||
}
|
||||
|
||||
|
@ -16,11 +16,11 @@ class GithubActionsReport extends Report
|
||||
foreach ($this->issues_data as $issue_data) {
|
||||
$output .= sprintf(
|
||||
'::%s file=%s,line=%s,col=%s::%s',
|
||||
($issue_data['severity'] === Config::REPORT_ERROR ? 'error' : 'warning'),
|
||||
$issue_data['file_name'],
|
||||
$issue_data['line_from'],
|
||||
$issue_data['column_from'],
|
||||
$issue_data['message']
|
||||
($issue_data->severity === Config::REPORT_ERROR ? 'error' : 'warning'),
|
||||
$issue_data->file_name,
|
||||
$issue_data->line_from,
|
||||
$issue_data->column_from,
|
||||
$issue_data->message
|
||||
) . "\n";
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ class JsonSummaryReport extends Report
|
||||
$type_counts = [];
|
||||
|
||||
foreach ($this->issues_data as $issue_data) {
|
||||
$type = $issue_data['type'];
|
||||
$type = $issue_data->type;
|
||||
|
||||
if (!isset($type_counts[$type])) {
|
||||
$type_counts[$type] = 0;
|
||||
|
@ -30,8 +30,8 @@ class JunitReport extends Report
|
||||
$ndata = [];
|
||||
|
||||
foreach ($this->issues_data as $error) {
|
||||
$is_error = $error['severity'] === Config::REPORT_ERROR;
|
||||
$is_warning = $error['severity'] === Config::REPORT_INFO;
|
||||
$is_error = $error->severity === Config::REPORT_ERROR;
|
||||
$is_warning = $error->severity === Config::REPORT_INFO;
|
||||
|
||||
if ($is_error) {
|
||||
$errors++;
|
||||
@ -44,7 +44,7 @@ class JunitReport extends Report
|
||||
|
||||
$tests++;
|
||||
|
||||
$fname = $error['file_name'];
|
||||
$fname = $error->file_name;
|
||||
|
||||
if (!isset($ndata[$fname])) {
|
||||
$ndata[$fname] = [
|
||||
@ -160,16 +160,6 @@ class JunitReport extends Report
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{
|
||||
* line_from: int,
|
||||
* type: string,
|
||||
* message: string,
|
||||
* selected_text: string,
|
||||
* snippet: string,
|
||||
* column_from: int,
|
||||
* column_to: int
|
||||
* } $issue_data
|
||||
*
|
||||
* @return array{
|
||||
* data: array{
|
||||
* column_from: int,
|
||||
@ -183,18 +173,18 @@ class JunitReport extends Report
|
||||
* type: string
|
||||
* }
|
||||
*/
|
||||
private function createFailure(array $issue_data) : array
|
||||
private function createFailure(\Psalm\Internal\Analyzer\IssueData $issue_data) : array
|
||||
{
|
||||
return [
|
||||
'type' => $issue_data['type'],
|
||||
'type' => $issue_data->type,
|
||||
'data' => [
|
||||
'message' => $issue_data['message'],
|
||||
'type' => $issue_data['type'],
|
||||
'snippet' => $issue_data['snippet'],
|
||||
'selected_text' => $issue_data['selected_text'],
|
||||
'line' => $issue_data['line_from'],
|
||||
'column_from' => $issue_data['column_from'],
|
||||
'column_to' => $issue_data['column_to'],
|
||||
'message' => $issue_data->message,
|
||||
'type' => $issue_data->type,
|
||||
'snippet' => $issue_data->snippet,
|
||||
'selected_text' => $issue_data->selected_text,
|
||||
'line' => $issue_data->line_from,
|
||||
'column_from' => $issue_data->column_from,
|
||||
'column_to' => $issue_data->column_to,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
@ -21,21 +21,17 @@ class PylintReport extends Report
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{severity: string, line_from: int, line_to: int, type: string, message: string,
|
||||
* file_name: string, file_path: string, snippet: string, from: int, to: int,
|
||||
* snippet_from: int, snippet_to: int, column_from: int, column_to: int} $issue_data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function format(array $issue_data): string
|
||||
private function format(\Psalm\Internal\Analyzer\IssueData $issue_data): string
|
||||
{
|
||||
$message = sprintf(
|
||||
'%s: %s',
|
||||
$issue_data['type'],
|
||||
$issue_data['message']
|
||||
$issue_data->type,
|
||||
$issue_data->message
|
||||
);
|
||||
|
||||
if ($issue_data['severity'] === Config::REPORT_ERROR) {
|
||||
if ($issue_data->severity === Config::REPORT_ERROR) {
|
||||
$code = 'E0001';
|
||||
} else {
|
||||
$code = 'W0001';
|
||||
@ -44,11 +40,11 @@ class PylintReport extends Report
|
||||
// https://docs.pylint.org/en/1.6.0/output.html doesn't mention what to do about 'column',
|
||||
// but it's still useful for users.
|
||||
// E.g. jenkins can't parse %s:%d:%d.
|
||||
$message = sprintf('%s (column %d)', $message, $issue_data['column_from']);
|
||||
$message = sprintf('%s (column %d)', $message, $issue_data->column_from);
|
||||
$issue_string = sprintf(
|
||||
'%s:%d: [%s] %s',
|
||||
$issue_data['file_name'],
|
||||
$issue_data['line_from'],
|
||||
$issue_data->file_name,
|
||||
$issue_data->line_from,
|
||||
$code,
|
||||
$message
|
||||
);
|
||||
|
@ -24,20 +24,20 @@ class SonarqubeReport extends Report
|
||||
foreach ($this->issues_data as $issue_data) {
|
||||
$report['issues'][] = [
|
||||
'engineId' => 'Psalm',
|
||||
'ruleId' => $issue_data['type'],
|
||||
'ruleId' => $issue_data->type,
|
||||
'primaryLocation' => [
|
||||
'message' => $issue_data['message'],
|
||||
'filePath' => $issue_data['file_name'],
|
||||
'message' => $issue_data->message,
|
||||
'filePath' => $issue_data->file_name,
|
||||
'textRange' => [
|
||||
'startLine' => $issue_data['line_from'],
|
||||
'endLine' => $issue_data['line_to'],
|
||||
'startLine' => $issue_data->line_from,
|
||||
'endLine' => $issue_data->line_to,
|
||||
// Columns in external issue reports are indexed from 0
|
||||
'startColumn' => max(0, $issue_data['column_from'] - 1),
|
||||
'endColumn' => max(0, $issue_data['column_to'] - 1),
|
||||
'startColumn' => max(0, $issue_data->column_from - 1),
|
||||
'endColumn' => max(0, $issue_data->column_to - 1),
|
||||
],
|
||||
],
|
||||
'type' => 'CODE_SMELL',
|
||||
'severity' => $issue_data['severity'] == Config::REPORT_ERROR ? 'CRITICAL' : 'MINOR',
|
||||
'severity' => $issue_data->severity == Config::REPORT_ERROR ? 'CRITICAL' : 'MINOR',
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -16,12 +16,12 @@ class TextReport extends Report
|
||||
foreach ($this->issues_data as $issue_data) {
|
||||
$output .= sprintf(
|
||||
'%s:%s:%s:%s - %s: %s',
|
||||
$issue_data['file_path'],
|
||||
$issue_data['line_from'],
|
||||
$issue_data['column_from'],
|
||||
($issue_data['severity'] === Config::REPORT_ERROR ? 'error' : 'warning'),
|
||||
$issue_data['type'],
|
||||
$issue_data['message']
|
||||
$issue_data->file_path,
|
||||
$issue_data->line_from,
|
||||
$issue_data->column_from,
|
||||
($issue_data->severity === Config::REPORT_ERROR ? 'error' : 'warning'),
|
||||
$issue_data->type,
|
||||
$issue_data->message
|
||||
) . "\n";
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
namespace Psalm\Test\Config\Plugin\Hook;
|
||||
|
||||
use Psalm\Codebase;
|
||||
use Psalm\Internal\Analyzer\IssueData;
|
||||
use Psalm\Plugin\Hook\{
|
||||
AfterAnalysisInterface
|
||||
};
|
||||
@ -14,9 +15,7 @@ class AfterAnalysis implements
|
||||
/**
|
||||
* Called after analysis is complete
|
||||
*
|
||||
* @param array<string, list<array{severity: string, line_from: int, line_to: int, type: string, message: string,
|
||||
* file_name: string, file_path: string, snippet: string, from: int, to: int,
|
||||
* snippet_from: int, snippet_to: int, column_from: int, column_to: int, selected_text: string}>> $issues
|
||||
* @param array<string, list<IssueData>> $issues
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
@ -141,62 +141,144 @@ class ErrorBaselineTest extends TestCase
|
||||
$baselineFile,
|
||||
[
|
||||
'sample/sample-file.php' => [
|
||||
[
|
||||
'file_name' => 'sample/sample-file.php',
|
||||
'type' => 'MixedAssignment',
|
||||
'severity' => 'error',
|
||||
'selected_text' => 'foo',
|
||||
],
|
||||
[
|
||||
'file_name' => 'sample\sample-file.php',
|
||||
'type' => 'MixedAssignment',
|
||||
'severity' => 'error',
|
||||
'selected_text' => 'bar',
|
||||
],
|
||||
[
|
||||
'file_name' => 'sample/sample-file.php',
|
||||
'type' => 'MixedAssignment',
|
||||
'severity' => 'error',
|
||||
'selected_text' => 'bat',
|
||||
],
|
||||
[
|
||||
'file_name' => 'sample\sample-file.php',
|
||||
'type' => 'MixedOperand',
|
||||
'severity' => 'error',
|
||||
'selected_text' => 'bing',
|
||||
],
|
||||
[
|
||||
'file_name' => 'sample/sample-file.php',
|
||||
'type' => 'AssignmentToVoid',
|
||||
'severity' => 'info',
|
||||
'selected_text' => 'bong',
|
||||
],
|
||||
[
|
||||
'file_name' => 'sample\sample-file.php',
|
||||
'type' => 'CircularReference',
|
||||
'severity' => 'suppress',
|
||||
'selected_text' => 'birdy',
|
||||
],
|
||||
new \Psalm\Internal\Analyzer\IssueData(
|
||||
'error',
|
||||
0,
|
||||
0,
|
||||
'MixedAssignment',
|
||||
'Message',
|
||||
'sample/sample-file.php',
|
||||
'sample/sample-file.php',
|
||||
'foo',
|
||||
'foo',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
new \Psalm\Internal\Analyzer\IssueData(
|
||||
'error',
|
||||
0,
|
||||
0,
|
||||
'MixedAssignment',
|
||||
'Message',
|
||||
'sample/sample-file.php',
|
||||
'sample/sample-file.php',
|
||||
'bar',
|
||||
'bar',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
new \Psalm\Internal\Analyzer\IssueData(
|
||||
'error',
|
||||
0,
|
||||
0,
|
||||
'MixedAssignment',
|
||||
'Message',
|
||||
'sample/sample-file.php',
|
||||
'sample/sample-file.php',
|
||||
'bat',
|
||||
'bat',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
new \Psalm\Internal\Analyzer\IssueData(
|
||||
'error',
|
||||
0,
|
||||
0,
|
||||
'MixedOperand',
|
||||
'Message',
|
||||
'sample/sample-file.php',
|
||||
'sample/sample-file.php',
|
||||
'bing',
|
||||
'bing',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
new \Psalm\Internal\Analyzer\IssueData(
|
||||
'info',
|
||||
0,
|
||||
0,
|
||||
'AssignmentToVoid',
|
||||
'Message',
|
||||
'sample/sample-file.php',
|
||||
'sample/sample-file.php',
|
||||
'bong',
|
||||
'bong',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
],
|
||||
'sample/sample-file2.php' => [
|
||||
[
|
||||
'file_name' => 'sample/sample-file2.php',
|
||||
'type' => 'MixedAssignment',
|
||||
'severity' => 'error',
|
||||
'selected_text' => 'boardy',
|
||||
],
|
||||
[
|
||||
'file_name' => 'sample\sample-file2.php',
|
||||
'type' => 'MixedAssignment',
|
||||
'severity' => 'error',
|
||||
'selected_text' => 'bardy',
|
||||
],
|
||||
[
|
||||
'file_name' => 'sample/sample-file2.php',
|
||||
'type' => 'TypeCoercion',
|
||||
'severity' => 'error',
|
||||
'selected_text' => 'hardy' . "\n",
|
||||
],
|
||||
new \Psalm\Internal\Analyzer\IssueData(
|
||||
'error',
|
||||
0,
|
||||
0,
|
||||
'MixedAssignment',
|
||||
'Message',
|
||||
'sample/sample-file2.php',
|
||||
'sample/sample-file2.php',
|
||||
'boardy',
|
||||
'boardy',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
new \Psalm\Internal\Analyzer\IssueData(
|
||||
'error',
|
||||
0,
|
||||
0,
|
||||
'MixedAssignment',
|
||||
'Message',
|
||||
'sample/sample-file2.php',
|
||||
'sample/sample-file2.php',
|
||||
'bardy',
|
||||
'bardy',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
new \Psalm\Internal\Analyzer\IssueData(
|
||||
'error',
|
||||
0,
|
||||
0,
|
||||
'TypeCoercion',
|
||||
'Message',
|
||||
'sample/sample-file2.php',
|
||||
'sample/sample-file2.php',
|
||||
'hardy' . "\n",
|
||||
'hardy' . "\n",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
],
|
||||
],
|
||||
false
|
||||
@ -260,38 +342,93 @@ class ErrorBaselineTest extends TestCase
|
||||
|
||||
$newIssues = [
|
||||
'sample/sample-file.php' => [
|
||||
[
|
||||
'file_name' => 'sample/sample-file.php',
|
||||
'type' => 'MixedAssignment',
|
||||
'severity' => 'error',
|
||||
'selected_text' => 'foo',
|
||||
],
|
||||
[
|
||||
'file_name' => 'sample/sample-file.php',
|
||||
'type' => 'MixedAssignment',
|
||||
'severity' => 'error',
|
||||
'selected_text' => 'bar',
|
||||
],
|
||||
[
|
||||
'file_name' => 'sample/sample-file.php',
|
||||
'type' => 'MixedOperand',
|
||||
'severity' => 'error',
|
||||
'selected_text' => 'bat',
|
||||
],
|
||||
[
|
||||
'file_name' => 'sample/sample-file.php',
|
||||
'type' => 'MixedOperand',
|
||||
'severity' => 'error',
|
||||
'selected_text' => 'bam',
|
||||
],
|
||||
new \Psalm\Internal\Analyzer\IssueData(
|
||||
'error',
|
||||
0,
|
||||
0,
|
||||
'MixedAssignment',
|
||||
'Message',
|
||||
'sample/sample-file.php',
|
||||
'sample/sample-file.php',
|
||||
'foo',
|
||||
'foo',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
new \Psalm\Internal\Analyzer\IssueData(
|
||||
'error',
|
||||
0,
|
||||
0,
|
||||
'MixedAssignment',
|
||||
'Message',
|
||||
'sample/sample-file.php',
|
||||
'sample/sample-file.php',
|
||||
'bar',
|
||||
'bar',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
new \Psalm\Internal\Analyzer\IssueData(
|
||||
'error',
|
||||
0,
|
||||
0,
|
||||
'MixedOperand',
|
||||
'Message',
|
||||
'sample/sample-file.php',
|
||||
'sample/sample-file.php',
|
||||
'bat',
|
||||
'bat',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
new \Psalm\Internal\Analyzer\IssueData(
|
||||
'error',
|
||||
0,
|
||||
0,
|
||||
'MixedOperand',
|
||||
'Message',
|
||||
'sample/sample-file.php',
|
||||
'sample/sample-file.php',
|
||||
'bam',
|
||||
'bam',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
],
|
||||
'sample/sample-file2.php' => [
|
||||
[
|
||||
'file_name' => 'sample/sample-file2.php',
|
||||
'type' => 'TypeCoercion',
|
||||
'severity' => 'error',
|
||||
'selected_text' => 'tar',
|
||||
],
|
||||
new \Psalm\Internal\Analyzer\IssueData(
|
||||
'error',
|
||||
0,
|
||||
0,
|
||||
'TypeCoercion',
|
||||
'Message',
|
||||
'sample/sample-file2.php',
|
||||
'sample/sample-file2.php',
|
||||
'tar',
|
||||
'tar',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
],
|
||||
];
|
||||
|
||||
|
@ -92,7 +92,7 @@ class TemporaryUpdateTest extends \Psalm\Tests\TestCase
|
||||
|
||||
foreach ($data as $file_issues) {
|
||||
foreach ($file_issues as $issue_data) {
|
||||
$found_positions[] = $issue_data['from'];
|
||||
$found_positions[] = $issue_data->from;
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,7 +118,7 @@ class TemporaryUpdateTest extends \Psalm\Tests\TestCase
|
||||
|
||||
foreach ($data as $file_issues) {
|
||||
foreach ($file_issues as $issue_data) {
|
||||
$found_positions[] = $issue_data['from'];
|
||||
$found_positions[] = $issue_data->from;
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,7 +146,7 @@ class TemporaryUpdateTest extends \Psalm\Tests\TestCase
|
||||
|
||||
foreach ($data as $file_issues) {
|
||||
foreach ($file_issues as $issue_data) {
|
||||
$found_positions[] = $issue_data['from'];
|
||||
$found_positions[] = $issue_data->from;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,42 +20,42 @@ class IssueBufferTest extends TestCase
|
||||
IssueBuffer::clear();
|
||||
IssueBuffer::addIssues([
|
||||
'/path/one.php' => [
|
||||
[
|
||||
"severity" => "error",
|
||||
"type" => "MissingPropertyType",
|
||||
"message" => 'Message',
|
||||
"file_name" =>"one.php",
|
||||
"file_path" => "/path/one.php",
|
||||
"snippet" => "snippet-1",
|
||||
"selected_text" => "snippet-1",
|
||||
"from"=> 0,
|
||||
"to"=> 0,
|
||||
"snippet_from" => 0,
|
||||
"snippet_to" => 0,
|
||||
"column_from" => 0,
|
||||
"column_to" => 0,
|
||||
"line_from" => 0,
|
||||
"line_to" => 0,
|
||||
]
|
||||
new \Psalm\Internal\Analyzer\IssueData(
|
||||
"error",
|
||||
0,
|
||||
0,
|
||||
"MissingPropertyType",
|
||||
'Message',
|
||||
"one.php",
|
||||
"/path/one.php",
|
||||
"snippet-1",
|
||||
"snippet-1",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
],
|
||||
'/path/two.php' => [
|
||||
[
|
||||
"severity" => "error",
|
||||
"type" => "MissingPropertyType",
|
||||
"message" => 'Message',
|
||||
"file_name" =>"two.php",
|
||||
"file_path" => "/path/two.php",
|
||||
"snippet" => "snippet-2",
|
||||
"selected_text" => "snippet-2",
|
||||
"from"=> 0,
|
||||
"to"=> 0,
|
||||
"snippet_from" => 0,
|
||||
"snippet_to" => 0,
|
||||
"column_from" => 0,
|
||||
"column_to" => 0,
|
||||
"line_from" => 0,
|
||||
"line_to" => 0,
|
||||
]
|
||||
new \Psalm\Internal\Analyzer\IssueData(
|
||||
"error",
|
||||
0,
|
||||
0,
|
||||
"MissingPropertyType",
|
||||
'Message',
|
||||
"two.php",
|
||||
"/path/two.php",
|
||||
"snippet-2",
|
||||
"snippet-2",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
]
|
||||
]);
|
||||
$baseline = [
|
||||
|
@ -54,13 +54,13 @@ class JsonOutputTest extends TestCase
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
$issue_data = IssueBuffer::getIssuesData()['somefile.php'][0];
|
||||
|
||||
$this->assertSame('somefile.php', $issue_data['file_path']);
|
||||
$this->assertSame('error', $issue_data['severity']);
|
||||
$this->assertSame($message, $issue_data['message']);
|
||||
$this->assertSame($line_number, $issue_data['line_from']);
|
||||
$this->assertSame('somefile.php', $issue_data->file_path);
|
||||
$this->assertSame('error', $issue_data->severity);
|
||||
$this->assertSame($message, $issue_data->message);
|
||||
$this->assertSame($line_number, $issue_data->line_from);
|
||||
$this->assertSame(
|
||||
$error,
|
||||
substr($code, $issue_data['from'], $issue_data['to'] - $issue_data['from'])
|
||||
substr($code, $issue_data->from, $issue_data->to - $issue_data->from)
|
||||
);
|
||||
}
|
||||
|
||||
@ -184,7 +184,12 @@ echo $a;';
|
||||
'column_to' => 8,
|
||||
],
|
||||
],
|
||||
$issue_data
|
||||
\array_map(
|
||||
function ($d) {
|
||||
return (array) $d;
|
||||
},
|
||||
$issue_data
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -188,23 +188,23 @@ echo $a;';
|
||||
public function testFilteredJsonReportIsStillArray(): void
|
||||
{
|
||||
$issues_data = [
|
||||
22 => [
|
||||
'severity' => 'info',
|
||||
'line_from' => 15,
|
||||
'line_to' => 15,
|
||||
'type' => 'PossiblyUndefinedGlobalVariable',
|
||||
'message' => 'Possibly undefined global variable $a, first seen on line 10',
|
||||
'file_name' => 'somefile.php',
|
||||
'file_path' => 'somefile.php',
|
||||
'snippet' => 'echo $a',
|
||||
'selected_text' => '$a',
|
||||
'from' => 201,
|
||||
'to' => 203,
|
||||
'snippet_from' => 196,
|
||||
'snippet_to' => 203,
|
||||
'column_from' => 6,
|
||||
'column_to' => 8,
|
||||
],
|
||||
22 => new \Psalm\Internal\Analyzer\IssueData(
|
||||
'info',
|
||||
15,
|
||||
15,
|
||||
'PossiblyUndefinedGlobalVariable',
|
||||
'Possibly undefined global variable $a, first seen on line 10',
|
||||
'somefile.php',
|
||||
'somefile.php',
|
||||
'echo $a',
|
||||
'$a',
|
||||
201,
|
||||
203,
|
||||
196,
|
||||
203,
|
||||
6,
|
||||
8,
|
||||
),
|
||||
];
|
||||
|
||||
$report_options = ProjectAnalyzer::getFileReportOptions([__DIR__ . '/test-report.json'])[0];
|
||||
|
Loading…
x
Reference in New Issue
Block a user