From 07bfdff72da7d091e26cd8b507ebeca35861ed3b Mon Sep 17 00:00:00 2001 From: jens1o Date: Mon, 10 Apr 2017 12:24:22 +0200 Subject: [PATCH 01/16] :rocket: support constants --- .../completion/constant_with_namespace.php | 46 +++++++++++++++++++ fixtures/global_symbols.php | 7 +++ src/DefinitionResolver.php | 7 ++- src/Index/Index.php | 2 +- src/Protocol/SymbolInformation.php | 15 ++++-- tests/LanguageServerTest.php | 4 +- tests/Server/ServerTestCase.php | 28 ++++++----- tests/Server/TextDocument/HoverTest.php | 14 ++++++ tests/Server/Workspace/SymbolTest.php | 3 +- 9 files changed, 106 insertions(+), 20 deletions(-) create mode 100644 fixtures/completion/constant_with_namespace.php diff --git a/fixtures/completion/constant_with_namespace.php b/fixtures/completion/constant_with_namespace.php new file mode 100644 index 0000000..b31d25c --- /dev/null +++ b/fixtures/completion/constant_with_namespace.php @@ -0,0 +1,46 @@ +namespacedName . '::' . $node->name; } - } + } else if ($node instanceof Node\Expr\FuncCall && $node->name instanceof Node\Name && strtolower((string)$node->name) === 'define') { + if (!isset($node->args[0]) || !($node->args[0]->value instanceof Node\Scalar\String_)) { + return null; + } + return (string)$node->args[0]->value->value; + } } } diff --git a/src/Index/Index.php b/src/Index/Index.php index 5c24813..b753476 100644 --- a/src/Index/Index.php +++ b/src/Index/Index.php @@ -117,7 +117,7 @@ class Index implements ReadableIndex, \Serializable * Registers a definition * * @param string $fqn The fully qualified name of the symbol - * @param string $definition The Definition object + * @param Definition $definition The Definition object * @return void */ public function setDefinition(string $fqn, Definition $definition) diff --git a/src/Protocol/SymbolInformation.php b/src/Protocol/SymbolInformation.php index 299dc55..a2ab964 100644 --- a/src/Protocol/SymbolInformation.php +++ b/src/Protocol/SymbolInformation.php @@ -50,9 +50,18 @@ class SymbolInformation { $parent = $node->getAttribute('parentNode'); $symbol = new self; - if ($node instanceof Node\Stmt\Class_) { - $symbol->kind = SymbolKind::CLASS_; - } else if ($node instanceof Node\Stmt\Trait_) { + if ( + $node instanceof Node\Expr\FuncCall + && $node->name instanceof Node\Name + && strtolower((string)$node->name) === 'define' + && isset($node->args[0]) + && $node->args[0]->value instanceof Node\Scalar\String_ + ) { + // constants with define() like + // define('TEST_PROPERTY', true); + $symbol->kind = SymbolKind::CONSTANT; + $symbol->name = (string)$node->args[0]->value->value; + } else if ($node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\Trait_) { $symbol->kind = SymbolKind::CLASS_; } else if ($node instanceof Node\Stmt\Interface_) { $symbol->kind = SymbolKind::INTERFACE; diff --git a/tests/LanguageServerTest.php b/tests/LanguageServerTest.php index c32a76a..fb52ef6 100644 --- a/tests/LanguageServerTest.php +++ b/tests/LanguageServerTest.php @@ -57,7 +57,7 @@ class LanguageServerTest extends TestCase if ($msg->body->method === 'window/logMessage' && $promise->state === Promise::PENDING) { if ($msg->body->params->type === MessageType::ERROR) { $promise->reject(new Exception($msg->body->params->message)); - } else if (strpos($msg->body->params->message, 'All 26 PHP files parsed') !== false) { + } else if (strpos($msg->body->params->message, 'All 27 PHP files parsed') !== false) { $promise->fulfill(); } } @@ -103,7 +103,7 @@ class LanguageServerTest extends TestCase if ($promise->state === Promise::PENDING) { $promise->reject(new Exception($msg->body->params->message)); } - } else if (strpos($msg->body->params->message, 'All 26 PHP files parsed') !== false) { + } else if (strpos($msg->body->params->message, 'All 27 PHP files parsed') !== false) { $promise->fulfill(); } } diff --git a/tests/Server/ServerTestCase.php b/tests/Server/ServerTestCase.php index f5fec55..127f0e2 100644 --- a/tests/Server/ServerTestCase.php +++ b/tests/Server/ServerTestCase.php @@ -72,18 +72,19 @@ abstract class ServerTestCase extends TestCase $this->definitionLocations = [ // Global - 'TEST_CONST' => new Location($globalSymbolsUri, new Range(new Position( 9, 6), new Position( 9, 22))), - 'TestClass' => new Location($globalSymbolsUri, new Range(new Position(20, 0), new Position(61, 1))), - 'ChildClass' => new Location($globalSymbolsUri, new Range(new Position(99, 0), new Position(99, 37))), - 'TestTrait' => new Location($globalSymbolsUri, new Range(new Position(63, 0), new Position(66, 1))), - 'TestInterface' => new Location($globalSymbolsUri, new Range(new Position(68, 0), new Position(71, 1))), - 'TestClass::TEST_CLASS_CONST' => new Location($globalSymbolsUri, new Range(new Position(27, 10), new Position(27, 32))), - 'TestClass::testProperty' => new Location($globalSymbolsUri, new Range(new Position(41, 11), new Position(41, 24))), - 'TestClass::staticTestProperty' => new Location($globalSymbolsUri, new Range(new Position(34, 18), new Position(34, 37))), - 'TestClass::staticTestMethod()' => new Location($globalSymbolsUri, new Range(new Position(46, 4), new Position(49, 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))), - 'whatever()' => new Location($globalReferencesUri, new Range(new Position(21, 0), new Position(23, 1))), + 'TEST_PROPERTY' => new Location($globalSymbolsUri, new Range(new Position(104, 0), new Position(104, 30))), + 'TEST_CONST' => new Location($globalSymbolsUri, new Range(new Position( 9, 6), new Position( 9, 22))), + 'TestClass' => new Location($globalSymbolsUri, new Range(new Position(20, 0), new Position(61, 1))), + 'ChildClass' => new Location($globalSymbolsUri, new Range(new Position(99, 0), new Position(99, 37))), + 'TestTrait' => new Location($globalSymbolsUri, new Range(new Position(63, 0), new Position(66, 1))), + 'TestInterface' => new Location($globalSymbolsUri, new Range(new Position(68, 0), new Position(71, 1))), + 'TestClass::TEST_CLASS_CONST' => new Location($globalSymbolsUri, new Range(new Position(27, 10), new Position(27, 32))), + 'TestClass::testProperty' => new Location($globalSymbolsUri, new Range(new Position(41, 11), new Position(41, 24))), + 'TestClass::staticTestProperty' => new Location($globalSymbolsUri, new Range(new Position(34, 18), new Position(34, 37))), + 'TestClass::staticTestMethod()' => new Location($globalSymbolsUri, new Range(new Position(46, 4), new Position(49, 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))), + 'whatever()' => new Location($globalReferencesUri, new Range(new Position(21, 0), new Position(23, 1))), // Namespaced 'TestNamespace' => new Location($symbolsUri, new Range(new Position( 2, 10), new Position( 2, 23))), @@ -163,6 +164,9 @@ abstract class ServerTestCase extends TestCase ], // Global + 'TEST_PROPERTY' => [ + 0 => new Location($globalSymbolsUri, new Range(new Position(106, 6), new Position(106, 19))) + ], 'TEST_CONST' => [ 0 => new Location($referencesUri, new Range(new Position(29, 5), new Position(29, 15))), 1 => new Location($globalReferencesUri, new Range(new Position(29, 5), new Position(29, 15))) diff --git a/tests/Server/TextDocument/HoverTest.php b/tests/Server/TextDocument/HoverTest.php index cdc1718..628aab5 100644 --- a/tests/Server/TextDocument/HoverTest.php +++ b/tests/Server/TextDocument/HoverTest.php @@ -156,6 +156,20 @@ class HoverTest extends ServerTestCase ], $reference->range), $result); } + public function testHoverForGlobalConstant() { + // print TEST_PROPERTY ? 'true' : 'false'; + // Get hover for TEST_PROPERTY + $reference = $this->getReferenceLocations('TEST_PROPERTY')[0]; + $result = $this->textDocument->hover( + new TextDocumentIdentifier($reference->uri), + $reference->range->end + )->wait(); + $this->assertEquals(new Hover([ + new MarkedString('php', "range), $result); + } + public function testHoverForVariable() { // echo $var; diff --git a/tests/Server/Workspace/SymbolTest.php b/tests/Server/Workspace/SymbolTest.php index 5d0ed34..733acf4 100644 --- a/tests/Server/Workspace/SymbolTest.php +++ b/tests/Server/Workspace/SymbolTest.php @@ -58,9 +58,10 @@ class SymbolTest extends ServerTestCase new SymbolInformation('TestInterface', SymbolKind::INTERFACE, $this->getDefinitionLocation('TestInterface'), ''), new SymbolInformation('test_function', SymbolKind::FUNCTION, $this->getDefinitionLocation('test_function()'), ''), new SymbolInformation('ChildClass', SymbolKind::CLASS_, $this->getDefinitionLocation('ChildClass'), ''), + new SymbolInformation('define', SymbolKind::CONSTANT, $this->getDefinitionLocation('TEST_PROPERTY'), ''), new SymbolInformation('whatever', SymbolKind::FUNCTION, $this->getDefinitionLocation('whatever()'), ''), - new SymbolInformation('SecondTestNamespace', SymbolKind::NAMESPACE, $this->getDefinitionLocation('SecondTestNamespace'), '') + new SymbolInformation('SecondTestNamespace', SymbolKind::NAMESPACE, $this->getDefinitionLocation('SecondTestNamespace'), '') ], $result); // @codingStandardsIgnoreEnd } From 9ff8957f479b3b8995fbce5318c39f0e04f06bb0 Mon Sep 17 00:00:00 2001 From: jens1o Date: Mon, 10 Apr 2017 12:27:59 +0200 Subject: [PATCH 02/16] fix double definiton --- .../completion/constant_with_namespace.php | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/fixtures/completion/constant_with_namespace.php b/fixtures/completion/constant_with_namespace.php index b31d25c..cade11f 100644 --- a/fixtures/completion/constant_with_namespace.php +++ b/fixtures/completion/constant_with_namespace.php @@ -21,26 +21,3 @@ namespace { HELLO\world(); } - Date: Mon, 10 Apr 2017 12:33:33 +0200 Subject: [PATCH 03/16] fix code style --- src/DefinitionResolver.php | 2 +- tests/Server/TextDocument/HoverTest.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/DefinitionResolver.php b/src/DefinitionResolver.php index 9376ced..bbf9076 100644 --- a/src/DefinitionResolver.php +++ b/src/DefinitionResolver.php @@ -887,6 +887,6 @@ class DefinitionResolver return null; } return (string)$node->args[0]->value->value; - } + } } } diff --git a/tests/Server/TextDocument/HoverTest.php b/tests/Server/TextDocument/HoverTest.php index 628aab5..9815437 100644 --- a/tests/Server/TextDocument/HoverTest.php +++ b/tests/Server/TextDocument/HoverTest.php @@ -156,7 +156,8 @@ class HoverTest extends ServerTestCase ], $reference->range), $result); } - public function testHoverForGlobalConstant() { + public function testHoverForGlobalConstant() + { // print TEST_PROPERTY ? 'true' : 'false'; // Get hover for TEST_PROPERTY $reference = $this->getReferenceLocations('TEST_PROPERTY')[0]; From 76e7170f154c04b1fcea4d35bb863e70712a0bd9 Mon Sep 17 00:00:00 2001 From: jens1o Date: Mon, 17 Apr 2017 12:15:46 +0200 Subject: [PATCH 04/16] rename test constant and fix name gets renamed bug --- fixtures/global_symbols.php | 4 +- src/Protocol/SymbolInformation.php | 11 ++++- tests/Server/ServerTestCase.php | 6 +-- tests/Server/TextDocument/HoverTest.php | 8 ++-- tests/Server/Workspace/SymbolTest.php | 60 ++++++++++++------------- 5 files changed, 48 insertions(+), 41 deletions(-) diff --git a/fixtures/global_symbols.php b/fixtures/global_symbols.php index 11f78bd..ac93b68 100644 --- a/fixtures/global_symbols.php +++ b/fixtures/global_symbols.php @@ -102,6 +102,6 @@ class ChildClass extends TestClass {} /** * Lorem ipsum dolor sit amet, consectetur. */ -define('TEST_PROPERTY', false); +define('TEST_DEFINE_CONSTANT', false); -print TEST_PROPERTY ? 'true' : 'false'; +print TEST_DEFINE_CONSTANT ? 'true' : 'false'; diff --git a/src/Protocol/SymbolInformation.php b/src/Protocol/SymbolInformation.php index a2ab964..7ee34d0 100644 --- a/src/Protocol/SymbolInformation.php +++ b/src/Protocol/SymbolInformation.php @@ -58,9 +58,8 @@ class SymbolInformation && $node->args[0]->value instanceof Node\Scalar\String_ ) { // constants with define() like - // define('TEST_PROPERTY', true); + // define('TEST_DEFINE_CONSTANT', false); $symbol->kind = SymbolKind::CONSTANT; - $symbol->name = (string)$node->args[0]->value->value; } else if ($node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\Trait_) { $symbol->kind = SymbolKind::CLASS_; } else if ($node instanceof Node\Stmt\Interface_) { @@ -91,6 +90,14 @@ class SymbolInformation } if ($node instanceof Node\Name) { $symbol->name = (string)$node; + } else if( + $node instanceof Node\Expr\FuncCall + && $node->name instanceof Node\Name + && strtolower((string)$node->name) === 'define' + && isset($node->args[0]) + && $node->args[0]->value instanceof Node\Scalar\String_ + ) { + $symbol->name = (string)$node->args[0]->value->value; } else if ($node instanceof Node\Expr\Assign || $node instanceof Node\Expr\AssignOp) { $symbol->name = $node->var->name; } else if ($node instanceof Node\Expr\ClosureUse) { diff --git a/tests/Server/ServerTestCase.php b/tests/Server/ServerTestCase.php index 127f0e2..1154216 100644 --- a/tests/Server/ServerTestCase.php +++ b/tests/Server/ServerTestCase.php @@ -72,7 +72,7 @@ abstract class ServerTestCase extends TestCase $this->definitionLocations = [ // Global - 'TEST_PROPERTY' => new Location($globalSymbolsUri, new Range(new Position(104, 0), new Position(104, 30))), + 'TEST_DEFINE_CONSTANT' => new Location($globalSymbolsUri, new Range(new Position(104, 0), new Position(104, 37))), 'TEST_CONST' => new Location($globalSymbolsUri, new Range(new Position( 9, 6), new Position( 9, 22))), 'TestClass' => new Location($globalSymbolsUri, new Range(new Position(20, 0), new Position(61, 1))), 'ChildClass' => new Location($globalSymbolsUri, new Range(new Position(99, 0), new Position(99, 37))), @@ -164,8 +164,8 @@ abstract class ServerTestCase extends TestCase ], // Global - 'TEST_PROPERTY' => [ - 0 => new Location($globalSymbolsUri, new Range(new Position(106, 6), new Position(106, 19))) + 'TEST_DEFINE_CONSTANT' => [ + 0 => new Location($globalSymbolsUri, new Range(new Position(106, 6), new Position(106, 26))) ], 'TEST_CONST' => [ 0 => new Location($referencesUri, new Range(new Position(29, 5), new Position(29, 15))), diff --git a/tests/Server/TextDocument/HoverTest.php b/tests/Server/TextDocument/HoverTest.php index 9815437..4da707a 100644 --- a/tests/Server/TextDocument/HoverTest.php +++ b/tests/Server/TextDocument/HoverTest.php @@ -158,15 +158,15 @@ class HoverTest extends ServerTestCase public function testHoverForGlobalConstant() { - // print TEST_PROPERTY ? 'true' : 'false'; - // Get hover for TEST_PROPERTY - $reference = $this->getReferenceLocations('TEST_PROPERTY')[0]; + // print TEST_DEFINE_CONSTANT ? 'true' : 'false'; + // Get hover for TEST_DEFINE_CONSTANT + $reference = $this->getReferenceLocations('TEST_DEFINE_CONSTANT')[0]; $result = $this->textDocument->hover( new TextDocumentIdentifier($reference->uri), $reference->range->end )->wait(); $this->assertEquals(new Hover([ - new MarkedString('php', "range), $result); } diff --git a/tests/Server/Workspace/SymbolTest.php b/tests/Server/Workspace/SymbolTest.php index 733acf4..65ce804 100644 --- a/tests/Server/Workspace/SymbolTest.php +++ b/tests/Server/Workspace/SymbolTest.php @@ -29,39 +29,39 @@ class SymbolTest extends ServerTestCase $referencesUri = pathToUri(realpath(__DIR__ . '/../../../fixtures/references.php')); // @codingStandardsIgnoreStart $this->assertEquals([ - new SymbolInformation('TestNamespace', SymbolKind::NAMESPACE, new Location($referencesUri, new Range(new Position(2, 10), new Position(2, 23))), ''), + new SymbolInformation('TestNamespace', SymbolKind::NAMESPACE, new Location($referencesUri, new Range(new Position(2, 10), new Position(2, 23))), ''), // Namespaced - new SymbolInformation('TEST_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestNamespace\\TEST_CONST'), 'TestNamespace'), - new SymbolInformation('TestClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\TestClass'), 'TestNamespace'), - new SymbolInformation('TEST_CLASS_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestNamespace\\TestClass::TEST_CLASS_CONST'), 'TestNamespace\\TestClass'), - new SymbolInformation('staticTestProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestNamespace\\TestClass::staticTestProperty'), 'TestNamespace\\TestClass'), - new SymbolInformation('testProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestNamespace\\TestClass::testProperty'), 'TestNamespace\\TestClass'), - new SymbolInformation('staticTestMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestNamespace\\TestClass::staticTestMethod()'), 'TestNamespace\\TestClass'), - new SymbolInformation('testMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestNamespace\\TestClass::testMethod()'), 'TestNamespace\\TestClass'), - new SymbolInformation('TestTrait', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\TestTrait'), 'TestNamespace'), - new SymbolInformation('TestInterface', SymbolKind::INTERFACE, $this->getDefinitionLocation('TestNamespace\\TestInterface'), 'TestNamespace'), - new SymbolInformation('test_function', SymbolKind::FUNCTION, $this->getDefinitionLocation('TestNamespace\\test_function()'), 'TestNamespace'), - new SymbolInformation('ChildClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\ChildClass'), 'TestNamespace'), - new SymbolInformation('Example', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\Example'), 'TestNamespace'), - new SymbolInformation('__construct', SymbolKind::CONSTRUCTOR, $this->getDefinitionLocation('TestNamespace\\Example::__construct'), 'TestNamespace\\Example'), - new SymbolInformation('__destruct', SymbolKind::CONSTRUCTOR, $this->getDefinitionLocation('TestNamespace\\Example::__destruct'), 'TestNamespace\\Example'), - new SymbolInformation('whatever', SymbolKind::FUNCTION, $this->getDefinitionLocation('TestNamespace\\whatever()'), 'TestNamespace'), + new SymbolInformation('TEST_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestNamespace\\TEST_CONST'), 'TestNamespace'), + new SymbolInformation('TestClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\TestClass'), 'TestNamespace'), + new SymbolInformation('TEST_CLASS_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestNamespace\\TestClass::TEST_CLASS_CONST'), 'TestNamespace\\TestClass'), + new SymbolInformation('staticTestProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestNamespace\\TestClass::staticTestProperty'), 'TestNamespace\\TestClass'), + new SymbolInformation('testProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestNamespace\\TestClass::testProperty'), 'TestNamespace\\TestClass'), + new SymbolInformation('staticTestMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestNamespace\\TestClass::staticTestMethod()'), 'TestNamespace\\TestClass'), + new SymbolInformation('testMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestNamespace\\TestClass::testMethod()'), 'TestNamespace\\TestClass'), + new SymbolInformation('TestTrait', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\TestTrait'), 'TestNamespace'), + new SymbolInformation('TestInterface', SymbolKind::INTERFACE, $this->getDefinitionLocation('TestNamespace\\TestInterface'), 'TestNamespace'), + new SymbolInformation('test_function', SymbolKind::FUNCTION, $this->getDefinitionLocation('TestNamespace\\test_function()'), 'TestNamespace'), + new SymbolInformation('ChildClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\ChildClass'), 'TestNamespace'), + new SymbolInformation('Example', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\Example'), 'TestNamespace'), + new SymbolInformation('__construct', SymbolKind::CONSTRUCTOR, $this->getDefinitionLocation('TestNamespace\\Example::__construct'), 'TestNamespace\\Example'), + new SymbolInformation('__destruct', SymbolKind::CONSTRUCTOR, $this->getDefinitionLocation('TestNamespace\\Example::__destruct'), 'TestNamespace\\Example'), + new SymbolInformation('whatever', SymbolKind::FUNCTION, $this->getDefinitionLocation('TestNamespace\\whatever()'), 'TestNamespace'), // Global - new SymbolInformation('TEST_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TEST_CONST'), ''), - new SymbolInformation('TestClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestClass'), ''), - new SymbolInformation('TEST_CLASS_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestClass::TEST_CLASS_CONST'), 'TestClass'), - new SymbolInformation('staticTestProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestClass::staticTestProperty'), 'TestClass'), - new SymbolInformation('testProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestClass::testProperty'), 'TestClass'), - new SymbolInformation('staticTestMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestClass::staticTestMethod()'), 'TestClass'), - new SymbolInformation('testMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestClass::testMethod()'), 'TestClass'), - new SymbolInformation('TestTrait', SymbolKind::CLASS_, $this->getDefinitionLocation('TestTrait'), ''), - new SymbolInformation('TestInterface', SymbolKind::INTERFACE, $this->getDefinitionLocation('TestInterface'), ''), - new SymbolInformation('test_function', SymbolKind::FUNCTION, $this->getDefinitionLocation('test_function()'), ''), - new SymbolInformation('ChildClass', SymbolKind::CLASS_, $this->getDefinitionLocation('ChildClass'), ''), - new SymbolInformation('define', SymbolKind::CONSTANT, $this->getDefinitionLocation('TEST_PROPERTY'), ''), - new SymbolInformation('whatever', SymbolKind::FUNCTION, $this->getDefinitionLocation('whatever()'), ''), + new SymbolInformation('TEST_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TEST_CONST'), ''), + new SymbolInformation('TestClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestClass'), ''), + new SymbolInformation('TEST_CLASS_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestClass::TEST_CLASS_CONST'), 'TestClass'), + new SymbolInformation('staticTestProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestClass::staticTestProperty'), 'TestClass'), + new SymbolInformation('testProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestClass::testProperty'), 'TestClass'), + new SymbolInformation('staticTestMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestClass::staticTestMethod()'), 'TestClass'), + new SymbolInformation('testMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestClass::testMethod()'), 'TestClass'), + new SymbolInformation('TestTrait', SymbolKind::CLASS_, $this->getDefinitionLocation('TestTrait'), ''), + new SymbolInformation('TestInterface', SymbolKind::INTERFACE, $this->getDefinitionLocation('TestInterface'), ''), + 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('whatever', SymbolKind::FUNCTION, $this->getDefinitionLocation('whatever()'), ''), - new SymbolInformation('SecondTestNamespace', SymbolKind::NAMESPACE, $this->getDefinitionLocation('SecondTestNamespace'), '') + new SymbolInformation('SecondTestNamespace', SymbolKind::NAMESPACE, $this->getDefinitionLocation('SecondTestNamespace'), '') ], $result); // @codingStandardsIgnoreEnd } From 7380acc49fbacb4d5a6b3a7bf76d6dd55eed2043 Mon Sep 17 00:00:00 2001 From: jens1o Date: Mon, 17 Apr 2017 12:18:27 +0200 Subject: [PATCH 05/16] fix code style --- src/Protocol/SymbolInformation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocol/SymbolInformation.php b/src/Protocol/SymbolInformation.php index 7ee34d0..d173426 100644 --- a/src/Protocol/SymbolInformation.php +++ b/src/Protocol/SymbolInformation.php @@ -90,7 +90,7 @@ class SymbolInformation } if ($node instanceof Node\Name) { $symbol->name = (string)$node; - } else if( + } else if ( $node instanceof Node\Expr\FuncCall && $node->name instanceof Node\Name && strtolower((string)$node->name) === 'define' From 6fea33db04a9aceccd2baaa7d3548906206376d9 Mon Sep 17 00:00:00 2001 From: jens1o Date: Mon, 17 Apr 2017 16:04:12 +0200 Subject: [PATCH 06/16] unify code --- src/Protocol/SymbolInformation.php | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Protocol/SymbolInformation.php b/src/Protocol/SymbolInformation.php index d173426..ea03f9f 100644 --- a/src/Protocol/SymbolInformation.php +++ b/src/Protocol/SymbolInformation.php @@ -50,6 +50,8 @@ class SymbolInformation { $parent = $node->getAttribute('parentNode'); $symbol = new self; + $setDefaultName = true; + if ( $node instanceof Node\Expr\FuncCall && $node->name instanceof Node\Name @@ -60,6 +62,8 @@ class SymbolInformation // constants with define() like // define('TEST_DEFINE_CONSTANT', false); $symbol->kind = SymbolKind::CONSTANT; + $symbol->name = (string)$node->args[0]->value->value; + $setDefaultName = false; } else if ($node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\Trait_) { $symbol->kind = SymbolKind::CLASS_; } else if ($node instanceof Node\Stmt\Interface_) { @@ -90,23 +94,18 @@ class SymbolInformation } if ($node instanceof Node\Name) { $symbol->name = (string)$node; - } else if ( - $node instanceof Node\Expr\FuncCall - && $node->name instanceof Node\Name - && strtolower((string)$node->name) === 'define' - && isset($node->args[0]) - && $node->args[0]->value instanceof Node\Scalar\String_ - ) { - $symbol->name = (string)$node->args[0]->value->value; } else if ($node instanceof Node\Expr\Assign || $node instanceof Node\Expr\AssignOp) { $symbol->name = $node->var->name; } else if ($node instanceof Node\Expr\ClosureUse) { $symbol->name = $node->var; } else if (isset($node->name)) { - $symbol->name = (string)$node->name; + if($setDefaultName) { + $symbol->name = (string)$node->name; + } } else { return null; } + $symbol->location = Location::fromNode($node); if ($fqn !== null) { $parts = preg_split('/(::|->|\\\\)/', $fqn); From 9d1af8412254f24c43c61c71392d4fb405bd7237 Mon Sep 17 00:00:00 2001 From: jens1o Date: Mon, 17 Apr 2017 16:06:30 +0200 Subject: [PATCH 07/16] code style --- src/Protocol/SymbolInformation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocol/SymbolInformation.php b/src/Protocol/SymbolInformation.php index ea03f9f..2d09d26 100644 --- a/src/Protocol/SymbolInformation.php +++ b/src/Protocol/SymbolInformation.php @@ -99,7 +99,7 @@ class SymbolInformation } else if ($node instanceof Node\Expr\ClosureUse) { $symbol->name = $node->var; } else if (isset($node->name)) { - if($setDefaultName) { + if ($setDefaultName) { $symbol->name = (string)$node->name; } } else { From 93fae1bb13cdbd1e4a0baf9d0f0373e3e67007c1 Mon Sep 17 00:00:00 2001 From: jens1o Date: Mon, 17 Apr 2017 16:16:31 +0200 Subject: [PATCH 08/16] update code style --- src/Protocol/SymbolInformation.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Protocol/SymbolInformation.php b/src/Protocol/SymbolInformation.php index 2d09d26..0a813ef 100644 --- a/src/Protocol/SymbolInformation.php +++ b/src/Protocol/SymbolInformation.php @@ -50,7 +50,6 @@ class SymbolInformation { $parent = $node->getAttribute('parentNode'); $symbol = new self; - $setDefaultName = true; if ( $node instanceof Node\Expr\FuncCall @@ -63,7 +62,6 @@ class SymbolInformation // define('TEST_DEFINE_CONSTANT', false); $symbol->kind = SymbolKind::CONSTANT; $symbol->name = (string)$node->args[0]->value->value; - $setDefaultName = false; } else if ($node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\Trait_) { $symbol->kind = SymbolKind::CLASS_; } else if ($node instanceof Node\Stmt\Interface_) { @@ -98,10 +96,8 @@ class SymbolInformation $symbol->name = $node->var->name; } else if ($node instanceof Node\Expr\ClosureUse) { $symbol->name = $node->var; - } else if (isset($node->name)) { - if ($setDefaultName) { - $symbol->name = (string)$node->name; - } + } else if (isset($node->name) && !isset($symbol->name)) { + $symbol->name = (string)$node->name; } else { return null; } From 2625a1062b29cc26fa5ff090815cdfe6799f39bc Mon Sep 17 00:00:00 2001 From: jens1o Date: Mon, 17 Apr 2017 16:32:19 +0200 Subject: [PATCH 09/16] fix test & revert last commit --- src/Protocol/SymbolInformation.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Protocol/SymbolInformation.php b/src/Protocol/SymbolInformation.php index 0a813ef..2d09d26 100644 --- a/src/Protocol/SymbolInformation.php +++ b/src/Protocol/SymbolInformation.php @@ -50,6 +50,7 @@ class SymbolInformation { $parent = $node->getAttribute('parentNode'); $symbol = new self; + $setDefaultName = true; if ( $node instanceof Node\Expr\FuncCall @@ -62,6 +63,7 @@ class SymbolInformation // define('TEST_DEFINE_CONSTANT', false); $symbol->kind = SymbolKind::CONSTANT; $symbol->name = (string)$node->args[0]->value->value; + $setDefaultName = false; } else if ($node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\Trait_) { $symbol->kind = SymbolKind::CLASS_; } else if ($node instanceof Node\Stmt\Interface_) { @@ -96,8 +98,10 @@ class SymbolInformation $symbol->name = $node->var->name; } else if ($node instanceof Node\Expr\ClosureUse) { $symbol->name = $node->var; - } else if (isset($node->name) && !isset($symbol->name)) { - $symbol->name = (string)$node->name; + } else if (isset($node->name)) { + if ($setDefaultName) { + $symbol->name = (string)$node->name; + } } else { return null; } From 8ac306f653564697583f1dcc75747c375fd6f41c Mon Sep 17 00:00:00 2001 From: Felix Becker Date: Mon, 17 Apr 2017 16:37:21 +0200 Subject: [PATCH 10/16] Update SymbolInformation.php --- src/Protocol/SymbolInformation.php | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Protocol/SymbolInformation.php b/src/Protocol/SymbolInformation.php index 2d09d26..a1ce983 100644 --- a/src/Protocol/SymbolInformation.php +++ b/src/Protocol/SymbolInformation.php @@ -50,7 +50,6 @@ class SymbolInformation { $parent = $node->getAttribute('parentNode'); $symbol = new self; - $setDefaultName = true; if ( $node instanceof Node\Expr\FuncCall @@ -63,7 +62,6 @@ class SymbolInformation // define('TEST_DEFINE_CONSTANT', false); $symbol->kind = SymbolKind::CONSTANT; $symbol->name = (string)$node->args[0]->value->value; - $setDefaultName = false; } else if ($node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\Trait_) { $symbol->kind = SymbolKind::CLASS_; } else if ($node instanceof Node\Stmt\Interface_) { @@ -92,18 +90,19 @@ class SymbolInformation } else { return null; } - if ($node instanceof Node\Name) { - $symbol->name = (string)$node; - } else if ($node instanceof Node\Expr\Assign || $node instanceof Node\Expr\AssignOp) { - $symbol->name = $node->var->name; - } else if ($node instanceof Node\Expr\ClosureUse) { - $symbol->name = $node->var; - } else if (isset($node->name)) { - if ($setDefaultName) { + + if (!isset($symbol->name)) { + if ($node instanceof Node\Name) { + $symbol->name = (string)$node; + } else if ($node instanceof Node\Expr\Assign || $node instanceof Node\Expr\AssignOp) { + $symbol->name = $node->var->name; + } else if ($node instanceof Node\Expr\ClosureUse) { + $symbol->name = $node->var; + } else if (isset($node->name)) { $symbol->name = (string)$node->name; + } else { + return null; } - } else { - return null; } $symbol->location = Location::fromNode($node); From ede90472d0768eb958791abf24cb8440b374da1f Mon Sep 17 00:00:00 2001 From: Felix Becker Date: Mon, 17 Apr 2017 16:40:29 +0200 Subject: [PATCH 11/16] Remove whitespace --- src/Protocol/SymbolInformation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocol/SymbolInformation.php b/src/Protocol/SymbolInformation.php index a1ce983..4fb1d3f 100644 --- a/src/Protocol/SymbolInformation.php +++ b/src/Protocol/SymbolInformation.php @@ -91,7 +91,7 @@ class SymbolInformation return null; } - if (!isset($symbol->name)) { + if (!isset($symbol->name)) { if ($node instanceof Node\Name) { $symbol->name = (string)$node; } else if ($node instanceof Node\Expr\Assign || $node instanceof Node\Expr\AssignOp) { From 23438b82815e55012e06ebfbf0d595690e0ec25f Mon Sep 17 00:00:00 2001 From: jens1o Date: Mon, 17 Apr 2017 21:01:42 +0200 Subject: [PATCH 12/16] :rocket: Support self reference --- fixtures/global_references.php | 3 +++ fixtures/global_symbols.php | 15 +++++++++++ src/DefinitionResolver.php | 26 ++++++++++++++++++-- tests/Server/ServerTestCase.php | 12 +++++++++ tests/Server/TextDocument/CompletionTest.php | 9 +++++++ tests/Server/TextDocument/HoverTest.php | 15 +++++++++++ tests/Server/Workspace/SymbolTest.php | 3 +++ 7 files changed, 81 insertions(+), 2 deletions(-) diff --git a/fixtures/global_references.php b/fixtures/global_references.php index c76c934..7370d45 100644 --- a/fixtures/global_references.php +++ b/fixtures/global_references.php @@ -41,3 +41,6 @@ TestClass::$staticTestProperty[123]->testProperty; $child = new ChildClass; echo $child->testMethod(); + +// resolve self expression +Something::getInstance()->hello(); diff --git a/fixtures/global_symbols.php b/fixtures/global_symbols.php index ac93b68..f7fec6e 100644 --- a/fixtures/global_symbols.php +++ b/fixtures/global_symbols.php @@ -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!'; + } +} diff --git a/src/DefinitionResolver.php b/src/DefinitionResolver.php index bbf9076..83f7898 100644 --- a/src/DefinitionResolver.php +++ b/src/DefinitionResolver.php @@ -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 diff --git a/tests/Server/ServerTestCase.php b/tests/Server/ServerTestCase.php index 1154216..61507be 100644 --- a/tests/Server/ServerTestCase.php +++ b/tests/Server/ServerTestCase.php @@ -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 diff --git a/tests/Server/TextDocument/CompletionTest.php b/tests/Server/TextDocument/CompletionTest.php index 29851e0..9cc9aeb 100644 --- a/tests/Server/TextDocument/CompletionTest.php +++ b/tests/Server/TextDocument/CompletionTest.php @@ -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', diff --git a/tests/Server/TextDocument/HoverTest.php b/tests/Server/TextDocument/HoverTest.php index 4da707a..7b4925c 100644 --- a/tests/Server/TextDocument/HoverTest.php +++ b/tests/Server/TextDocument/HoverTest.php @@ -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', "range), $result); + } + public function testHoverForClassLikeDefinition() { // class TestClass implements TestInterface diff --git a/tests/Server/Workspace/SymbolTest.php b/tests/Server/Workspace/SymbolTest.php index 65ce804..209e569 100644 --- a/tests/Server/Workspace/SymbolTest.php +++ b/tests/Server/Workspace/SymbolTest.php @@ -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'), '') From 393eb6ff91ce55b27cff13a64b7817dd6fa35ad5 Mon Sep 17 00:00:00 2001 From: jens1o Date: Mon, 17 Apr 2017 21:03:40 +0200 Subject: [PATCH 13/16] fix variable naming --- src/DefinitionResolver.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/DefinitionResolver.php b/src/DefinitionResolver.php index 83f7898..17e8315 100644 --- a/src/DefinitionResolver.php +++ b/src/DefinitionResolver.php @@ -745,10 +745,8 @@ class DefinitionResolver if (is_string($node->type)) { // Resolve a string like "bool" to a type object $type = $this->typeResolver->resolve($node->type); - } else if ($node->returnType instanceof Node\Name) { - $type = (string)$node->returnType; - - if (strtolower($type) === 'self') { + } else if ($node->type instanceof Node\Name) { + if (strtolower($node->type) === 'self') { // handle self reference $class = getClosestNode($node, Node\Stmt\Class_::class); From d0b275b33a25f38fa8f34763951164341a9e5798 Mon Sep 17 00:00:00 2001 From: Jens Hausdorf Date: Mon, 17 Apr 2017 21:18:19 +0200 Subject: [PATCH 14/16] fix code style --- src/DefinitionResolver.php | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/DefinitionResolver.php b/src/DefinitionResolver.php index 17e8315..7e8b8b8 100644 --- a/src/DefinitionResolver.php +++ b/src/DefinitionResolver.php @@ -745,17 +745,13 @@ class DefinitionResolver if (is_string($node->type)) { // Resolve a string like "bool" to a type object $type = $this->typeResolver->resolve($node->type); - } else if ($node->type instanceof Node\Name) { - if (strtolower($node->type) === 'self') { - // handle self reference - $class = getClosestNode($node, Node\Stmt\Class_::class); - - if($class !== null) { - return new Types\Object_(new Fqsen('\\' . $class->name)); - } + } else if ($node->type instanceof Node\Name && strtolower($node->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); @@ -784,16 +780,12 @@ 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 ($node->returnType instanceof Node\Name && strtolower((string)$node->returnType) === 'self') { + // handle self reference + $class = getClosestNode($node, Node\Stmt\Class_::class); - 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)); - } + if ($class !== null) { + return new Types\Object_(new Fqsen('\\' . $class->name)); } } return new Types\Object_(new Fqsen('\\' . (string)$node->returnType)); From 3cc0c038bfd3fd1fa0dbd539a7b51e37ce60a921 Mon Sep 17 00:00:00 2001 From: Jens Hausdorf Date: Mon, 17 Apr 2017 21:22:52 +0200 Subject: [PATCH 15/16] fix test --- src/DefinitionResolver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DefinitionResolver.php b/src/DefinitionResolver.php index 7e8b8b8..ebcebcf 100644 --- a/src/DefinitionResolver.php +++ b/src/DefinitionResolver.php @@ -745,7 +745,7 @@ class DefinitionResolver if (is_string($node->type)) { // Resolve a string like "bool" to a type object $type = $this->typeResolver->resolve($node->type); - } else if ($node->type instanceof Node\Name && strtolower($node->type) === 'self') { + } else if ($node->type instanceof Node\Name && strtolower((string)$node->type) === 'self') { // handle self reference $class = getClosestNode($node, Node\Stmt\Class_::class); if ($class !== null) { From 8551907577b27e60f4b78d02efa1726ea68abb42 Mon Sep 17 00:00:00 2001 From: jens1o Date: Mon, 17 Apr 2017 22:17:38 +0200 Subject: [PATCH 16/16] progress --- fixtures/global_symbols.php | 6 +++++- src/DefinitionResolver.php | 2 +- tests/Server/ServerTestCase.php | 6 ++++-- tests/Server/TextDocument/HoverTest.php | 14 ++++++++++++++ tests/Server/Workspace/SymbolTest.php | 1 + 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/fixtures/global_symbols.php b/fixtures/global_symbols.php index 63d6abf..395b49c 100644 --- a/fixtures/global_symbols.php +++ b/fixtures/global_symbols.php @@ -119,4 +119,8 @@ class Something { public function hello() { echo 'Hi!'; } -} \ No newline at end of file + + public function selfParamTest(self $something) { + $something->hello(); + } +} diff --git a/src/DefinitionResolver.php b/src/DefinitionResolver.php index ebcebcf..bf04c9d 100644 --- a/src/DefinitionResolver.php +++ b/src/DefinitionResolver.php @@ -747,7 +747,7 @@ class DefinitionResolver $type = $this->typeResolver->resolve($node->type); } else if ($node->type instanceof Node\Name && strtolower((string)$node->type) === 'self') { // handle self reference - $class = getClosestNode($node, Node\Stmt\Class_::class); + $class = getClosestNode($node->type, Node\Stmt\Class_::class); if ($class !== null) { return new Types\Object_(new Fqsen('\\' . $class->name)); } diff --git a/tests/Server/ServerTestCase.php b/tests/Server/ServerTestCase.php index 61507be..4eb5752 100644 --- a/tests/Server/ServerTestCase.php +++ b/tests/Server/ServerTestCase.php @@ -85,9 +85,10 @@ 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' => new Location($globalSymbolsUri, new Range(new Position(109, 0), new Position(125, 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))), + 'Something::selfParamTest()' => new Location($globalSymbolsUri, new Range(new Position(122, 4), new Position(124, 5))), // Namespaced 'TestNamespace' => new Location($symbolsUri, new Range(new Position( 2, 10), new Position( 2, 23))), @@ -219,7 +220,8 @@ abstract class ServerTestCase extends TestCase 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() + 0 => new Location($globalReferencesUri, new Range(new Position(45, 0), new Position(56, 9))), // Something::getInstance()->hello() + 1 => new Location($globalSymbolsUri, new Range(new Position(123, 8), new Position(123, 18))) // $something->hello(); ], 'Something::getInstance()' => [ 0 => new Location($globalReferencesUri, new Range(new Position(45, 0), new Position(45, 24))) // Something::getInstance()->hello() diff --git a/tests/Server/TextDocument/HoverTest.php b/tests/Server/TextDocument/HoverTest.php index 7b4925c..0b32e38 100644 --- a/tests/Server/TextDocument/HoverTest.php +++ b/tests/Server/TextDocument/HoverTest.php @@ -46,6 +46,20 @@ class HoverTest extends ServerTestCase ], $reference->range), $result); } + public function testHoverForSelfParamTypeDefinition() + { + // class Something + // get hover for Something::getInstance() (returns a instance of Something) + $reference = $this->getReferenceLocations('Something')[1]; + $result = $this->textDocument->hover( + new TextDocumentIdentifier($reference->uri), + $reference->range->end + )->wait(); + $this->assertEquals(new Hover([ + new MarkedString('php', "range), $result); + } + public function testHoverForClassLikeDefinition() { // class TestClass implements TestInterface diff --git a/tests/Server/Workspace/SymbolTest.php b/tests/Server/Workspace/SymbolTest.php index 209e569..3ef4300 100644 --- a/tests/Server/Workspace/SymbolTest.php +++ b/tests/Server/Workspace/SymbolTest.php @@ -62,6 +62,7 @@ class SymbolTest extends ServerTestCase 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('selfParamTest', SymbolKind::METHOD, $this->getDefinitionLocation('Something::selfParamTest()'), 'Something'), new SymbolInformation('whatever', SymbolKind::FUNCTION, $this->getDefinitionLocation('whatever()'), ''), new SymbolInformation('SecondTestNamespace', SymbolKind::NAMESPACE, $this->getDefinitionLocation('SecondTestNamespace'), '')