diff --git a/fixtures/completion/this_return_value.php b/fixtures/completion/this_return_value.php new file mode 100644 index 0000000..ae44071 --- /dev/null +++ b/fixtures/completion/this_return_value.php @@ -0,0 +1,16 @@ +foo()->q + } + public function qux() { + + } +} diff --git a/src/DefinitionResolver.php b/src/DefinitionResolver.php index 713d868..e5dafc8 100644 --- a/src/DefinitionResolver.php +++ b/src/DefinitionResolver.php @@ -574,7 +574,6 @@ class DefinitionResolver // $this -> Type\this // $myVariable -> type of corresponding assignment expression if ($expr instanceof Node\Expression\Variable || $expr instanceof Node\UseVariableName) { - // TODO: this will need to change when fluent interfaces are supported if ($expr->getName() === 'this') { return new Types\Object_(new Fqsen('\\' . $this->getContainingClassFqn($expr))); } @@ -667,13 +666,27 @@ class DefinitionResolver } else { $classFqn = substr((string)$t->getFqsen(), 1); } - $fqn = $classFqn . '->' . $expr->memberName->getText($expr->getFileContents()); + $add = '->' . $expr->memberName->getText($expr->getFileContents()); if ($expr->parent instanceof Node\Expression\CallExpression) { - $fqn .= '()'; + $add .= '()'; } + $fqn = $classFqn . $add; $def = $this->index->getDefinition($fqn); if ($def !== null) { return $def->type; + } else { + $classDef = $this->index->getDefinition($classFqn); + if ($classDef !== null && is_array($classDef->extends)) { + foreach ($classDef->extends as $parent) { + $def = $this->index->getDefinition($parent . $add); + if ($def !== null) { + if ($def->type instanceof Types\This) { + return new Types\Object_(new Fqsen('\\' . $classFqn)); + } + return $def->type; + } + } + } } } } diff --git a/tests/Server/TextDocument/CompletionTest.php b/tests/Server/TextDocument/CompletionTest.php index 3cdb5f8..a766e78 100644 --- a/tests/Server/TextDocument/CompletionTest.php +++ b/tests/Server/TextDocument/CompletionTest.php @@ -653,4 +653,31 @@ class CompletionTest extends TestCase ) ], true), $items); } + + public function testThisReturnValue() + { + $completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/this_return_value.php'); + $this->loader->open($completionUri, file_get_contents($completionUri)); + $items = $this->textDocument->completion( + new TextDocumentIdentifier($completionUri), + new Position(10, 19) + )->wait(); + $this->assertEquals(new CompletionList([ + new CompletionItem( + 'foo', + CompletionItemKind::METHOD, + '$this' // Return type of the method + ), + new CompletionItem( + 'bar', + CompletionItemKind::METHOD, + 'mixed' // Return type of the method + ), + new CompletionItem( + 'qux', + CompletionItemKind::METHOD, + 'mixed' // Return type of the method + ) + ], true), $items); + } }