From 42abb69137c177dc27aab252e91efc7cb143c836 Mon Sep 17 00:00:00 2001 From: Felix Becker Date: Mon, 10 Oct 2016 13:53:56 +0200 Subject: [PATCH 1/5] Only hold content for open files in memory --- src/LanguageServer.php | 2 +- src/PhpDocument.php | 56 +++++++++++++++++++++++++++---------- src/Server/TextDocument.php | 12 ++++++++ 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/src/LanguageServer.php b/src/LanguageServer.php index cee9faa..50411ab 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->getDocument($uri)->parse(file_get_contents($file)); Loop\setTimeout($processFile, 0); } else { diff --git a/src/PhpDocument.php b/src/PhpDocument.php index 963e0c9..e4de3e5 100644 --- a/src/PhpDocument.php +++ b/src/PhpDocument.php @@ -8,6 +8,7 @@ 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; class PhpDocument { @@ -53,14 +54,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 @@ -150,21 +151,32 @@ class PhpDocument public function updateContent(string $content) { $this->content = $content; - $this->parse(); + $this->parse($content); } /** - * Re-parses a source file, updates symbols, reports parsing errors - * that may have occured as diagnostics and returns parsed nodes. + * Unloads the content from memory * * @return void */ - public function parse() + public function removeContent() + { + unset($this->content); + } + + /** + * Re-parses a source file, updates symbols and reports parsing errors + * that may have occured as diagnostics. + * + * @param string $content + * @return void + */ + public function parse(string $content) { $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 @@ -177,8 +189,8 @@ class PhpDocument foreach ($errors as $error) { $diagnostic = new Diagnostic(); $diagnostic->range = new Range( - new Position($error->getStartLine() - 1, $error->hasColumnInfo() ? $error->getStartColumn($this->content) - 1 : 0), - new Position($error->getEndLine() - 1, $error->hasColumnInfo() ? $error->getEndColumn($this->content) : 0) + new Position($error->getStartLine() - 1, $error->hasColumnInfo() ? $error->getStartColumn($content) - 1 : 0), + new Position($error->getEndLine() - 1, $error->hasColumnInfo() ? $error->getEndColumn($content) : 0) ); $diagnostic->severity = DiagnosticSeverity::ERROR; $diagnostic->source = 'php'; @@ -199,7 +211,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; @@ -213,7 +225,7 @@ class PhpDocument $this->project->addDefinitionDocument($fqn, $this); } - $this->stmts = $stmts; + $this->statements = $stmts; } } @@ -234,12 +246,29 @@ class PhpDocument * Returns this document's text content. * * @return string + * @throws Exception If the content was not loaded */ public function getContent() { + if (!isset($this->content)) { + throw new Exception('Content is not loaded'); + } return $this->content; } + /** + * Returns this document's AST. + * + * @return Node[] + */ + public function getStatements() + { + if (!isset($this->statements)) { + $this->parse($this->getContent()); + } + return $this->statements; + } + /** * Returns the URI of the document * @@ -258,13 +287,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->getStatements()); return $finder->node; } diff --git a/src/Server/TextDocument.php b/src/Server/TextDocument.php index 39a9699..075256c 100644 --- a/src/Server/TextDocument.php +++ b/src/Server/TextDocument.php @@ -77,6 +77,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->getDocument($textDocument->uri)->removeContent(); + } /** * The document formatting request is sent from the server to the client to format a whole document. From 1d5ee25939c61792d8d3754d42b5b6aed4780baf Mon Sep 17 00:00:00 2001 From: Felix Becker Date: Mon, 10 Oct 2016 14:12:11 +0200 Subject: [PATCH 2/5] Add test for didClose --- tests/Server/TextDocument/DidCloseTest.php | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/Server/TextDocument/DidCloseTest.php diff --git a/tests/Server/TextDocument/DidCloseTest.php b/tests/Server/TextDocument/DidCloseTest.php new file mode 100644 index 0000000..f473ace --- /dev/null +++ b/tests/Server/TextDocument/DidCloseTest.php @@ -0,0 +1,34 @@ +getDocument('whatever'); + $phpDocument->updateContent('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->expectException(Exception::class); + $phpDocument->getContent(); + } +} From 3cf1fd9c97640b5e71cc751e3d2ab66a95fe229e Mon Sep 17 00:00:00 2001 From: Felix Becker Date: Mon, 10 Oct 2016 15:16:07 +0200 Subject: [PATCH 3/5] Remove invalid URI formatting test --- tests/Server/TextDocument/FormattingTest.php | 10 ---------- 1 file changed, 10 deletions(-) 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); - } } From eb3673b55d9a16f6a5faa23b8ebece73830d7008 Mon Sep 17 00:00:00 2001 From: Felix Becker Date: Mon, 10 Oct 2016 16:12:23 +0200 Subject: [PATCH 4/5] Don't keep AST in memory --- src/LanguageServer.php | 2 +- src/PhpDocument.php | 122 +++++++++++--------------- src/Project.php | 29 +++--- src/Protocol/SymbolInformation.php | 36 ++++++++ src/Server/TextDocument.php | 11 ++- src/Server/Workspace.php | 11 ++- tests/PhpDocumentTest.php | 4 +- tests/ProjectTest.php | 48 ---------- tests/Server/Workspace/SymbolTest.php | 45 ++++++---- 9 files changed, 146 insertions(+), 162 deletions(-) diff --git a/src/LanguageServer.php b/src/LanguageServer.php index 50411ab..f23d271 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)->parse(file_get_contents($file)); + $this->project->getDocument($uri)->updateContent(file_get_contents($file), false); Loop\setTimeout($processFile, 0); } else { diff --git a/src/PhpDocument.php b/src/PhpDocument.php index e4de3e5..39b997c 100644 --- a/src/PhpDocument.php +++ b/src/PhpDocument.php @@ -9,6 +9,7 @@ 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 { @@ -85,83 +86,36 @@ class PhpDocument } /** - * Returns all symbols in this document. + * Returns true if the content of this document is being held in memory * - * @return SymbolInformation[]|null + * @return bool */ - public function getSymbols() + public function isLoaded() { - 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; + return isset($this->content); } /** - * 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. - * - * @param string $content - * @return void - */ - public function updateContent(string $content) - { - $this->content = $content; - $this->parse($content); - } - - /** - * Unloads the content from memory + * Loads the content from disk and saves statements and definitions in memory * * @return void */ - public function removeContent() + public function load() + { + $this->updateContent(file_get_contents(uriToPath($this->getUri())), true); + } + + /** + * Unloads the content, statements and definitions from memory + * + * @return void + */ + public function unload() { unset($this->content); + unset($this->statements); + unset($this->definitions); + unset($this->references); } /** @@ -169,10 +123,15 @@ class PhpDocument * that may have occured as diagnostics. * * @param string $content + * @param bool $keepInMemory Wether to keep content, statements and definitions in memory or only update project definitions * @return void */ - public function parse(string $content) + public function updateContent(string $content, bool $keepInMemory = true) { + $keepInMemory = $keepInMemory || $this->isLoaded(); + if ($keepInMemory) { + $this->content = $content; + } $stmts = null; $errors = []; try { @@ -219,13 +178,15 @@ 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->statements = $stmts; + if ($keepInMemory) { + $this->statements = $stmts; + $this->definitions = $definitionCollector->definitions; + } } } @@ -261,7 +222,7 @@ class PhpDocument * * @return Node[] */ - public function getStatements() + public function &getStatements() { if (!isset($this->statements)) { $this->parse($this->getContent()); @@ -302,7 +263,21 @@ class PhpDocument */ public function getDefinitionByFqn(string $fqn) { - return $this->definitions[$fqn] ?? null; + return $this->getDefinitions()[$fqn] ?? null; + } + + /** + * Returns a map from fully qualified name (FQN) to Nodes defined in this document + * + * @return Node[] + * @throws Exception If the definitions are not loaded + */ + public function &getDefinitions() + { + if (!isset($this->definitions)) { + throw new Exception('Definitions of this document are not loaded'); + } + return $this->definitions; } /** @@ -313,7 +288,7 @@ class PhpDocument */ public function isDefined(string $fqn): bool { - return isset($this->definitions[$fqn]); + return isset($this->getDefinitions()[$fqn]); } /** @@ -511,6 +486,9 @@ class PhpDocument return null; } $document = $this->project->getDefinitionDocument($fqn); + if (!$document->isLoaded()) { + $document->load(); + } if (!isset($document)) { return null; } diff --git a/src/Project.php b/src/Project.php index d9ff73d..41319ed 100644 --- a/src/Project.php +++ b/src/Project.php @@ -83,6 +83,17 @@ class Project return $this->definitions[$fqn] ?? null; } + /** + * Returns an associative array [string => PhpDocument] + * that maps fully qualified symbol names to loaded PhpDocuments + * + * @return PhpDocument[] + */ + public function &getDefinitionDocuments() + { + return $this->definitions; + } + /** * Returns true if the given FQN is defined in the project * @@ -93,22 +104,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 075256c..9c8799a 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; } /** @@ -87,7 +92,7 @@ class TextDocument */ public function didClose(TextDocumentIdentifier $textDocument) { - $this->project->getDocument($textDocument->uri)->removeContent(); + $this->project->getDocument($textDocument->uri)->unload(); } /** diff --git a/src/Server/Workspace.php b/src/Server/Workspace.php index c6d963a..5186008 100644 --- a/src/Server/Workspace.php +++ b/src/Server/Workspace.php @@ -53,6 +53,15 @@ class Workspace */ public function symbol(string $query): array { - return $this->project->findSymbols($query); + $symbols = []; + foreach ($this->project->getDefinitionDocuments() as $fqn => $document) { + if ($query === '' || stripos($fqn, $query) !== false) { + if (!$document->isLoaded()) { + $document->load(); + } + $symbols[] = SymbolInformation::fromNode($document->getDefinitionByFqn($fqn), $fqn); + } + } + return $symbols; } } diff --git a/tests/PhpDocumentTest.php b/tests/PhpDocumentTest.php index 93075fc..f6ab98a 100644 --- a/tests/PhpDocumentTest.php +++ b/tests/PhpDocumentTest.php @@ -28,9 +28,7 @@ class PhpDocumentTest extends TestCase $document->updateContent("getSymbols(); - - $this->assertEquals([], json_decode(json_encode($symbols), true)); + $this->assertEquals([], $document->getDefinitions()); } public function testGetNodeAtPosition() diff --git a/tests/ProjectTest.php b/tests/ProjectTest.php index 5fb9afb..97c49f9 100644 --- a/tests/ProjectTest.php +++ b/tests/ProjectTest.php @@ -36,52 +36,4 @@ class ProjectTest extends TestCase $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/Workspace/SymbolTest.php b/tests/Server/Workspace/SymbolTest.php index 345b142..f238207 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->getDocument($this->symbolsUri)->updateContent(file_get_contents($this->symbolsUri), false); + $project->getDocument($this->referencesUri)->updateContent(file_get_contents($this->referencesUri), false); } 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, From 58fb1b9e131c1b71c3d4bf1b97cbebeb9e0804c2 Mon Sep 17 00:00:00 2001 From: Felix Becker Date: Mon, 10 Oct 2016 17:03:09 +0200 Subject: [PATCH 5/5] Fix symbol search crash --- src/PhpDocument.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/PhpDocument.php b/src/PhpDocument.php index 39b997c..4dd7929 100644 --- a/src/PhpDocument.php +++ b/src/PhpDocument.php @@ -307,16 +307,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) {