🚀 Support self reference
parent
ede90472d0
commit
23438b8281
|
@ -41,3 +41,6 @@ TestClass::$staticTestProperty[123]->testProperty;
|
|||
|
||||
$child = new ChildClass;
|
||||
echo $child->testMethod();
|
||||
|
||||
// resolve self expression
|
||||
Something::getInstance()->hello();
|
||||
|
|
|
@ -105,3 +105,18 @@ class ChildClass extends TestClass {}
|
|||
define('TEST_DEFINE_CONSTANT', false);
|
||||
|
||||
print TEST_DEFINE_CONSTANT ? 'true' : 'false';
|
||||
|
||||
// resolve self type test
|
||||
class Something {
|
||||
|
||||
public static function getInstance(): self {
|
||||
return new self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing
|
||||
*/
|
||||
public function hello() {
|
||||
echo 'Hi!';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -745,9 +745,19 @@ class DefinitionResolver
|
|||
if (is_string($node->type)) {
|
||||
// Resolve a string like "bool" to a type object
|
||||
$type = $this->typeResolver->resolve($node->type);
|
||||
} else {
|
||||
$type = new Types\Object_(new Fqsen('\\' . (string)$node->type));
|
||||
} else if ($node->returnType instanceof Node\Name) {
|
||||
$type = (string)$node->returnType;
|
||||
|
||||
if (strtolower($type) === 'self') {
|
||||
// handle self reference
|
||||
$class = getClosestNode($node, Node\Stmt\Class_::class);
|
||||
|
||||
if($class !== null) {
|
||||
return new Types\Object_(new Fqsen('\\' . $class->name));
|
||||
}
|
||||
}
|
||||
}
|
||||
$type = new Types\Object_(new Fqsen('\\' . (string)$node->type));
|
||||
}
|
||||
if ($node->default !== null) {
|
||||
$defaultType = $this->resolveExpressionNodeToType($node->default);
|
||||
|
@ -776,6 +786,18 @@ class DefinitionResolver
|
|||
// Resolve a string like "bool" to a type object
|
||||
return $this->typeResolver->resolve($node->returnType);
|
||||
}
|
||||
if ($node->returnType instanceof Node\Name) {
|
||||
$type = (string)$node->returnType;
|
||||
|
||||
if (strtolower($type) === 'self') {
|
||||
// handle self reference
|
||||
$class = getClosestNode($node, Node\Stmt\Class_::class);
|
||||
|
||||
if ($class !== null) {
|
||||
return new Types\Object_(new Fqsen('\\' . $class->name));
|
||||
}
|
||||
}
|
||||
}
|
||||
return new Types\Object_(new Fqsen('\\' . (string)$node->returnType));
|
||||
}
|
||||
// Unknown return type
|
||||
|
|
|
@ -85,6 +85,9 @@ abstract class ServerTestCase extends TestCase
|
|||
'TestClass::testMethod()' => new Location($globalSymbolsUri, new Range(new Position(57, 4), new Position(60, 5))),
|
||||
'test_function()' => new Location($globalSymbolsUri, new Range(new Position(78, 0), new Position(81, 1))),
|
||||
'whatever()' => new Location($globalReferencesUri, new Range(new Position(21, 0), new Position(23, 1))),
|
||||
'Something' => new Location($globalSymbolsUri, new Range(new Position(109, 0), new Position(121, 1))),
|
||||
'Something::getInstance()' => new Location($globalSymbolsUri, new Range(new Position(111, 4), new Position(113, 5))),
|
||||
'Something::hello()' => new Location($globalSymbolsUri, new Range(new Position(118, 4), new Position(120, 5))),
|
||||
|
||||
// Namespaced
|
||||
'TestNamespace' => new Location($symbolsUri, new Range(new Position( 2, 10), new Position( 2, 23))),
|
||||
|
@ -214,6 +217,15 @@ abstract class ServerTestCase extends TestCase
|
|||
'test_function()' => [
|
||||
0 => new Location($globalReferencesUri, new Range(new Position(10, 0), new Position(10, 13))),
|
||||
1 => new Location($globalReferencesUri, new Range(new Position(31, 13), new Position(31, 40)))
|
||||
],
|
||||
'Something' => [
|
||||
0 => new Location($globalReferencesUri, new Range(new Position(45, 0), new Position(56, 9))) // Something::getInstance()->hello()
|
||||
],
|
||||
'Something::getInstance()' => [
|
||||
0 => new Location($globalReferencesUri, new Range(new Position(45, 0), new Position(45, 24))) // Something::getInstance()->hello()
|
||||
],
|
||||
'Something::hello()' => [
|
||||
0 => new Location($globalReferencesUri, new Range(new Position(45, 0), new Position(45, 33))) // Something::getInstance()->hello()
|
||||
]
|
||||
];
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
|
|
@ -179,6 +179,15 @@ class CompletionTest extends TestCase
|
|||
null,
|
||||
'\ChildClass'
|
||||
),
|
||||
new CompletionItem(
|
||||
'Something',
|
||||
CompletionItemKind::CLASS_,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
'\Something'
|
||||
),
|
||||
// Namespaced, `use`d TestClass definition (inserted as TestClass)
|
||||
new CompletionItem(
|
||||
'TestClass',
|
||||
|
|
|
@ -31,6 +31,21 @@ class HoverTest extends ServerTestCase
|
|||
], $reference->range), $result);
|
||||
}
|
||||
|
||||
public function testHoverForSelfReturnTypeDefintion()
|
||||
{
|
||||
// class Something
|
||||
// get hover for Something::getInstance() (returns a instance of Something)
|
||||
$reference = $this->getReferenceLocations('Something::hello()')[0];
|
||||
$result = $this->textDocument->hover(
|
||||
new TextDocumentIdentifier($reference->uri),
|
||||
$reference->range->end
|
||||
)->wait();
|
||||
$this->assertEquals(new Hover([
|
||||
new MarkedString('php', "<?php\npublic function hello()"),
|
||||
'Does nothing'
|
||||
], $reference->range), $result);
|
||||
}
|
||||
|
||||
public function testHoverForClassLikeDefinition()
|
||||
{
|
||||
// class TestClass implements TestInterface
|
||||
|
|
|
@ -59,6 +59,9 @@ class SymbolTest extends ServerTestCase
|
|||
new SymbolInformation('test_function', SymbolKind::FUNCTION, $this->getDefinitionLocation('test_function()'), ''),
|
||||
new SymbolInformation('ChildClass', SymbolKind::CLASS_, $this->getDefinitionLocation('ChildClass'), ''),
|
||||
new SymbolInformation('TEST_DEFINE_CONSTANT', SymbolKind::CONSTANT, $this->getDefinitionLocation('TEST_DEFINE_CONSTANT'), ''),
|
||||
new SymbolInformation('Something', SymbolKind::CLASS_, $this->getDefinitionLocation('Something'), ''),
|
||||
new SymbolInformation('getInstance', SymbolKind::METHOD, $this->getDefinitionLocation('Something::getInstance()'), 'Something'),
|
||||
new SymbolInformation('hello', SymbolKind::METHOD, $this->getDefinitionLocation('Something::hello()'), 'Something'),
|
||||
new SymbolInformation('whatever', SymbolKind::FUNCTION, $this->getDefinitionLocation('whatever()'), ''),
|
||||
|
||||
new SymbolInformation('SecondTestNamespace', SymbolKind::NAMESPACE, $this->getDefinitionLocation('SecondTestNamespace'), '')
|
||||
|
|
Loading…
Reference in New Issue