1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Add end line/column data for LSP support

This commit is contained in:
Matthew Brown 2018-02-19 18:16:09 -05:00
parent 04a1583783
commit a99e89495b
6 changed files with 152 additions and 97 deletions

View File

@ -14,6 +14,9 @@ class CodeLocation
/** @var int */
private $line_number;
/** @var int */
private $end_line_number = -1;
/** @var int */
private $file_start;
@ -36,7 +39,10 @@ class CodeLocation
private $selection_end = -1;
/** @var int */
private $column = -1;
private $column_from = -1;
/** @var int */
private $column_to = -1;
/** @var string */
private $snippet = '';
@ -252,11 +258,17 @@ class CodeLocation
}
// reset preview start to beginning of line
$this->column = $this->selection_start -
$this->column_from = $this->selection_start -
(int)strrpos($file_contents, "\n", $this->selection_start - strlen($file_contents));
// reset preview start to beginning of line
$this->column_to = $this->selection_end -
(int)strrpos($file_contents, "\n", $this->selection_end - strlen($file_contents));
$this->snippet = substr($file_contents, $this->preview_start, $this->preview_end - $this->preview_start);
$this->text = substr($file_contents, $this->selection_start, $this->selection_end - $this->selection_start);
$this->end_line_number = $this->line_number + substr_count($this->snippet, "\n");
}
/**
@ -267,6 +279,16 @@ class CodeLocation
return $this->docblock_line_number ?: $this->line_number;
}
/**
* @return int
*/
public function getEndLineNumber()
{
$this->calculateRealLocation();
return $this->end_line_number;
}
/**
* @return string
*/
@ -294,7 +316,17 @@ class CodeLocation
{
$this->calculateRealLocation();
return $this->column;
return $this->column_from;
}
/**
* @return int
*/
public function getEndColumn()
{
$this->calculateRealLocation();
return $this->column_to;
}
/**

View File

@ -170,10 +170,10 @@ class Analyzer
// Wait for all tasks to complete and collect the results.
/**
* @var array<array{issues: array<int, array{severity: string, line_number: string, type: string,
* @var array<array{issues: 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: int}>, file_references: array<string, array<string,bool>>,
* mixed_counts: array<string, array{0: int, 1: int}>}>
* snippet_from: int, snippet_to: int, column_from: int, column_to: int}>, file_references: array<string,
* array<string,bool>>, mixed_counts: array<string, array{0: int, 1: int}>}>
*/
$forked_pool_data = $pool->wait();

View File

@ -82,9 +82,9 @@ abstract class CodeIssue
/**
* @param string $severity
*
* @return array{severity: string, line_number: int, type: string, message: string, file_name: string,
* @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: int}
* snippet_to: int, column_from: int, column_to: int}
*/
public function toArray($severity = Config::REPORT_ERROR)
{
@ -97,7 +97,8 @@ abstract class CodeIssue
return [
'severity' => $severity,
'line_number' => $location->getLineNumber(),
'line_from' => $location->getLineNumber(),
'line_to' => $location->getEndLineNumber(),
'type' => $issue_type,
'message' => $this->getMessage(),
'file_name' => $location->file_name,
@ -108,7 +109,8 @@ abstract class CodeIssue
'to' => $selection_bounds[1],
'snippet_from' => $snippet_bounds[0],
'snippet_to' => $snippet_bounds[1],
'column' => $location->getColumn(),
'column_from' => $location->getColumn(),
'column_to' => $location->getEndColumn(),
];
}
}

View File

