From 15e004fb9b5839bb250ff8a589340beaaefe4bcc Mon Sep 17 00:00:00 2001 From: Felix Becker Date: Tue, 11 Oct 2016 14:42:56 +0200 Subject: [PATCH] Only hold AST for open files in memory (#63) * Only hold content for open files in memory * Add test for didClose * Remove invalid URI formatting test * Don't keep AST in memory * Fix symbol search crash * Change Project map to FQN => URI Removes PhpDocument::load(), isLoaded(), unload() * Add docblocks * Rename some functions * Extend documentation * Correct docblock --- src/LanguageServer.php | 2 +- src/PhpDocument.php | 118 +++++------------- src/Project.php | 113 ++++++++++++----- src/Protocol/SymbolInformation.php | 36 ++++++ src/Server/TextDocument.php | 23 +++- src/Server/Workspace.php | 8 +- tests/NodeVisitor/DefinitionCollectorTest.php | 11 +- tests/PhpDocumentTest.php | 11 +- tests/ProjectTest.php | 59 +-------- tests/Server/TextDocument/DefinitionTest.php | 6 +- tests/Server/TextDocument/DidChangeTest.php | 3 +- tests/Server/TextDocument/DidCloseTest.php | 32 +++++ .../TextDocument/DocumentSymbolTest.php | 2 +- tests/Server/TextDocument/FormattingTest.php | 10 -- tests/Server/Workspace/SymbolTest.php | 45 ++++--- 15 files changed, 258 insertions(+), 221 deletions(-) create mode 100644 tests/Server/TextDocument/DidCloseTest.php diff --git a/src/LanguageServer.php b/src/LanguageServer.php index cee9faa..c9fd73b 100644 --- a/src/LanguageServer.php +++ b/src/LanguageServer.php @@ -153,7 +153,7 @@ class LanguageServer extends \AdvancedJsonRpc\Dispatcher $shortName = substr($file, strlen($rootPath) + 1); $this->client->window->logMessage(MessageType::INFO, "Parsing file $fileNum/$numTotalFiles: $shortName."); - $this->project->getDocument($uri)->updateContent(file_get_contents($file)); + $this->project->loadDocument($uri); Loop\setTimeout($processFile, 0); } else { diff --git a/src/PhpDocument.php b/src/PhpDocument.php index f0136ad..f82d37e 100644 --- a/src/PhpDocument.php +++ b/src/PhpDocument.php @@ -8,6 +8,8 @@ use LanguageServer\NodeVisitor\{NodeAtPositionFinder, ReferencesAdder, Definitio use PhpParser\{Error, Comment, Node, ParserFactory, NodeTraverser, Lexer, Parser}; use PhpParser\PrettyPrinter\Standard as PrettyPrinter; use PhpParser\NodeVisitor\NameResolver; +use Exception; +use function LanguageServer\uriToPath; class PhpDocument { @@ -53,14 +55,14 @@ class PhpDocument * * @var Node[] */ - private $stmts = []; + private $statements; /** * Map from fully qualified name (FQN) to Node * * @var Node[] */ - private $definitions = []; + private $definitions; /** * Map from fully qualified name (FQN) to array of nodes that reference the symbol @@ -71,78 +73,23 @@ class PhpDocument /** * @param string $uri The URI of the document + * @param string $content The content of the document * @param Project $project The Project this document belongs to (to register definitions etc) * @param LanguageClient $client The LanguageClient instance (to report errors etc) * @param Parser $parser The PHPParser instance */ - public function __construct(string $uri, Project $project, LanguageClient $client, Parser $parser) + public function __construct(string $uri, string $content, Project $project, LanguageClient $client, Parser $parser) { $this->uri = $uri; $this->project = $project; $this->client = $client; $this->parser = $parser; + $this->updateContent($content); } /** - * Returns all symbols in this document. - * - * @return SymbolInformation[]|null - */ - public function getSymbols() - { - if (!isset($this->definitions)) { - return null; - } - $nodeSymbolKindMap = [ - 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, - Node\Stmt\ClassMethod::class => SymbolKind::METHOD, - Node\Stmt\PropertyProperty::class => SymbolKind::PROPERTY, - Node\Const_::class => SymbolKind::CONSTANT - ]; - $symbols = []; - foreach ($this->definitions as $fqn => $node) { - $class = get_class($node); - if (!isset($nodeSymbolKindMap[$class])) { - continue; - } - $symbol = new SymbolInformation(); - $symbol->kind = $nodeSymbolKindMap[$class]; - $symbol->name = (string)$node->name; - $symbol->location = Location::fromNode($node); - $parts = preg_split('/(::|\\\\)/', $fqn); - array_pop($parts); - $symbol->containerName = implode('\\', $parts); - $symbols[] = $symbol; - } - return $symbols; - } - - /** - * Returns symbols in this document filtered by query string. - * - * @param string $query The search query - * @return SymbolInformation[]|null - */ - public function findSymbols(string $query) - { - $symbols = $this->getSymbols(); - if ($symbols === null) { - return null; - } - if ($query === '') { - return $symbols; - } - return array_filter($symbols, function($symbol) use ($query) { - return stripos($symbol->name, $query) !== false; - }); - } - - /** - * Updates the content on this document. + * Re-parses a source file, updates symbols and reports parsing errors + * that may have occured as diagnostics. * * @param string $content * @return void @@ -150,21 +97,10 @@ class PhpDocument public function updateContent(string $content) { $this->content = $content; - $this->parse(); - } - - /** - * Re-parses a source file, updates symbols, reports parsing errors - * that may have occured as diagnostics and returns parsed nodes. - * - * @return void - */ - public function parse() - { $stmts = null; $errors = []; try { - $stmts = $this->parser->parse($this->content); + $stmts = $this->parser->parse($content); } catch (\PhpParser\Error $e) { // Lexer can throw errors. e.g for unterminated comments // unfortunately we don't get a location back @@ -200,7 +136,7 @@ class PhpDocument $traverser->addVisitor(new ReferencesAdder($this)); // Add column attributes to nodes - $traverser->addVisitor(new ColumnCalculator($this->content)); + $traverser->addVisitor(new ColumnCalculator($content)); // Collect all definitions $definitionCollector = new DefinitionCollector; @@ -208,13 +144,13 @@ class PhpDocument $traverser->traverse($stmts); - $this->definitions = $definitionCollector->definitions; // Register this document on the project for all the symbols defined in it foreach ($definitionCollector->definitions as $fqn => $node) { - $this->project->addDefinitionDocument($fqn, $this); + $this->project->setDefinitionUri($fqn, $this->uri); } - $this->stmts = $stmts; + $this->statements = $stmts; + $this->definitions = $definitionCollector->definitions; } } @@ -225,7 +161,7 @@ class PhpDocument */ public function getFormattedText() { - if (empty($this->getContent())) { + if (empty($this->content)) { return []; } return Formatter::format($this->content, $this->uri); @@ -259,13 +195,10 @@ class PhpDocument */ public function getNodeAtPosition(Position $position) { - if ($this->stmts === null) { - return null; - } $traverser = new NodeTraverser; $finder = new NodeAtPositionFinder($position); $traverser->addVisitor($finder); - $traverser->traverse($this->stmts); + $traverser->traverse($this->statements); return $finder->node; } @@ -280,6 +213,16 @@ class PhpDocument return $this->definitions[$fqn] ?? null; } + /** + * Returns a map from fully qualified name (FQN) to Nodes defined in this document + * + * @return Node[] + */ + public function getDefinitions() + { + return $this->definitions; + } + /** * Returns true if the given FQN is defined in this document * @@ -307,16 +250,11 @@ class PhpDocument */ public function getDefinedFqn(Node $node) { - if ($node instanceof Node\Name) { - $nameNode = $node; - $node = $node->getAttribute('parentNode'); - } - // Only the class node should count as the definition, not the name node // Anonymous classes don't count as a definition - if ($node instanceof Node\Stmt\ClassLike && !isset($nameNode) && isset($node->name)) { + if ($node instanceof Node\Stmt\ClassLike && isset($node->name)) { // Class, interface or trait declaration return (string)$node->namespacedName; - } else if ($node instanceof Node\Stmt\Function_ && !isset($nameNode)) { + } else if ($node instanceof Node\Stmt\Function_) { // Function: use functionName() as the name return (string)$node->namespacedName . '()'; } else if ($node instanceof Node\Stmt\ClassMethod) { diff --git a/src/Project.php b/src/Project.php index d9ff73d..8aaa669 100644 --- a/src/Project.php +++ b/src/Project.php @@ -18,10 +18,9 @@ class Project private $documents = []; /** - * An associative array [string => PhpDocument] - * that maps fully qualified symbol names to loaded PhpDocuments + * An associative array that maps fully qualified symbol names to document URIs * - * @var PhpDocument[] + * @var string[] */ private $definitions = []; @@ -48,7 +47,8 @@ class Project } /** - * Returns the document indicated by uri. Instantiates a new document if none exists. + * Returns the document indicated by uri. + * If the document is not open, tries to read it from disk, but the document is not added the list of open documents. * * @param string $uri * @return LanguageServer\PhpDocument @@ -56,20 +56,93 @@ class Project public function getDocument(string $uri) { if (!isset($this->documents[$uri])) { - $this->documents[$uri] = new PhpDocument($uri, $this, $this->client, $this->parser); + return $this->loadDocument($uri); + } else { + return $this->documents[$uri]; } - return $this->documents[$uri]; } /** - * Adds a document as the container for a specific symbol + * Reads a document from disk. + * The document is NOT added to the list of open documents, but definitions are registered. * - * @param string $fqn The fully qualified name of the symbol + * @param string $uri + * @return LanguageServer\PhpDocument + */ + public function loadDocument(string $uri) + { + $content = file_get_contents(uriToPath($uri)); + if (isset($this->documents[$uri])) { + $document = $this->documents[$uri]; + $document->updateContent($content); + } else { + $document = new PhpDocument($uri, $content, $this, $this->client, $this->parser); + } + return $document; + } + + /** + * Ensures a document is loaded and added to the list of open documents. + * + * @param string $uri + * @param string $content * @return void */ - public function addDefinitionDocument(string $fqn, PhpDocument $document) + public function openDocument(string $uri, string $content) { - $this->definitions[$fqn] = $document; + if (isset($this->documents[$uri])) { + $document = $this->documents[$uri]; + $document->updateContent($content); + } else { + $document = new PhpDocument($uri, $content, $this, $this->client, $this->parser); + $this->documents[$uri] = $document; + } + return $document; + } + + /** + * Removes the document with the specified URI from the list of open documents + * + * @param string $uri + * @return void + */ + public function closeDocument(string $uri) + { + unset($this->documents[$uri]); + } + + /** + * Returns true if the document is open (and loaded) + * + * @param string $uri + * @return bool + */ + public function isDocumentOpen(string $uri): bool + { + return isset($this->documents[$uri]); + } + + /** + * Returns an associative array [string => string] that maps fully qualified symbol names + * to URIs of the document where the symbol is defined + * + * @return PhpDocument[] + */ + public function getDefinitionUris() + { + return $this->definitions; + } + + /** + * Adds a document URI as the container for a specific symbol + * + * @param string $fqn The fully qualified name of the symbol + * @param string $uri The URI + * @return void + */ + public function setDefinitionUri(string $fqn, string $uri) + { + $this->definitions[$fqn] = $uri; } /** @@ -80,7 +153,7 @@ class Project */ public function getDefinitionDocument(string $fqn) { - return $this->definitions[$fqn] ?? null; + return isset($this->definitions[$fqn]) ? $this->getDocument($this->definitions[$fqn]) : null; } /** @@ -93,22 +166,4 @@ class Project { return isset($this->definitions[$fqn]); } - - /** - * Finds symbols in all documents, filtered by query parameter. - * - * @param string $query - * @return SymbolInformation[] - */ - public function findSymbols(string $query) - { - $queryResult = []; - foreach ($this->documents as $uri => $document) { - $documentQueryResult = $document->findSymbols($query); - if ($documentQueryResult !== null) { - $queryResult = array_merge($queryResult, $documentQueryResult); - } - } - return $queryResult; - } } diff --git a/src/Protocol/SymbolInformation.php b/src/Protocol/SymbolInformation.php index e02fd9b..461b430 100644 --- a/src/Protocol/SymbolInformation.php +++ b/src/Protocol/SymbolInformation.php @@ -3,6 +3,7 @@ namespace LanguageServer\Protocol; use PhpParser\Node; +use Exception; /** * Represents information about programming constructs like variables, classes, @@ -37,4 +38,39 @@ class SymbolInformation * @var string|null */ public $containerName; + + /** + * Converts a Node to a SymbolInformation + * + * @param Node $node + * @param string $fqn If given, $containerName will be extracted from it + * @return self + */ + public static function fromNode(Node $node, string $fqn = null) + { + $nodeSymbolKindMap = [ + 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, + Node\Stmt\ClassMethod::class => SymbolKind::METHOD, + Node\Stmt\PropertyProperty::class => SymbolKind::PROPERTY, + Node\Const_::class => SymbolKind::CONSTANT + ]; + $class = get_class($node); + if (!isset($nodeSymbolKindMap[$class])) { + throw new Exception("Not a declaration node: $class"); + } + $symbol = new self; + $symbol->kind = $nodeSymbolKindMap[$class]; + $symbol->name = (string)$node->name; + $symbol->location = Location::fromNode($node); + if ($fqn !== null) { + $parts = preg_split('/(::|\\\\)/', $fqn); + array_pop($parts); + $symbol->containerName = implode('\\', $parts); + } + return $symbol; + } } diff --git a/src/Server/TextDocument.php b/src/Server/TextDocument.php index f98ec57..7c5a971 100644 --- a/src/Server/TextDocument.php +++ b/src/Server/TextDocument.php @@ -14,7 +14,8 @@ use LanguageServer\Protocol\{ Position, FormattingOptions, TextEdit, - Location + Location, + SymbolInformation }; /** @@ -49,7 +50,11 @@ class TextDocument */ public function documentSymbol(TextDocumentIdentifier $textDocument): array { - return $this->project->getDocument($textDocument->uri)->getSymbols(); + $symbols = []; + foreach ($this->project->getDocument($textDocument->uri)->getDefinitions() as $fqn => $node) { + $symbols[] = SymbolInformation::fromNode($node, $fqn); + } + return $symbols; } /** @@ -62,7 +67,7 @@ class TextDocument */ public function didOpen(TextDocumentItem $textDocument) { - $this->project->getDocument($textDocument->uri)->updateContent($textDocument->text); + $this->project->openDocument($textDocument->uri, $textDocument->text); } /** @@ -77,6 +82,18 @@ class TextDocument $this->project->getDocument($textDocument->uri)->updateContent($contentChanges[0]->text); } + /** + * The document close notification is sent from the client to the server when the document got closed in the client. + * The document's truth now exists where the document's uri points to (e.g. if the document's uri is a file uri the + * truth now exists on disk). + * + * @param \LanguageServer\Protocol\TextDocumentItem $textDocument The document that was closed + * @return void + */ + public function didClose(TextDocumentIdentifier $textDocument) + { + $this->project->closeDocument($textDocument->uri); + } /** * The document formatting request is sent from the server to the client to format a whole document. diff --git a/src/Server/Workspace.php b/src/Server/Workspace.php index c6d963a..42471c5 100644 --- a/src/Server/Workspace.php +++ b/src/Server/Workspace.php @@ -53,6 +53,12 @@ class Workspace */ public function symbol(string $query): array { - return $this->project->findSymbols($query); + $symbols = []; + foreach ($this->project->getDefinitionUris() as $fqn => $uri) { + if ($query === '' || stripos($fqn, $query) !== false) { + $symbols[] = SymbolInformation::fromNode($this->project->getDocument($uri)->getDefinitionByFqn($fqn), $fqn); + } + } + return $symbols; } } diff --git a/tests/NodeVisitor/DefinitionCollectorTest.php b/tests/NodeVisitor/DefinitionCollectorTest.php index 554ba2e..10ec058 100644 --- a/tests/NodeVisitor/DefinitionCollectorTest.php +++ b/tests/NodeVisitor/DefinitionCollectorTest.php @@ -9,6 +9,7 @@ use PhpParser\NodeVisitor\NameResolver; use LanguageServer\{LanguageClient, Project, PhpDocument}; use LanguageServer\Tests\MockProtocolStream; use LanguageServer\NodeVisitor\{ReferencesAdder, DefinitionCollector}; +use function LanguageServer\pathToUri; class DefinitionCollectorTest extends TestCase { @@ -17,13 +18,14 @@ class DefinitionCollectorTest extends TestCase $client = new LanguageClient(new MockProtocolStream()); $project = new Project($client); $parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7); - $document = new PhpDocument('symbols', $project, $client, $parser); + $uri = pathToUri(realpath(__DIR__ . '/../../fixtures/symbols.php')); + $document = $project->loadDocument($uri); $traverser = new NodeTraverser; $traverser->addVisitor(new NameResolver); $traverser->addVisitor(new ReferencesAdder($document)); $definitionCollector = new DefinitionCollector; $traverser->addVisitor($definitionCollector); - $stmts = $parser->parse(file_get_contents(__DIR__ . '/../../fixtures/symbols.php')); + $stmts = $parser->parse(file_get_contents($uri)); $traverser->traverse($stmts); $defs = $definitionCollector->definitions; $this->assertEquals([ @@ -55,13 +57,14 @@ class DefinitionCollectorTest extends TestCase $client = new LanguageClient(new MockProtocolStream()); $project = new Project($client); $parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7); - $document = new PhpDocument('references', $project, $client, $parser); + $uri = pathToUri(realpath(__DIR__ . '/../../fixtures/references.php')); + $document = $project->loadDocument($uri); $traverser = new NodeTraverser; $traverser->addVisitor(new NameResolver); $traverser->addVisitor(new ReferencesAdder($document)); $definitionCollector = new DefinitionCollector; $traverser->addVisitor($definitionCollector); - $stmts = $parser->parse(file_get_contents(__DIR__ . '/../../fixtures/references.php')); + $stmts = $parser->parse(file_get_contents($uri)); $traverser->traverse($stmts); $defs = $definitionCollector->definitions; $this->assertEquals(['TestNamespace\\whatever()'], array_keys($defs)); diff --git a/tests/PhpDocumentTest.php b/tests/PhpDocumentTest.php index 93075fc..c14a6b3 100644 --- a/tests/PhpDocumentTest.php +++ b/tests/PhpDocumentTest.php @@ -24,19 +24,14 @@ class PhpDocumentTest extends TestCase public function testParsesVariableVariables() { - $document = $this->project->getDocument('whatever'); + $document = $this->project->openDocument('whatever', "updateContent("getSymbols(); - - $this->assertEquals([], json_decode(json_encode($symbols), true)); + $this->assertEquals([], $document->getDefinitions()); } public function testGetNodeAtPosition() { - $document = $this->project->getDocument('whatever'); - $document->updateContent("project->openDocument('whatever', "getNodeAtPosition(new Position(1, 13)); $this->assertInstanceOf(Node\Name\FullyQualified::class, $node); $this->assertEquals('SomeClass', (string)$node); diff --git a/tests/ProjectTest.php b/tests/ProjectTest.php index 5fb9afb..affbe2c 100644 --- a/tests/ProjectTest.php +++ b/tests/ProjectTest.php @@ -8,6 +8,7 @@ use LanguageServer\Tests\MockProtocolStream; use LanguageServer\{Server, Client, LanguageClient, Project, PhpDocument}; use LanguageServer\Protocol\{TextDocumentItem, TextDocumentIdentifier, SymbolKind, DiagnosticSeverity, FormattingOptions}; use AdvancedJsonRpc\{Request as RequestBody, Response as ResponseBody}; +use function LanguageServer\pathToUri; class ProjectTest extends TestCase { @@ -21,67 +22,19 @@ class ProjectTest extends TestCase $this->project = new Project(new LanguageClient(new MockProtocolStream())); } - public function testGetDocumentCreatesNewDocument() + public function testGetDocumentLoadsDocument() { - $document = $this->project->getDocument('file:///document1.php'); + $document = $this->project->getDocument(pathToUri(__FILE__)); $this->assertNotNull($document); $this->assertInstanceOf(PhpDocument::class, $document); } - public function testGetDocumentCreatesDocumentOnce() + public function testGetDocumentReturnsOpenedInstance() { - $document1 = $this->project->getDocument('file:///document1.php'); - $document2 = $this->project->getDocument('file:///document1.php'); + $document1 = $this->project->openDocument(pathToUri(__FILE__), file_get_contents(__FILE__)); + $document2 = $this->project->getDocument(pathToUri(__FILE__)); $this->assertSame($document1, $document2); } - - public function testFindSymbols() - { - $this->project->getDocument('file:///document1.php')->updateContent("project->getDocument('file:///document2.php')->updateContent("project->getDocument('invalid_file')->updateContent(file_get_contents(__DIR__ . '/../fixtures/invalid_file.php')); - - $symbols = $this->project->findSymbols('ba'); - - $this->assertEquals([ - [ - 'name' => 'bar', - 'kind' => SymbolKind::FUNCTION, - 'location' => [ - 'uri' => 'file:///document1.php', - 'range' => [ - 'start' => [ - 'line' => 2, - 'character' => 0 - ], - 'end' => [ - 'line' => 2, - 'character' => 17 - ] - ] - ], - 'containerName' => null - ], - [ - 'name' => 'baz', - 'kind' => SymbolKind::FUNCTION, - 'location' => [ - 'uri' => 'file:///document2.php', - 'range' => [ - 'start' => [ - 'line' => 1, - 'character' => 0 - ], - 'end' => [ - 'line' => 1, - 'character' => 17 - ] - ] - ], - 'containerName' => null - ] - ], json_decode(json_encode($symbols), true)); - } } diff --git a/tests/Server/TextDocument/DefinitionTest.php b/tests/Server/TextDocument/DefinitionTest.php index 455a2b3..f26bb49 100644 --- a/tests/Server/TextDocument/DefinitionTest.php +++ b/tests/Server/TextDocument/DefinitionTest.php @@ -20,9 +20,9 @@ class DefinitionTest extends TestCase $client = new LanguageClient(new MockProtocolStream()); $project = new Project($client); $this->textDocument = new Server\TextDocument($project, $client); - $project->getDocument('references')->updateContent(file_get_contents(__DIR__ . '/../../../fixtures/references.php')); - $project->getDocument('symbols')->updateContent(file_get_contents(__DIR__ . '/../../../fixtures/symbols.php')); - $project->getDocument('use')->updateContent(file_get_contents(__DIR__ . '/../../../fixtures/use.php')); + $project->openDocument('references', file_get_contents(__DIR__ . '/../../../fixtures/references.php')); + $project->openDocument('symbols', file_get_contents(__DIR__ . '/../../../fixtures/symbols.php')); + $project->openDocument('use', file_get_contents(__DIR__ . '/../../../fixtures/use.php')); } public function testDefinitionFileBeginning() { diff --git a/tests/Server/TextDocument/DidChangeTest.php b/tests/Server/TextDocument/DidChangeTest.php index 081978f..291e9d8 100644 --- a/tests/Server/TextDocument/DidChangeTest.php +++ b/tests/Server/TextDocument/DidChangeTest.php @@ -22,8 +22,7 @@ class DidChangeTest extends TestCase $client = new LanguageClient(new MockProtocolStream()); $project = new Project($client); $textDocument = new Server\TextDocument($project, $client); - $phpDocument = $project->getDocument('whatever'); - $phpDocument->updateContent("openDocument('whatever', "openDocument('whatever', 'hello world'); + + $textDocumentItem = new TextDocumentItem(); + $textDocumentItem->uri = 'whatever'; + $textDocumentItem->languageId = 'php'; + $textDocumentItem->version = 1; + $textDocumentItem->text = 'hello world'; + $textDocument->didOpen($textDocumentItem); + + $textDocument->didClose(new TextDocumentIdentifier($textDocumentItem->uri)); + + $this->assertFalse($project->isDocumentOpen($textDocumentItem->uri)); + } +} diff --git a/tests/Server/TextDocument/DocumentSymbolTest.php b/tests/Server/TextDocument/DocumentSymbolTest.php index e5edfe7..601fbf9 100644 --- a/tests/Server/TextDocument/DocumentSymbolTest.php +++ b/tests/Server/TextDocument/DocumentSymbolTest.php @@ -20,7 +20,7 @@ class DocumentSymbolTest extends TestCase $client = new LanguageClient(new MockProtocolStream()); $project = new Project($client); $this->textDocument = new Server\TextDocument($project, $client); - $project->getDocument('symbols')->updateContent(file_get_contents(__DIR__ . '/../../../fixtures/symbols.php')); + $project->openDocument('symbols', file_get_contents(__DIR__ . '/../../../fixtures/symbols.php')); } public function test() diff --git a/tests/Server/TextDocument/FormattingTest.php b/tests/Server/TextDocument/FormattingTest.php index 957f4a6..4d8ef24 100644 --- a/tests/Server/TextDocument/FormattingTest.php +++ b/tests/Server/TextDocument/FormattingTest.php @@ -57,14 +57,4 @@ class FormattingTest extends TestCase 'newText' => $expected ]], json_decode(json_encode($result), true)); } - - public function testFormattingInvalidUri() - { - $client = new LanguageClient(new MockProtocolStream()); - $project = new Project($client); - $textDocument = new Server\TextDocument($project, $client); - - $result = $textDocument->formatting(new TextDocumentIdentifier('whatever'), new FormattingOptions()); - $this->assertSame([], $result); - } } diff --git a/tests/Server/Workspace/SymbolTest.php b/tests/Server/Workspace/SymbolTest.php index 345b142..fe90cf4 100644 --- a/tests/Server/Workspace/SymbolTest.php +++ b/tests/Server/Workspace/SymbolTest.php @@ -1,13 +1,14 @@ workspace = new Server\Workspace($project, $client); - $project->getDocument('symbols')->updateContent(file_get_contents(__DIR__ . '/../../../fixtures/symbols.php')); - $project->getDocument('references')->updateContent(file_get_contents(__DIR__ . '/../../../fixtures/references.php')); + $this->symbolsUri = pathToUri(realpath(__DIR__ . '/../../../fixtures/symbols.php')); + $this->referencesUri = pathToUri(realpath(__DIR__ . '/../../../fixtures/references.php')); + $project->loadDocument($this->symbolsUri); + $project->loadDocument($this->referencesUri); } public function testEmptyQueryReturnsAllSymbols() @@ -34,7 +47,7 @@ class SymbolTest extends TestCase 'name' => 'TEST_CONST', 'kind' => SymbolKind::CONSTANT, 'location' => [ - 'uri' => 'symbols', + 'uri' => $this->symbolsUri, 'range' => [ 'start' => [ 'line' => 4, @@ -52,7 +65,7 @@ class SymbolTest extends TestCase 'name' => 'TestClass', 'kind' => SymbolKind::CLASS_, 'location' => [ - 'uri' => 'symbols', + 'uri' => $this->symbolsUri, 'range' => [ 'start' => [ 'line' => 6, @@ -70,7 +83,7 @@ class SymbolTest extends TestCase 'name' => 'TEST_CLASS_CONST', 'kind' => SymbolKind::CONSTANT, 'location' => [ - 'uri' => 'symbols', + 'uri' => $this->symbolsUri, 'range' => [ 'start' => [ 'line' => 8, @@ -88,7 +101,7 @@ class SymbolTest extends TestCase 'name' => 'staticTestProperty', 'kind' => SymbolKind::PROPERTY, 'location' => [ - 'uri' => 'symbols', + 'uri' => $this->symbolsUri, 'range' => [ 'start' => [ 'line' => 9, @@ -106,7 +119,7 @@ class SymbolTest extends TestCase 'name' => 'testProperty', 'kind' => SymbolKind::PROPERTY, 'location' => [ - 'uri' => 'symbols', + 'uri' => $this->symbolsUri, 'range' => [ 'start' => [ 'line' => 10, @@ -124,7 +137,7 @@ class SymbolTest extends TestCase 'name' => 'staticTestMethod', 'kind' => SymbolKind::METHOD, 'location' => [ - 'uri' => 'symbols', + 'uri' => $this->symbolsUri, 'range' => [ 'start' => [ 'line' => 12, @@ -142,7 +155,7 @@ class SymbolTest extends TestCase 'name' => 'testMethod', 'kind' => SymbolKind::METHOD, 'location' => [ - 'uri' => 'symbols', + 'uri' => $this->symbolsUri, 'range' => [ 'start' => [ 'line' => 17, @@ -160,7 +173,7 @@ class SymbolTest extends TestCase 'name' => 'TestTrait', 'kind' => SymbolKind::CLASS_, 'location' => [ - 'uri' => 'symbols', + 'uri' => $this->symbolsUri, 'range' => [ 'start' => [ 'line' => 23, @@ -178,7 +191,7 @@ class SymbolTest extends TestCase 'name' => 'TestInterface', 'kind' => SymbolKind::INTERFACE, 'location' => [ - 'uri' => 'symbols', + 'uri' => $this->symbolsUri, 'range' => [ 'start' => [ 'line' => 28, @@ -196,7 +209,7 @@ class SymbolTest extends TestCase 'name' => 'test_function', 'kind' => SymbolKind::FUNCTION, 'location' => [ - 'uri' => 'symbols', + 'uri' => $this->symbolsUri, 'range' => [ 'start' => [ 'line' => 33, @@ -214,7 +227,7 @@ class SymbolTest extends TestCase 'name' => 'whatever', 'kind' => SymbolKind::FUNCTION, 'location' => [ - 'uri' => 'references', + 'uri' => $this->referencesUri, 'range' => [ 'start' => [ 'line' => 15, @@ -240,7 +253,7 @@ class SymbolTest extends TestCase 'name' => 'staticTestMethod', 'kind' => SymbolKind::METHOD, 'location' => [ - 'uri' => 'symbols', + 'uri' => $this->symbolsUri, 'range' => [ 'start' => [ 'line' => 12, @@ -258,7 +271,7 @@ class SymbolTest extends TestCase 'name' => 'testMethod', 'kind' => SymbolKind::METHOD, 'location' => [ - 'uri' => 'symbols', + 'uri' => $this->symbolsUri, 'range' => [ 'start' => [ 'line' => 17,