diff --git a/fixtures/completion/constant_with_namespace.php b/fixtures/completion/constant_with_namespace.php new file mode 100644 index 00000000..cade11f4 --- /dev/null +++ b/fixtures/completion/constant_with_namespace.php @@ -0,0 +1,23 @@ +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 5c24813e..b753476e 100644 --- a/src/Index/Index.php +++ b/src/Index/Index.php @@ -117,7 +117,7 @@ public function getDefinition(string $fqn, bool $globalFallback = false) * 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 299dc55b..4fb1d3fc 100644 --- a/src/Protocol/SymbolInformation.php +++ b/src/Protocol/SymbolInformation.php @@ -50,9 +50,19 @@ public static function fromNode(Node $node, string $fqn = null) { $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_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_) { $symbol->kind = SymbolKind::INTERFACE; @@ -80,17 +90,21 @@ public static function fromNode(Node $node, string $fqn = null) } 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)) { - $symbol->name = (string)$node->name; - } else { - return null; + + 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; + } } + $symbol->location = Location::fromNode($node); if ($fqn !== null) { $parts = preg_split('/(::|->|\\\\)/', $fqn); diff --git a/tests/LanguageServerTest.php b/tests/LanguageServerTest.php index c32a76a3..fb52ef64 100644 --- a/tests/LanguageServerTest.php +++ b/tests/LanguageServerTest.php @@ -57,7 +57,7 @@ public function testIndexingWithDirectFileAccess() 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 @@ public function testIndexingWithFilesAndContentRequests() 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 f5fec55d..11542161 100644 --- a/tests/Server/ServerTestCase.php +++ b/tests/Server/ServerTestCase.php @@ -72,18 +72,19 @@ public function setUp() $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_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))), + '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 @@ public function setUp() ], // Global + '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))), 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 cdc17189..4da707a6 100644 --- a/tests/Server/TextDocument/HoverTest.php +++ b/tests/Server/TextDocument/HoverTest.php @@ -156,6 +156,21 @@ public function testHoverForConstant() ], $reference->range), $result); } + public function testHoverForGlobalConstant() + { + // 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); + } + public function testHoverForVariable() { // echo $var; diff --git a/tests/Server/Workspace/SymbolTest.php b/tests/Server/Workspace/SymbolTest.php index 5d0ed346..65ce8047 100644 --- a/tests/Server/Workspace/SymbolTest.php +++ b/tests/Server/Workspace/SymbolTest.php @@ -29,38 +29,39 @@ public function testEmptyQueryReturnsAllSymbols() $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('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 }