feat(completion): complete function and constant aliases
parent
f5b1256cf9
commit
10a4592d9a
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Whatever;
|
||||||
|
|
||||||
|
use const TestNamespace\InnerNamespace\INNER_CONST;
|
||||||
|
use const TestNamespace\InnerNamespace\INNER_CONST as ALIASED_CONST;
|
||||||
|
use const TestNamespace\InnerNamespace\NON_EXISTENT_CONST;
|
||||||
|
|
||||||
|
INNER_C;
|
||||||
|
|
||||||
|
ALIASED_C;
|
||||||
|
|
||||||
|
NON_EXISTENT_C;
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TestNs;
|
||||||
|
|
||||||
|
use function TestNamespace\InnerNamespace\inner_function;
|
||||||
|
use function TestNamespace\InnerNamespace\inner_function2 as second_function;
|
||||||
|
use function TestNamespace\InnerNamespace\i_dont_exist;
|
||||||
|
|
||||||
|
inner_f;
|
||||||
|
second_f;
|
||||||
|
i_dont_ex;
|
|
@ -108,3 +108,8 @@ namespace TestNamespace\InnerNamespace;
|
||||||
|
|
||||||
class InnerClass {
|
class InnerClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const INNER_CONST = 333;
|
||||||
|
|
||||||
|
function inner_function(InnerClass $i) {}
|
||||||
|
function inner_function2(InnerClass $i) {}
|
||||||
|
|
|
@ -389,6 +389,8 @@ class CompletionProvider
|
||||||
*
|
*
|
||||||
* Yields
|
* Yields
|
||||||
* - Aliased classes
|
* - Aliased classes
|
||||||
|
* - Aliased functions (when not creating)
|
||||||
|
* - Aliased constants (when not creating)
|
||||||
* - Completions from current namespace
|
* - Completions from current namespace
|
||||||
* - Roamed completions from the global namespace (when not creating and not already in root NS)
|
* - Roamed completions from the global namespace (when not creating and not already in root NS)
|
||||||
* - PHP keywords (when not creating)
|
* - PHP keywords (when not creating)
|
||||||
|
@ -403,7 +405,7 @@ class CompletionProvider
|
||||||
bool $requireCanBeInstantiated
|
bool $requireCanBeInstantiated
|
||||||
): \Generator {
|
): \Generator {
|
||||||
// Aliases
|
// Aliases
|
||||||
list($namespaceAliases,,) = $importTables;
|
list($namespaceAliases, $functionAliases, $constAliases) = $importTables;
|
||||||
// use Foo\Bar
|
// use Foo\Bar
|
||||||
yield from $this->getCompletionsForAliases(
|
yield from $this->getCompletionsForAliases(
|
||||||
$prefix,
|
$prefix,
|
||||||
|
@ -411,6 +413,12 @@ class CompletionProvider
|
||||||
$requireCanBeInstantiated,
|
$requireCanBeInstantiated,
|
||||||
CompletionItemKind::CLASS_
|
CompletionItemKind::CLASS_
|
||||||
);
|
);
|
||||||
|
if (!$requireCanBeInstantiated) {
|
||||||
|
// use function Foo\createBar
|
||||||
|
yield from $this->getCompletionsForAliases($prefix, $functionAliases, false, CompletionItemKind::FUNCTION);
|
||||||
|
// use const Foo\BAR_TYPE_COCKTAIL
|
||||||
|
yield from $this->getCompletionsForAliases($prefix, $constAliases, false, CompletionItemKind::VARIABLE);
|
||||||
|
}
|
||||||
|
|
||||||
// Completions from the current namespace
|
// Completions from the current namespace
|
||||||
yield from $this->getCompletionsForFqnPrefix(
|
yield from $this->getCompletionsForFqnPrefix(
|
||||||
|
|
|
@ -38,8 +38,12 @@ class DefinitionCollectorTest extends TestCase
|
||||||
'TestNamespace\\Example->__destruct()',
|
'TestNamespace\\Example->__destruct()',
|
||||||
'TestNamespace\\InnerNamespace',
|
'TestNamespace\\InnerNamespace',
|
||||||
'TestNamespace\\InnerNamespace\\InnerClass',
|
'TestNamespace\\InnerNamespace\\InnerClass',
|
||||||
|
'TestNamespace\\InnerNamespace\\INNER_CONST',
|
||||||
|
'TestNamespace\\InnerNamespace\\inner_function()',
|
||||||
|
'TestNamespace\\InnerNamespace\\inner_function2()',
|
||||||
], array_keys($defNodes));
|
], array_keys($defNodes));
|
||||||
|
|
||||||
|
// @codingStandardsIgnoreStart
|
||||||
$this->assertInstanceOf(Node\ConstElement::class, $defNodes['TestNamespace\\TEST_CONST']);
|
$this->assertInstanceOf(Node\ConstElement::class, $defNodes['TestNamespace\\TEST_CONST']);
|
||||||
$this->assertInstanceOf(Node\Statement\ClassDeclaration::class, $defNodes['TestNamespace\\TestClass']);
|
$this->assertInstanceOf(Node\Statement\ClassDeclaration::class, $defNodes['TestNamespace\\TestClass']);
|
||||||
$this->assertInstanceOf(Node\ConstElement::class, $defNodes['TestNamespace\\TestClass::TEST_CLASS_CONST']);
|
$this->assertInstanceOf(Node\ConstElement::class, $defNodes['TestNamespace\\TestClass::TEST_CLASS_CONST']);
|
||||||
|
@ -56,6 +60,10 @@ class DefinitionCollectorTest extends TestCase
|
||||||
$this->assertInstanceOf(Node\MethodDeclaration::class, $defNodes['TestNamespace\\Example->__construct()']);
|
$this->assertInstanceOf(Node\MethodDeclaration::class, $defNodes['TestNamespace\\Example->__construct()']);
|
||||||
$this->assertInstanceOf(Node\MethodDeclaration::class, $defNodes['TestNamespace\\Example->__destruct()']);
|
$this->assertInstanceOf(Node\MethodDeclaration::class, $defNodes['TestNamespace\\Example->__destruct()']);
|
||||||
$this->assertInstanceOf(Node\Statement\ClassDeclaration::class, $defNodes['TestNamespace\\InnerNamespace\\InnerClass']);
|
$this->assertInstanceOf(Node\Statement\ClassDeclaration::class, $defNodes['TestNamespace\\InnerNamespace\\InnerClass']);
|
||||||
|
$this->assertInstanceOf(Node\ConstElement::class, $defNodes['TestNamespace\InnerNamespace\INNER_CONST']);
|
||||||
|
$this->assertInstanceOf(Node\Statement\FunctionDeclaration::class, $defNodes['TestNamespace\InnerNamespace\inner_function()']);
|
||||||
|
$this->assertInstanceOf(Node\Statement\FunctionDeclaration::class, $defNodes['TestNamespace\InnerNamespace\inner_function2()']);
|
||||||
|
// @codingStandardsIgnoreEnd
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDoesNotCollectReferences()
|
public function testDoesNotCollectReferences()
|
||||||
|
|
|
@ -110,6 +110,9 @@ abstract class ServerTestCase extends TestCase
|
||||||
'TestNamespace\\Example::__destruct' => new Location($symbolsUri, new Range(new Position(103, 4), new Position(103, 35))),
|
'TestNamespace\\Example::__destruct' => new Location($symbolsUri, new Range(new Position(103, 4), new Position(103, 35))),
|
||||||
'TestNamespace\\InnerNamespace' => new Location($symbolsUri, new Range(new Position(106, 0), new Position(106, 39))),
|
'TestNamespace\\InnerNamespace' => new Location($symbolsUri, new Range(new Position(106, 0), new Position(106, 39))),
|
||||||
'TestNamespace\\InnerNamespace\\InnerClass' => new Location($symbolsUri, new Range(new Position(108, 0), new Position(109, 1))),
|
'TestNamespace\\InnerNamespace\\InnerClass' => new Location($symbolsUri, new Range(new Position(108, 0), new Position(109, 1))),
|
||||||
|
'TestNamespace\\InnerNamespace\\INNER_CONST' => new Location($symbolsUri, new Range(new Position(111, 6), new Position(111, 23))),
|
||||||
|
'TestNamespace\\InnerNamespace\\inner_function()' => new Location($symbolsUri, new Range(new Position(113, 0), new Position(113, 41))),
|
||||||
|
'TestNamespace\\InnerNamespace\\inner_function2()' => new Location($symbolsUri, new Range(new Position(114, 0), new Position(114, 42))),
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->referenceLocations = [
|
$this->referenceLocations = [
|
||||||
|
|
|
@ -315,7 +315,16 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
'AliasNamespace\\InnerClass'
|
'AliasNamespace\\InnerClass'
|
||||||
)
|
),
|
||||||
|
new CompletionItem(
|
||||||
|
'INNER_CONST',
|
||||||
|
CompletionItemKind::VARIABLE,
|
||||||
|
'int',
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
'AliasNamespace\\INNER_CONST'
|
||||||
|
),
|
||||||
], true),
|
], true),
|
||||||
$items
|
$items
|
||||||
);
|
);
|
||||||
|
@ -343,6 +352,180 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
'AliasNamespace\InnerClass'
|
'AliasNamespace\InnerClass'
|
||||||
),
|
),
|
||||||
|
new CompletionItem(
|
||||||
|
'INNER_CONST',
|
||||||
|
CompletionItemKind::VARIABLE,
|
||||||
|
'int',
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
'AliasNamespace\INNER_CONST'
|
||||||
|
),
|
||||||
|
new CompletionItem(
|
||||||
|
'inner_function',
|
||||||
|
CompletionItemKind::FUNCTION,
|
||||||
|
'mixed',
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
'AliasNamespace\inner_function'
|
||||||
|
),
|
||||||
|
new CompletionItem(
|
||||||
|
'inner_function2',
|
||||||
|
CompletionItemKind::FUNCTION,
|
||||||
|
'mixed',
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
'AliasNamespace\inner_function2'
|
||||||
|
),
|
||||||
|
], true),
|
||||||
|
$items
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests completion with `use function ..inner_function`.
|
||||||
|
*/
|
||||||
|
public function testUseFunction()
|
||||||
|
{
|
||||||
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/used_function.php');
|
||||||
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
|
$items = $this->textDocument->completion(
|
||||||
|
new TextDocumentIdentifier($completionUri),
|
||||||
|
new Position(8, 7)
|
||||||
|
)->wait();
|
||||||
|
$this->assertEquals(
|
||||||
|
new CompletionList([
|
||||||
|
new CompletionItem(
|
||||||
|
'inner_function',
|
||||||
|
CompletionItemKind::FUNCTION,
|
||||||
|
'TestNamespace\InnerNamespace'
|
||||||
|
),
|
||||||
|
], true),
|
||||||
|
$items
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests completion with `use function .. as second_function;`.
|
||||||
|
*/
|
||||||
|
public function testUseFunctionAs()
|
||||||
|
{
|
||||||
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/used_function.php');
|
||||||
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
|
$items = $this->textDocument->completion(
|
||||||
|
new TextDocumentIdentifier($completionUri),
|
||||||
|
new Position(9, 8)
|
||||||
|
)->wait();
|
||||||
|
$this->assertEquals(
|
||||||
|
new CompletionList([
|
||||||
|
new CompletionItem(
|
||||||
|
'second_function',
|
||||||
|
CompletionItemKind::FUNCTION,
|
||||||
|
'TestNamespace\InnerNamespace'
|
||||||
|
),
|
||||||
|
], true),
|
||||||
|
$items
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests completion with `use function .. as second_function;`.
|
||||||
|
*/
|
||||||
|
public function testUseFunctionNotExists()
|
||||||
|
{
|
||||||
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/used_function.php');
|
||||||
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
|
$items = $this->textDocument->completion(
|
||||||
|
new TextDocumentIdentifier($completionUri),
|
||||||
|
new Position(10, 9)
|
||||||
|
)->wait();
|
||||||
|
$this->assertEquals(
|
||||||
|
new CompletionList([
|
||||||
|
new CompletionItem(
|
||||||
|
'i_dont_exist',
|
||||||
|
CompletionItemKind::FUNCTION,
|
||||||
|
'TestNamespace\InnerNamespace',
|
||||||
|
''
|
||||||
|
),
|
||||||
|
], true),
|
||||||
|
$items
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests completion with `use const ..INNER_CONST`
|
||||||
|
*/
|
||||||
|
public function testUseConst()
|
||||||
|
{
|
||||||
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/used_const.php');
|
||||||
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
|
$items = $this->textDocument->completion(
|
||||||
|
new TextDocumentIdentifier($completionUri),
|
||||||
|
new Position(8, 7)
|
||||||
|
)->wait();
|
||||||
|
$this->assertEquals(
|
||||||
|
new CompletionList([
|
||||||
|
new CompletionItem(
|
||||||
|
'INNER_CONST',
|
||||||
|
CompletionItemKind::VARIABLE,
|
||||||
|
'int',
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
'INNER_CONST'
|
||||||
|
),
|
||||||
|
], true),
|
||||||
|
$items
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests completion with `use const .. as ALIASED_CONST;`.
|
||||||
|
*/
|
||||||
|
public function testUseConsttAs()
|
||||||
|
{
|
||||||
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/used_const.php');
|
||||||
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
|
$items = $this->textDocument->completion(
|
||||||
|
new TextDocumentIdentifier($completionUri),
|
||||||
|
new Position(10, 9)
|
||||||
|
)->wait();
|
||||||
|
$this->assertEquals(
|
||||||
|
new CompletionList([
|
||||||
|
new CompletionItem(
|
||||||
|
'INNER_CONST',
|
||||||
|
CompletionItemKind::VARIABLE,
|
||||||
|
'int',
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
'ALIASED_CONST'
|
||||||
|
),
|
||||||
|
], true),
|
||||||
|
$items
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests completion with `use const NON_EXISTENT_CONST`
|
||||||
|
*/
|
||||||
|
public function testUseConsttNonExistent()
|
||||||
|
{
|
||||||
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/used_const.php');
|
||||||
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
|
$items = $this->textDocument->completion(
|
||||||
|
new TextDocumentIdentifier($completionUri),
|
||||||
|
new Position(12, 14)
|
||||||
|
)->wait();
|
||||||
|
$this->assertEquals(
|
||||||
|
new CompletionList([
|
||||||
|
new CompletionItem(
|
||||||
|
'NON_EXISTENT_CONST',
|
||||||
|
CompletionItemKind::VARIABLE,
|
||||||
|
'TestNamespace\InnerNamespace'
|
||||||
|
),
|
||||||
], true),
|
], true),
|
||||||
$items
|
$items
|
||||||
);
|
);
|
||||||
|
|
|
@ -35,6 +35,9 @@ class DocumentSymbolTest extends ServerTestCase
|
||||||
new SymbolInformation('__destruct', SymbolKind::CONSTRUCTOR, $this->getDefinitionLocation('TestNamespace\\Example::__destruct'), 'TestNamespace\\Example'),
|
new SymbolInformation('__destruct', SymbolKind::CONSTRUCTOR, $this->getDefinitionLocation('TestNamespace\\Example::__destruct'), 'TestNamespace\\Example'),
|
||||||
new SymbolInformation('TestNamespace\\InnerNamespace', SymbolKind::NAMESPACE, $this->getDefinitionLocation('TestNamespace\\InnerNamespace'), 'TestNamespace'),
|
new SymbolInformation('TestNamespace\\InnerNamespace', SymbolKind::NAMESPACE, $this->getDefinitionLocation('TestNamespace\\InnerNamespace'), 'TestNamespace'),
|
||||||
new SymbolInformation('InnerClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\InnerNamespace\\InnerClass'), 'TestNamespace\\InnerNamespace'),
|
new SymbolInformation('InnerClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\InnerNamespace\\InnerClass'), 'TestNamespace\\InnerNamespace'),
|
||||||
|
new SymbolInformation('INNER_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestNamespace\\InnerNamespace\\INNER_CONST'), 'TestNamespace\\InnerNamespace'),
|
||||||
|
new SymbolInformation('inner_function', SymbolKind::FUNCTION, $this->getDefinitionLocation('TestNamespace\\InnerNamespace\\inner_function()'), 'TestNamespace\\InnerNamespace'),
|
||||||
|
new SymbolInformation('inner_function2', SymbolKind::FUNCTION, $this->getDefinitionLocation('TestNamespace\\InnerNamespace\\inner_function2()'),'TestNamespace\\InnerNamespace'),
|
||||||
], $result);
|
], $result);
|
||||||
// @codingStandardsIgnoreEnd
|
// @codingStandardsIgnoreEnd
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,10 @@ class SymbolTest extends ServerTestCase
|
||||||
new SymbolInformation('__destruct', SymbolKind::CONSTRUCTOR, $this->getDefinitionLocation('TestNamespace\\Example::__destruct'), 'TestNamespace\\Example'),
|
new SymbolInformation('__destruct', SymbolKind::CONSTRUCTOR, $this->getDefinitionLocation('TestNamespace\\Example::__destruct'), 'TestNamespace\\Example'),
|
||||||
new SymbolInformation('TestNamespace\\InnerNamespace', SymbolKind::NAMESPACE, $this->getDefinitionLocation('TestNamespace\\InnerNamespace'), 'TestNamespace'),
|
new SymbolInformation('TestNamespace\\InnerNamespace', SymbolKind::NAMESPACE, $this->getDefinitionLocation('TestNamespace\\InnerNamespace'), 'TestNamespace'),
|
||||||
new SymbolInformation('InnerClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\InnerNamespace\\InnerClass'), 'TestNamespace\\InnerNamespace'),
|
new SymbolInformation('InnerClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\InnerNamespace\\InnerClass'), 'TestNamespace\\InnerNamespace'),
|
||||||
|
new SymbolInformation('INNER_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestNamespace\\InnerNamespace\\INNER_CONST'), 'TestNamespace\\InnerNamespace'),
|
||||||
|
new SymbolInformation('inner_function', SymbolKind::FUNCTION, $this->getDefinitionLocation('TestNamespace\\InnerNamespace\\inner_function()'), 'TestNamespace\\InnerNamespace'),
|
||||||
|
new SymbolInformation('inner_function2', SymbolKind::FUNCTION, $this->getDefinitionLocation('TestNamespace\\InnerNamespace\\inner_function2()'), 'TestNamespace\InnerNamespace'),
|
||||||
|
|
||||||
new SymbolInformation('whatever', SymbolKind::FUNCTION, $this->getDefinitionLocation('TestNamespace\\whatever()'), 'TestNamespace'),
|
new SymbolInformation('whatever', SymbolKind::FUNCTION, $this->getDefinitionLocation('TestNamespace\\whatever()'), 'TestNamespace'),
|
||||||
// Global
|
// Global
|
||||||
new SymbolInformation('TEST_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TEST_CONST'), ''),
|
new SymbolInformation('TEST_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TEST_CONST'), ''),
|
||||||
|
|
Loading…
Reference in New Issue