1
0
Fork 0

speedup autocomplete with ReadableIndex::getDefinitionsForNamespace

pull/451/head
Nicolas MURE 2017-08-06 16:48:41 +02:00
parent 1ec8d8d8e2
commit 2d91ee8eff
No known key found for this signature in database
GPG Key ID: E5B036F9145C4CAA
4 changed files with 133 additions and 6 deletions

View File

@ -201,21 +201,44 @@ class CompletionProvider
$this->definitionResolver->resolveExpressionNodeToType($node->dereferencableExpression) $this->definitionResolver->resolveExpressionNodeToType($node->dereferencableExpression)
); );
$checksCount = 0;
$start = microtime(true);
// Add the object access operator to only get members of all parents // Add the object access operator to only get members of all parents
$prefixes = []; $namespaces = [];
foreach ($this->expandParentFqns($fqns) as $prefix) { foreach ($this->expandParentFqns($fqns) as $namespace) {
$prefixes[] = $prefix . '->'; $namespaces[] = $namespace;
} }
// Collect all definitions that match any of the prefixes // Collect all definitions that match any of the prefixes
foreach ($this->index->getDefinitions() as $fqn => $def) { foreach ($namespaces as $namespace) {
foreach ($prefixes as $prefix) { foreach ($this->index->getDefinitionsForNamespace($namespace) as $fqn => $def) {
if (substr($fqn, 0, strlen($prefix)) === $prefix && $def->isMember) { ++$checksCount;
$prefix = $namespace . '->';
if (substr($fqn, 0, strlen($prefix)) === $prefix && !$def->isMember) {
$list->items[] = CompletionItem::fromDefinition($def); $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 ( } elseif (
($scoped = $node->parent) instanceof Node\Expression\ScopedPropertyAccessExpression || ($scoped = $node->parent) instanceof Node\Expression\ScopedPropertyAccessExpression ||
($scoped = $node) instanceof Node\Expression\ScopedPropertyAccessExpression ($scoped = $node) instanceof Node\Expression\ScopedPropertyAccessExpression

View File

@ -115,6 +115,23 @@ abstract class AbstractAggregateIndex implements ReadableIndex
return $defs; 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 * Returns the Definition object by a specific FQN
* *

View File

@ -21,6 +21,13 @@ class Index implements ReadableIndex, \Serializable
*/ */
private $definitions = []; 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 * 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; 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 * Returns the Definition object by a specific FQN
* *
@ -123,6 +144,7 @@ class Index implements ReadableIndex, \Serializable
public function setDefinition(string $fqn, Definition $definition) public function setDefinition(string $fqn, Definition $definition)
{ {
$this->definitions[$fqn] = $definition; $this->definitions[$fqn] = $definition;
$this->setNamespaceDefinition($fqn, $definition);
$this->emit('definition-added'); $this->emit('definition-added');
} }
@ -137,6 +159,7 @@ class Index implements ReadableIndex, \Serializable
{ {
unset($this->definitions[$fqn]); unset($this->definitions[$fqn]);
unset($this->references[$fqn]); unset($this->references[$fqn]);
$this->removeNamespaceDefinition($fqn);
} }
/** /**
@ -207,6 +230,7 @@ class Index implements ReadableIndex, \Serializable
foreach ($data as $prop => $val) { foreach ($data as $prop => $val) {
$this->$prop = $val; $this->$prop = $val;
} }
$this->buildNamespaceDefinitionsIndex();
} }
/** /**
@ -222,4 +246,59 @@ class Index implements ReadableIndex, \Serializable
'staticComplete' => $this->staticComplete '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;
}
} }

View File

@ -37,6 +37,14 @@ interface ReadableIndex extends EmitterInterface
*/ */
public function getDefinitions(): array; 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 * Returns the Definition object by a specific FQN
* *