From 56d95102d8497593997dcb6041f34c2550c3d56b Mon Sep 17 00:00:00 2001 From: Ivan Bozhanov Date: Thu, 6 Jul 2017 19:29:13 +0300 Subject: [PATCH] moved ancestor generator to Definition --- src/CompletionProvider.php | 15 ++++++--------- src/Definition.php | 39 ++++++++++++++++++++++++++++++++++++++ src/DefinitionResolver.php | 24 +++++++++-------------- 3 files changed, 54 insertions(+), 24 deletions(-) diff --git a/src/CompletionProvider.php b/src/CompletionProvider.php index f4f091d..eff8c33 100644 --- a/src/CompletionProvider.php +++ b/src/CompletionProvider.php @@ -201,7 +201,7 @@ class CompletionProvider ); // Include parent classes - $prefixes = $this->expandParentFqns($prefixes); + $prefixes = iterator_to_array($this->expandParentFqns($prefixes), false); // Add the object access operator to only get members foreach ($prefixes as &$prefix) { @@ -237,7 +237,7 @@ class CompletionProvider ); // Add parent classes - $prefixes = $this->expandParentFqns($prefixes); + $prefixes = iterator_to_array($this->expandParentFqns($prefixes), false); // Append :: operator to only get static members foreach ($prefixes as &$prefix) { @@ -382,18 +382,15 @@ class CompletionProvider * @param string[] $fqns * @return string[] */ - private function expandParentFqns(array $fqns): array + private function expandParentFqns(array $fqns) { - $expanded = $fqns; foreach ($fqns as $fqn) { + yield $fqn; $def = $this->index->getDefinition($fqn); - if ($def) { - foreach ($this->expandParentFqns($def->extends ?? []) as $parent) { - $expanded[] = $parent; - } + if ($def !== null) { + yield from $def->getAncestorFQNs($this->index); } } - return $expanded; } /** diff --git a/src/Definition.php b/src/Definition.php index cf0f574..02afb62 100644 --- a/src/Definition.php +++ b/src/Definition.php @@ -3,6 +3,7 @@ declare(strict_types = 1); namespace LanguageServer; +use LanguageServer\Index\ReadableIndex; use phpDocumentor\Reflection\{Types, Type, Fqsen, TypeResolver}; use LanguageServer\Protocol\SymbolInformation; use Exception; @@ -95,4 +96,42 @@ class Definition * @var string */ public $documentation; + + /** + * Gets the definitons of all ancestor classes + * + * @return Definition[] + */ + public function getAncestorDefinitions(ReadableIndex $index, bool $includeSelf = false) + { + if ($includeSelf) { + yield $this; + } + if (is_array($this->extends)) { + // iterating once, storing the references and iterating again + // guarantees that closest definitions are returned first + $definitions = []; + foreach ($this->extends as $fqn) { + $def = $index->getDefinition($fqn); + if ($def !== null) { + yield $def; + $definitions[] = $def; + } + } + foreach ($definitions as $def) { + yield from $def->getAncestorDefinitions($index); + } + } + } + /** + * Gets the FQNs of all parent classes + * + * @return string[] + */ + public function getAncestorFQNs(ReadableIndex $index, bool $includeSelf = false) + { + foreach ($this->getAncestorDefinitions($index, $includeSelf) as $def) { + yield $def->fqn; + } + } } diff --git a/src/DefinitionResolver.php b/src/DefinitionResolver.php index 3650b59..4483a6c 100644 --- a/src/DefinitionResolver.php +++ b/src/DefinitionResolver.php @@ -670,23 +670,17 @@ class DefinitionResolver if ($expr->parent instanceof Node\Expression\CallExpression) { $add .= '()'; } - $lookupDefinition = function (string $base, string $add) use (&$lookupDefinition) { - $def = $this->index->getDefinition($base . $add); - if ($def !== null) { - yield $def; - } - $baseDef = $this->index->getDefinition($base); - if ($baseDef !== null && is_array($baseDef->extends)) { - foreach ($baseDef->extends as $name) { - yield from $lookupDefinition($name, $add); + $classDef = $this->index->getDefinition($classFqn); + if ($classDef !== null) { + foreach ($classDef->getAncestorFQNs($this->index, true) as $fqn) { + $def = $this->index->getDefinition($fqn . $add); + if ($def !== null) { + if ($def->type instanceof Types\This) { + return new Types\Object_(new Fqsen('\\' . $classFqn)); + } + return $def->type; } } - }; - foreach ($lookupDefinition($classFqn, $add) as $def) { - if ($def->type instanceof Types\This) { - return new Types\Object_(new Fqsen('\\' . $classFqn)); - } - return $def->type; } } }