Improve DocBlockParser error handling
parent
7669ba9c21
commit
02e1a5b8f5
|
@ -3,9 +3,11 @@ declare(strict_types = 1);
|
|||
|
||||
namespace LanguageServer\NodeVisitor;
|
||||
|
||||
use PhpParser\{NodeVisitorAbstract, Node};
|
||||
use PhpParser;
|
||||
use PhpParser\{NodeVisitorAbstract, Node, Comment};
|
||||
use phpDocumentor\Reflection\DocBlockFactory;
|
||||
use phpDocumentor\Reflection\Types\Context;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Decorates all nodes with a docBlock attribute that is an instance of phpDocumentor\Reflection\DocBlock
|
||||
|
@ -31,6 +33,11 @@ class DocBlockParser extends NodeVisitorAbstract
|
|||
*/
|
||||
private $aliases;
|
||||
|
||||
/**
|
||||
* @var PhpParser\Error[]
|
||||
*/
|
||||
public $errors = [];
|
||||
|
||||
public function __construct(DocBlockFactory $docBlockFactory)
|
||||
{
|
||||
$this->docBlockFactory = $docBlockFactory;
|
||||
|
@ -54,8 +61,17 @@ class DocBlockParser extends NodeVisitorAbstract
|
|||
return;
|
||||
}
|
||||
$context = new Context($this->namespace, $this->aliases);
|
||||
$docBlock = $this->docBlockFactory->create($docComment->getText(), $context);
|
||||
$node->setAttribute('docBlock', $docBlock);
|
||||
try {
|
||||
$docBlock = $this->docBlockFactory->create($docComment->getText(), $context);
|
||||
$node->setAttribute('docBlock', $docBlock);
|
||||
} catch (Exception $e) {
|
||||
$this->errors[] = new PhpParser\Error($e->getMessage(), [
|
||||
'startFilePos' => $docComment->getFilePos(),
|
||||
'endFilePos' => $docComment->getFilePos() + strlen($docComment->getText()),
|
||||
'startLine' => $docComment->getLine(),
|
||||
'endLine' => $docComment->getLine() + preg_match_all('/[\\n\\r]/', $docComment->getText()) + 1
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function leaveNode(Node $node)
|
||||
|
|
|
@ -138,19 +138,8 @@ class PhpDocument
|
|||
|
||||
$diagnostics = [];
|
||||
foreach ($errors as $error) {
|
||||
$diagnostic = new Diagnostic();
|
||||
$startLine = max($error->getStartLine() - 1, 0);
|
||||
$startColumn = $error->hasColumnInfo() ? $error->getStartColumn($this->content) - 1 : 0;
|
||||
$endLine = max($error->getEndLine() - 1, $startLine);
|
||||
$endColumn = $error->hasColumnInfo() ? $error->getEndColumn($this->content) : 0;
|
||||
$diagnostic->range = new Range(new Position($startLine, $startColumn), new Position($endLine, $endColumn));
|
||||
$diagnostic->severity = DiagnosticSeverity::ERROR;
|
||||
$diagnostic->source = 'php';
|
||||
// Do not include "on line ..." in the error message
|
||||
$diagnostic->message = $error->getRawMessage();
|
||||
$diagnostics[] = $diagnostic;
|
||||
$diagnostics[] = Diagnostic::fromError($error, $this->content, DiagnosticSeverity::ERROR, 'php');
|
||||
}
|
||||
$this->client->textDocument->publishDiagnostics($this->uri, $diagnostics);
|
||||
|
||||
// $stmts can be null in case of a fatal parsing error
|
||||
if ($stmts) {
|
||||
|
@ -166,9 +155,16 @@ class PhpDocument
|
|||
$traverser->addVisitor(new ColumnCalculator($content));
|
||||
|
||||
// Parse docblocks and add docBlock attributes to nodes
|
||||
$traverser->addVisitor(new DocBlockParser($this->docBlockFactory));
|
||||
$docBlockParser = new DocBlockParser($this->docBlockFactory);
|
||||
$traverser->addVisitor($docBlockParser);
|
||||
|
||||
$traverser->traverse($stmts);
|
||||
|
||||
// Report errors from parsing docblocks
|
||||
foreach ($docBlockParser->errors as $error) {
|
||||
$diagnostics[] = Diagnostic::fromError($error, $this->content, DiagnosticSeverity::WARNING, 'php');
|
||||
}
|
||||
|
||||
$traverser = new NodeTraverser;
|
||||
|
||||
// Collect all definitions
|
||||
|
@ -195,6 +191,8 @@ class PhpDocument
|
|||
|
||||
$this->stmts = $stmts;
|
||||
}
|
||||
|
||||
$this->client->textDocument->publishDiagnostics($this->uri, $diagnostics);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace LanguageServer\Protocol;
|
||||
|
||||
use PhpParser\Error;
|
||||
|
||||
/**
|
||||
* Represents a diagnostic, such as a compiler error or warning. Diagnostic objects are only valid in the scope of a
|
||||
* resource.
|
||||
|
@ -44,4 +46,40 @@ class Diagnostic
|
|||
* @var string
|
||||
*/
|
||||
public $message;
|
||||
|
||||
/**
|
||||
* Creates a diagnostic from a PhpParser Error
|
||||
*
|
||||
* @param Error $error Message and code will be used
|
||||
* @param string $content The file content to calculate the column info
|
||||
* @param int $severity DiagnosticSeverity
|
||||
* @param string $source A human-readable string describing the source of this diagnostic
|
||||
* @return self
|
||||
*/
|
||||
public static function fromError(Error $error, string $content, int $severity = null, string $source = null): self
|
||||
{
|
||||
return new self(
|
||||
$error->getRawMessage(), // Do not include "on line ..." in the error message
|
||||
Range::fromError($error, $content),
|
||||
$error->getCode(),
|
||||
$severity,
|
||||
$source
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message The diagnostic's message
|
||||
* @param Range $range The range at which the message applies
|
||||
* @param int $code The diagnostic's code
|
||||
* @param int $severity DiagnosticSeverity
|
||||
* @param string $source A human-readable string describing the source of this diagnostic
|
||||
*/
|
||||
public function __construct(string $message = null, Range $range = null, int $code = null, int $severity = null, string $source = null)
|
||||
{
|
||||
$this->message = $message;
|
||||
$this->range = $range;
|
||||
$this->code = $code;
|
||||
$this->severity = $severity;
|
||||
$this->source = $source;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ class Hover
|
|||
/**
|
||||
* The hover's content
|
||||
*
|
||||
* @var string|MarkedString|(string|MarkedString)[]
|
||||
* @var string|MarkedString|string[]|MarkedString[]
|
||||
*/
|
||||
public $contents;
|
||||
|
||||
|
@ -22,7 +22,7 @@ class Hover
|
|||
public $range;
|
||||
|
||||
/**
|
||||
* @param string|MarkedString|(string|MarkedString)[] $contents The hover's content
|
||||
* @param string|MarkedString|string[]|MarkedString[] $contents The hover's content
|
||||
* @param Range $range An optional range
|
||||
*/
|
||||
public function __construct($contents = null, $range = null)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace LanguageServer\Protocol;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\{Error, Node};
|
||||
|
||||
/**
|
||||
* A range in a text document expressed as (zero-based) start and end positions.
|
||||
|
@ -37,6 +37,22 @@ class Range
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the range where an error occured
|
||||
*
|
||||
* @param \PhpParser\Error $error
|
||||
* @param string $content
|
||||
* @return self
|
||||
*/
|
||||
public static function fromError(Error $error, string $content)
|
||||
{
|
||||
$startLine = max($error->getStartLine() - 1, 0);
|
||||
$endLine = max($error->getEndLine() - 1, $startLine);
|
||||
$startColumn = $error->hasColumnInfo() ? $error->getStartColumn($content) - 1 : 0;
|
||||
$endColumn = $error->hasColumnInfo() ? $error->getEndColumn($content) : 0;
|
||||
return new self(new Position($startLine, $startColumn), new Position($endLine, $endColumn));
|
||||
}
|
||||
|
||||
public function __construct(Position $start = null, Position $end = null)
|
||||
{
|
||||
$this->start = $start;
|
||||
|
|
Loading…
Reference in New Issue