Skip to content

Report validation errors #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions fixtures/InvalidFile.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

interface class
{

}
23 changes: 23 additions & 0 deletions fixtures/Symbols.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace TestNamespace;

class TestClass
{
public $testProperty;

public function testMethod($testParameter)
{
$testVariable = 123;
}
}

trait TestTrait
{

}

interface TestInterface
{

}
43 changes: 43 additions & 0 deletions src/Client/TextDocument.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
declare(strict_types = 1);

namespace LanguageServer\Client;

use AdvancedJsonRpc\Notification as NotificationBody;
use PhpParser\{Error, Comment, Node, ParserFactory, NodeTraverser, Lexer};
use PhpParser\NodeVisitor\NameResolver;
use LanguageServer\ProtocolWriter;
use LanguageServer\Protocol\{TextDocumentItem, TextDocumentIdentifier, VersionedTextDocumentIdentifier, Message};

/**
* Provides method handlers for all textDocument/* methods
*/
class TextDocument
{
/**
* @var ProtocolWriter
*/
private $protocolWriter;

public function __construct(ProtocolWriter $protocolWriter)
{
$this->protocolWriter = $protocolWriter;
}

/**
* Diagnostics notification are sent from the server to the client to signal results of validation runs.
*
* @param string $uri
* @param Diagnostic[] $diagnostics
*/
public function publishDiagnostics(string $uri, array $diagnostics)
{
$this->protocolWriter->write(new Message(new NotificationBody(
'textDocument/publishDiagnostics',
(object)[
'uri' => $uri,
'diagnostics' => $diagnostics
]
)));
}
}
24 changes: 24 additions & 0 deletions src/LanguageClient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
declare(strict_types = 1);

namespace LanguageServer;

use LanguageServer\Client\TextDocument;

class LanguageClient
{
/**
* Handles textDocument/* methods
*
* @var Client\TextDocument
*/
public $textDocument;

private $protocolWriter;

public function __construct(ProtocolWriter $writer)
{
$this->protocolWriter = $writer;
$this->textDocument = new TextDocument($writer);
}
}
11 changes: 10 additions & 1 deletion src/LanguageServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@

namespace LanguageServer;

use LanguageServer\Server\TextDocument;
use LanguageServer\Protocol\{ServerCapabilities, ClientCapabilities, TextDocumentSyncKind, Message};
use LanguageServer\Protocol\InitializeResult;
use AdvancedJsonRpc\{Dispatcher, ResponseError, Response as ResponseBody, Request as RequestBody};

class LanguageServer extends \AdvancedJsonRpc\Dispatcher
{
/**
* Handles textDocument/* method calls
*
* @var Server\TextDocument
*/
public $textDocument;

public $telemetry;
public $window;
public $workspace;
Expand All @@ -17,6 +24,7 @@ class LanguageServer extends \AdvancedJsonRpc\Dispatcher

private $protocolReader;
private $protocolWriter;
private $client;

public function __construct(ProtocolReader $reader, ProtocolWriter $writer)
{
Expand Down Expand Up @@ -47,7 +55,8 @@ public function __construct(ProtocolReader $reader, ProtocolWriter $writer)
}
});
$this->protocolWriter = $writer;
$this->textDocument = new TextDocumentManager();
$this->client = new LanguageClient($writer);
$this->textDocument = new Server\TextDocument($this->client);
}

/**
Expand Down
26 changes: 26 additions & 0 deletions src/Protocol/PublishDiagnosticsNotification.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace LanguageServer\Protocol;

use AdvancedJsonRpc\Notification;

/**
* Diagnostics notification are sent from the server to the client to signal results of validation runs.
*/
class PublishDiagnosticsNotification extends Notification
{
/**
* @var PublishDiagnosticsParams
*/
public $params;

/**
* @param string $uri
* @param Diagnostic[] $diagnostics
*/
public function __construct(string $uri, array $diagnostics)
{
$this->method = 'textDocument/publishDiagnostics';
$this->params = $params;
}
}
22 changes: 22 additions & 0 deletions src/Protocol/PublishDiagnosticsParams.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace LanguageServer\Protocol\TextDocument;

use LanguageServer\Protocol\Params;