@ -8,8 +8,9 @@ use Psalm\Issue\CodeIssue;
class IssueBuffer
{
/**
* @var array<int, array{severity: string, line_number: string, type: string, message: string, file_name: string,
* file_path: string, snippet: string, from: int, to: int, snippet_from: int, snippet_to: int, column: int}>
* @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}>
*/
protected static $issues_data = [];
@ -112,22 +113,22 @@ class IssueBuffer
}
/**
* @param array{severity: string, line_number: string, type: string, message: string, file_name: string,
* file_path: string, snippet: string, from: int, to: int, snippet_from: int, snippet_to: int,
* column: int} $issue_data
* @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
*/
protected static function getEmacsOutput(array $issue_data)
{
return $issue_data['file_path'] . ':' . $issue_data['line_number'] . ':' . $issue_data['column'] . ':' .
return $issue_data['file_path'] . ':' . $issue_data['line_from'] . ':' . $issue_data['column_from'] . ':' .
($issue_data['severity'] === Config::REPORT_ERROR ? 'error' : 'warning') . ' - ' . $issue_data['message'];
}
/**
* @param array{severity: string, line_number: string, type: string, message: string, file_name: string,
* @param array{severity: string, line_from: int, type: string, message: string, file_name: string,
* file_path: string, snippet: string, from: int, to: int, snippet_from: int, snippet_to: int,
* column: int} $issue_data
* column_from: int, column_to: int} $issue_data
* @param bool $use_color
*
* @return string
@ -145,7 +146,7 @@ class IssueBuffer
}
$issue_string .= ': ' . $issue_data['type'] . ' - ' . $issue_data['file_name'] . ':' .
$issue_data['line_number'] . ':' . $issue_data['column'] . ' - ' . $issue_data['message'] . PHP_EOL;
$issue_data['line_from'] . ':' . $issue_data['column_from'] . ' - ' . $issue_data['message'] . PHP_EOL;
$snippet = $issue_data['snippet'];
@ -164,8 +165,9 @@ class IssueBuffer
}
/**
* @return array<int, array{severity: string, line_number: string, type: string, message: string, file_name: string,
* file_path: string, snippet: string, from: int, to: int, snippet_from: int, snippet_to: int, column: int}>
* @return array<int, array{severity: string, line_from: 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}>
*/
public static function getIssuesData()
{
@ -173,9 +175,9 @@ class IssueBuffer
}
/**
* @param array<int, array{severity: string, line_number: string, type: string, message: string,
* @param array<int, array{severity: string, line_from: int, type: string, message: string,
* file_name: string, file_path: string, snippet: string, from: int, to: int, snippet_from: int,
* snippet_to: int, column: int}> $issues_data
* snippet_to: int, column_from: int, column_to: int}> $issues_data
*
* @return void
*/
@ -209,15 +211,15 @@ class IssueBuffer
/** @return int */
function (array $d1, array $d2) {
if ($d1['file_path'] === $d2['file_path']) {
if ($d1['line_number'] === $d2['line_number']) {
if ($d1['column'] === $d2['column']) {
if ($d1['line_from'] === $d2['line_from']) {
if ($d1['column_from'] === $d2['column_from']) {
return 0;
}
return $d1['column'] > $d2['column'] ? 1 : -1;
return $d1['column_from'] > $d2['column_from'] ? 1 : -1;
}
return $d1['line_number'] > $d2['line_number'] ? 1 : -1;
return $d1['line_from'] > $d2['line_from'] ? 1 : -1;
}
return $d1['file_path'] > $d2['file_path'] ? 1 : -1;

View File

@ -54,7 +54,7 @@ class JsonOutputTest extends TestCase
$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_number']);
$this->assertSame($line_number, $issue_data['line_from']);
$this->assertSame(
$error,
substr($code, $issue_data['from'], $issue_data['to'] - $issue_data['from'])
@ -96,7 +96,8 @@ echo $a;';
[
[
'severity' => 'error',
'line_number' => 7,
'line_from' => 7,
'line_to' => 7,
'type' => 'UndefinedConstant',
'message' => 'Const CHANGE_ME is not defined',
'file_name' => 'somefile.php',
@ -107,11 +108,13 @@ echo $a;';
'to' => 134,
'snippet_from' => 120,
'snippet_to' => 135,
'column' => 6,
'column_from' => 6,
'column_to' => 15
],
[
'severity' => 'error',
'line_number' => 15,
'line_from' => 15,
'line_to' => 15,
'type' => 'PossiblyUndefinedGlobalVariable',
'message' => 'Possibly undefined global variable $a, first seen on line 10',
'file_name' => 'somefile.php',
@ -122,11 +125,13 @@ echo $a;';
'to' => 203,
'snippet_from' => 196,
'snippet_to' => 203,
'column' => 6,
'column_from' => 6,
'column_to' => 8
],
[
'severity' => 'error',
'line_number' => 3,
'line_from' => 3,
'line_to' => 3,
'type' => 'UndefinedVariable',
'message' => 'Cannot find referenced variable $as_you',
'file_name' => 'somefile.php',
@ -137,11 +142,13 @@ echo $a;';
'to' => 73,
'snippet_from' => 57,
'snippet_to' => 83,
'column' => 10,
'column_from' => 10,
'column_to' => 17
],
[
'severity' => 'error',
'line_number' => 2,
'line_from' => 2,
'line_to' => 2,
'type' => 'UnusedParam',
'message' => 'Param $your_code is never referenced in this method',
'file_name' => 'somefile.php',
@ -152,11 +159,13 @@ echo $a;';
'to' => 44,
'snippet_from' => 6,
'snippet_to' => 56,
'column' => 29,
'column_from' => 29,
'column_to' => 39
],
[
'severity' => 'error',
'line_number' => 2,
'line_from' => 2,
'line_to' => 4,
'type' => 'MixedInferredReturnType',
'message' => 'Could not verify return type \'string|null\' for psalmCanVerify',
'file_name' => 'somefile.php',
@ -169,7 +178,8 @@ echo $a;';
'to' => 54,
'snippet_from' => 6,
'snippet_to' => 85,
'column' => 42,
'column_from' => 42,
'column_to' => 49
],
],
$issue_data

View File

@ -114,68 +114,77 @@ echo $a;';
$issue_data = [
[
'severity' => 'error',
'line_number' => 7,
'type' => 'UndefinedConstant',
'message' => 'Const CHANGE_ME is not defined',
'file_name' => 'somefile.php',
'file_path' => 'somefile.php',
'snippet' => 'echo CHANGE_ME;',
'selected_text' => 'CHANGE_ME',
'from' => 125,
'to' => 134,
'snippet_from' => 120,
'snippet_to' => 135,
'column' => 6,
],
[
'severity' => 'error',
'line_number' => 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' => 6,
],
[
'severity' => 'error',
'line_number' => 3,
'type' => 'UndefinedVariable',
'message' => 'Cannot find referenced variable $as_you',
'file_name' => 'somefile.php',
'file_path' => 'somefile.php',
'snippet' => ' return $as_you . "type";',
'selected_text' => '$as_you',
'from' => 66,
'to' => 73,
'snippet_from' => 57,
'snippet_to' => 83,
'column' => 10,
],
[
'severity' => 'error',
'line_number' => 2,
'type' => 'MixedInferredReturnType',
'message' => 'Could not verify return type \'string|null\' for psalmCanVerify',
'file_name' => 'somefile.php',
'file_path' => 'somefile.php',
'snippet' => 'function psalmCanVerify(int $your_code): ?string {
'severity' => 'error',
'line_from' => 7,
'line_to' => 7,
'type' => 'UndefinedConstant',
'message' => 'Const CHANGE_ME is not defined',
'file_name' => 'somefile.php',
'file_path' => 'somefile.php',
'snippet' => 'echo CHANGE_ME;',
'selected_text' => 'CHANGE_ME',
'from' => 125,
'to' => 134,
'snippet_from' => 120,
'snippet_to' => 135,
'column_from' => 6,
'column_to' => 15
],
[
'severity' => 'error',
'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
],
[
'severity' => 'error',
'line_from' => 3,
'line_to' => 3,
'type' => 'UndefinedVariable',
'message' => 'Cannot find referenced variable $as_you',
'file_name' => 'somefile.php',
'file_path' => 'somefile.php',
'snippet' => ' return $as_you . "type";',
'selected_text' => '$as_you',
'from' => 66,
'to' => 73,
'snippet_from' => 57,
'snippet_to' => 83,
'column_from' => 10,
'column_to' => 17
],
[
'severity' => 'error',
'line_from' => 2,
'line_to' => 4,
'type' => 'MixedInferredReturnType',
'message' => 'Could not verify return type \'string|null\' for psalmCanVerify',
'file_name' => 'somefile.php',
'file_path' => 'somefile.php',
'snippet' => 'function psalmCanVerify(int $your_code): ?string {
return $as_you . "type";
}',
'selected_text' => '?string',
'from' => 47,
'to' => 54,
'snippet_from' => 6,
'snippet_to' => 85,
'column' => 42,
],
'selected_text' => '?string',
'from' => 47,
'to' => 54,
'snippet_from' => 6,
'snippet_to' => 85,
'column_from' => 42,
'column_to' => 49
],
];
$emacs = 'somefile.php:7:6:error - Const CHANGE_ME is not defined
somefile.php:15:6:error - Possibly undefined global variable $a, first seen on line 10
somefile.php:3:10:error - Cannot find referenced variable $as_you