1
0
Fork 0

🚀 Support self reference

pull/354/head
jens1o 2017-04-17 21:01:42 +02:00
parent ede90472d0
commit 23438b8281
7 changed files with 81 additions and 2 deletions

View File

@ -41,3 +41,6 @@ TestClass::$staticTestProperty[123]->testProperty;
$child = new ChildClass; $child = new ChildClass;
echo $child->testMethod(); echo $child->testMethod();
// resolve self expression
Something::getInstance()->hello();

View File

@ -105,3 +105,18 @@ class ChildClass extends TestClass {}
define('TEST_DEFINE_CONSTANT', false); define('TEST_DEFINE_CONSTANT', false);
print TEST_DEFINE_CONSTANT ? 'true' : '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!';
}
}

View File

@ -745,10 +745,20 @@ class DefinitionResolver
if (is_string($node->type)) { if (is_string($node->type)) {
// Resolve a string like "bool" to a type object // Resolve a string like "bool" to a type object
$type = $this->typeResolver->resolve($node->type); $type = $this->typeResolver->resolve($node->type);
} else { } else if ($node->returnType instanceof Node\Name) {
$type = new Types\Object_(new Fqsen('\\' . (string)$node->type)); $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) { if ($node->default !== null) {
$defaultType = $this->resolveExpressionNodeToType($node->default); $defaultType = $this->resolveExpressionNodeToType($node->default);
if (isset($type) && !is_a($type, get_class($defaultType))) { if (isset($type) && !is_a($type, get_class($defaultType))) {
@ -776,6 +786,18 @@ class DefinitionResolver
// Resolve a string like "bool" to a type object // Resolve a string like "bool" to a type object
return $this->typeResolver->resolve($node->returnType); 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)); return new Types\Object_(new Fqsen('\\' . (string)$node->returnType));
} }
// Unknown return type // Unknown return type

View File

@ -85,6 +85,9 @@ abstract class ServerTestCase extends TestCase
'TestClass::testMethod()' => new Location($globalSymbolsUri, new Range(new Position(57, 4), new Position(60, 5))), '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))), '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))), '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 // Namespaced
'TestNamespace' => new Location($symbolsUri, new Range(new Position( 2, 10), new Position( 2, 23))), '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()' => [ 'test_function()' => [
0 => new Location($globalReferencesUri, new Range(new Position(10, 0), new Position(10, 13))), 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))) 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 // @codingStandardsIgnoreEnd

View File

@ -179,6 +179,15 @@ class CompletionTest extends TestCase
null, null,
'\ChildClass' '\ChildClass'
), ),
new CompletionItem(
'Something',
CompletionItemKind::CLASS_,
null,
null,
null,
null,
'\Something'
),
// Namespaced, `use`d TestClass definition (inserted as TestClass) // Namespaced, `use`d TestClass definition (inserted as TestClass)
new CompletionItem( new CompletionItem(
'TestClass', 'TestClass',

View File

@ -31,6 +31,21 @@ class HoverTest extends ServerTestCase
], $reference->range), $result); ], $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() public function testHoverForClassLikeDefinition()
{ {
// class TestClass implements TestInterface // class TestClass implements TestInterface

View File

@ -59,6 +59,9 @@ class SymbolTest extends ServerTestCase
new SymbolInformation('test_function', SymbolKind::FUNCTION, $this->getDefinitionLocation('test_function()'), ''), new SymbolInformation('test_function', SymbolKind::FUNCTION, $this->getDefinitionLocation('test_function()'), ''),
new SymbolInformation('ChildClass', SymbolKind::CLASS_, $this->getDefinitionLocation('ChildClass'), ''), new SymbolInformation('ChildClass', SymbolKind::CLASS_, $this->getDefinitionLocation('ChildClass'), ''),
new SymbolInformation('TEST_DEFINE_CONSTANT', SymbolKind::CONSTANT, $this->getDefinitionLocation('TEST_DEFINE_CONSTANT'), ''), 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('whatever', SymbolKind::FUNCTION, $this->getDefinitionLocation('whatever()'), ''),
new SymbolInformation('SecondTestNamespace', SymbolKind::NAMESPACE, $this->getDefinitionLocation('SecondTestNamespace'), '') new SymbolInformation('SecondTestNamespace', SymbolKind::NAMESPACE, $this->getDefinitionLocation('SecondTestNamespace'), '')