speedup autocomplete with ReadableIndex::getDefinitionsForNamespace
parent
1ec8d8d8e2
commit
2d91ee8eff
|
@ -201,21 +201,44 @@ class CompletionProvider
|
|||
$this->definitionResolver->resolveExpressionNodeToType($node->dereferencableExpression)
|
||||
);
|
||||
|
||||
$checksCount = 0;
|
||||
$start = microtime(true);
|
||||
// Add the object access operator to only get members of all parents
|
||||
$prefixes = [];
|
||||
foreach ($this->expandParentFqns($fqns) as $prefix) {
|
||||
$prefixes[] = $prefix . '->';
|
||||
$namespaces = [];
|
||||
foreach ($this->expandParentFqns($fqns) as $namespace) {
|
||||
$namespaces[] = $namespace;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
foreach ($namespaces as $namespace) {
|
||||
foreach ($this->index->getDefinitionsForNamespace($namespace) as $fqn => $def) {
|
||||
++$checksCount;
|
||||
$prefix = $namespace . '->';
|
||||
if (substr($fqn, 0, strlen($prefix)) === $prefix && !$def->isMember) {
|
||||
$list->items[] = CompletionItem::fromDefinition($def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// $prefixes = [];
|
||||
// foreach ($this->expandParentFqns($fqns) as $prefix) {
|
||||
// $prefixes[] = $prefix . '->';
|
||||
// }
|
||||
// foreach ($this->index->getDefinitions() as $fqn => $def) {
|
||||
// foreach ($prefixes as $prefix) {
|
||||
// ++$checksCount;
|
||||
// if (substr($fqn, 0, strlen($prefix)) === $prefix && !$def->isGlobal) {
|
||||
// $list->items[] = CompletionItem::fromDefinition($def);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
$duration = microtime(true) - $start;
|
||||
file_put_contents(
|
||||
'/home/nicolas/tmp/php_language-server.log',
|
||||
sprintf("%d items found, %d checks, memory : %d bytes, %ss\n", sizeof($list->items), $checksCount, memory_get_usage(true), $duration),
|
||||
FILE_APPEND
|
||||
);
|
||||
|
||||
} elseif (
|
||||
($scoped = $node->parent) instanceof Node\Expression\ScopedPropertyAccessExpression ||
|
||||
($scoped = $node) instanceof Node\Expression\ScopedPropertyAccessExpression
|
||||
|
|
|
@ -115,6 +115,23 @@ abstract class AbstractAggregateIndex implements ReadableIndex
|
|||
return $defs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Definitions that are in the given namespace
|
||||
*
|
||||
* @param string $namespace
|
||||
* @return Definitions[]
|
||||
*/
|
||||
public function getDefinitionsForNamespace(string $namespace): array
|
||||
{
|
||||
$defs = [];
|
||||
foreach ($this->getIndexes() as $index) {
|
||||
foreach ($index->getDefinitionsForNamespace($namespace) as $fqn => $def) {
|
||||
$defs[$fqn] = $def;
|
||||
}
|
||||
}
|
||||
return $defs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Definition object by a specific FQN
|
||||
*
|
||||
|
|
|
@ -21,6 +21,13 @@ class Index implements ReadableIndex, \Serializable
|
|||
*/
|
||||
private $definitions = [];
|
||||
|
||||
/**
|
||||
* An associative array that maps namespaces to an associative array of FQN to Definitions
|
||||
*
|
||||
* @var Definition[]
|
||||
*/
|
||||
private $namespaceDefinitions = [];
|
||||
|
||||
/**
|
||||
* An associative array that maps fully qualified symbol names to arrays of document URIs that reference the symbol
|
||||
*
|
||||
|
@ -94,6 +101,20 @@ class Index implements ReadableIndex, \Serializable
|
|||
return $this->definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Definitions that are in the given namespace
|
||||
*
|
||||
* @param string $namespace
|
||||
* @return Definitions[]
|
||||
*/
|
||||
public function getDefinitionsForNamespace(string $namespace): array
|
||||
{
|
||||
return isset($this->namespaceDefinitions[$namespace])
|
||||
? $this->namespaceDefinitions[$namespace]
|
||||
: []
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Definition object by a specific FQN
|
||||
*
|
||||
|
@ -123,6 +144,7 @@ class Index implements ReadableIndex, \Serializable
|
|||
public function setDefinition(string $fqn, Definition $definition)
|
||||
{
|
||||
$this->definitions[$fqn] = $definition;
|
||||
$this->setNamespaceDefinition($fqn, $definition);
|
||||
$this->emit('definition-added');
|
||||
}
|
||||
|
||||
|
@ -137,6 +159,7 @@ class Index implements ReadableIndex, \Serializable
|
|||
{
|
||||
unset($this->definitions[$fqn]);
|
||||
unset($this->references[$fqn]);
|
||||
$this->removeNamespaceDefinition($fqn);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -207,6 +230,7 @@ class Index implements ReadableIndex, \Serializable
|
|||
foreach ($data as $prop => $val) {
|
||||
$this->$prop = $val;
|
||||
}
|
||||
$this->buildNamespaceDefinitionsIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -222,4 +246,59 @@ class Index implements ReadableIndex, \Serializable
|
|||
'staticComplete' => $this->staticComplete
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private function buildNamespaceDefinitionsIndex()
|
||||
{
|
||||
foreach ($this->definitions as $fqn => $definition) {
|
||||
$this->setNamespaceDefinition($fqn, $definition);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a definition to a namespace
|
||||
*
|
||||
* @param string $fqn The fully qualified name of the symbol
|
||||
* @param Definition $definition The Definition object
|
||||
* @return void
|
||||
*/
|
||||
private function setNamespaceDefinition(string $fqn, Definition $definition)
|
||||
{
|
||||
$namespace = $this->extractNamespace($fqn);
|
||||
if (!isset($this->namespaceDefinitions[$namespace])) {
|
||||
$this->namespaceDefinitions[$namespace] = [];
|
||||
}
|
||||
$this->namespaceDefinitions[$namespace][$fqn] = $definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a definition from a namespace
|
||||
*
|
||||
* @param string $fqn The fully qualified name of the symbol
|
||||
* @return void
|
||||
*/
|
||||
private function removeNamespaceDefinition(string $fqn)
|
||||
{
|
||||
$namespace = $this->extractNamespace($fqn);
|
||||
if (isset($this->namespaceDefinitions[$namespace])) {
|
||||
unset($this->namespaceDefinitions[$namespace][$fqn]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fqn
|
||||
* @return string The namespace extracted from the given FQN
|
||||
*/
|
||||
private function extractNamespace(string $fqn): string
|
||||
{
|
||||
foreach (['::', '->'] as $operator) {
|
||||
if (false !== ($pos = strpos($fqn, $operator))) {
|
||||
return substr($fqn, 0, $pos);
|
||||
}
|
||||
}
|
||||
|
||||
return $fqn;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,14 @@ interface ReadableIndex extends EmitterInterface
|
|||
*/
|
||||
public function getDefinitions(): array;
|
||||
|
||||
/**
|
||||
* Returns the Definitions that are in the given namespace
|
||||
*
|
||||
* @param string $namespace
|
||||
* @return Definitions[]
|
||||
*/
|
||||
public function getDefinitionsForNamespace(string $namespace): array;
|
||||
|
||||
/**
|
||||
* Returns the Definition object by a specific FQN
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue