1
0
Fork 0

Improve DocBlockParser error handling

pull/50/head
Felix Becker 2016-10-19 03:39:09 +02:00
parent 7669ba9c21
commit 02e1a5b8f5
5 changed files with 87 additions and 19 deletions

View File

@ -3,9 +3,11 @@ declare(strict_types = 1);
namespace LanguageServer\NodeVisitor; namespace LanguageServer\NodeVisitor;
use PhpParser\{NodeVisitorAbstract, Node}; use PhpParser;
use PhpParser\{NodeVisitorAbstract, Node, Comment};
use phpDocumentor\Reflection\DocBlockFactory; use phpDocumentor\Reflection\DocBlockFactory;
use phpDocumentor\Reflection\Types\Context; use phpDocumentor\Reflection\Types\Context;
use Exception;
/** /**
* Decorates all nodes with a docBlock attribute that is an instance of phpDocumentor\Reflection\DocBlock * 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; private $aliases;
/**
* @var PhpParser\Error[]
*/
public $errors = [];
public function __construct(DocBlockFactory $docBlockFactory) public function __construct(DocBlockFactory $docBlockFactory)
{ {
$this->docBlockFactory = $docBlockFactory; $this->docBlockFactory = $docBlockFactory;
@ -54,8 +61,17 @@ class DocBlockParser extends NodeVisitorAbstract
return; return;
} }
$context = new Context($this->namespace, $this->aliases); $context = new Context($this->namespace, $this->aliases);
$docBlock = $this->docBlockFactory->create($docComment->getText(), $context); try {
$node->setAttribute('docBlock', $docBlock); $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) public function leaveNode(Node $node)

View File

@ -138,19 +138,8 @@ class PhpDocument
$diagnostics = []; $diagnostics = [];
foreach ($errors as $error) { foreach ($errors as $error) {
$diagnostic = new Diagnostic(); $diagnostics[] = Diagnostic::fromError($error, $this->content, DiagnosticSeverity::ERROR, 'php');
$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;
} }
$this->client->textDocument->publishDiagnostics($this->uri, $diagnostics);
// $stmts can be null in case of a fatal parsing error // $stmts can be null in case of a fatal parsing error
if ($stmts) { if ($stmts) {
@ -166,9 +155,16 @@ class PhpDocument
$traverser->addVisitor(new ColumnCalculator($content)); $traverser->addVisitor(new ColumnCalculator($content));
// Parse docblocks and add docBlock attributes to nodes // 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); $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; $traverser = new NodeTraverser;
// Collect all definitions // Collect all definitions
@ -195,6 +191,8 @@ class PhpDocument
$this->stmts = $stmts; $this->stmts = $stmts;
} }
$this->client->textDocument->publishDiagnostics($this->uri, $diagnostics);
} }
/** /**

View File

@ -2,6 +2,8 @@
namespace LanguageServer\Protocol; 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 * Represents a diagnostic, such as a compiler error or warning. Diagnostic objects are only valid in the scope of a
* resource. * resource.
@ -44,4 +46,40 @@ class Diagnostic
* @var string * @var string
*/ */
public $message; 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;
}
} }

View File

@ -10,7 +10,7 @@ class Hover
/** /**
* The hover's content * The hover's content
* *
* @var string|MarkedString|(string|MarkedString)[] * @var string|MarkedString|string[]|MarkedString[]
*/ */
public $contents; public $contents;
@ -22,7 +22,7 @@ class Hover
public $range; 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 * @param Range $range An optional range
*/ */
public function __construct($contents = null, $range = null) public function __construct($contents = null, $range = null)

View File

@ -2,7 +2,7 @@
namespace LanguageServer\Protocol; namespace LanguageServer\Protocol;
use PhpParser\Node; use PhpParser\{Error, Node};
/** /**
* A range in a text document expressed as (zero-based) start and end positions. * 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) public function __construct(Position $start = null, Position $end = null)
{ {
$this->start = $start; $this->start = $start;