Clean up completions, fix exceptions thrown from running strpos on empty strings
parent
1fa29ccae5
commit
67081c4abe
|
@ -13,6 +13,7 @@ use LanguageServer\Protocol\{
|
||||||
CompletionItem,
|
CompletionItem,
|
||||||
CompletionItemKind
|
CompletionItemKind
|
||||||
};
|
};
|
||||||
|
use function LanguageServer\{strStartsWith};
|
||||||
use Microsoft\PhpParser as Tolerant;
|
use Microsoft\PhpParser as Tolerant;
|
||||||
|
|
||||||
class CompletionProvider
|
class CompletionProvider
|
||||||
|
@ -245,10 +246,8 @@ class CompletionProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->index->getDefinitions() as $fqn => $def) {
|
foreach ($this->index->getDefinitions() as $fqn => $def) {
|
||||||
if (
|
$fqnStartsWithPrefix = strStartsWith($fqn, $prefix);
|
||||||
($def->canBeInstantiated || ($def->isGlobal && !isset($creation))) && (empty($prefix) || strpos($fqn, $prefix) !== false)
|
if (($def->canBeInstantiated || ($def->isGlobal && !isset($creation))) && strStartsWith($fqn, $prefix)) {
|
||||||
|
|
||||||
) {
|
|
||||||
if ($namespaceDefinition !== null && $namespaceDefinition->name !== null) {
|
if ($namespaceDefinition !== null && $namespaceDefinition->name !== null) {
|
||||||
$namespacePrefix = (string)Tolerant\ResolvedName::buildName($namespaceDefinition->name->nameParts, $node->getFileContents());
|
$namespacePrefix = (string)Tolerant\ResolvedName::buildName($namespaceDefinition->name->nameParts, $node->getFileContents());
|
||||||
|
|
||||||
|
@ -257,7 +256,7 @@ class CompletionProvider
|
||||||
$isNotFullyQualified = !($class instanceof Tolerant\Node\QualifiedName) || !$class->isFullyQualifiedName();
|
$isNotFullyQualified = !($class instanceof Tolerant\Node\QualifiedName) || !$class->isFullyQualifiedName();
|
||||||
if ($isNotFullyQualified) {
|
if ($isNotFullyQualified) {
|
||||||
foreach ($namespaceImportTable as $alias => $name) {
|
foreach ($namespaceImportTable as $alias => $name) {
|
||||||
if (strpos($fqn, $name) === 0) {
|
if (strStartsWith($fqn, $name)) {
|
||||||
$fqn = $alias;
|
$fqn = $alias;
|
||||||
$isAliased = true;
|
$isAliased = true;
|
||||||
break;
|
break;
|
||||||
|
@ -266,13 +265,13 @@ class CompletionProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!$isNotFullyQualified && ((strpos($fqn, $prefix) === 0) || strpos($fqn, $namespacePrefix . "\\" . $prefix) === 0)) {
|
if (!$isNotFullyQualified && ($fqnStartsWithPrefix || strStartsWith($fqn, $namespacePrefix . "\\" . $prefix))) {
|
||||||
$fqn = $fqn;
|
// $fqn = $fqn;
|
||||||
}
|
}
|
||||||
elseif (!$isAliased && !array_search($fqn, array_values($namespaceImportTable))) {
|
elseif (!$isAliased && !array_search($fqn, array_values($namespaceImportTable))) {
|
||||||
if (empty($prefix)) {
|
if (empty($prefix)) {
|
||||||
$fqn = '\\' . $fqn;
|
$fqn = '\\' . $fqn;
|
||||||
} elseif (strpos($fqn, $namespacePrefix . "\\" . $prefix) === 0) {
|
} elseif (strStartsWith($fqn, $namespacePrefix . "\\" . $prefix)) {
|
||||||
$fqn = substr($fqn, strlen($namespacePrefix) + 1);
|
$fqn = substr($fqn, strlen($namespacePrefix) + 1);
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
|
@ -280,7 +279,7 @@ class CompletionProvider
|
||||||
} elseif (!$isAliased) {
|
} elseif (!$isAliased) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} elseif (strpos($fqn, $prefix) === 0 && $class->isFullyQualifiedName()) {
|
} elseif ($fqnStartsWithPrefix && $class->isFullyQualifiedName()) {
|
||||||
$fqn = '\\' . $fqn;
|
$fqn = '\\' . $fqn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,23 +292,19 @@ class CompletionProvider
|
||||||
|
|
||||||
if (!isset($creation)) {
|
if (!isset($creation)) {
|
||||||
foreach (self::KEYWORDS as $keyword) {
|
foreach (self::KEYWORDS as $keyword) {
|
||||||
if (strpos($keyword, $prefix) === 0) {
|
|
||||||
$item = new CompletionItem($keyword, CompletionItemKind::KEYWORD);
|
$item = new CompletionItem($keyword, CompletionItemKind::KEYWORD);
|
||||||
$item->insertText = $keyword . ' ';
|
$item->insertText = $keyword . ' ';
|
||||||
$list->items[] = $item;
|
$list->items[] = $item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} elseif (TolerantParserHelpers::isConstantFetch($node)) {
|
} elseif (TolerantParserHelpers::isConstantFetch($node)) {
|
||||||
$prefix = (string) ($node->getResolvedName() ?? Tolerant\ResolvedName::buildName($node->nameParts, $node->getFileContents()));
|
$prefix = (string) ($node->getResolvedName() ?? Tolerant\ResolvedName::buildName($node->nameParts, $node->getFileContents()));
|
||||||
foreach (self::KEYWORDS as $keyword) {
|
foreach (self::KEYWORDS as $keyword) {
|
||||||
if (strpos($keyword, $prefix) === 0) {
|
|
||||||
$item = new CompletionItem($keyword, CompletionItemKind::KEYWORD);
|
$item = new CompletionItem($keyword, CompletionItemKind::KEYWORD);
|
||||||
$item->insertText = $keyword . ' ';
|
$item->insertText = $keyword . ' ';
|
||||||
$list->items[] = $item;
|
$list->items[] = $item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return $list;
|
return $list;
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,3 +189,7 @@ function getVendorDir(\stdClass $composerJson = null): string
|
||||||
{
|
{
|
||||||
return $composerJson->config->{'vendor-dir'} ?? 'vendor';
|
return $composerJson->config->{'vendor-dir'} ?? 'vendor';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function strStartsWith(string $haystack, string $prefix): bool {
|
||||||
|
return empty($prefix) || strpos($haystack, $prefix) === 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace LanguageServer\Tests\Utils;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function LanguageServer\{strStartsWith};
|
||||||
|
|
||||||
|
class UtilsTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testStrStartsWithDataProvider(): array {
|
||||||
|
return [
|
||||||
|
['a', 'b', false],
|
||||||
|
['', 'a', false],
|
||||||
|
['foobar', 'bar', false],
|
||||||
|
|
||||||
|
['a', '', true],
|
||||||
|
['', '', true],
|
||||||
|
|
||||||
|
['foobar', 'foob', true],
|
||||||
|
['foobar', 'f', true],
|
||||||
|
['FOOBAR', 'foo', false],
|
||||||
|
['foobar', 'foobar', true]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider testStrStartsWithDataProvider
|
||||||
|
*/
|
||||||
|
public function testStrStartsWith($haystack, $prefix, $expectedResult)
|
||||||
|
{
|
||||||
|
$this->assertEquals(strStartsWith($haystack, $prefix), $expectedResult);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue