feat(completion): completion for relative names
parent
0bc5b81561
commit
75e07b86a0
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TestNamespace\InnerNamespace;
|
||||||
|
|
||||||
|
use TestNamespace\TestClass as InnerClass;
|
||||||
|
|
||||||
|
// Both of these should complete to namespace\InnerClass, for \TestNamespace\InnerNamespace\InnerClass
|
||||||
|
namespace\;
|
||||||
|
namespace\InnerCl;
|
|
@ -277,6 +277,7 @@ class CompletionProvider
|
||||||
|
|
||||||
} elseif (
|
} elseif (
|
||||||
ParserHelpers\isConstantFetch($node)
|
ParserHelpers\isConstantFetch($node)
|
||||||
|
|| $node instanceof Node\RelativeSpecifier
|
||||||
// Creation gets set in case of an instantiation (`new` expression)
|
// Creation gets set in case of an instantiation (`new` expression)
|
||||||
|| ($creation = $node->parent) instanceof Node\Expression\ObjectCreationExpression
|
|| ($creation = $node->parent) instanceof Node\Expression\ObjectCreationExpression
|
||||||
|| (($creation = $node) instanceof Node\Expression\ObjectCreationExpression)
|
|| (($creation = $node) instanceof Node\Expression\ObjectCreationExpression)
|
||||||
|
@ -288,13 +289,19 @@ class CompletionProvider
|
||||||
// MY_CONS|
|
// MY_CONS|
|
||||||
// MyCla|
|
// MyCla|
|
||||||
// \MyCla|
|
// \MyCla|
|
||||||
|
// namespace\| // This is the special case when Node\RelativeSpecifier is matched.
|
||||||
|
// namespace\MyC|
|
||||||
|
|
||||||
// The name Node under the cursor
|
// The name Node under the cursor
|
||||||
$nameNode = isset($creation) ? $creation->classTypeDesignator : $node;
|
$nameNode = isset($creation) ? $creation->classTypeDesignator : $node;
|
||||||
|
|
||||||
if ($nameNode instanceof Node\QualifiedName) {
|
if ($nameNode instanceof Node\QualifiedName) {
|
||||||
/** @var string The typed name. */
|
/** @var string The typed name. If relative, without the namespace\. */
|
||||||
$prefix = (string)PhpParser\ResolvedName::buildName($nameNode->nameParts, $nameNode->getFileContents());
|
$prefix = (string)PhpParser\ResolvedName::buildName($nameNode->nameParts, $nameNode->getFileContents());
|
||||||
|
} else if ($nameNode instanceof Node\RelativeSpecifier) {
|
||||||
|
// The prefix is supposed to not have the leading namespace\ specifier. The token at point is
|
||||||
|
// "namespace\", so prefix should be empty.
|
||||||
|
$prefix = '';
|
||||||
} else {
|
} else {
|
||||||
$prefix = $nameNode->getText($node->getFileContents());
|
$prefix = $nameNode->getText($node->getFileContents());
|
||||||
}
|
}
|
||||||
|
@ -305,13 +312,16 @@ class CompletionProvider
|
||||||
|
|
||||||
/** @var bool Whether the prefix is qualified (contains at least one backslash) */
|
/** @var bool Whether the prefix is qualified (contains at least one backslash) */
|
||||||
$isFullyQualified = false;
|
$isFullyQualified = false;
|
||||||
|
/** @var bool|null Whether the prefix is qualified (contains at least one backslash) */
|
||||||
/** @var bool Whether the prefix is qualified (contains at least one backslash) */
|
|
||||||
$isQualified = false;
|
$isQualified = false;
|
||||||
|
/** @var bool Whether the prefix starts with namespace\ */
|
||||||
|
$isRelative = false;
|
||||||
if ($nameNode instanceof Node\QualifiedName) {
|
if ($nameNode instanceof Node\QualifiedName) {
|
||||||
$isFullyQualified = $nameNode->isFullyQualifiedName();
|
$isFullyQualified = $nameNode->isFullyQualifiedName();
|
||||||
$isQualified = $nameNode->isQualifiedName();
|
$isQualified = $nameNode->isQualifiedName();
|
||||||
|
$isRelative = $nameNode->isRelativeName();
|
||||||
|
} else if ($nameNode instanceof Node\RelativeSpecifier) {
|
||||||
|
$isRelative = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var bool Whether we are in a new expression */
|
/** @var bool Whether we are in a new expression */
|
||||||
|
@ -324,6 +334,9 @@ class CompletionProvider
|
||||||
// \Prefix\Goes\Here| - Only return completions from the root namespace.
|
// \Prefix\Goes\Here| - Only return completions from the root namespace.
|
||||||
/** @var $items \Generator|CompletionItem[] Generator yielding CompletionItems indexed by their FQN */
|
/** @var $items \Generator|CompletionItem[] Generator yielding CompletionItems indexed by their FQN */
|
||||||
$items = $this->getCompletionsForFqnPrefix($prefix, $isCreation, false);
|
$items = $this->getCompletionsForFqnPrefix($prefix, $isCreation, false);
|
||||||
|
} else if ($isRelative) {
|
||||||
|
// namespace\Something| - Only return completions from the current namespace.
|
||||||
|
$items = $this->getCompletionsForFqnPrefix(nameConcat($currentNamespace, $prefix), $isCreation, false);
|
||||||
} else if ($isQualified) {
|
} else if ($isQualified) {
|
||||||
// Prefix\Goes\Here|
|
// Prefix\Goes\Here|
|
||||||
$items = $this->getPartiallyQualifiedCompletions(
|
$items = $this->getPartiallyQualifiedCompletions(
|
||||||
|
|
|
@ -325,6 +325,54 @@ class CompletionTest extends TestCase
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests completion at `namespace\|`
|
||||||
|
*/
|
||||||
|
public function testRelativeNoPrefix()
|
||||||
|
{
|
||||||
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/relative.php');
|
||||||
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
|
$items = $this->textDocument->completion(
|
||||||
|
new TextDocumentIdentifier($completionUri),
|
||||||
|
new Position(7, 10)
|
||||||
|
)->wait();
|
||||||
|
$this->assertEquals(
|
||||||
|
new CompletionList([
|
||||||
|
new CompletionItem(
|
||||||
|
'InnerClass',
|
||||||
|
CompletionItemKind::CLASS_,
|
||||||
|
'TestNamespace\InnerNamespace',
|
||||||
|
''
|
||||||
|
),
|
||||||
|
], true),
|
||||||
|
$items
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests completion at `namespace\TestCla|`
|
||||||
|
*/
|
||||||
|
public function testRelativeWithPrefix()
|
||||||
|
{
|
||||||
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/relative.php');
|
||||||
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
|
$items = $this->textDocument->completion(
|
||||||
|
new TextDocumentIdentifier($completionUri),
|
||||||
|
new Position(8, 17)
|
||||||
|
)->wait();
|
||||||
|
$this->assertEquals(
|
||||||
|
new CompletionList([
|
||||||
|
new CompletionItem(
|
||||||
|
'InnerClass',
|
||||||
|
CompletionItemKind::CLASS_,
|
||||||
|
'TestNamespace\InnerNamespace',
|
||||||
|
''
|
||||||
|
),
|
||||||
|
], true),
|
||||||
|
$items
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests completion at `TestClass::$st|`
|
* Tests completion at `TestClass::$st|`
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue