diff --git a/src/CompletionProvider.php b/src/CompletionProvider.php index d774423e..a5f91194 100644 --- a/src/CompletionProvider.php +++ b/src/CompletionProvider.php @@ -218,16 +218,13 @@ public function provideCompletion(PhpDocument $doc, Position $pos, CompletionCon $this->definitionResolver->resolveExpressionNodeToType($node->dereferencableExpression) ); - // Add the object access operator to only get members of all parents - $prefixes = []; - foreach ($this->expandParentFqns($fqns) as $prefix) { - $prefixes[] = $prefix . '->'; - } - - // Collect all definitions that match any of the prefixes - foreach ($this->index->getDefinitions() as $fqn => $def) { - foreach ($prefixes as $prefix) { - if (substr($fqn, 0, strlen($prefix)) === $prefix && $def->isMember) { + // The FQNs of the symbol and its parents (eg the implemented interfaces) + foreach ($this->expandParentFqns($fqns) as $parentFqn) { + // Collect fqn definitions + foreach ($this->index->getDescendantDefinitionsForFqn($parentFqn, true) as $fqn => $def) { + // Add the object access operator to only get members of all parents + $prefix = $parentFqn . '->'; + if (substr($fqn, 0, strlen($prefix)) === $prefix) { $list->items[] = CompletionItem::fromDefinition($def); } } @@ -251,16 +248,13 @@ public function provideCompletion(PhpDocument $doc, Position $pos, CompletionCon $classType = $this->definitionResolver->resolveExpressionNodeToType($scoped->scopeResolutionQualifier) ); - // Append :: operator to only get static members of all parents - $prefixes = []; - foreach ($this->expandParentFqns($fqns) as $prefix) { - $prefixes[] = $prefix . '::'; - } - - // Collect all definitions that match any of the prefixes - foreach ($this->index->getDefinitions() as $fqn => $def) { - foreach ($prefixes as $prefix) { - if (substr(strtolower($fqn), 0, strlen($prefix)) === strtolower($prefix) && $def->isMember) { + // The FQNs of the symbol and its parents (eg the implemented interfaces) + foreach ($this->expandParentFqns($fqns) as $parentFqn) { + // Collect fqn definitions + foreach ($this->index->getDescendantDefinitionsForFqn($parentFqn, true) as $fqn => $def) { + // Append :: operator to only get static members of all parents + $prefix = strtolower($parentFqn . '::'); + if (substr(strtolower($fqn), 0, strlen($prefix)) === $prefix) { $list->items[] = CompletionItem::fromDefinition($def); } } @@ -324,17 +318,15 @@ public function provideCompletion(PhpDocument $doc, Position $pos, CompletionCon } } - // Suggest global symbols that either + // Suggest global (ie non member) symbols that either // - start with the current namespace + prefix, if the Name node is not fully qualified // - start with just the prefix, if the Name node is fully qualified - foreach ($this->index->getDefinitions() as $fqn => $def) { + foreach ($this->index->getDefinitions(false) as $fqn => $def) { $fqnStartsWithPrefix = substr($fqn, 0, $prefixLen) === $prefix; if ( - // Exclude methods, properties etc. - !$def->isMember - && ( + ( !$prefix || ( // Either not qualified, but a matching prefix with global fallback diff --git a/src/Index/AbstractAggregateIndex.php b/src/Index/AbstractAggregateIndex.php index 5377c3a4..3458d552 100644 --- a/src/Index/AbstractAggregateIndex.php +++ b/src/Index/AbstractAggregateIndex.php @@ -99,20 +99,31 @@ public function isStaticComplete(): bool } /** - * Returns an associative array [string => Definition] that maps fully qualified symbol names - * to Definitions + * Returns a Generator providing an associative array [string => Definition] + * that maps fully qualified symbol names to Definitions (global or not) * - * @return Definition[] + * @param boolean|null $member Indicates if we want member or non-member definitions (null for both, default null) + * @return \Generator yields Definition */ - public function getDefinitions(): array + public function getDefinitions(bool $member = null): \Generator { - $defs = []; foreach ($this->getIndexes() as $index) { - foreach ($index->getDefinitions() as $fqn => $def) { - $defs[$fqn] = $def; - } + yield from $index->getDefinitions($member); + } + } + + /** + * Returns a Generator that yields all the descendant Definitions of a given FQN + * + * @param string $fqn + * @param boolean|null $member Indicates if we want member or non-member definitions (null for both, default null) + * @return \Generator yields Definition + */ + public function getDescendantDefinitionsForFqn(string $fqn, bool $member = null): \Generator + { + foreach ($this->getIndexes() as $index) { + yield from $index->getDescendantDefinitionsForFqn($fqn, $member); } - return $defs; } /** @@ -132,19 +143,15 @@ public function getDefinition(string $fqn, bool $globalFallback = false) } /** - * Returns all URIs in this index that reference a symbol + * Returns a Generator providing all URIs in this index that reference a symbol * * @param string $fqn The fully qualified name of the symbol - * @return string[] + * @return \Generator yields string */ - public function getReferenceUris(string $fqn): array + public function getReferenceUris(string $fqn): \Generator { - $refs = []; foreach ($this->getIndexes() as $index) { - foreach ($index->getReferenceUris($fqn) as $ref) { - $refs[] = $ref; - } + yield from $index->getReferenceUris($fqn); } - return $refs; } } diff --git a/src/Index/Index.php b/src/Index/Index.php index 9cb975e5..1099fab7 100644 --- a/src/Index/Index.php +++ b/src/Index/Index.php @@ -15,14 +15,42 @@ class Index implements ReadableIndex, \Serializable use EmitterTrait; /** - * An associative array that maps fully qualified symbol names to Definitions + * An associative array that maps splitted fully qualified symbol names + * to non-member definitions, eg : + * [ + * 'Psr' => [ + * '\Log' => [ + * '\LoggerInterface' => [ + * '' => $definition, + * ], + * ], + * ], + * ] * - * @var Definition[] + * @var array */ - private $definitions = []; + private $nonMemberDefinitions = []; /** - * An associative array that maps fully qualified symbol names to arrays of document URIs that reference the symbol + * An associative array that maps splitted fully qualified symbol names + * to member definitions, eg : + * [ + * 'Psr' => [ + * '\Log' => [ + * '\LoggerInterface' => [ + * '->log()' => $definition, + * ], + * ], + * ], + * ] + * + * @var array + */ + private $memberDefinitions = []; + + /** + * An associative array that maps fully qualified symbol names + * to arrays of document URIs that reference the symbol * * @var string[][] */ @@ -84,14 +112,48 @@ public function isStaticComplete(): bool } /** - * Returns an associative array [string => Definition] that maps fully qualified symbol names - * to Definitions + * Returns a Generator providing an associative array [string => Definition] + * that maps fully qualified symbol names to Definitions (global or not) * - * @return Definition[] + * @param boolean|null $member Indicates if we want member or non-member definitions (null for both, default null) + * @return \Generator yields Definition */ - public function getDefinitions(): array + public function getDefinitions(bool $member = null): \Generator { - return $this->definitions; + if (true === $member) { + yield from $this->yieldDefinitionsRecursively($this->memberDefinitions); + } elseif (false === $member) { + yield from $this->yieldDefinitionsRecursively($this->nonMemberDefinitions); + } else { + yield from $this->yieldDefinitionsRecursively($this->memberDefinitions); + yield from $this->yieldDefinitionsRecursively($this->nonMemberDefinitions); + } + } + + /** + * Returns a Generator that yields all the descendant Definitions of a given FQN + * + * @param string $fqn + * @param boolean|null $member Indicates if we want member or non-member definitions (null for both, default null) + * @return \Generator yields Definition + */ + public function getDescendantDefinitionsForFqn(string $fqn, bool $member = null): \Generator + { + $parts = $this->splitFqn($fqn); + if ('' === end($parts)) { + // we want to return all the definitions in the given FQN, not only + // the one (non member) matching exactly the FQN. + array_pop($parts); + } + + if (true === $member) { + yield from $this->doGetDescendantDefinitionsForFqn($fqn, $parts, $this->memberDefinitions); + } elseif (false === $member) { + yield from $this->doGetDescendantDefinitionsForFqn($fqn, $parts, $this->nonMemberDefinitions); + } else { + yield from $this->doGetDescendantDefinitionsForFqn($fqn, $parts, $this->memberDefinitions); + yield from $this->doGetDescendantDefinitionsForFqn($fqn, $parts, $this->nonMemberDefinitions); + } } /** @@ -103,12 +165,22 @@ public function getDefinitions(): array */ public function getDefinition(string $fqn, bool $globalFallback = false) { - if (isset($this->definitions[$fqn])) { - return $this->definitions[$fqn]; + $parts = $this->splitFqn($fqn); + + $result = $this->getIndexValue($parts, $this->memberDefinitions); + if ($result instanceof Definition) { + return $result; } + + $result = $this->getIndexValue($parts, $this->nonMemberDefinitions); + if ($result instanceof Definition) { + return $result; + } + if ($globalFallback) { $parts = explode('\\', $fqn); $fqn = end($parts); + return $this->getDefinition($fqn); } } @@ -122,7 +194,14 @@ public function getDefinition(string $fqn, bool $globalFallback = false) */ public function setDefinition(string $fqn, Definition $definition) { - $this->definitions[$fqn] = $definition; + $parts = $this->splitFqn($fqn); + + if ($definition->isMember) { + $this->indexDefinition(0, $parts, $this->memberDefinitions, $definition); + } else { + $this->indexDefinition(0, $parts, $this->nonMemberDefinitions, $definition); + } + $this->emit('definition-added'); } @@ -135,19 +214,24 @@ public function setDefinition(string $fqn, Definition $definition) */ public function removeDefinition(string $fqn) { - unset($this->definitions[$fqn]); + $parts = $this->splitFqn($fqn); + $this->removeIndexedDefinition(0, $parts, $this->memberDefinitions, $this->memberDefinitions); + $this->removeIndexedDefinition(0, $parts, $this->nonMemberDefinitions, $this->nonMemberDefinitions); + unset($this->references[$fqn]); } /** - * Returns all URIs in this index that reference a symbol + * Returns a Generator providing all URIs in this index that reference a symbol * * @param string $fqn The fully qualified name of the symbol - * @return string[] + * @return \Generator yields string */ - public function getReferenceUris(string $fqn): array + public function getReferenceUris(string $fqn): \Generator { - return $this->references[$fqn] ?? []; + foreach ($this->references[$fqn] ?? [] as $uri) { + yield $uri; + } } /** @@ -204,6 +288,15 @@ public function removeReferenceUri(string $fqn, string $uri) public function unserialize($serialized) { $data = unserialize($serialized); + + if (isset($data['definitions'])) { + foreach ($data['definitions'] as $fqn => $definition) { + $this->setDefinition($fqn, $definition); + } + + unset($data['definitions']); + } + foreach ($data as $prop => $val) { $this->$prop = $val; } @@ -216,10 +309,187 @@ public function unserialize($serialized) public function serialize() { return serialize([ - 'definitions' => $this->definitions, + 'definitions' => iterator_to_array($this->getDefinitions(), true), 'references' => $this->references, 'complete' => $this->complete, 'staticComplete' => $this->staticComplete ]); } + + /** + * Returns a Generator that yields all the descendant Definitions of a given FQN + * in the given definition index. + * + * @param string $fqn + * @param string[] $parts The splitted FQN + * @param array &$storage The definitions index to look into + * @return \Generator yields Definition + */ + private function doGetDescendantDefinitionsForFqn(string $fqn, array $parts, array &$storage): \Generator + { + $result = $this->getIndexValue($parts, $storage); + + if ($result instanceof Definition) { + yield $fqn => $result; + } elseif (is_array($result)) { + yield from $this->yieldDefinitionsRecursively($result, $fqn); + } + } + + /** + * Returns a Generator that yields all the Definitions in the given $storage recursively. + * The generator yields key => value pairs, e.g. + * `'Psr\Log\LoggerInterface->log()' => $definition` + * + * @param array &$storage + * @param string $prefix (optional) + * @return \Generator + */ + private function yieldDefinitionsRecursively(array &$storage, string $prefix = ''): \Generator + { + foreach ($storage as $key => $value) { + if (!is_array($value)) { + yield $prefix.$key => $value; + } else { + yield from $this->yieldDefinitionsRecursively($value, $prefix.$key); + } + } + } + + /** + * Splits the given FQN into an array, eg : + * - `'Psr\Log\LoggerInterface->log'` will be `['Psr', '\Log', '\LoggerInterface', '->log()']` + * - `'\Exception->getMessage()'` will be `['\Exception', '->getMessage()']` + * - `'PHP_VERSION'` will be `['PHP_VERSION']` + * + * @param string $fqn + * @return string[] + */ + private function splitFqn(string $fqn): array + { + // split fqn at backslashes + $parts = explode('\\', $fqn); + + // write back the backslach prefix to the first part if it was present + if ('' === $parts[0]) { + if (count($parts) > 1) { + $parts = array_slice($parts, 1); + } + + $parts[0] = '\\' . $parts[0]; + } + + // write back the backslashes prefixes for the other parts + for ($i = 1; $i < count($parts); $i++) { + $parts[$i] = '\\' . $parts[$i]; + } + + // split the last part in 2 parts at the operator + $hasOperator = false; + $lastPart = end($parts); + foreach (['::', '->'] as $operator) { + $endParts = explode($operator, $lastPart); + if (count($endParts) > 1) { + $hasOperator = true; + // replace the last part by its pieces + array_pop($parts); + $parts[] = $endParts[0]; + $parts[] = $operator . $endParts[1]; + break; + } + } + + if (!$hasOperator) { + // add an empty part to store the non-member definition to avoid + // definition collisions in the index array, eg + // 'Psr\Log\LoggerInterface' will be stored at + // ['Psr']['\Log']['\LoggerInterface'][''] to be able to also store + // member definitions, ie 'Psr\Log\LoggerInterface->log()' will be + // stored at ['Psr']['\Log']['\LoggerInterface']['->log()'] + $parts[] = ''; + } + + return $parts; + } + + /** + * Return the values stored in this index under the given $parts array. + * It can be an index node or a Definition if the $parts are precise + * enough. Returns null when nothing is found. + * + * @param string[] $parts The splitted FQN + * @param array &$storage The array in which to store the $definition + * @return array|Definition|null + */ + private function getIndexValue(array $parts, array &$storage) + { + $part = $parts[0]; + + if (!isset($storage[$part])) { + return null; + } + + $parts = array_slice($parts, 1); + // we've reached the last provided part + if (0 === count($parts)) { + return $storage[$part]; + } + + return $this->getIndexValue($parts, $storage[$part]); + } + + /** + * Recursive function that stores the given Definition in the given $storage array represented + * as a tree matching the given $parts. + * + * @param int $level The current level of FQN part + * @param string[] $parts The splitted FQN + * @param array &$storage The array in which to store the $definition + * @param Definition $definition The Definition to store + */ + private function indexDefinition(int $level, array $parts, array &$storage, Definition $definition) + { + $part = $parts[$level]; + + if ($level + 1 === count($parts)) { + $storage[$part] = $definition; + + return; + } + + if (!isset($storage[$part])) { + $storage[$part] = []; + } + + $this->indexDefinition($level + 1, $parts, $storage[$part], $definition); + } + + /** + * Recursive function that removes the definition matching the given $parts from the given + * $storage array. The function also looks up recursively to remove the parents of the + * definition which no longer has children to avoid to let empty arrays in the index. + * + * @param int $level The current level of FQN part + * @param string[] $parts The splitted FQN + * @param array &$storage The current array in which to remove data + * @param array &$rootStorage The root storage array + */ + private function removeIndexedDefinition(int $level, array $parts, array &$storage, array &$rootStorage) + { + $part = $parts[$level]; + + if ($level + 1 === count($parts)) { + if (isset($storage[$part])) { + unset($storage[$part]); + + if (0 === count($storage)) { + // parse again the definition tree to remove the parent + // when it has no more children + $this->removeIndexedDefinition(0, array_slice($parts, 0, $level), $rootStorage, $rootStorage); + } + } + } elseif (isset($storage[$part])) { + $this->removeIndexedDefinition($level + 1, $parts, $storage[$part], $rootStorage); + } + } } diff --git a/src/Index/ReadableIndex.php b/src/Index/ReadableIndex.php index 67b20b63..d02f22b0 100644 --- a/src/Index/ReadableIndex.php +++ b/src/Index/ReadableIndex.php @@ -30,12 +30,22 @@ public function isComplete(): bool; public function isStaticComplete(): bool; /** - * Returns an associative array [string => Definition] that maps fully qualified symbol names - * to Definitions + * Returns a Generator providing an associative array [string => Definition] + * that maps fully qualified symbol names to Definitions (global or not) * - * @return Definitions[] + * @param boolean|null $member Indicates if we want member or non-member definitions (null for both, default null) + * @return \Generator yields Definition */ - public function getDefinitions(): array; + public function getDefinitions(bool $member = null): \Generator; + + /** + * Returns a Generator that yields all the descendant Definitions of a given FQN + * + * @param string $fqn + * @param boolean|null $member Indicates if we want member or non-member definitions (null for both, default null) + * @return \Generator yields Definition + */ + public function getDescendantDefinitionsForFqn(string $fqn, bool $member = null): \Generator; /** * Returns the Definition object by a specific FQN @@ -47,10 +57,10 @@ public function getDefinitions(): array; public function getDefinition(string $fqn, bool $globalFallback = false); /** - * Returns all URIs in this index that reference a symbol + * Returns a Generator that yields all URIs in this index that reference a symbol * * @param string $fqn The fully qualified name of the symbol - * @return string[] + * @return \Generator yields string */ - public function getReferenceUris(string $fqn): array; + public function getReferenceUris(string $fqn): \Generator; } diff --git a/src/Server/TextDocument.php b/src/Server/TextDocument.php index 32094388..0ad2d815 100644 --- a/src/Server/TextDocument.php +++ b/src/Server/TextDocument.php @@ -220,10 +220,11 @@ public function references( return []; } } - $refDocuments = yield Promise\all(array_map( - [$this->documentLoader, 'getOrLoad'], - $this->index->getReferenceUris($fqn) - )); + $refDocumentPromises = []; + foreach ($this->index->getReferenceUris($fqn) as $uri) { + $refDocumentPromises[] = $this->documentLoader->getOrLoad($uri); + } + $refDocuments = yield Promise\all($refDocumentPromises); foreach ($refDocuments as $document) { $refs = $document->getReferenceNodesByFqn($fqn); if ($refs !== null) { diff --git a/tests/Server/TextDocument/CompletionTest.php b/tests/Server/TextDocument/CompletionTest.php index 424dc3ca..97165781 100644 --- a/tests/Server/TextDocument/CompletionTest.php +++ b/tests/Server/TextDocument/CompletionTest.php @@ -652,18 +652,6 @@ public function testThisWithPrefix() new Position(12, 16) )->wait(); $this->assertEquals(new CompletionList([ - new CompletionItem( - 'testProperty', - CompletionItemKind::PROPERTY, - '\TestClass', // Type of the property - 'Reprehenderit magna velit mollit ipsum do.' - ), - new CompletionItem( - 'testMethod', - CompletionItemKind::METHOD, - '\TestClass', // Return type of the method - 'Non culpa nostrud mollit esse sunt laboris in irure ullamco cupidatat amet.' - ), new CompletionItem( 'foo', CompletionItemKind::PROPERTY, @@ -687,7 +675,19 @@ public function testThisWithPrefix() CompletionItemKind::METHOD, 'mixed', // Return type of the method null - ) + ), + new CompletionItem( + 'testProperty', + CompletionItemKind::PROPERTY, + '\TestClass', // Type of the property + 'Reprehenderit magna velit mollit ipsum do.' + ), + new CompletionItem( + 'testMethod', + CompletionItemKind::METHOD, + '\TestClass', // Return type of the method + 'Non culpa nostrud mollit esse sunt laboris in irure ullamco cupidatat amet.' + ), ], true), $items); } @@ -700,11 +700,6 @@ public function testThisReturnValue() new Position(17, 23) )->wait(); $this->assertEquals(new CompletionList([ - new CompletionItem( - 'foo', - CompletionItemKind::METHOD, - '$this' // Return type of the method - ), new CompletionItem( 'bar', CompletionItemKind::METHOD, @@ -714,7 +709,12 @@ public function testThisReturnValue() 'qux', CompletionItemKind::METHOD, 'mixed' // Return type of the method - ) + ), + new CompletionItem( + 'foo', + CompletionItemKind::METHOD, + '$this' // Return type of the method + ), ], true), $items); } } diff --git a/tests/Server/Workspace/SymbolTest.php b/tests/Server/Workspace/SymbolTest.php index 765841bb..02de5abe 100644 --- a/tests/Server/Workspace/SymbolTest.php +++ b/tests/Server/Workspace/SymbolTest.php @@ -30,41 +30,40 @@ public function testEmptyQueryReturnsAllSymbols() // @codingStandardsIgnoreStart $this->assertEquals([ - new SymbolInformation('TestNamespace', SymbolKind::NAMESPACE, new Location($referencesUri, new Range(new Position(2, 0), new Position(2, 24))), ''), - // Namespaced - new SymbolInformation('TEST_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestNamespace\\TEST_CONST'), 'TestNamespace'), - new SymbolInformation('TestClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\TestClass'), 'TestNamespace'), + // member new SymbolInformation('TEST_CLASS_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestNamespace\\TestClass::TEST_CLASS_CONST'), 'TestNamespace\\TestClass'), new SymbolInformation('staticTestProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestNamespace\\TestClass::staticTestProperty'), 'TestNamespace\\TestClass'), new SymbolInformation('testProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestNamespace\\TestClass::testProperty'), 'TestNamespace\\TestClass'), new SymbolInformation('staticTestMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestNamespace\\TestClass::staticTestMethod()'), 'TestNamespace\\TestClass'), new SymbolInformation('testMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestNamespace\\TestClass::testMethod()'), 'TestNamespace\\TestClass'), + new SymbolInformation('__construct', SymbolKind::CONSTRUCTOR, $this->getDefinitionLocation('TestNamespace\\Example::__construct'), 'TestNamespace\\Example'), + new SymbolInformation('__destruct', SymbolKind::CONSTRUCTOR, $this->getDefinitionLocation('TestNamespace\\Example::__destruct'), 'TestNamespace\\Example'), + new SymbolInformation('TEST_CLASS_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestClass::TEST_CLASS_CONST'), 'TestClass'), + new SymbolInformation('staticTestProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestClass::staticTestProperty'), 'TestClass'), + new SymbolInformation('testProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestClass::testProperty'), 'TestClass'), + new SymbolInformation('staticTestMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestClass::staticTestMethod()'), 'TestClass'), + new SymbolInformation('testMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestClass::testMethod()'), 'TestClass'), + // non member + new SymbolInformation('TEST_DEFINE_CONSTANT', SymbolKind::CONSTANT, $this->getDefinitionLocation('TEST_DEFINE_CONSTANT'), ''), + new SymbolInformation('unusedProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('UnusedClass::unusedProperty'), 'UnusedClass'), + new SymbolInformation('unusedMethod', SymbolKind::METHOD, $this->getDefinitionLocation('UnusedClass::unusedMethod'), 'UnusedClass'), + new SymbolInformation('TestNamespace', SymbolKind::NAMESPACE, new Location($referencesUri, new Range(new Position(2, 0), new Position(2, 24))), ''), + new SymbolInformation('TEST_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestNamespace\\TEST_CONST'), 'TestNamespace'), + new SymbolInformation('TestClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\TestClass'), 'TestNamespace'), new SymbolInformation('TestTrait', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\TestTrait'), 'TestNamespace'), new SymbolInformation('TestInterface', SymbolKind::INTERFACE, $this->getDefinitionLocation('TestNamespace\\TestInterface'), 'TestNamespace'), new SymbolInformation('test_function', SymbolKind::FUNCTION, $this->getDefinitionLocation('TestNamespace\\test_function()'), 'TestNamespace'), new SymbolInformation('ChildClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\ChildClass'), 'TestNamespace'), new SymbolInformation('Example', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\Example'), 'TestNamespace'), - new SymbolInformation('__construct', SymbolKind::CONSTRUCTOR, $this->getDefinitionLocation('TestNamespace\\Example::__construct'), 'TestNamespace\\Example'), - new SymbolInformation('__destruct', SymbolKind::CONSTRUCTOR, $this->getDefinitionLocation('TestNamespace\\Example::__destruct'), 'TestNamespace\\Example'), new SymbolInformation('whatever', SymbolKind::FUNCTION, $this->getDefinitionLocation('TestNamespace\\whatever()'), 'TestNamespace'), - // Global new SymbolInformation('TEST_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TEST_CONST'), ''), new SymbolInformation('TestClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestClass'), ''), - new SymbolInformation('TEST_CLASS_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestClass::TEST_CLASS_CONST'), 'TestClass'), - new SymbolInformation('staticTestProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestClass::staticTestProperty'), 'TestClass'), - new SymbolInformation('testProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestClass::testProperty'), 'TestClass'), - new SymbolInformation('staticTestMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestClass::staticTestMethod()'), 'TestClass'), - new SymbolInformation('testMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestClass::testMethod()'), 'TestClass'), new SymbolInformation('TestTrait', SymbolKind::CLASS_, $this->getDefinitionLocation('TestTrait'), ''), new SymbolInformation('TestInterface', SymbolKind::INTERFACE, $this->getDefinitionLocation('TestInterface'), ''), new SymbolInformation('test_function', SymbolKind::FUNCTION, $this->getDefinitionLocation('test_function()'), ''), new SymbolInformation('ChildClass', SymbolKind::CLASS_, $this->getDefinitionLocation('ChildClass'), ''), - new SymbolInformation('TEST_DEFINE_CONSTANT', SymbolKind::CONSTANT, $this->getDefinitionLocation('TEST_DEFINE_CONSTANT'), ''), new SymbolInformation('UnusedClass', SymbolKind::CLASS_, $this->getDefinitionLocation('UnusedClass'), ''), - new SymbolInformation('unusedProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('UnusedClass::unusedProperty'), 'UnusedClass'), - new SymbolInformation('unusedMethod', SymbolKind::METHOD, $this->getDefinitionLocation('UnusedClass::unusedMethod'), 'UnusedClass'), new SymbolInformation('whatever', SymbolKind::FUNCTION, $this->getDefinitionLocation('whatever()'), ''), - new SymbolInformation('SecondTestNamespace', SymbolKind::NAMESPACE, $this->getDefinitionLocation('SecondTestNamespace'), ''), ], $result); // @codingStandardsIgnoreEnd