class PublishDiagnosticsParams extends Params
{
/**
* The URI for which diagnostic information is reported.
*
* @var string
*/
public $uri;

/**
* An array of diagnostic information items.
*
* @var LanguageServer\Protocol\Diagnostic[]
*/
public $diagnostics;
}
8 changes: 8 additions & 0 deletions src/Protocol/TextDocumentIdentifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,12 @@ class TextDocumentIdentifier
* @var string
*/
public $uri;

/**
* @param string $uri The text document's URI.
*/
public function __construct(string $uri = null)
{
$this->uri = $uri;
}
}
54 changes: 45 additions & 9 deletions src/TextDocumentManager.php → src/Server/TextDocument.php
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
<?php

namespace LanguageServer;
namespace LanguageServer\Server;

use PhpParser\{Error, Comment, Node, ParserFactory, NodeTraverser, Lexer};
use PhpParser\NodeVisitor\NameResolver;
use LanguageServer\Protocol\{TextDocumentItem, TextDocumentIdentifier, VersionedTextDocumentIdentifier};
use LanguageServer\{LanguageClient, ColumnCalculator, SymbolFinder};
use LanguageServer\Protocol\{
TextDocumentItem,
TextDocumentIdentifier,
VersionedTextDocumentIdentifier,
Diagnostic,
DiagnosticSeverity,
Range,
Position
};

/**
* Provides method handlers for all textDocument/* methods
*/
class TextDocumentManager
class TextDocument
{
/**
* @var PhpParser\Parser
Expand All @@ -23,8 +32,16 @@ class TextDocumentManager
*/
private $asts;

public function __construct()
/**
* The lanugage client object to call methods on the client
*
* @var LanguageServer\LanguageClient
*/
private $client;

public function __construct(LanguageClient $client)
{
$this->client = $client;
$lexer = new Lexer(['usedAttributes' => ['comments', 'startLine', 'endLine', 'startFilePos', 'endFilePos']]);
$this->parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7, $lexer, ['throwOnError' => false]);
}
Expand Down Expand Up @@ -74,20 +91,39 @@ public function didChange(VersionedTextDocumentIdentifier $textDocument, array $
$this->updateAst($textDocument->uri, $contentChanges[0]->text);
}

/**
* Re-parses a source file, updates the AST and reports parsing errors that may occured as diagnostics
*
* @param string $uri The URI of the source file
* @param string $content The new content of the source file
* @return void
*/
private function updateAst(string $uri, string $content)
{
$stmts = $this->parser->parse($content);
// TODO report errors as diagnostics
// foreach ($parser->getErrors() as $error) {
// error_log($error->getMessage());
// }
$diagnostics = [];
foreach ($this->parser->getErrors() as $error) {
$diagnostic = new Diagnostic();
$diagnostic->range = new Range(
new Position($error->getStartLine() - 1, $error->hasColumnInfo() ? $error->getStartColumn($content) - 1 : 0),
new Position($error->getEndLine() - 1, $error->hasColumnInfo() ? $error->getEndColumn($content) - 1 : 0)
);
$diagnostic->severity = DiagnosticSeverity::ERROR;
$diagnostic->source = 'php';
// Do not include "on line ..." in the error message
$diagnostic->message = $error->getRawMessage();
$diagnostics[] = $diagnostic;
}
if (count($diagnostics) > 0) {
$this->client->textDocument->publishDiagnostics($uri, $diagnostics);
}
// $stmts can be null in case of a fatal parsing error
if ($stmts) {
$traverser = new NodeTraverser;
$traverser->addVisitor(new NameResolver);
$traverser->addVisitor(new ColumnCalculator($content));
$traverser->traverse($stmts);
$this->asts[$uri] = $stmts;
}
$this->asts[$uri] = $stmts;
}
}
1 change: 1 addition & 0 deletions src/SymbolFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class SymbolFinder extends NodeVisitorAbstract
{
const NODE_SYMBOL_KIND_MAP = [
Node\Stmt\Class_::class => SymbolKind::CLASS_,
Node\Stmt\Trait_::class => SymbolKind::CLASS_,
Node\Stmt\Interface_::class => SymbolKind::INTERFACE,
Node\Stmt\Namespace_::class => SymbolKind::NAMESPACE,
Node\Stmt\Function_::class => SymbolKind::FUNCTION,
Expand Down
Loading