1
0
Fork 0

Clean up completions, fix exceptions thrown from running strpos on empty strings

pull/357/head
Rob Lourens 2017-05-18 14:26:34 -07:00
parent 1fa29ccae5
commit 67081c4abe
3 changed files with 52 additions and 19 deletions

View File

@ -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,21 +292,17 @@ 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;
}
} }
} }

View File

@ -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;
}

34
tests/Utils/UtilsTest.php Normal file
View File

@ -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);
}
}