1
0
Fork 0

Properly filter completion on empty property

pull/165/head
Felix Becker 2016-11-22 21:24:39 +01:00
parent 51de0b5dfc
commit d66cc763bc
4 changed files with 81 additions and 8 deletions

View File

@ -1,4 +1,4 @@
<?php <?php
$obj = new TestClass; $obj = new TestClass;
$obj->t $obj->

View File

@ -56,12 +56,36 @@ class CompletionProvider
|| $node instanceof Node\Expr\StaticPropertyFetch || $node instanceof Node\Expr\StaticPropertyFetch
|| $node instanceof Node\Expr\ClassConstFetch || $node instanceof Node\Expr\ClassConstFetch
) { ) {
/** The FQN to be completed */ $nodeToResolve = $node;
$prefix = $this->definitionResolver->resolveReferenceNodeToFqn($node) ?? ''; if (!is_string($node->name)) {
$prefixLen = strlen($prefix); // If the name is an Error node, just filter by the class
if ($node instanceof Node\Expr\MethodCall || $node instanceof Node\Expr\PropertyFetch) {
$nodeToResolve = $node->var;
} else {
$nodeToResolve = $node->class;
}
}
$prefixes = DefinitionResolver::getFqnsFromType(
$this->definitionResolver->resolveExpressionNodeToType($nodeToResolve)
);
if (!is_string($node->name)) {
// If we are just filtering by the class, add the appropiate operator to the prefix
// to filter the type of symbol
foreach ($prefixes as &$prefix) {
if ($node instanceof Node\Expr\MethodCall || $node instanceof Node\Expr\PropertyFetch) {
$prefix .= '->';
} else if ($node instanceof Node\Expr\StaticCall || $node instanceof Node\Expr\ClassConstFetch) {
$prefix .= '::';
} else if ($node instanceof Node\Expr\StaticPropertyFetch) {
$prefix .= '::$';
}
}
}
foreach ($this->project->getDefinitions() as $fqn => $def) { foreach ($this->project->getDefinitions() as $fqn => $def) {
if (substr($fqn, 0, $prefixLen) === $prefix && !$def->isGlobal) { foreach ($prefixes as $prefix) {
$items[] = CompletionItem::fromDefinition($def); if (substr($fqn, 0, strlen($prefix)) === $prefix && !$def->isGlobal) {
$items[] = CompletionItem::fromDefinition($def);
}
} }
} }
} else if ( } else if (

View File

@ -146,6 +146,31 @@ class DefinitionResolver
return $this->project->getDefinition($fqn, $globalFallback); return $this->project->getDefinition($fqn, $globalFallback);
} }
/**
* Returns all possible FQNs in a type
*
* @param Type $type
* @return string[]
*/
public static function getFqnsFromType(Type $type): array
{
$fqns = [];
if ($type instanceof Types\Object_) {
$fqsen = $type->getFqsen();
if ($fqsen !== null) {
$fqns[] = substr((string)$fqsen, 1);
}
}
if ($type instanceof Types\Compound) {
for ($i = 0; $t = $type->get($i); $i++) {
foreach (self::getFqnsFromType($type) as $fqn) {
$fqns[] = $fqn;
}
}
}
return $fqns;
}
/** /**
* Given any node, returns the FQN of the symbol that is referenced * Given any node, returns the FQN of the symbol that is referenced
* Returns null if the FQN could not be resolved or the reference node references a variable * Returns null if the FQN could not be resolved or the reference node references a variable

View File

@ -30,13 +30,37 @@ class CompletionTest extends TestCase
$this->textDocument = new Server\TextDocument($this->project, $client); $this->textDocument = new Server\TextDocument($this->project, $client);
} }
public function testForPropertiesAndMethods() public function testPropertyAndMethodWithPrefix()
{
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/property_with_prefix.php');
$this->project->openDocument($completionUri, file_get_contents($completionUri));
$items = $this->textDocument->completion(
new TextDocumentIdentifier($completionUri),
new Position(3, 7)
)->wait();
$this->assertEquals([
new CompletionItem(
'testProperty',
CompletionItemKind::PROPERTY,
'\TestClass', // Type of the property
'Reprehenderit magna velit mollit ipsum do.'
),
new CompletionItem(
'testMethod',
CompletionItemKind::METHOD,
'\TestClass', // Return type of the method
'Non culpa nostrud mollit esse sunt laboris in irure ullamco cupidatat amet.'
)
], $items);
}
public function testPropertyAndMethodWithoutPrefix()
{ {
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/property.php'); $completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/property.php');
$this->project->openDocument($completionUri, file_get_contents($completionUri)); $this->project->openDocument($completionUri, file_get_contents($completionUri));
$items = $this->textDocument->completion( $items = $this->textDocument->completion(
new TextDocumentIdentifier($completionUri), new TextDocumentIdentifier($completionUri),
new Position(3, 7) new Position(3, 6)
)->wait(); )->wait();
$this->assertEquals([ $this->assertEquals([
new CompletionItem( new CompletionItem(