2016-06-10 00:08:25 +02:00
|
|
|
<?php
|
2016-07-26 00:37:44 +02:00
|
|
|
namespace Psalm\Issue;
|
2016-06-10 00:08:25 +02:00
|
|
|
|
2016-12-04 01:11:30 +01:00
|
|
|
use Psalm\CodeLocation;
|
|
|
|
|
2016-06-10 00:08:25 +02:00
|
|
|
abstract class CodeIssue
|
|
|
|
{
|
|
|
|
const CODE_EXCEPTION = 1;
|
|
|
|
|
2016-11-02 07:29:00 +01:00
|
|
|
/**
|
2016-12-04 01:11:30 +01:00
|
|
|
* @var CodeLocation
|
2016-11-02 07:29:00 +01:00
|
|
|
*/
|
2016-12-04 01:11:30 +01:00
|
|
|
protected $code_location;
|
2016-11-01 05:39:41 +01:00
|
|
|
|
2016-11-02 07:29:00 +01:00
|
|
|
/**
|
|
|
|
* @var string
|
|
|
|
*/
|
2016-06-10 00:08:25 +02:00
|
|
|
protected $message;
|
|
|
|
|
2016-11-01 05:39:41 +01:00
|
|
|
/**
|
2016-12-04 01:11:30 +01:00
|
|
|
* @param string $message
|
|
|
|
* @param CodeLocation $code_location
|
2016-11-01 05:39:41 +01:00
|
|
|
*/
|
2016-12-04 01:11:30 +01:00
|
|
|
public function __construct($message, CodeLocation $code_location)
|
2016-06-10 00:08:25 +02:00
|
|
|
{
|
2016-12-04 01:11:30 +01:00
|
|
|
$this->code_location = $code_location;
|
2016-06-10 00:08:25 +02:00
|
|
|
$this->message = $message;
|
|
|
|
}
|
|
|
|
|
2016-11-02 07:29:00 +01:00
|
|
|
/**
|
|
|
|
* @return int
|
|
|
|
*/
|
2016-06-10 00:08:25 +02:00
|
|
|
public function getLineNumber()
|
|
|
|
{
|
2016-12-04 01:11:30 +01:00
|
|
|
return $this->code_location->line_number;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return int[]
|
|
|
|
*/
|
|
|
|
public function getFileRange()
|
|
|
|
{
|
|
|
|
return [$this->code_location->file_start, $this->code_location->file_end];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getFilePath()
|
|
|
|
{
|
|
|
|
return $this->code_location->file_path;
|
2016-06-10 00:08:25 +02:00
|
|
|
}
|
|
|
|
|
2016-11-02 07:29:00 +01:00
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
2016-06-10 00:08:25 +02:00
|
|
|
public function getFileName()
|
|
|
|
{
|
2016-12-04 01:11:30 +01:00
|
|
|
return $this->code_location->file_name;
|
2016-06-10 00:08:25 +02:00
|
|
|
}
|
|
|
|
|
2016-11-02 07:29:00 +01:00
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
2016-06-10 00:08:25 +02:00
|
|
|
public function getMessage()
|
|
|
|
{
|
2016-12-04 01:11:30 +01:00
|
|
|
return $this->code_location->file_name . ':' . $this->code_location->line_number .' - ' . $this->message;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string
|
2016-12-06 22:33:47 +01:00
|
|
|
* @psalm-suppress MixedArrayAccess
|
2016-12-04 01:11:30 +01:00
|
|
|
*/
|
|
|
|
public function getFileSnippet()
|
|
|
|
{
|
2016-12-06 22:33:47 +01:00
|
|
|
$selection_start = $this->code_location->file_start;
|
|
|
|
$selection_end = $this->code_location->file_end;
|
|
|
|
|
2016-12-04 01:11:30 +01:00
|
|
|
$preview_start = $this->code_location->preview_start;
|
|
|
|
|
|
|
|
$file_contents = (string)file_get_contents($this->code_location->file_path);
|
|
|
|
|
2016-12-06 22:33:47 +01:00
|
|
|
$preview_end = (int)strpos(
|
|
|
|
$file_contents,
|
|
|
|
"\n",
|
|
|
|
$this->code_location->single_line ? $selection_start : $selection_end
|
|
|
|
);
|
|
|
|
|
|
|
|
if ($this->code_location->comment_line_number && $preview_start < $selection_start) {
|
2016-12-07 01:41:52 +01:00
|
|
|
$preview_lines = explode(
|
|
|
|
"\n",
|
|
|
|
substr($file_contents, $preview_start, $selection_start - $preview_start - 1)
|
|
|
|
);
|
2016-12-04 01:11:30 +01:00
|
|
|
|
|
|
|
$preview_offset = 0;
|
|
|
|
|
|
|
|
$i = 0;
|
|
|
|
|
2016-12-06 22:33:47 +01:00
|
|
|
$comment_line_offset = $this->code_location->comment_line_number - $this->code_location->line_number;
|
|
|
|
|
|
|
|
for ($i = 0; $i < $comment_line_offset; $i++) {
|
|
|
|
$preview_offset += strlen($preview_lines[$i]) + 1;
|
2016-12-04 01:11:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$preview_offset += (int)strpos($preview_lines[$i], '@');
|
|
|
|
|
2016-12-06 22:33:47 +01:00
|
|
|
$selection_start = $preview_offset + $preview_start;
|
|
|
|
$selection_end = (int)strpos($file_contents, "\n", $selection_start);
|
2016-12-07 01:41:52 +01:00
|
|
|
} elseif ($this->code_location->regex) {
|
2016-12-06 22:33:47 +01:00
|
|
|
$preview_snippet = substr($file_contents, $selection_start, $selection_end - $selection_start);
|
2016-12-04 01:11:30 +01:00
|
|
|
|
2016-12-06 22:33:47 +01:00
|
|
|
if (preg_match($this->code_location->regex, $preview_snippet, $matches, PREG_OFFSET_CAPTURE)) {
|
|
|
|
$selection_start = $selection_start + (int)$matches[1][1];
|
|
|
|
$selection_end = $selection_start + strlen((string)$matches[1][0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// reset preview start to beginning of line
|
|
|
|
$preview_start = (int)strrpos(
|
2016-12-04 01:11:30 +01:00
|
|
|
$file_contents,
|
|
|
|
"\n",
|
2016-12-06 22:33:47 +01:00
|
|
|
min($preview_start, $selection_start) - strlen($file_contents)
|
2016-12-04 01:11:30 +01:00
|
|
|
) + 1;
|
|
|
|
|
2016-12-06 22:33:47 +01:00
|
|
|
$code_line = substr($file_contents, $preview_start, $preview_end - $preview_start);
|
|
|
|
|
|
|
|
$code_line_error_start = $selection_start - $preview_start;
|
|
|
|
$code_line_error_length = $selection_end - $selection_start + 1;
|
2016-12-04 01:11:30 +01:00
|
|
|
return substr($code_line, 0, $code_line_error_start) .
|
|
|
|
"\e[97;41m" . substr($code_line, $code_line_error_start, $code_line_error_length) .
|
|
|
|
"\e[0m" . substr($code_line, $code_line_error_length + $code_line_error_start) . PHP_EOL;
|
2016-06-10 00:08:25 +02:00
|
|
|
}
|
|
|
|
}
|