style: format with prettier
parent
8e1ea8696b
commit
4884bf8955
18
README.md
18
README.md
|
@ -17,6 +17,7 @@ Uses the great [Tolerant PHP Parser](https://github.com/Microsoft/tolerant-php-p
|
||||||
and an [event loop](http://sabre.io/event/loop/) for concurrency.
|
and an [event loop](http://sabre.io/event/loop/) for concurrency.
|
||||||
|
|
||||||
**Table of Contents**
|
**Table of Contents**
|
||||||
|
|
||||||
- [Features](#features)
|
- [Features](#features)
|
||||||
- [Performance](#performance)
|
- [Performance](#performance)
|
||||||
- [Versioning](#versioning)
|
- [Versioning](#versioning)
|
||||||
|
@ -25,22 +26,26 @@ and an [event loop](http://sabre.io/event/loop/) for concurrency.
|
||||||
- [Used by](#used-by)
|
- [Used by](#used-by)
|
||||||
- [Contributing](#contributing)
|
- [Contributing](#contributing)
|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
### [Completion](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#textDocument_completion)
|
### [Completion](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#textDocument_completion)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### [Signature Help](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#textDocument_signatureHelp)
|
### [Signature Help](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#textDocument_signatureHelp)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### [Go To Definition](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#goto-definition-request)
|
### [Go To Definition](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#goto-definition-request)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### [Find References](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#find-references-request)
|
### [Find References](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#find-references-request)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### [Hover](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#hover-request)
|
### [Hover](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#hover-request)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
@ -49,15 +54,18 @@ A hover request returns a declaration line (marked with language `php`) and the
|
||||||
For Parameters, it will return the `@param` tag.
|
For Parameters, it will return the `@param` tag.
|
||||||
|
|
||||||
### [Document Symbols](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#document-symbols-request)
|
### [Document Symbols](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#document-symbols-request)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### [Workspace Symbols](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#workspace-symbols-request)
|
### [Workspace Symbols](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#workspace-symbols-request)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
The query is matched case-insensitively against the fully qualified name of the symbol.
|
The query is matched case-insensitively against the fully qualified name of the symbol.
|
||||||
Non-Standard: An empty query will return _all_ symbols found in the workspace.
|
Non-Standard: An empty query will return _all_ symbols found in the workspace.
|
||||||
|
|
||||||
### Error reporting through [Publish Diagnostics](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#publishdiagnostics-notification)
|
### Error reporting through [Publish Diagnostics](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#publishdiagnostics-notification)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
PHP parse errors are reported as errors, parse errors of docblocks are reported as warnings.
|
PHP parse errors are reported as errors, parse errors of docblocks are reported as warnings.
|
||||||
|
@ -70,6 +78,7 @@ Completion, type resolval etc. will use the standard PHP library and common exte
|
||||||
### What is considered a definition?
|
### What is considered a definition?
|
||||||
|
|
||||||
Globally searchable definitions are:
|
Globally searchable definitions are:
|
||||||
|
|
||||||
- classes
|
- classes
|
||||||
- interfaces
|
- interfaces
|
||||||
- traits
|
- traits
|
||||||
|
@ -79,11 +88,13 @@ Globally searchable definitions are:
|
||||||
- constants with `const` keyword
|
- constants with `const` keyword
|
||||||
|
|
||||||
Definitions resolved just-in-time when needed:
|
Definitions resolved just-in-time when needed:
|
||||||
|
|
||||||
- variable assignments
|
- variable assignments
|
||||||
- parameters
|
- parameters
|
||||||
- closure `use` statements
|
- closure `use` statements
|
||||||
|
|
||||||
Not supported yet:
|
Not supported yet:
|
||||||
|
|
||||||
- constants with `define()`
|
- constants with `define()`
|
||||||
|
|
||||||
Namespaces are not considerd a declaration by design because they only make up a part of the fully qualified name
|
Namespaces are not considerd a declaration by design because they only make up a part of the fully qualified name
|
||||||
|
@ -92,6 +103,7 @@ and don't map to one unique declaration.
|
||||||
### What is considered a reference?
|
### What is considered a reference?
|
||||||
|
|
||||||
Definitions/references/hover currently work for
|
Definitions/references/hover currently work for
|
||||||
|
|
||||||
- class instantiations
|
- class instantiations
|
||||||
- static method calls
|
- static method calls
|
||||||
- class constant access
|
- class constant access
|
||||||
|
@ -163,6 +175,7 @@ Start the language server with
|
||||||
### Command line arguments
|
### Command line arguments
|
||||||
|
|
||||||
#### `--tcp=host:port` (optional)
|
#### `--tcp=host:port` (optional)
|
||||||
|
|
||||||
Causes the server to use a tcp connection for communicating with the language client instead of using STDIN/STDOUT.
|
Causes the server to use a tcp connection for communicating with the language client instead of using STDIN/STDOUT.
|
||||||
The server will try to connect to the specified address.
|
The server will try to connect to the specified address.
|
||||||
Strongly recommended on Windows because of blocking STDIO.
|
Strongly recommended on Windows because of blocking STDIO.
|
||||||
|
@ -172,6 +185,7 @@ Example:
|
||||||
php bin/php-language-server.php --tcp=127.0.0.1:12345
|
php bin/php-language-server.php --tcp=127.0.0.1:12345
|
||||||
|
|
||||||
#### `--tcp-server=host:port` (optional)
|
#### `--tcp-server=host:port` (optional)
|
||||||
|
|
||||||
Causes the server to use a tcp connection for communicating with the language client instead of using STDIN/STDOUT.
|
Causes the server to use a tcp connection for communicating with the language client instead of using STDIN/STDOUT.
|
||||||
The server will listen on the given address for a connection.
|
The server will listen on the given address for a connection.
|
||||||
If PCNTL is available, will fork a child process for every connection.
|
If PCNTL is available, will fork a child process for every connection.
|
||||||
|
@ -182,6 +196,7 @@ Example:
|
||||||
php bin/php-language-server.php --tcp-server=127.0.0.1:12345
|
php bin/php-language-server.php --tcp-server=127.0.0.1:12345
|
||||||
|
|
||||||
#### `--memory-limit=integer` (optional)
|
#### `--memory-limit=integer` (optional)
|
||||||
|
|
||||||
Sets memory limit for language server.
|
Sets memory limit for language server.
|
||||||
Equivalent to [memory-limit](http://php.net/manual/en/ini.core.php#ini.memory-limit) php.ini directive.
|
Equivalent to [memory-limit](http://php.net/manual/en/ini.core.php#ini.memory-limit) php.ini directive.
|
||||||
The default is 4GB (which is way more than needed).
|
The default is 4GB (which is way more than needed).
|
||||||
|
@ -191,6 +206,7 @@ Example:
|
||||||
php bin/php-language-server.php --memory-limit=256M
|
php bin/php-language-server.php --memory-limit=256M
|
||||||
|
|
||||||
## Used by
|
## Used by
|
||||||
|
|
||||||
- [VS Code PHP IntelliSense](https://github.com/felixfbecker/vscode-php-intellisense)
|
- [VS Code PHP IntelliSense](https://github.com/felixfbecker/vscode-php-intellisense)
|
||||||
- [Eclipse Che](https://eclipse.org/che/)
|
- [Eclipse Che](https://eclipse.org/che/)
|
||||||
- [Eclipse IDE (LSP4E-PHP)](https://github.com/eclipselabs/lsp4e-php)
|
- [Eclipse IDE (LSP4E-PHP)](https://github.com/eclipselabs/lsp4e-php)
|
||||||
|
|
|
@ -37,14 +37,18 @@ foreach (new RecursiveIteratorIterator($iterator) as $file) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($testProviderArray) === 0) {
|
if (count($testProviderArray) === 0) {
|
||||||
throw new Exception("ERROR: Validation testsuite frameworks not found - run `git submodule update --init --recursive` to download.");
|
throw new Exception(
|
||||||
|
"ERROR: Validation testsuite frameworks not found - run `git submodule update --init --recursive` to download."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$index = new Index;
|
$index = new Index();
|
||||||
$definitionResolver = new DefinitionResolver($index);
|
$definitionResolver = new DefinitionResolver($index);
|
||||||
$completionProvider = new CompletionProvider($definitionResolver, $index);
|
$completionProvider = new CompletionProvider($definitionResolver, $index);
|
||||||
$docBlockFactory = DocBlockFactory::createInstance();
|
$docBlockFactory = DocBlockFactory::createInstance();
|
||||||
$completionFile = realpath(__DIR__ . '/../validation/frameworks/symfony/src/Symfony/Component/HttpFoundation/Request.php');
|
$completionFile = realpath(
|
||||||
|
__DIR__ . '/../validation/frameworks/symfony/src/Symfony/Component/HttpFoundation/Request.php'
|
||||||
|
);
|
||||||
$parser = new PhpParser\Parser();
|
$parser = new PhpParser\Parser();
|
||||||
$completionDocument = null;
|
$completionDocument = null;
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,16 @@ unset($xdebugHandler);
|
||||||
|
|
||||||
$totalSize = 0;
|
$totalSize = 0;
|
||||||
|
|
||||||
$frameworks = ["drupal", "wordpress", "php-language-server", "tolerant-php-parser", "math-php", "symfony", "codeigniter", "cakephp"];
|
$frameworks = [
|
||||||
|
"drupal",
|
||||||
|
"wordpress",
|
||||||
|
"php-language-server",
|
||||||
|
"tolerant-php-parser",
|
||||||
|
"math-php",
|
||||||
|
"symfony",
|
||||||
|
"codeigniter",
|
||||||
|
"cakephp"
|
||||||
|
];
|
||||||
|
|
||||||
foreach ($frameworks as $framework) {
|
foreach ($frameworks as $framework) {
|
||||||
$iterator = new RecursiveDirectoryIterator(__DIR__ . "/../validation/frameworks/$framework");
|
$iterator = new RecursiveDirectoryIterator(__DIR__ . "/../validation/frameworks/$framework");
|
||||||
|
@ -36,7 +45,9 @@ foreach($frameworks as $framework) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($testProviderArray) === 0) {
|
if (count($testProviderArray) === 0) {
|
||||||
throw new Exception("ERROR: Validation testsuite frameworks not found - run `git submodule update --init --recursive` to download.");
|
throw new Exception(
|
||||||
|
"ERROR: Validation testsuite frameworks not found - run `git submodule update --init --recursive` to download."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$start = microtime(true);
|
$start = microtime(true);
|
||||||
|
@ -52,18 +63,24 @@ foreach($frameworks as $framework) {
|
||||||
$fileContents = file_get_contents($testCaseFile);
|
$fileContents = file_get_contents($testCaseFile);
|
||||||
|
|
||||||
$docBlockFactory = DocBlockFactory::createInstance();
|
$docBlockFactory = DocBlockFactory::createInstance();
|
||||||
$index = new Index;
|
$index = new Index();
|
||||||
$maxRecursion = [];
|
$maxRecursion = [];
|
||||||
$definitions = [];
|
$definitions = [];
|
||||||
|
|
||||||
$definitionResolver = new DefinitionResolver($index);
|
$definitionResolver = new DefinitionResolver($index);
|
||||||
$parser = new PhpParser\Parser();
|
$parser = new PhpParser\Parser();
|
||||||
|
|
||||||
$document = new PhpDocument($testCaseFile, $fileContents, $index, $parser, $docBlockFactory, $definitionResolver);
|
$document = new PhpDocument(
|
||||||
|
$testCaseFile,
|
||||||
|
$fileContents,
|
||||||
|
$index,
|
||||||
|
$parser,
|
||||||
|
$docBlockFactory,
|
||||||
|
$definitionResolver
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "------------------------------\n";
|
echo "------------------------------\n";
|
||||||
|
|
||||||
echo "Time [$framework]: " . (microtime(true) - $start) . PHP_EOL;
|
echo "Time [$framework]: " . (microtime(true) - $start) . PHP_EOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,10 @@ $options = getopt('', ['tcp::', 'tcp-server::', 'memory-limit::']);
|
||||||
|
|
||||||
ini_set('memory_limit', $options['memory-limit'] ?? '4G');
|
ini_set('memory_limit', $options['memory-limit'] ?? '4G');
|
||||||
|
|
||||||
foreach ([__DIR__ . '/../../../autoload.php', __DIR__ . '/../autoload.php', __DIR__ . '/../vendor/autoload.php'] as $file) {
|
foreach (
|
||||||
|
[__DIR__ . '/../../../autoload.php', __DIR__ . '/../autoload.php', __DIR__ . '/../vendor/autoload.php']
|
||||||
|
as $file
|
||||||
|
) {
|
||||||
if (file_exists($file)) {
|
if (file_exists($file)) {
|
||||||
require $file;
|
require $file;
|
||||||
break;
|
break;
|
||||||
|
@ -48,10 +51,7 @@ if (!empty($options['tcp'])) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
stream_set_blocking($socket, false);
|
stream_set_blocking($socket, false);
|
||||||
$ls = new LanguageServer(
|
$ls = new LanguageServer(new ProtocolStreamReader($socket), new ProtocolStreamWriter($socket));
|
||||||
new ProtocolStreamReader($socket),
|
|
||||||
new ProtocolStreamWriter($socket)
|
|
||||||
);
|
|
||||||
Loop\run();
|
Loop\run();
|
||||||
} elseif (!empty($options['tcp-server'])) {
|
} elseif (!empty($options['tcp-server'])) {
|
||||||
// Run a TCP Server
|
// Run a TCP Server
|
||||||
|
@ -66,7 +66,7 @@ if (!empty($options['tcp'])) {
|
||||||
if (!$pcntlAvailable) {
|
if (!$pcntlAvailable) {
|
||||||
$logger->notice('PCNTL is not available. Only a single connection will be accepted');
|
$logger->notice('PCNTL is not available. Only a single connection will be accepted');
|
||||||
}
|
}
|
||||||
while ($socket = stream_socket_accept($tcpServer, -1)) {
|
while (($socket = stream_socket_accept($tcpServer, -1))) {
|
||||||
$logger->debug('Connection accepted');
|
$logger->debug('Connection accepted');
|
||||||
stream_set_blocking($socket, false);
|
stream_set_blocking($socket, false);
|
||||||
if ($pcntlAvailable) {
|
if ($pcntlAvailable) {
|
||||||
|
@ -91,10 +91,7 @@ if (!empty($options['tcp'])) {
|
||||||
} else {
|
} else {
|
||||||
// If PCNTL is not available, we only accept one connection.
|
// If PCNTL is not available, we only accept one connection.
|
||||||
// An exit notification will terminate the server
|
// An exit notification will terminate the server
|
||||||
$ls = new LanguageServer(
|
$ls = new LanguageServer(new ProtocolStreamReader($socket), new ProtocolStreamWriter($socket));
|
||||||
new ProtocolStreamReader($socket),
|
|
||||||
new ProtocolStreamWriter($socket)
|
|
||||||
);
|
|
||||||
Loop\run();
|
Loop\run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,9 +99,6 @@ if (!empty($options['tcp'])) {
|
||||||
// Use STDIO
|
// Use STDIO
|
||||||
$logger->debug('Listening on STDIN');
|
$logger->debug('Listening on STDIN');
|
||||||
stream_set_blocking(STDIN, false);
|
stream_set_blocking(STDIN, false);
|
||||||
$ls = new LanguageServer(
|
$ls = new LanguageServer(new ProtocolStreamReader(STDIN), new ProtocolStreamWriter(STDOUT));
|
||||||
new ProtocolStreamReader(STDIN),
|
|
||||||
new ProtocolStreamWriter(STDOUT)
|
|
||||||
);
|
|
||||||
Loop\run();
|
Loop\run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
status:
|
status:
|
||||||
project:
|
project:
|
||||||
|
@ -8,7 +7,7 @@ coverage:
|
||||||
base: auto
|
base: auto
|
||||||
|
|
||||||
comment:
|
comment:
|
||||||
layout: "header, diff, tree, changes"
|
layout: 'header, diff, tree, changes'
|
||||||
behavior: default
|
behavior: default
|
||||||
require_changes: false # if true: only post the comment if coverage changes
|
require_changes: false # if true: only post the comment if coverage changes
|
||||||
branches: null
|
branches: null
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
collectors:
|
collectors:
|
||||||
|
|
||||||
# pull requests for new major versions
|
# pull requests for new major versions
|
||||||
- type: php-composer
|
- type: php-composer
|
||||||
path: /
|
path: /
|
||||||
actors:
|
actors:
|
||||||
- type: php-composer
|
- type: php-composer
|
||||||
versions: "Y.0.0"
|
versions: 'Y.0.0'
|
||||||
settings:
|
settings:
|
||||||
commit_message_prefix: "chore: "
|
commit_message_prefix: 'chore: '
|
||||||
- type: js-npm
|
- type: js-npm
|
||||||
path: /
|
path: /
|
||||||
actors:
|
actors:
|
||||||
- type: js-npm
|
- type: js-npm
|
||||||
versions: "Y.0.0"
|
versions: 'Y.0.0'
|
||||||
settings:
|
settings:
|
||||||
commit_message_prefix: "chore: "
|
commit_message_prefix: 'chore: '
|
||||||
|
|
|
@ -32,7 +32,10 @@ class ClientCache implements Cache
|
||||||
*/
|
*/
|
||||||
public function get(string $key): Promise
|
public function get(string $key): Promise
|
||||||
{
|
{
|
||||||
return $this->client->xcache->get($key)->then('unserialize')->otherwise(function () {
|
return $this->client->xcache
|
||||||
|
->get($key)
|
||||||
|
->then('unserialize')
|
||||||
|
->otherwise(function () {
|
||||||
// Ignore
|
// Ignore
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,11 +53,12 @@ class TextDocument
|
||||||
*/
|
*/
|
||||||
public function xcontent(TextDocumentIdentifier $textDocument): Promise
|
public function xcontent(TextDocumentIdentifier $textDocument): Promise
|
||||||
{
|
{
|
||||||
return $this->handler->request(
|
return $this->handler
|
||||||
'textDocument/xcontent',
|
->request('textDocument/xcontent', [
|
||||||
['textDocument' => $textDocument]
|
'textDocument' => $textDocument
|
||||||
)->then(function ($result) {
|
])
|
||||||
return $this->mapper->map($result, new TextDocumentItem);
|
->then(function ($result) {
|
||||||
|
return $this->mapper->map($result, new TextDocumentItem());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,10 @@ class Window
|
||||||
*/
|
*/
|
||||||
public function showMessage(int $type, string $message): Promise
|
public function showMessage(int $type, string $message): Promise
|
||||||
{
|
{
|
||||||
return $this->handler->notify('window/showMessage', ['type' => $type, 'message' => $message]);
|
return $this->handler->notify('window/showMessage', [
|
||||||
|
'type' => $type,
|
||||||
|
'message' => $message
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,6 +46,9 @@ class Window
|
||||||
*/
|
*/
|
||||||
public function logMessage(int $type, string $message): Promise
|
public function logMessage(int $type, string $message): Promise
|
||||||
{
|
{
|
||||||
return $this->handler->notify('window/logMessage', ['type' => $type, 'message' => $message]);
|
return $this->handler->notify('window/logMessage', [
|
||||||
|
'type' => $type,
|
||||||
|
'message' => $message
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,10 +37,7 @@ class Workspace
|
||||||
*/
|
*/
|
||||||
public function xfiles(string $base = null): Promise
|
public function xfiles(string $base = null): Promise
|
||||||
{
|
{
|
||||||
return $this->handler->request(
|
return $this->handler->request('workspace/xfiles', ['base' => $base])->then(function (array $textDocuments) {
|
||||||
'workspace/xfiles',
|
|
||||||
['base' => $base]
|
|
||||||
)->then(function (array $textDocuments) {
|
|
||||||
return $this->mapper->mapArray($textDocuments, [], TextDocumentIdentifier::class);
|
return $this->mapper->mapArray($textDocuments, [], TextDocumentIdentifier::class);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,9 @@ class XCache
|
||||||
*/
|
*/
|
||||||
public function set(string $key, $value): Promise
|
public function set(string $key, $value): Promise
|
||||||
{
|
{
|
||||||
return $this->handler->notify('xcache/set', ['key' => $key, 'value' => $value]);
|
return $this->handler->notify('xcache/set', [
|
||||||
|
'key' => $key,
|
||||||
|
'value' => $value
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ class ClientHandler
|
||||||
{
|
{
|
||||||
$this->protocolReader = $protocolReader;
|
$this->protocolReader = $protocolReader;
|
||||||
$this->protocolWriter = $protocolWriter;
|
$this->protocolWriter = $protocolWriter;
|
||||||
$this->idGenerator = new IdGenerator;
|
$this->idGenerator = new IdGenerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,12 +40,10 @@ class ClientHandler
|
||||||
public function request(string $method, $params): Promise
|
public function request(string $method, $params): Promise
|
||||||
{
|
{
|
||||||
$id = $this->idGenerator->generate();
|
$id = $this->idGenerator->generate();
|
||||||
return $this->protocolWriter->write(
|
return $this->protocolWriter
|
||||||
new Message(
|
->write(new Message(new AdvancedJsonRpc\Request($id, $method, (object) $params)))
|
||||||
new AdvancedJsonRpc\Request($id, $method, (object)$params)
|
->then(function () use ($id) {
|
||||||
)
|
$promise = new Promise();
|
||||||
)->then(function () use ($id) {
|
|
||||||
$promise = new Promise;
|
|
||||||
$listener = function (Message $msg) use ($id, $promise, &$listener) {
|
$listener = function (Message $msg) use ($id, $promise, &$listener) {
|
||||||
if (AdvancedJsonRpc\Response::isResponse($msg->body) && $msg->body->id === $id) {
|
if (AdvancedJsonRpc\Response::isResponse($msg->body) && $msg->body->id === $id) {
|
||||||
// Received a response
|
// Received a response
|
||||||
|
@ -71,10 +69,6 @@ class ClientHandler
|
||||||
*/
|
*/
|
||||||
public function notify(string $method, $params): Promise
|
public function notify(string $method, $params): Promise
|
||||||
{
|
{
|
||||||
return $this->protocolWriter->write(
|
return $this->protocolWriter->write(new Message(new AdvancedJsonRpc\Notification($method, (object) $params)));
|
||||||
new Message(
|
|
||||||
new AdvancedJsonRpc\Notification($method, (object)$params)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,7 @@ class CompletionProvider
|
||||||
'from', // As in yield from
|
'from', // As in yield from
|
||||||
'strict_types',
|
'strict_types',
|
||||||
'ticks', // As in declare(ticks=1)
|
'ticks', // As in declare(ticks=1)
|
||||||
'encoding', // As in declare(encoding='EBCDIC')
|
'encoding' // As in declare(encoding='EBCDIC')
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,18 +163,19 @@ class CompletionProvider
|
||||||
// Get the node at the position under the cursor
|
// Get the node at the position under the cursor
|
||||||
$offset = $node === null ? -1 : $pos->toOffset($node->getFileContents());
|
$offset = $node === null ? -1 : $pos->toOffset($node->getFileContents());
|
||||||
if (
|
if (
|
||||||
$node !== null
|
$node !== null &&
|
||||||
&& $offset > $node->getEndPosition()
|
$offset > $node->getEndPosition() &&
|
||||||
&& $node->parent !== null
|
$node->parent !== null &&
|
||||||
&& $node->parent->getLastChild() instanceof PhpParser\MissingToken
|
$node->parent->getLastChild() instanceof PhpParser\MissingToken
|
||||||
) {
|
) {
|
||||||
$node = $node->parent;
|
$node = $node->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
$list = new CompletionList;
|
$list = new CompletionList();
|
||||||
$list->isIncomplete = true;
|
$list->isIncomplete = true;
|
||||||
|
|
||||||
if ($node instanceof Node\Expression\Variable &&
|
if (
|
||||||
|
$node instanceof Node\Expression\Variable &&
|
||||||
$node->parent instanceof Node\Expression\ObjectCreationExpression &&
|
$node->parent instanceof Node\Expression\ObjectCreationExpression &&
|
||||||
$node->name instanceof PhpParser\MissingToken
|
$node->name instanceof PhpParser\MissingToken
|
||||||
) {
|
) {
|
||||||
|
@ -186,19 +187,13 @@ class CompletionProvider
|
||||||
$content = $doc->getContent();
|
$content = $doc->getContent();
|
||||||
$offset = $pos->toOffset($content);
|
$offset = $pos->toOffset($content);
|
||||||
if (
|
if (
|
||||||
$node === null
|
|
||||||
|| (
|
|
||||||
$node instanceof Node\Statement\InlineHtml
|
|
||||||
&& (
|
|
||||||
$context !== null
|
|
||||||
// Make sure to not suggest on the > trigger character in HTML
|
// Make sure to not suggest on the > trigger character in HTML
|
||||||
&& (
|
$node === null ||
|
||||||
$context->triggerKind === CompletionTriggerKind::INVOKED
|
($node instanceof Node\Statement\InlineHtml &&
|
||||||
|| $context->triggerCharacter === '<'
|
($context !== null &&
|
||||||
)
|
($context->triggerKind === CompletionTriggerKind::INVOKED ||
|
||||||
)
|
$context->triggerCharacter === '<'))) ||
|
||||||
)
|
$pos == new Position(0, 0)
|
||||||
|| $pos == new Position(0, 0)
|
|
||||||
) {
|
) {
|
||||||
// HTML, beginning of file
|
// HTML, beginning of file
|
||||||
|
|
||||||
|
@ -209,12 +204,11 @@ class CompletionProvider
|
||||||
stripStringOverlap($doc->getRange(new Range(new Position(0, 0), $pos)), '<?php')
|
stripStringOverlap($doc->getRange(new Range(new Position(0, 0), $pos)), '<?php')
|
||||||
);
|
);
|
||||||
$list->items[] = $item;
|
$list->items[] = $item;
|
||||||
|
|
||||||
} elseif (
|
} elseif (
|
||||||
$node instanceof Node\Expression\Variable
|
$node instanceof Node\Expression\Variable &&
|
||||||
&& !(
|
!(
|
||||||
$node->parent instanceof Node\Expression\ScopedPropertyAccessExpression
|
$node->parent instanceof Node\Expression\ScopedPropertyAccessExpression &&
|
||||||
&& $node->parent->memberName === $node
|
$node->parent->memberName === $node
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
// Variables
|
// Variables
|
||||||
|
@ -225,7 +219,7 @@ class CompletionProvider
|
||||||
// Find variables, parameters and use statements in the scope
|
// Find variables, parameters and use statements in the scope
|
||||||
$namePrefix = $node->getName() ?? '';
|
$namePrefix = $node->getName() ?? '';
|
||||||
foreach ($this->suggestVariablesAtNode($node, $namePrefix) as $var) {
|
foreach ($this->suggestVariablesAtNode($node, $namePrefix) as $var) {
|
||||||
$item = new CompletionItem;
|
$item = new CompletionItem();
|
||||||
$item->kind = CompletionItemKind::VARIABLE;
|
$item->kind = CompletionItemKind::VARIABLE;
|
||||||
$item->label = '$' . $var->getName();
|
$item->label = '$' . $var->getName();
|
||||||
$item->documentation = $this->definitionResolver->getDocumentationFromNode($var);
|
$item->documentation = $this->definitionResolver->getDocumentationFromNode($var);
|
||||||
|
@ -236,7 +230,6 @@ class CompletionProvider
|
||||||
);
|
);
|
||||||
$list->items[] = $item;
|
$list->items[] = $item;
|
||||||
}
|
}
|
||||||
|
|
||||||
} elseif ($node instanceof Node\Expression\MemberAccessExpression) {
|
} elseif ($node instanceof Node\Expression\MemberAccessExpression) {
|
||||||
// Member access expressions
|
// Member access expressions
|
||||||
//
|
//
|
||||||
|
@ -260,7 +253,6 @@ class CompletionProvider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} elseif (
|
} elseif (
|
||||||
($scoped = $node->parent) instanceof Node\Expression\ScopedPropertyAccessExpression ||
|
($scoped = $node->parent) instanceof Node\Expression\ScopedPropertyAccessExpression ||
|
||||||
($scoped = $node) instanceof Node\Expression\ScopedPropertyAccessExpression
|
($scoped = $node) instanceof Node\Expression\ScopedPropertyAccessExpression
|
||||||
|
@ -276,7 +268,7 @@ class CompletionProvider
|
||||||
|
|
||||||
// Resolve all possible types to FQNs
|
// Resolve all possible types to FQNs
|
||||||
$fqns = FqnUtilities\getFqnsFromType(
|
$fqns = FqnUtilities\getFqnsFromType(
|
||||||
$classType = $this->definitionResolver->resolveExpressionNodeToType($scoped->scopeResolutionQualifier)
|
($classType = $this->definitionResolver->resolveExpressionNodeToType($scoped->scopeResolutionQualifier))
|
||||||
);
|
);
|
||||||
|
|
||||||
// The FQNs of the symbol and its parents (eg the implemented interfaces)
|
// The FQNs of the symbol and its parents (eg the implemented interfaces)
|
||||||
|
@ -291,12 +283,11 @@ class CompletionProvider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} elseif (
|
} elseif (
|
||||||
ParserHelpers\isConstantFetch($node)
|
|
||||||
// Creation gets set in case of an instantiation (`new` expression)
|
// Creation gets set in case of an instantiation (`new` expression)
|
||||||
|| ($creation = $node->parent) instanceof Node\Expression\ObjectCreationExpression
|
ParserHelpers\isConstantFetch($node) ||
|
||||||
|| (($creation = $node) instanceof Node\Expression\ObjectCreationExpression)
|
($creation = $node->parent) instanceof Node\Expression\ObjectCreationExpression ||
|
||||||
|
($creation = $node) instanceof Node\Expression\ObjectCreationExpression
|
||||||
) {
|
) {
|
||||||
// Class instantiations, function calls, constant fetches, class names
|
// Class instantiations, function calls, constant fetches, class names
|
||||||
//
|
//
|
||||||
|
@ -311,7 +302,10 @@ class CompletionProvider
|
||||||
|
|
||||||
if ($nameNode instanceof Node\QualifiedName) {
|
if ($nameNode instanceof Node\QualifiedName) {
|
||||||
/** @var string The typed name. */
|
/** @var string The typed name. */
|
||||||
$prefix = (string)PhpParser\ResolvedName::buildName($nameNode->nameParts, $nameNode->getFileContents());
|
$prefix = (string) PhpParser\ResolvedName::buildName(
|
||||||
|
$nameNode->nameParts,
|
||||||
|
$nameNode->getFileContents()
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
$prefix = $nameNode->getText($node->getFileContents());
|
$prefix = $nameNode->getText($node->getFileContents());
|
||||||
}
|
}
|
||||||
|
@ -361,7 +355,6 @@ class CompletionProvider
|
||||||
$item->insertText = substr($item->insertText, 0, -2);
|
$item->insertText = substr($item->insertText, 0, -2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return $list;
|
return $list;
|
||||||
}
|
}
|
||||||
|
@ -422,11 +415,7 @@ class CompletionProvider
|
||||||
// Aliases
|
// Aliases
|
||||||
list($namespaceAliases, ,) = $importTables;
|
list($namespaceAliases, ,) = $importTables;
|
||||||
// use Foo\Bar
|
// use Foo\Bar
|
||||||
yield from $this->getCompletionsForAliases(
|
yield from $this->getCompletionsForAliases($prefix, $namespaceAliases, $requireCanBeInstantiated);
|
||||||
$prefix,
|
|
||||||
$namespaceAliases,
|
|
||||||
$requireCanBeInstantiated
|
|
||||||
);
|
|
||||||
|
|
||||||
// Completions from the current namespace
|
// Completions from the current namespace
|
||||||
yield from $this->getCompletionsForFqnPrefix(
|
yield from $this->getCompletionsForFqnPrefix(
|
||||||
|
@ -527,11 +516,7 @@ class CompletionProvider
|
||||||
$prefixFirstPart = nameGetFirstPart($prefix);
|
$prefixFirstPart = nameGetFirstPart($prefix);
|
||||||
// Matched alias.
|
// Matched alias.
|
||||||
$resolvedPrefix = nameConcat($aliasFqn, nameWithoutFirstPart($prefix));
|
$resolvedPrefix = nameConcat($aliasFqn, nameWithoutFirstPart($prefix));
|
||||||
$completionItems = $this->getCompletionsForFqnPrefix(
|
$completionItems = $this->getCompletionsForFqnPrefix($resolvedPrefix, $requireCanBeInstantiated, false);
|
||||||
$resolvedPrefix,
|
|
||||||
$requireCanBeInstantiated,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
// Convert FQNs in the CompletionItems so they are expressed in terms of the alias.
|
// Convert FQNs in the CompletionItems so they are expressed in terms of the alias.
|
||||||
foreach ($completionItems as $fqn => $completionItem) {
|
foreach ($completionItems as $fqn => $completionItem) {
|
||||||
/** @var string $fqn with the leading parts determined by the alias removed. Has the leading backslash. */
|
/** @var string $fqn with the leading parts determined by the alias removed. Has the leading backslash. */
|
||||||
|
@ -625,7 +610,7 @@ class CompletionProvider
|
||||||
while ($level && !($level instanceof PhpParser\FunctionLike)) {
|
while ($level && !($level instanceof PhpParser\FunctionLike)) {
|
||||||
// Walk siblings before the node
|
// Walk siblings before the node
|
||||||
$sibling = $level;
|
$sibling = $level;
|
||||||
while ($sibling = $sibling->getPreviousSibling()) {
|
while (($sibling = $sibling->getPreviousSibling())) {
|
||||||
// Collect all variables inside the sibling node
|
// Collect all variables inside the sibling node
|
||||||
foreach ($this->findVariableDefinitionsInNode($sibling, $namePrefix) as $var) {
|
foreach ($this->findVariableDefinitionsInNode($sibling, $namePrefix) as $var) {
|
||||||
$vars[$var->getName()] = $var;
|
$vars[$var->getName()] = $var;
|
||||||
|
@ -644,9 +629,11 @@ class CompletionProvider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($level instanceof Node\Expression\AnonymousFunctionCreationExpression
|
if (
|
||||||
&& $level->anonymousFunctionUseClause !== null
|
$level instanceof Node\Expression\AnonymousFunctionCreationExpression &&
|
||||||
&& $level->anonymousFunctionUseClause->useVariableNameList !== null) {
|
$level->anonymousFunctionUseClause !== null &&
|
||||||
|
$level->anonymousFunctionUseClause->useVariableNameList !== null
|
||||||
|
) {
|
||||||
foreach ($level->anonymousFunctionUseClause->useVariableNameList->getValues() as $use) {
|
foreach ($level->anonymousFunctionUseClause->useVariableNameList->getValues() as $use) {
|
||||||
$useName = $use->getName();
|
$useName = $use->getName();
|
||||||
if (empty($namePrefix) || strpos($useName, $namePrefix) !== false) {
|
if (empty($namePrefix) || strpos($useName, $namePrefix) !== false) {
|
||||||
|
@ -679,8 +666,9 @@ class CompletionProvider
|
||||||
$vars[] = $node->leftOperand;
|
$vars[] = $node->leftOperand;
|
||||||
} elseif ($node instanceof Node\ForeachKey || $node instanceof Node\ForeachValue) {
|
} elseif ($node instanceof Node\ForeachKey || $node instanceof Node\ForeachValue) {
|
||||||
foreach ($node->getDescendantNodes() as $descendantNode) {
|
foreach ($node->getDescendantNodes() as $descendantNode) {
|
||||||
if ($descendantNode instanceof Node\Expression\Variable
|
if (
|
||||||
&& ($namePrefix === '' || strpos($descendantNode->getName(), $namePrefix) !== false)
|
$descendantNode instanceof Node\Expression\Variable &&
|
||||||
|
($namePrefix === '' || strpos($descendantNode->getName(), $namePrefix) !== false)
|
||||||
) {
|
) {
|
||||||
$vars[] = $descendantNode;
|
$vars[] = $descendantNode;
|
||||||
}
|
}
|
||||||
|
@ -700,8 +688,8 @@ class CompletionProvider
|
||||||
|
|
||||||
private function isAssignmentToVariableWithPrefix(Node $node, string $namePrefix): bool
|
private function isAssignmentToVariableWithPrefix(Node $node, string $namePrefix): bool
|
||||||
{
|
{
|
||||||
return $node instanceof Node\Expression\AssignmentExpression
|
return $node instanceof Node\Expression\AssignmentExpression &&
|
||||||
&& $node->leftOperand instanceof Node\Expression\Variable
|
$node->leftOperand instanceof Node\Expression\Variable &&
|
||||||
&& ($namePrefix === '' || strpos($node->leftOperand->getName(), $namePrefix) !== false);
|
($namePrefix === '' || strpos($node->leftOperand->getName(), $namePrefix) !== false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,10 @@ use Sabre\Uri;
|
||||||
use function Sabre\Event\coroutine;
|
use function Sabre\Event\coroutine;
|
||||||
use Microsoft\PhpParser;
|
use Microsoft\PhpParser;
|
||||||
|
|
||||||
foreach ([__DIR__ . '/../../../autoload.php', __DIR__ . '/../autoload.php', __DIR__ . '/../vendor/autoload.php'] as $file) {
|
foreach (
|
||||||
|
[__DIR__ . '/../../../autoload.php', __DIR__ . '/../autoload.php', __DIR__ . '/../vendor/autoload.php']
|
||||||
|
as $file
|
||||||
|
) {
|
||||||
if (file_exists($file)) {
|
if (file_exists($file)) {
|
||||||
require $file;
|
require $file;
|
||||||
break;
|
break;
|
||||||
|
@ -23,18 +26,22 @@ class ComposerScripts
|
||||||
{
|
{
|
||||||
public static function parseStubs()
|
public static function parseStubs()
|
||||||
{
|
{
|
||||||
|
// Change URI to phpstubs://
|
||||||
|
// Create a new document and add it to $index
|
||||||
coroutine(function () {
|
coroutine(function () {
|
||||||
|
$index = new StubsIndex();
|
||||||
|
|
||||||
$index = new StubsIndex;
|
$finder = new FileSystemFilesFinder();
|
||||||
|
$contentRetriever = new FileSystemContentRetriever();
|
||||||
$finder = new FileSystemFilesFinder;
|
|
||||||
$contentRetriever = new FileSystemContentRetriever;
|
|
||||||
$docBlockFactory = DocBlockFactory::createInstance();
|
$docBlockFactory = DocBlockFactory::createInstance();
|
||||||
$parser = new PhpParser\Parser();
|
$parser = new PhpParser\Parser();
|
||||||
$definitionResolver = new DefinitionResolver($index);
|
$definitionResolver = new DefinitionResolver($index);
|
||||||
|
|
||||||
$stubsLocation = null;
|
$stubsLocation = null;
|
||||||
foreach ([__DIR__ . '/../../../jetbrains/phpstorm-stubs', __DIR__ . '/../vendor/jetbrains/phpstorm-stubs'] as $dir) {
|
foreach (
|
||||||
|
[__DIR__ . '/../../../jetbrains/phpstorm-stubs', __DIR__ . '/../vendor/jetbrains/phpstorm-stubs']
|
||||||
|
as $dir
|
||||||
|
) {
|
||||||
if (file_exists($dir)) {
|
if (file_exists($dir)) {
|
||||||
$stubsLocation = Path::canonicalize($dir);
|
$stubsLocation = Path::canonicalize($dir);
|
||||||
break;
|
break;
|
||||||
|
@ -44,19 +51,17 @@ class ComposerScripts
|
||||||
throw new \Exception('jetbrains/phpstorm-stubs package not found');
|
throw new \Exception('jetbrains/phpstorm-stubs package not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
$uris = yield $finder->find("$stubsLocation/**/*.php");
|
$uris = (yield $finder->find("$stubsLocation/**/*.php"));
|
||||||
|
|
||||||
foreach ($uris as $uri) {
|
foreach ($uris as $uri) {
|
||||||
echo "Parsing $uri\n";
|
echo "Parsing $uri\n";
|
||||||
$content = yield $contentRetriever->retrieve($uri);
|
$content = (yield $contentRetriever->retrieve($uri));
|
||||||
|
|
||||||
// Change URI to phpstubs://
|
|
||||||
$parts = Uri\parse($uri);
|
$parts = Uri\parse($uri);
|
||||||
$parts['path'] = Path::makeRelative($parts['path'], $stubsLocation);
|
$parts['path'] = Path::makeRelative($parts['path'], $stubsLocation);
|
||||||
$parts['scheme'] = 'phpstubs';
|
$parts['scheme'] = 'phpstubs';
|
||||||
$uri = Uri\build($parts);
|
$uri = Uri\build($parts);
|
||||||
|
|
||||||
// Create a new document and add it to $index
|
|
||||||
new PhpDocument($uri, $content, $index, $parser, $docBlockFactory, $definitionResolver);
|
new PhpDocument($uri, $content, $index, $parser, $docBlockFactory, $definitionResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,8 @@ class ClientContentRetriever implements ContentRetriever
|
||||||
*/
|
*/
|
||||||
public function retrieve(string $uri): Promise
|
public function retrieve(string $uri): Promise
|
||||||
{
|
{
|
||||||
return $this->client->textDocument->xcontent(new TextDocumentIdentifier($uri))
|
return $this->client->textDocument
|
||||||
|
->xcontent(new TextDocumentIdentifier($uri))
|
||||||
->then(function (TextDocumentItem $textDocument) {
|
->then(function (TextDocumentItem $textDocument) {
|
||||||
return $textDocument->text;
|
return $textDocument->text;
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,9 +9,7 @@ use LanguageServerProtocol\SymbolInformation;
|
||||||
use Microsoft\PhpParser;
|
use Microsoft\PhpParser;
|
||||||
use Microsoft\PhpParser\Node;
|
use Microsoft\PhpParser\Node;
|
||||||
use Microsoft\PhpParser\FunctionLike;
|
use Microsoft\PhpParser\FunctionLike;
|
||||||
use phpDocumentor\Reflection\{
|
use phpDocumentor\Reflection\{DocBlock, DocBlockFactory, Fqsen, Type, TypeResolver, Types};
|
||||||
DocBlock, DocBlockFactory, Fqsen, Type, TypeResolver, Types
|
|
||||||
};
|
|
||||||
|
|
||||||
class DefinitionResolver
|
class DefinitionResolver
|
||||||
{
|
{
|
||||||
|
@ -49,7 +47,7 @@ class DefinitionResolver
|
||||||
public function __construct(ReadableIndex $index)
|
public function __construct(ReadableIndex $index)
|
||||||
{
|
{
|
||||||
$this->index = $index;
|
$this->index = $index;
|
||||||
$this->typeResolver = new TypeResolver;
|
$this->typeResolver = new TypeResolver();
|
||||||
$this->docBlockFactory = DocBlockFactory::createInstance();
|
$this->docBlockFactory = DocBlockFactory::createInstance();
|
||||||
$this->signatureInformationFactory = new SignatureInformationFactory($this);
|
$this->signatureInformationFactory = new SignatureInformationFactory($this);
|
||||||
}
|
}
|
||||||
|
@ -66,8 +64,10 @@ class DefinitionResolver
|
||||||
// - [PropertyDeclaration] // public $a, [$b = 3], $c; => public $b = 3;
|
// - [PropertyDeclaration] // public $a, [$b = 3], $c; => public $b = 3;
|
||||||
// - [ConstDeclaration|ClassConstDeclaration] // "const A = 3, [B = 4];" => "const B = 4;"
|
// - [ConstDeclaration|ClassConstDeclaration] // "const A = 3, [B = 4];" => "const B = 4;"
|
||||||
if (
|
if (
|
||||||
($declaration = ParserHelpers\tryGetPropertyDeclaration($node)) && ($elements = $declaration->propertyElements) ||
|
(($declaration = ParserHelpers\tryGetPropertyDeclaration($node)) &&
|
||||||
($declaration = ParserHelpers\tryGetConstOrClassConstDeclaration($node)) && ($elements = $declaration->constElements)
|
($elements = $declaration->propertyElements)) ||
|
||||||
|
(($declaration = ParserHelpers\tryGetConstOrClassConstDeclaration($node)) &&
|
||||||
|
($elements = $declaration->constElements))
|
||||||
) {
|
) {
|
||||||
$defLine = $declaration->getText();
|
$defLine = $declaration->getText();
|
||||||
$defLineStart = $declaration->getStart();
|
$defLineStart = $declaration->getStart();
|
||||||
|
@ -105,7 +105,8 @@ class DefinitionResolver
|
||||||
|
|
||||||
// For properties and constants, set the node to the declaration node, rather than the individual property.
|
// For properties and constants, set the node to the declaration node, rather than the individual property.
|
||||||
// This is because they get defined as part of a list.
|
// This is because they get defined as part of a list.
|
||||||
$constOrPropertyDeclaration = ParserHelpers\tryGetPropertyDeclaration($node) ?? ParserHelpers\tryGetConstOrClassConstDeclaration($node);
|
$constOrPropertyDeclaration =
|
||||||
|
ParserHelpers\tryGetPropertyDeclaration($node) ?? ParserHelpers\tryGetConstOrClassConstDeclaration($node);
|
||||||
if ($constOrPropertyDeclaration !== null) {
|
if ($constOrPropertyDeclaration !== null) {
|
||||||
$node = $constOrPropertyDeclaration;
|
$node = $constOrPropertyDeclaration;
|
||||||
}
|
}
|
||||||
|
@ -180,53 +181,50 @@ class DefinitionResolver
|
||||||
*/
|
*/
|
||||||
public function createDefinitionFromNode(Node $node, string $fqn = null): Definition
|
public function createDefinitionFromNode(Node $node, string $fqn = null): Definition
|
||||||
{
|
{
|
||||||
$def = new Definition;
|
$def = new Definition();
|
||||||
$def->fqn = $fqn;
|
$def->fqn = $fqn;
|
||||||
|
|
||||||
// Determines whether the suggestion will show after "new"
|
// Determines whether the suggestion will show after "new"
|
||||||
$def->canBeInstantiated = (
|
$def->canBeInstantiated =
|
||||||
$node instanceof Node\Statement\ClassDeclaration &&
|
$node instanceof
|
||||||
|
Node\Statement\ClassDeclaration &&
|
||||||
// check whether it is not an abstract class
|
// check whether it is not an abstract class
|
||||||
($node->abstractOrFinalModifier === null || $node->abstractOrFinalModifier->kind !== PhpParser\TokenKind::AbstractKeyword)
|
($node->abstractOrFinalModifier === null ||
|
||||||
);
|
$node->abstractOrFinalModifier->kind !== PhpParser\TokenKind::AbstractKeyword);
|
||||||
|
|
||||||
// Interfaces, classes, traits, namespaces, functions, and global const elements
|
// Interfaces, classes, traits, namespaces, functions, and global const elements
|
||||||
$def->isMember = !(
|
$def->isMember = !(
|
||||||
$node instanceof PhpParser\ClassLike ||
|
$node instanceof PhpParser\ClassLike ||
|
||||||
|
|
||||||
($node instanceof Node\Statement\NamespaceDefinition && $node->name !== null) ||
|
($node instanceof Node\Statement\NamespaceDefinition && $node->name !== null) ||
|
||||||
|
|
||||||
$node instanceof Node\Statement\FunctionDeclaration ||
|
$node instanceof Node\Statement\FunctionDeclaration ||
|
||||||
|
|
||||||
($node instanceof Node\ConstElement && $node->parent->parent instanceof Node\Statement\ConstDeclaration)
|
($node instanceof Node\ConstElement && $node->parent->parent instanceof Node\Statement\ConstDeclaration)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Definition is affected by global namespace fallback if it is a global constant or a global function
|
// Definition is affected by global namespace fallback if it is a global constant or a global function
|
||||||
$def->roamed = (
|
$def->roamed =
|
||||||
$fqn !== null
|
$fqn !== null &&
|
||||||
&& strpos($fqn, '\\') === false
|
strpos($fqn, '\\') === false &&
|
||||||
&& (
|
(($node instanceof Node\ConstElement && $node->parent->parent instanceof Node\Statement\ConstDeclaration) ||
|
||||||
($node instanceof Node\ConstElement && $node->parent->parent instanceof Node\Statement\ConstDeclaration)
|
$node instanceof Node\Statement\FunctionDeclaration);
|
||||||
|| $node instanceof Node\Statement\FunctionDeclaration
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Static methods and static property declarations
|
// Static methods and static property declarations
|
||||||
$def->isStatic = (
|
$def->isStatic =
|
||||||
($node instanceof Node\MethodDeclaration && $node->isStatic()) ||
|
($node instanceof Node\MethodDeclaration && $node->isStatic()) ||
|
||||||
|
(($propertyDeclaration = ParserHelpers\tryGetPropertyDeclaration($node)) !== null &&
|
||||||
|
$propertyDeclaration->isStatic());
|
||||||
|
|
||||||
(($propertyDeclaration = ParserHelpers\tryGetPropertyDeclaration($node)) !== null
|
if (
|
||||||
&& $propertyDeclaration->isStatic())
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($node instanceof Node\Statement\ClassDeclaration &&
|
|
||||||
// TODO - this should be better represented in the parser API
|
// TODO - this should be better represented in the parser API
|
||||||
$node->classBaseClause !== null && $node->classBaseClause->baseClass !== null) {
|
$node instanceof Node\Statement\ClassDeclaration &&
|
||||||
|
$node->classBaseClause !== null &&
|
||||||
|
$node->classBaseClause->baseClass !== null
|
||||||
|
) {
|
||||||
$def->extends = [(string) $node->classBaseClause->baseClass->getResolvedName()];
|
$def->extends = [(string) $node->classBaseClause->baseClass->getResolvedName()];
|
||||||
} elseif (
|
} elseif (
|
||||||
$node instanceof Node\Statement\InterfaceDeclaration &&
|
|
||||||
// TODO - this should be better represented in the parser API
|
// TODO - this should be better represented in the parser API
|
||||||
$node->interfaceBaseClause !== null && $node->interfaceBaseClause->interfaceNameList !== null
|
$node instanceof Node\Statement\InterfaceDeclaration &&
|
||||||
|
$node->interfaceBaseClause !== null &&
|
||||||
|
$node->interfaceBaseClause->interfaceNameList !== null
|
||||||
) {
|
) {
|
||||||
$def->extends = [];
|
$def->extends = [];
|
||||||
foreach ($node->interfaceBaseClause->interfaceNameList->getValues() as $n) {
|
foreach ($node->interfaceBaseClause->interfaceNameList->getValues() as $n) {
|
||||||
|
@ -261,10 +259,12 @@ class DefinitionResolver
|
||||||
// Variables are not indexed globally, as they stay in the file scope anyway.
|
// Variables are not indexed globally, as they stay in the file scope anyway.
|
||||||
// Ignore variable nodes that are part of ScopedPropertyAccessExpression,
|
// Ignore variable nodes that are part of ScopedPropertyAccessExpression,
|
||||||
// as the scoped property access expression node is handled separately.
|
// as the scoped property access expression node is handled separately.
|
||||||
if ($node instanceof Node\Expression\Variable &&
|
if (
|
||||||
!($parent instanceof Node\Expression\ScopedPropertyAccessExpression)) {
|
$node instanceof Node\Expression\Variable &&
|
||||||
|
!($parent instanceof Node\Expression\ScopedPropertyAccessExpression)
|
||||||
|
) {
|
||||||
// Resolve $this to the containing class definition.
|
// Resolve $this to the containing class definition.
|
||||||
if ($node->getName() === 'this' && $fqn = $this->getContainingClassFqn($node)) {
|
if ($node->getName() === 'this' && ($fqn = $this->getContainingClassFqn($node))) {
|
||||||
return $this->index->getDefinition($fqn, false);
|
return $this->index->getDefinition($fqn, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,11 +330,11 @@ class DefinitionResolver
|
||||||
} elseif ($node instanceof Node\Expression\MemberAccessExpression) {
|
} elseif ($node instanceof Node\Expression\MemberAccessExpression) {
|
||||||
return $this->resolveMemberAccessExpressionNodeToFqn($node);
|
return $this->resolveMemberAccessExpressionNodeToFqn($node);
|
||||||
} elseif (ParserHelpers\isConstantFetch($node)) {
|
} elseif (ParserHelpers\isConstantFetch($node)) {
|
||||||
return (string)($node->getNamespacedName());
|
return (string) $node->getNamespacedName();
|
||||||
} elseif (
|
} elseif (
|
||||||
// A\B::C - constant access expression
|
// A\B::C - constant access expression
|
||||||
$node instanceof Node\Expression\ScopedPropertyAccessExpression
|
$node instanceof Node\Expression\ScopedPropertyAccessExpression &&
|
||||||
&& !($node->memberName instanceof Node\Expression\Variable)
|
!($node->memberName instanceof Node\Expression\Variable)
|
||||||
) {
|
) {
|
||||||
return $this->resolveScopedPropertyAccessExpressionNodeToFqn($node);
|
return $this->resolveScopedPropertyAccessExpressionNodeToFqn($node);
|
||||||
} elseif (
|
} elseif (
|
||||||
|
@ -355,8 +355,9 @@ class DefinitionResolver
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// Add use clause references
|
// Add use clause references
|
||||||
if (($useClause = $parent) instanceof Node\NamespaceUseGroupClause
|
if (
|
||||||
|| $useClause instanceof Node\NamespaceUseClause
|
($useClause = $parent) instanceof Node\NamespaceUseGroupClause ||
|
||||||
|
$useClause instanceof Node\NamespaceUseClause
|
||||||
) {
|
) {
|
||||||
$contents = $node->getFileContents();
|
$contents = $node->getFileContents();
|
||||||
if ($useClause instanceof Node\NamespaceUseGroupClause) {
|
if ($useClause instanceof Node\NamespaceUseGroupClause) {
|
||||||
|
@ -370,14 +371,21 @@ class DefinitionResolver
|
||||||
|
|
||||||
if ($useClause->functionOrConst === null) {
|
if ($useClause->functionOrConst === null) {
|
||||||
$useClause = $node->getFirstAncestor(Node\Statement\NamespaceUseDeclaration::class);
|
$useClause = $node->getFirstAncestor(Node\Statement\NamespaceUseDeclaration::class);
|
||||||
if ($useClause->functionOrConst !== null && $useClause->functionOrConst->kind === PhpParser\TokenKind::FunctionKeyword) {
|
if (
|
||||||
|
$useClause->functionOrConst !== null &&
|
||||||
|
$useClause->functionOrConst->kind === PhpParser\TokenKind::FunctionKeyword
|
||||||
|
) {
|
||||||
$name .= '()';
|
$name .= '()';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $name;
|
return $name;
|
||||||
} else {
|
} else {
|
||||||
$name = (string) PhpParser\ResolvedName::buildName($node->nameParts, $contents);
|
$name = (string) PhpParser\ResolvedName::buildName($node->nameParts, $contents);
|
||||||
if ($useClause->groupClauses === null && $useClause->parent->parent->functionOrConst !== null && $useClause->parent->parent->functionOrConst->kind === PhpParser\TokenKind::FunctionKeyword) {
|
if (
|
||||||
|
$useClause->groupClauses === null &&
|
||||||
|
$useClause->parent->parent->functionOrConst !== null &&
|
||||||
|
$useClause->parent->parent->functionOrConst->kind === PhpParser\TokenKind::FunctionKeyword
|
||||||
|
) {
|
||||||
$name .= '()';
|
$name .= '()';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -406,23 +414,19 @@ class DefinitionResolver
|
||||||
if ($varType instanceof Types\Compound) {
|
if ($varType instanceof Types\Compound) {
|
||||||
// For compound types, use the first FQN we find
|
// For compound types, use the first FQN we find
|
||||||
// (popular use case is ClassName|null)
|
// (popular use case is ClassName|null)
|
||||||
for ($i = 0; $t = $varType->get($i); $i++) {
|
for ($i = 0; ($t = $varType->get($i)); $i++) {
|
||||||
if (
|
if (
|
||||||
$t instanceof Types\This
|
$t instanceof Types\This ||
|
||||||
|| $t instanceof Types\Object_
|
$t instanceof Types\Object_ ||
|
||||||
|| $t instanceof Types\Static_
|
$t instanceof Types\Static_ ||
|
||||||
|| $t instanceof Types\Self_
|
$t instanceof Types\Self_
|
||||||
) {
|
) {
|
||||||
$varType = $t;
|
$varType = $t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (
|
if ($varType instanceof Types\This || $varType instanceof Types\Static_ || $varType instanceof Types\Self_) {
|
||||||
$varType instanceof Types\This
|
|
||||||
|| $varType instanceof Types\Static_
|
|
||||||
|| $varType instanceof Types\Self_
|
|
||||||
) {
|
|
||||||
// $this/static/self is resolved to the containing class
|
// $this/static/self is resolved to the containing class
|
||||||
$classFqn = self::getContainingClassFqn($access);
|
$classFqn = self::getContainingClassFqn($access);
|
||||||
} elseif (!($varType instanceof Types\Object_) || $varType->getFqsen() === null) {
|
} elseif (!($varType instanceof Types\Object_) || $varType->getFqsen() === null) {
|
||||||
|
@ -431,7 +435,9 @@ class DefinitionResolver
|
||||||
} else {
|
} else {
|
||||||
$classFqn = substr((string) $varType->getFqsen(), 1);
|
$classFqn = substr((string) $varType->getFqsen(), 1);
|
||||||
}
|
}
|
||||||
$memberSuffix = '->' . (string)($access->memberName->getText() ?? $access->memberName->getText($access->getFileContents()));
|
$memberSuffix =
|
||||||
|
'->' .
|
||||||
|
(string) ($access->memberName->getText() ?? $access->memberName->getText($access->getFileContents()));
|
||||||
if ($access->parent instanceof Node\Expression\CallExpression) {
|
if ($access->parent instanceof Node\Expression\CallExpression) {
|
||||||
$memberSuffix .= '()';
|
$memberSuffix .= '()';
|
||||||
}
|
}
|
||||||
|
@ -440,7 +446,7 @@ class DefinitionResolver
|
||||||
$implementorFqns = [$classFqn];
|
$implementorFqns = [$classFqn];
|
||||||
$visitedFqns = [];
|
$visitedFqns = [];
|
||||||
|
|
||||||
while ($implementorFqn = array_shift($implementorFqns)) {
|
while (($implementorFqn = array_shift($implementorFqns))) {
|
||||||
// If the member FQN exists, return it
|
// If the member FQN exists, return it
|
||||||
if ($this->index->getDefinition($implementorFqn . $memberSuffix)) {
|
if ($this->index->getDefinition($implementorFqn . $memberSuffix)) {
|
||||||
return $implementorFqn . $memberSuffix;
|
return $implementorFqn . $memberSuffix;
|
||||||
|
@ -467,8 +473,9 @@ class DefinitionResolver
|
||||||
return $classFqn . $memberSuffix;
|
return $classFqn . $memberSuffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function resolveScopedPropertyAccessExpressionNodeToFqn(Node\Expression\ScopedPropertyAccessExpression $scoped)
|
private function resolveScopedPropertyAccessExpressionNodeToFqn(
|
||||||
{
|
Node\Expression\ScopedPropertyAccessExpression $scoped
|
||||||
|
) {
|
||||||
if ($scoped->scopeResolutionQualifier instanceof Node\Expression\Variable) {
|
if ($scoped->scopeResolutionQualifier instanceof Node\Expression\Variable) {
|
||||||
$varType = $this->getTypeFromNode($scoped->scopeResolutionQualifier);
|
$varType = $this->getTypeFromNode($scoped->scopeResolutionQualifier);
|
||||||
if ($varType === null) {
|
if ($varType === null) {
|
||||||
|
@ -587,9 +594,11 @@ class DefinitionResolver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If it is a closure, also check use statements
|
// If it is a closure, also check use statements
|
||||||
if ($n instanceof Node\Expression\AnonymousFunctionCreationExpression &&
|
if (
|
||||||
|
$n instanceof Node\Expression\AnonymousFunctionCreationExpression &&
|
||||||
$n->anonymousFunctionUseClause !== null &&
|
$n->anonymousFunctionUseClause !== null &&
|
||||||
$n->anonymousFunctionUseClause->useVariableNameList !== null) {
|
$n->anonymousFunctionUseClause->useVariableNameList !== null
|
||||||
|
) {
|
||||||
foreach ($n->anonymousFunctionUseClause->useVariableNameList->getElements() as $use) {
|
foreach ($n->anonymousFunctionUseClause->useVariableNameList->getElements() as $use) {
|
||||||
if ($use->getName() === $name) {
|
if ($use->getName() === $name) {
|
||||||
return $use;
|
return $use;
|
||||||
|
@ -601,8 +610,7 @@ class DefinitionResolver
|
||||||
|
|
||||||
// Check each previous sibling node and their descendents for a variable assignment to that variable
|
// Check each previous sibling node and their descendents for a variable assignment to that variable
|
||||||
// Each previous sibling could contain a declaration of the variable
|
// Each previous sibling could contain a declaration of the variable
|
||||||
while (($prevSibling = $n->getPreviousSibling()) !== null && $n = $prevSibling) {
|
while (($prevSibling = $n->getPreviousSibling()) !== null && ($n = $prevSibling)) {
|
||||||
|
|
||||||
// Check the sibling itself
|
// Check the sibling itself
|
||||||
if (self::isVariableDeclaration($n, $name)) {
|
if (self::isVariableDeclaration($n, $name)) {
|
||||||
return $n;
|
return $n;
|
||||||
|
@ -615,7 +623,7 @@ class DefinitionResolver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (isset($n) && $n = $n->parent);
|
} while (isset($n) && ($n = $n->parent));
|
||||||
// Return null if nothing was found
|
// Return null if nothing was found
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -631,16 +639,18 @@ class DefinitionResolver
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
// TODO - clean this up
|
// TODO - clean this up
|
||||||
($n instanceof Node\Expression\AssignmentExpression && $n->operator->kind === PhpParser\TokenKind::EqualsToken)
|
$n instanceof Node\Expression\AssignmentExpression &&
|
||||||
&& $n->leftOperand instanceof Node\Expression\Variable && $n->leftOperand->getName() === $name
|
$n->operator->kind === PhpParser\TokenKind::EqualsToken &&
|
||||||
|
$n->leftOperand instanceof Node\Expression\Variable &&
|
||||||
|
$n->leftOperand->getName() === $name
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
($n instanceof Node\ForeachValue || $n instanceof Node\ForeachKey)
|
($n instanceof Node\ForeachValue || $n instanceof Node\ForeachKey) &&
|
||||||
&& $n->expression instanceof Node\Expression\Variable
|
$n->expression instanceof Node\Expression\Variable &&
|
||||||
&& $n->expression->getName() === $name
|
$n->expression->getName() === $name
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -666,7 +676,7 @@ class DefinitionResolver
|
||||||
if ($expr == null || $expr instanceof PhpParser\MissingToken || $expr instanceof PhpParser\SkippedToken) {
|
if ($expr == null || $expr instanceof PhpParser\MissingToken || $expr instanceof PhpParser\SkippedToken) {
|
||||||
// TODO some members are null or Missing/SkippedToken
|
// TODO some members are null or Missing/SkippedToken
|
||||||
// How do we handle this more generally?
|
// How do we handle this more generally?
|
||||||
return new Types\Mixed_;
|
return new Types\Mixed_();
|
||||||
}
|
}
|
||||||
|
|
||||||
// VARIABLE
|
// VARIABLE
|
||||||
|
@ -691,15 +701,17 @@ class DefinitionResolver
|
||||||
|
|
||||||
// FUNCTION CALL
|
// FUNCTION CALL
|
||||||
// Function calls are resolved to type corresponding to their FQN
|
// Function calls are resolved to type corresponding to their FQN
|
||||||
if ($expr instanceof Node\Expression\CallExpression &&
|
if (
|
||||||
|
$expr instanceof Node\Expression\CallExpression &&
|
||||||
!(
|
!(
|
||||||
$expr->callableExpression instanceof Node\Expression\ScopedPropertyAccessExpression ||
|
$expr->callableExpression instanceof Node\Expression\ScopedPropertyAccessExpression ||
|
||||||
$expr->callableExpression instanceof Node\Expression\MemberAccessExpression)
|
$expr->callableExpression instanceof Node\Expression\MemberAccessExpression
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
// Find the function definition
|
// Find the function definition
|
||||||
if ($expr->callableExpression instanceof Node\Expression) {
|
if ($expr->callableExpression instanceof Node\Expression) {
|
||||||
// Cannot get type for dynamic function call
|
// Cannot get type for dynamic function call
|
||||||
return new Types\Mixed_;
|
return new Types\Mixed_();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($expr->callableExpression instanceof Node\QualifiedName) {
|
if ($expr->callableExpression instanceof Node\QualifiedName) {
|
||||||
|
@ -717,11 +729,11 @@ class DefinitionResolver
|
||||||
if ($expr instanceof Node\ReservedWord) {
|
if ($expr instanceof Node\ReservedWord) {
|
||||||
$token = $expr->children->kind;
|
$token = $expr->children->kind;
|
||||||
if ($token === PhpParser\TokenKind::TrueReservedWord || $token === PhpParser\TokenKind::FalseReservedWord) {
|
if ($token === PhpParser\TokenKind::TrueReservedWord || $token === PhpParser\TokenKind::FalseReservedWord) {
|
||||||
return new Types\Boolean;
|
return new Types\Boolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($token === PhpParser\TokenKind::NullReservedWord) {
|
if ($token === PhpParser\TokenKind::NullReservedWord) {
|
||||||
return new Types\Null_;
|
return new Types\Null_();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -738,8 +750,9 @@ class DefinitionResolver
|
||||||
// MEMBER CALL EXPRESSION/SCOPED PROPERTY CALL EXPRESSION
|
// MEMBER CALL EXPRESSION/SCOPED PROPERTY CALL EXPRESSION
|
||||||
// The type of the member/scoped property call expression is the type of the method, so resolve the
|
// The type of the member/scoped property call expression is the type of the method, so resolve the
|
||||||
// type of the callable expression.
|
// type of the callable expression.
|
||||||
if ($expr instanceof Node\Expression\CallExpression && (
|
if (
|
||||||
$expr->callableExpression instanceof Node\Expression\MemberAccessExpression ||
|
$expr instanceof Node\Expression\CallExpression &&
|
||||||
|
($expr->callableExpression instanceof Node\Expression\MemberAccessExpression ||
|
||||||
$expr->callableExpression instanceof Node\Expression\ScopedPropertyAccessExpression)
|
$expr->callableExpression instanceof Node\Expression\ScopedPropertyAccessExpression)
|
||||||
) {
|
) {
|
||||||
return $this->resolveExpressionNodeToType($expr->callableExpression);
|
return $this->resolveExpressionNodeToType($expr->callableExpression);
|
||||||
|
@ -748,7 +761,7 @@ class DefinitionResolver
|
||||||
// MEMBER ACCESS EXPRESSION
|
// MEMBER ACCESS EXPRESSION
|
||||||
if ($expr instanceof Node\Expression\MemberAccessExpression) {
|
if ($expr instanceof Node\Expression\MemberAccessExpression) {
|
||||||
if ($expr->memberName instanceof Node\Expression) {
|
if ($expr->memberName instanceof Node\Expression) {
|
||||||
return new Types\Mixed_;
|
return new Types\Mixed_();
|
||||||
}
|
}
|
||||||
$var = $expr->dereferencableExpression;
|
$var = $expr->dereferencableExpression;
|
||||||
|
|
||||||
|
@ -757,14 +770,14 @@ class DefinitionResolver
|
||||||
if (!($objType instanceof Types\Compound)) {
|
if (!($objType instanceof Types\Compound)) {
|
||||||
$objType = new Types\Compound([$objType]);
|
$objType = new Types\Compound([$objType]);
|
||||||
}
|
}
|
||||||
for ($i = 0; $t = $objType->get($i); $i++) {
|
for ($i = 0; ($t = $objType->get($i)); $i++) {
|
||||||
if ($t instanceof Types\This) {
|
if ($t instanceof Types\This) {
|
||||||
$classFqn = self::getContainingClassFqn($expr);
|
$classFqn = self::getContainingClassFqn($expr);
|
||||||
if ($classFqn === null) {
|
if ($classFqn === null) {
|
||||||
return new Types\Mixed_;
|
return new Types\Mixed_();
|
||||||
}
|
}
|
||||||
} elseif (!($t instanceof Types\Object_) || $t->getFqsen() === null) {
|
} elseif (!($t instanceof Types\Object_) || $t->getFqsen() === null) {
|
||||||
return new Types\Mixed_;
|
return new Types\Mixed_();
|
||||||
} else {
|
} else {
|
||||||
$classFqn = substr((string) $t->getFqsen(), 1);
|
$classFqn = substr((string) $t->getFqsen(), 1);
|
||||||
}
|
}
|
||||||
|
@ -791,7 +804,7 @@ class DefinitionResolver
|
||||||
if ($expr instanceof Node\Expression\ScopedPropertyAccessExpression) {
|
if ($expr instanceof Node\Expression\ScopedPropertyAccessExpression) {
|
||||||
$classType = $this->resolveClassNameToType($expr->scopeResolutionQualifier);
|
$classType = $this->resolveClassNameToType($expr->scopeResolutionQualifier);
|
||||||
if (!($classType instanceof Types\Object_) || $classType->getFqsen() === null) {
|
if (!($classType instanceof Types\Object_) || $classType->getFqsen() === null) {
|
||||||
return new Types\Mixed_;
|
return new Types\Mixed_();
|
||||||
}
|
}
|
||||||
$fqn = substr((string) $classType->getFqsen(), 1) . '::';
|
$fqn = substr((string) $classType->getFqsen(), 1) . '::';
|
||||||
|
|
||||||
|
@ -803,7 +816,7 @@ class DefinitionResolver
|
||||||
|
|
||||||
$def = $this->index->getDefinition($fqn);
|
$def = $this->index->getDefinition($fqn);
|
||||||
if ($def === null) {
|
if ($def === null) {
|
||||||
return new Types\Mixed_;
|
return new Types\Mixed_();
|
||||||
}
|
}
|
||||||
return $def->type;
|
return $def->type;
|
||||||
}
|
}
|
||||||
|
@ -847,7 +860,10 @@ class DefinitionResolver
|
||||||
|
|
||||||
// NULL COALLESCE
|
// NULL COALLESCE
|
||||||
// $rightOperand ?? $leftOperand => resolves to type of $rightOperand or $leftOperand
|
// $rightOperand ?? $leftOperand => resolves to type of $rightOperand or $leftOperand
|
||||||
if ($expr instanceof Node\Expression\BinaryExpression && $expr->operator->kind === PhpParser\TokenKind::QuestionQuestionToken) {
|
if (
|
||||||
|
$expr instanceof Node\Expression\BinaryExpression &&
|
||||||
|
$expr->operator->kind === PhpParser\TokenKind::QuestionQuestionToken
|
||||||
|
) {
|
||||||
// ?? operator
|
// ?? operator
|
||||||
return new Types\Compound([
|
return new Types\Compound([
|
||||||
$this->resolveExpressionNodeToType($expr->leftOperand),
|
$this->resolveExpressionNodeToType($expr->leftOperand),
|
||||||
|
@ -862,14 +878,15 @@ class DefinitionResolver
|
||||||
// isset($var)
|
// isset($var)
|
||||||
// >, >=, <, <=, &&, ||, AND, OR, XOR, ==, ===, !=, !==
|
// >, >=, <, <=, &&, ||, AND, OR, XOR, ==, ===, !=, !==
|
||||||
if (
|
if (
|
||||||
ParserHelpers\isBooleanExpression($expr)
|
ParserHelpers\isBooleanExpression($expr) ||
|
||||||
|
($expr instanceof Node\Expression\CastExpression &&
|
||||||
|| ($expr instanceof Node\Expression\CastExpression && $expr->castType->kind === PhpParser\TokenKind::BoolCastToken)
|
$expr->castType->kind === PhpParser\TokenKind::BoolCastToken) ||
|
||||||
|| ($expr instanceof Node\Expression\UnaryOpExpression && $expr->operator->kind === PhpParser\TokenKind::ExclamationToken)
|
($expr instanceof Node\Expression\UnaryOpExpression &&
|
||||||
|| $expr instanceof Node\Expression\EmptyIntrinsicExpression
|
$expr->operator->kind === PhpParser\TokenKind::ExclamationToken) ||
|
||||||
|| $expr instanceof Node\Expression\IssetIntrinsicExpression
|
$expr instanceof Node\Expression\EmptyIntrinsicExpression ||
|
||||||
|
$expr instanceof Node\Expression\IssetIntrinsicExpression
|
||||||
) {
|
) {
|
||||||
return new Types\Boolean;
|
return new Types\Boolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
// STRING EXPRESSIONS: resolve to Types\String
|
// STRING EXPRESSIONS: resolve to Types\String
|
||||||
|
@ -880,11 +897,13 @@ class DefinitionResolver
|
||||||
// TODO: Magic constants (__CLASS__, __DIR__, __FUNCTION__, __METHOD__, __NAMESPACE__, __TRAIT__, __FILE__)
|
// TODO: Magic constants (__CLASS__, __DIR__, __FUNCTION__, __METHOD__, __NAMESPACE__, __TRAIT__, __FILE__)
|
||||||
if (
|
if (
|
||||||
($expr instanceof Node\Expression\BinaryExpression &&
|
($expr instanceof Node\Expression\BinaryExpression &&
|
||||||
($expr->operator->kind === PhpParser\TokenKind::DotToken || $expr->operator->kind === PhpParser\TokenKind::DotEqualsToken)) ||
|
($expr->operator->kind === PhpParser\TokenKind::DotToken ||
|
||||||
|
$expr->operator->kind === PhpParser\TokenKind::DotEqualsToken)) ||
|
||||||
$expr instanceof Node\StringLiteral ||
|
$expr instanceof Node\StringLiteral ||
|
||||||
($expr instanceof Node\Expression\CastExpression && $expr->castType->kind === PhpParser\TokenKind::StringCastToken)
|
($expr instanceof Node\Expression\CastExpression &&
|
||||||
|
$expr->castType->kind === PhpParser\TokenKind::StringCastToken)
|
||||||
) {
|
) {
|
||||||
return new Types\String_;
|
return new Types\String_();
|
||||||
}
|
}
|
||||||
|
|
||||||
// BINARY EXPRESSIONS:
|
// BINARY EXPRESSIONS:
|
||||||
|
@ -894,32 +913,30 @@ class DefinitionResolver
|
||||||
// Resolve to Types\Float
|
// Resolve to Types\Float
|
||||||
// [assignment] /=
|
// [assignment] /=
|
||||||
if (
|
if (
|
||||||
|
// Assignment expressions (TODO: consider making this a type of AssignmentExpression rather than kind of BinaryExpression)
|
||||||
$expr instanceof Node\Expression\BinaryExpression &&
|
$expr instanceof Node\Expression\BinaryExpression &&
|
||||||
($operator = $expr->operator->kind)
|
($operator = $expr->operator->kind) &&
|
||||||
&& ($operator === PhpParser\TokenKind::PlusToken ||
|
($operator === PhpParser\TokenKind::PlusToken ||
|
||||||
$operator === PhpParser\TokenKind::AsteriskAsteriskToken ||
|
$operator === PhpParser\TokenKind::AsteriskAsteriskToken ||
|
||||||
$operator === PhpParser\TokenKind::AsteriskToken ||
|
$operator === PhpParser\TokenKind::AsteriskToken ||
|
||||||
$operator === PhpParser\TokenKind::MinusToken ||
|
$operator === PhpParser\TokenKind::MinusToken ||
|
||||||
|
|
||||||
// Assignment expressions (TODO: consider making this a type of AssignmentExpression rather than kind of BinaryExpression)
|
|
||||||
$operator === PhpParser\TokenKind::AsteriskEqualsToken ||
|
$operator === PhpParser\TokenKind::AsteriskEqualsToken ||
|
||||||
$operator === PhpParser\TokenKind::AsteriskAsteriskEqualsToken ||
|
$operator === PhpParser\TokenKind::AsteriskAsteriskEqualsToken ||
|
||||||
$operator === PhpParser\TokenKind::MinusEqualsToken ||
|
$operator === PhpParser\TokenKind::MinusEqualsToken ||
|
||||||
$operator === PhpParser\TokenKind::PlusEqualsToken
|
$operator === PhpParser\TokenKind::PlusEqualsToken)
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
$this->resolveExpressionNodeToType($expr->leftOperand) instanceof Types\Integer
|
$this->resolveExpressionNodeToType($expr->leftOperand) instanceof Types\Integer &&
|
||||||
&& $this->resolveExpressionNodeToType($expr->rightOperand) instanceof Types\Integer
|
$this->resolveExpressionNodeToType($expr->rightOperand) instanceof Types\Integer
|
||||||
) {
|
) {
|
||||||
return new Types\Integer;
|
return new Types\Integer();
|
||||||
}
|
}
|
||||||
return new Types\Float_;
|
return new Types\Float_();
|
||||||
} elseif (
|
} elseif (
|
||||||
$expr instanceof Node\Expression\BinaryExpression &&
|
$expr instanceof Node\Expression\BinaryExpression &&
|
||||||
$expr->operator->kind === PhpParser\TokenKind::SlashEqualsToken
|
$expr->operator->kind === PhpParser\TokenKind::SlashEqualsToken
|
||||||
) {
|
) {
|
||||||
return new Types\Float_;
|
return new Types\Float_();
|
||||||
}
|
}
|
||||||
|
|
||||||
// INTEGER EXPRESSIONS: resolve to Types\Integer
|
// INTEGER EXPRESSIONS: resolve to Types\Integer
|
||||||
|
@ -928,16 +945,16 @@ class DefinitionResolver
|
||||||
// TODO: Magic constants (__LINE__)
|
// TODO: Magic constants (__LINE__)
|
||||||
if (
|
if (
|
||||||
// TODO: consider different Node types of float/int, also better property name (not "children")
|
// TODO: consider different Node types of float/int, also better property name (not "children")
|
||||||
($expr instanceof Node\NumericLiteral && $expr->children->kind === PhpParser\TokenKind::IntegerLiteralToken) ||
|
($expr instanceof Node\NumericLiteral &&
|
||||||
$expr instanceof Node\Expression\BinaryExpression && (
|
$expr->children->kind === PhpParser\TokenKind::IntegerLiteralToken) ||
|
||||||
($operator = $expr->operator->kind)
|
($expr instanceof Node\Expression\BinaryExpression &&
|
||||||
&& ($operator === PhpParser\TokenKind::LessThanEqualsGreaterThanToken ||
|
(($operator = $expr->operator->kind) &&
|
||||||
|
($operator === PhpParser\TokenKind::LessThanEqualsGreaterThanToken ||
|
||||||
$operator === PhpParser\TokenKind::AmpersandToken ||
|
$operator === PhpParser\TokenKind::AmpersandToken ||
|
||||||
$operator === PhpParser\TokenKind::CaretToken ||
|
$operator === PhpParser\TokenKind::CaretToken ||
|
||||||
$operator === PhpParser\TokenKind::BarToken)
|
$operator === PhpParser\TokenKind::BarToken)))
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
return new Types\Integer;
|
return new Types\Integer();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FLOAT EXPRESSIONS: resolve to Types\Float
|
// FLOAT EXPRESSIONS: resolve to Types\Float
|
||||||
|
@ -945,11 +962,14 @@ class DefinitionResolver
|
||||||
// [operator] /
|
// [operator] /
|
||||||
// [cast] (double)
|
// [cast] (double)
|
||||||
if (
|
if (
|
||||||
$expr instanceof Node\NumericLiteral && $expr->children->kind === PhpParser\TokenKind::FloatingLiteralToken ||
|
($expr instanceof Node\NumericLiteral &&
|
||||||
($expr instanceof Node\Expression\CastExpression && $expr->castType->kind === PhpParser\TokenKind::DoubleCastToken) ||
|
$expr->children->kind === PhpParser\TokenKind::FloatingLiteralToken) ||
|
||||||
($expr instanceof Node\Expression\BinaryExpression && $expr->operator->kind === PhpParser\TokenKind::SlashToken)
|
($expr instanceof Node\Expression\CastExpression &&
|
||||||
|
$expr->castType->kind === PhpParser\TokenKind::DoubleCastToken) ||
|
||||||
|
($expr instanceof Node\Expression\BinaryExpression &&
|
||||||
|
$expr->operator->kind === PhpParser\TokenKind::SlashToken)
|
||||||
) {
|
) {
|
||||||
return new Types\Float_;
|
return new Types\Float_();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ARRAY CREATION EXPRESSION:
|
// ARRAY CREATION EXPRESSION:
|
||||||
|
@ -962,7 +982,9 @@ class DefinitionResolver
|
||||||
if ($expr->arrayElements !== null) {
|
if ($expr->arrayElements !== null) {
|
||||||
foreach ($expr->arrayElements->getElements() as $item) {
|
foreach ($expr->arrayElements->getElements() as $item) {
|
||||||
$valueTypes[] = $this->resolveExpressionNodeToType($item->elementValue);
|
$valueTypes[] = $this->resolveExpressionNodeToType($item->elementValue);
|
||||||
$keyTypes[] = $item->elementKey ? $this->resolveExpressionNodeToType($item->elementKey) : new Types\Integer;
|
$keyTypes[] = $item->elementKey
|
||||||
|
? $this->resolveExpressionNodeToType($item->elementKey)
|
||||||
|
: new Types\Integer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$valueTypes = array_unique($valueTypes);
|
$valueTypes = array_unique($valueTypes);
|
||||||
|
@ -990,7 +1012,7 @@ class DefinitionResolver
|
||||||
if ($expr instanceof Node\Expression\SubscriptExpression) {
|
if ($expr instanceof Node\Expression\SubscriptExpression) {
|
||||||
$varType = $this->resolveExpressionNodeToType($expr->postfixExpression);
|
$varType = $this->resolveExpressionNodeToType($expr->postfixExpression);
|
||||||
if (!($varType instanceof Types\Array_)) {
|
if (!($varType instanceof Types\Array_)) {
|
||||||
return new Types\Mixed_;
|
return new Types\Mixed_();
|
||||||
}
|
}
|
||||||
return $varType->getValueType();
|
return $varType->getValueType();
|
||||||
}
|
}
|
||||||
|
@ -999,17 +1021,16 @@ class DefinitionResolver
|
||||||
// include, require, include_once, require_once
|
// include, require, include_once, require_once
|
||||||
if ($expr instanceof Node\Expression\ScriptInclusionExpression) {
|
if ($expr instanceof Node\Expression\ScriptInclusionExpression) {
|
||||||
// TODO: resolve path to PhpDocument and find return statement
|
// TODO: resolve path to PhpDocument and find return statement
|
||||||
return new Types\Mixed_;
|
return new Types\Mixed_();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($expr instanceof Node\QualifiedName) {
|
if ($expr instanceof Node\QualifiedName) {
|
||||||
return $this->resolveClassNameToType($expr);
|
return $this->resolveClassNameToType($expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Types\Mixed_;
|
return new Types\Mixed_();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes any class name node (from a static method call, or new node) and returns a Type object
|
* Takes any class name node (from a static method call, or new node) and returns a Type object
|
||||||
* Resolves keywords like self, static and parent
|
* Resolves keywords like self, static and parent
|
||||||
|
@ -1020,15 +1041,15 @@ class DefinitionResolver
|
||||||
public function resolveClassNameToType($class): Type
|
public function resolveClassNameToType($class): Type
|
||||||
{
|
{
|
||||||
if ($class instanceof Node\Expression) {
|
if ($class instanceof Node\Expression) {
|
||||||
return new Types\Mixed_;
|
return new Types\Mixed_();
|
||||||
}
|
}
|
||||||
if ($class instanceof PhpParser\Token && $class->kind === PhpParser\TokenKind::ClassKeyword) {
|
if ($class instanceof PhpParser\Token && $class->kind === PhpParser\TokenKind::ClassKeyword) {
|
||||||
// Anonymous class
|
// Anonymous class
|
||||||
return new Types\Object_;
|
return new Types\Object_();
|
||||||
}
|
}
|
||||||
if ($class instanceof PhpParser\Token && $class->kind === PhpParser\TokenKind::StaticKeyword) {
|
if ($class instanceof PhpParser\Token && $class->kind === PhpParser\TokenKind::StaticKeyword) {
|
||||||
// `new static`
|
// `new static`
|
||||||
return new Types\Static_;
|
return new Types\Static_();
|
||||||
}
|
}
|
||||||
$className = (string) $class->getResolvedName();
|
$className = (string) $class->getResolvedName();
|
||||||
|
|
||||||
|
@ -1036,13 +1057,13 @@ class DefinitionResolver
|
||||||
$classNode = $class->getFirstAncestor(Node\Statement\ClassDeclaration::class);
|
$classNode = $class->getFirstAncestor(Node\Statement\ClassDeclaration::class);
|
||||||
if ($className === 'parent') {
|
if ($className === 'parent') {
|
||||||
if ($classNode === null || $classNode->classBaseClause === null) {
|
if ($classNode === null || $classNode->classBaseClause === null) {
|
||||||
return new Types\Object_;
|
return new Types\Object_();
|
||||||
}
|
}
|
||||||
// parent is resolved to the parent class
|
// parent is resolved to the parent class
|
||||||
$classFqn = (string) $classNode->classBaseClause->baseClass->getResolvedName();
|
$classFqn = (string) $classNode->classBaseClause->baseClass->getResolvedName();
|
||||||
} else {
|
} else {
|
||||||
if ($classNode === null) {
|
if ($classNode === null) {
|
||||||
return new Types\Self_;
|
return new Types\Self_();
|
||||||
}
|
}
|
||||||
// self is resolved to the containing class
|
// self is resolved to the containing class
|
||||||
$classFqn = (string) $classNode->getNamespacedName();
|
$classFqn = (string) $classNode->getNamespacedName();
|
||||||
|
@ -1114,7 +1135,7 @@ class DefinitionResolver
|
||||||
}
|
}
|
||||||
$type = $defaultType;
|
$type = $defaultType;
|
||||||
}
|
}
|
||||||
return $type ?? new Types\Mixed_;
|
return $type ?? new Types\Mixed_();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTIONS AND METHODS
|
// FUNCTIONS AND METHODS
|
||||||
|
@ -1126,9 +1147,9 @@ class DefinitionResolver
|
||||||
// Functions/methods
|
// Functions/methods
|
||||||
$docBlock = $this->getDocBlock($node);
|
$docBlock = $this->getDocBlock($node);
|
||||||
if (
|
if (
|
||||||
$docBlock !== null
|
$docBlock !== null &&
|
||||||
&& !empty($returnTags = $docBlock->getTagsByName('return'))
|
!empty(($returnTags = $docBlock->getTagsByName('return'))) &&
|
||||||
&& $returnTags[0]->getType() !== null
|
$returnTags[0]->getType() !== null
|
||||||
) {
|
) {
|
||||||
// Use @return tag
|
// Use @return tag
|
||||||
$returnType = $returnTags[0]->getType();
|
$returnType = $returnTags[0]->getType();
|
||||||
|
@ -1154,7 +1175,7 @@ class DefinitionResolver
|
||||||
return new Types\Object_(new Fqsen('\\' . (string) $node->returnType->getResolvedName()));
|
return new Types\Object_(new Fqsen('\\' . (string) $node->returnType->getResolvedName()));
|
||||||
}
|
}
|
||||||
// Unknown return type
|
// Unknown return type
|
||||||
return new Types\Mixed_;
|
return new Types\Mixed_();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FOREACH KEY/VARIABLE
|
// FOREACH KEY/VARIABLE
|
||||||
|
@ -1168,8 +1189,9 @@ class DefinitionResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
// FOREACH VALUE/VARIABLE
|
// FOREACH VALUE/VARIABLE
|
||||||
if ($node instanceof Node\ForeachValue
|
if (
|
||||||
|| ($node instanceof Node\Expression\Variable && $node->parent instanceof Node\ForeachValue)
|
$node instanceof Node\ForeachValue ||
|
||||||
|
($node instanceof Node\Expression\Variable && $node->parent instanceof Node\ForeachValue)
|
||||||
) {
|
) {
|
||||||
$foreach = $node->getFirstAncestor(Node\Statement\ForeachStatement::class);
|
$foreach = $node->getFirstAncestor(Node\Statement\ForeachStatement::class);
|
||||||
$collectionType = $this->resolveExpressionNodeToType($foreach->forEachCollectionName);
|
$collectionType = $this->resolveExpressionNodeToType($foreach->forEachCollectionName);
|
||||||
|
@ -1184,17 +1206,17 @@ class DefinitionResolver
|
||||||
if (
|
if (
|
||||||
($declarationNode =
|
($declarationNode =
|
||||||
ParserHelpers\tryGetPropertyDeclaration($node) ??
|
ParserHelpers\tryGetPropertyDeclaration($node) ??
|
||||||
ParserHelpers\tryGetConstOrClassConstDeclaration($node)
|
ParserHelpers\tryGetConstOrClassConstDeclaration($node)) !== null ||
|
||||||
) !== null ||
|
($node = $node->parent) instanceof Node\Expression\AssignmentExpression
|
||||||
($node = $node->parent) instanceof Node\Expression\AssignmentExpression) {
|
) {
|
||||||
$declarationNode = $declarationNode ?? $node;
|
$declarationNode = $declarationNode ?? $node;
|
||||||
|
|
||||||
// Property, constant or variable
|
// Property, constant or variable
|
||||||
// Use @var tag
|
// Use @var tag
|
||||||
if (
|
if (
|
||||||
($docBlock = $this->getDocBlock($declarationNode))
|
($docBlock = $this->getDocBlock($declarationNode)) &&
|
||||||
&& !empty($varTags = $docBlock->getTagsByName('var'))
|
!empty(($varTags = $docBlock->getTagsByName('var'))) &&
|
||||||
&& ($type = $varTags[0]->getType())
|
($type = $varTags[0]->getType())
|
||||||
) {
|
) {
|
||||||
return $type;
|
return $type;
|
||||||
}
|
}
|
||||||
|
@ -1213,7 +1235,7 @@ class DefinitionResolver
|
||||||
// TODO: read @property tags of class
|
// TODO: read @property tags of class
|
||||||
// TODO: Try to infer the type from default value / constant value
|
// TODO: Try to infer the type from default value / constant value
|
||||||
// Unknown
|
// Unknown
|
||||||
return new Types\Mixed_;
|
return new Types\Mixed_();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The node does not have a type
|
// The node does not have a type
|
||||||
|
@ -1236,9 +1258,7 @@ class DefinitionResolver
|
||||||
// class C { } A\B\C
|
// class C { } A\B\C
|
||||||
// interface C { } A\B\C
|
// interface C { } A\B\C
|
||||||
// trait C { } A\B\C
|
// trait C { } A\B\C
|
||||||
if (
|
if ($node instanceof PhpParser\ClassLike) {
|
||||||
$node instanceof PhpParser\ClassLike
|
|
||||||
) {
|
|
||||||
$className = (string) $node->getNamespacedName();
|
$className = (string) $node->getNamespacedName();
|
||||||
// An (invalid) class declaration without a name will have an empty string as name,
|
// An (invalid) class declaration without a name will have an empty string as name,
|
||||||
// but should not define an FQN
|
// but should not define an FQN
|
||||||
|
@ -1295,12 +1315,12 @@ class DefinitionResolver
|
||||||
// }
|
// }
|
||||||
if (
|
if (
|
||||||
($propertyDeclaration = ParserHelpers\tryGetPropertyDeclaration($node)) !== null &&
|
($propertyDeclaration = ParserHelpers\tryGetPropertyDeclaration($node)) !== null &&
|
||||||
($classDeclaration =
|
($classDeclaration = $node->getFirstAncestor(
|
||||||
$node->getFirstAncestor(
|
|
||||||
Node\Expression\ObjectCreationExpression::class,
|
Node\Expression\ObjectCreationExpression::class,
|
||||||
PhpParser\ClassLike::class
|
PhpParser\ClassLike::class
|
||||||
)
|
)) !== null &&
|
||||||
) !== null && isset($classDeclaration->name)) {
|
isset($classDeclaration->name)
|
||||||
|
) {
|
||||||
$name = $node->getName();
|
$name = $node->getName();
|
||||||
if ($propertyDeclaration->isStatic()) {
|
if ($propertyDeclaration->isStatic()) {
|
||||||
// Static Property: use ClassName::$propertyName as name
|
// Static Property: use ClassName::$propertyName as name
|
||||||
|
|
|
@ -17,7 +17,7 @@ class CompletionItemFactory
|
||||||
*/
|
*/
|
||||||
public static function fromDefinition(Definition $def)
|
public static function fromDefinition(Definition $def)
|
||||||
{
|
{
|
||||||
$item = new CompletionItem;
|
$item = new CompletionItem();
|
||||||
$item->label = $def->symbolInformation->name;
|
$item->label = $def->symbolInformation->name;
|
||||||
$item->kind = CompletionItemKind::fromSymbolKind($def->symbolInformation->kind);
|
$item->kind = CompletionItemKind::fromSymbolKind($def->symbolInformation->kind);
|
||||||
if ($def->type) {
|
if ($def->type) {
|
||||||
|
|
|
@ -24,9 +24,12 @@ class LocationFactory
|
||||||
$node->getFileContents()
|
$node->getFileContents()
|
||||||
);
|
);
|
||||||
|
|
||||||
return new Location($node->getUri(), new Range(
|
return new Location(
|
||||||
|
$node->getUri(),
|
||||||
|
new Range(
|
||||||
new Position($range->start->line, $range->start->character),
|
new Position($range->start->line, $range->start->character),
|
||||||
new Position($range->end->line, $range->end->character)
|
new Position($range->end->line, $range->end->character)
|
||||||
));
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,17 +43,18 @@ class SymbolInformationFactory
|
||||||
} else {
|
} else {
|
||||||
$symbol->kind = SymbolKind::METHOD;
|
$symbol->kind = SymbolKind::METHOD;
|
||||||
}
|
}
|
||||||
} else if ($node instanceof Node\Expression\Variable && $node->getFirstAncestor(Node\PropertyDeclaration::class) !== null) {
|
} elseif (
|
||||||
|
$node instanceof Node\Expression\Variable &&
|
||||||
|
$node->getFirstAncestor(Node\PropertyDeclaration::class) !== null
|
||||||
|
) {
|
||||||
$symbol->kind = SymbolKind::PROPERTY;
|
$symbol->kind = SymbolKind::PROPERTY;
|
||||||
} elseif ($node instanceof Node\ConstElement) {
|
} elseif ($node instanceof Node\ConstElement) {
|
||||||
$symbol->kind = SymbolKind::CONSTANT;
|
$symbol->kind = SymbolKind::CONSTANT;
|
||||||
} elseif (
|
} elseif (
|
||||||
(
|
($node instanceof Node\Expression\AssignmentExpression &&
|
||||||
($node instanceof Node\Expression\AssignmentExpression)
|
$node->leftOperand instanceof Node\Expression\Variable) ||
|
||||||
&& $node->leftOperand instanceof Node\Expression\Variable
|
$node instanceof Node\UseVariableName ||
|
||||||
)
|
$node instanceof Node\Parameter
|
||||||
|| $node instanceof Node\UseVariableName
|
|
||||||
|| $node instanceof Node\Parameter
|
|
||||||
) {
|
) {
|
||||||
$symbol->kind = SymbolKind::VARIABLE;
|
$symbol->kind = SymbolKind::VARIABLE;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -20,7 +20,7 @@ function getFqnsFromType($type): array
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($type instanceof Types\Compound) {
|
if ($type instanceof Types\Compound) {
|
||||||
for ($i = 0; $t = $type->get($i); $i++) {
|
for ($i = 0; ($t = $type->get($i)); $i++) {
|
||||||
foreach (getFqnsFromType($t) as $fqn) {
|
foreach (getFqnsFromType($t) as $fqn) {
|
||||||
$fqns[] = $fqn;
|
$fqns[] = $fqn;
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,8 @@ function getFqnsFromType($type): array
|
||||||
*/
|
*/
|
||||||
function nameGetParent(string $name): string
|
function nameGetParent(string $name): string
|
||||||
{
|
{
|
||||||
if ($name === '') { // Special-case handling for the root namespace.
|
if ($name === '') {
|
||||||
|
// Special-case handling for the root namespace.
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
$parts = explode('\\', $name);
|
$parts = explode('\\', $name);
|
||||||
|
@ -113,6 +114,5 @@ function nameWithoutFirstPart(string $name): string
|
||||||
*/
|
*/
|
||||||
function nameStartsWith(string $name, string $prefix): bool
|
function nameStartsWith(string $name, string $prefix): bool
|
||||||
{
|
{
|
||||||
return strlen($name) >= strlen($prefix)
|
return strlen($name) >= strlen($prefix) && strncmp($name, $prefix, strlen($prefix)) === 0;
|
||||||
&& strncmp($name, $prefix, strlen($prefix)) === 0;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,7 @@ abstract class AbstractAggregateIndex implements ReadableIndex
|
||||||
public function getDefinition(string $fqn, bool $globalFallback = false)
|
public function getDefinition(string $fqn, bool $globalFallback = false)
|
||||||
{
|
{
|
||||||
foreach ($this->getIndexes() as $index) {
|
foreach ($this->getIndexes() as $index) {
|
||||||
if ($def = $index->getDefinition($fqn, $globalFallback)) {
|
if (($def = $index->getDefinition($fqn, $globalFallback))) {
|
||||||
return $def;
|
return $def;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ class DependenciesIndex extends AbstractAggregateIndex
|
||||||
public function getDependencyIndex(string $packageName): Index
|
public function getDependencyIndex(string $packageName): Index
|
||||||
{
|
{
|
||||||
if (!isset($this->indexes[$packageName])) {
|
if (!isset($this->indexes[$packageName])) {
|
||||||
$index = new Index;
|
$index = new Index();
|
||||||
$this->indexes[$packageName] = $index;
|
$this->indexes[$packageName] = $index;
|
||||||
$this->registerIndex($index);
|
$this->registerIndex($index);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,11 @@ class ProjectIndex extends AbstractAggregateIndex
|
||||||
*/
|
*/
|
||||||
private $sourceIndex;
|
private $sourceIndex;
|
||||||
|
|
||||||
public function __construct(Index $sourceIndex, DependenciesIndex $dependenciesIndex, \stdClass $composerJson = null)
|
public function __construct(
|
||||||
{
|
Index $sourceIndex,
|
||||||
|
DependenciesIndex $dependenciesIndex,
|
||||||
|
\stdClass $composerJson = null
|
||||||
|
) {
|
||||||
$this->sourceIndex = $sourceIndex;
|
$this->sourceIndex = $sourceIndex;
|
||||||
$this->dependenciesIndex = $dependenciesIndex;
|
$this->dependenciesIndex = $dependenciesIndex;
|
||||||
$this->composerJson = $composerJson;
|
$this->composerJson = $composerJson;
|
||||||
|
|
|
@ -103,9 +103,8 @@ class Indexer
|
||||||
public function index(): Promise
|
public function index(): Promise
|
||||||
{
|
{
|
||||||
return coroutine(function () {
|
return coroutine(function () {
|
||||||
|
|
||||||
$pattern = Path::makeAbsolute('**/*.php', $this->rootPath);
|
$pattern = Path::makeAbsolute('**/*.php', $this->rootPath);
|
||||||
$uris = yield $this->filesFinder->find($pattern);
|
$uris = (yield $this->filesFinder->find($pattern));
|
||||||
|
|
||||||
$count = count($uris);
|
$count = count($uris);
|
||||||
$startTime = microtime(true);
|
$startTime = microtime(true);
|
||||||
|
@ -132,7 +131,10 @@ class Indexer
|
||||||
|
|
||||||
// Index source
|
// Index source
|
||||||
// Definitions and static references
|
// Definitions and static references
|
||||||
$this->client->window->logMessage(MessageType::INFO, 'Indexing project for definitions and static references');
|
$this->client->window->logMessage(
|
||||||
|
MessageType::INFO,
|
||||||
|
'Indexing project for definitions and static references'
|
||||||
|
);
|
||||||
yield $this->indexFiles($source);
|
yield $this->indexFiles($source);
|
||||||
$this->sourceIndex->setStaticComplete();
|
$this->sourceIndex->setStaticComplete();
|
||||||
// Dynamic references
|
// Dynamic references
|
||||||
|
@ -147,7 +149,10 @@ class Indexer
|
||||||
$packageKey = null;
|
$packageKey = null;
|
||||||
$cacheKey = null;
|
$cacheKey = null;
|
||||||
$index = null;
|
$index = null;
|
||||||
foreach (array_merge($this->composerLock->packages, (array)$this->composerLock->{'packages-dev'}) as $package) {
|
foreach (
|
||||||
|
array_merge($this->composerLock->packages, (array) $this->composerLock->{'packages-dev'})
|
||||||
|
as $package
|
||||||
|
) {
|
||||||
// Check if package name matches and version is absolute
|
// Check if package name matches and version is absolute
|
||||||
// Dynamic constraints are not cached, because they can change every time
|
// Dynamic constraints are not cached, because they can change every time
|
||||||
$packageVersion = ltrim($package->version, 'v');
|
$packageVersion = ltrim($package->version, 'v');
|
||||||
|
@ -155,7 +160,7 @@ class Indexer
|
||||||
$packageKey = $packageName . ':' . $packageVersion;
|
$packageKey = $packageName . ':' . $packageVersion;
|
||||||
$cacheKey = self::CACHE_VERSION . ':' . $packageKey;
|
$cacheKey = self::CACHE_VERSION . ':' . $packageKey;
|
||||||
// Check cache
|
// Check cache
|
||||||
$index = yield $this->cache->get($cacheKey);
|
$index = (yield $this->cache->get($cacheKey));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,12 +173,18 @@ class Indexer
|
||||||
$index = $this->dependenciesIndex->getDependencyIndex($packageName);
|
$index = $this->dependenciesIndex->getDependencyIndex($packageName);
|
||||||
|
|
||||||
// Index definitions and static references
|
// Index definitions and static references
|
||||||
$this->client->window->logMessage(MessageType::INFO, 'Indexing ' . ($packageKey ?? $packageName) . ' for definitions and static references');
|
$this->client->window->logMessage(
|
||||||
|
MessageType::INFO,
|
||||||
|
'Indexing ' . ($packageKey ?? $packageName) . ' for definitions and static references'
|
||||||
|
);
|
||||||
yield $this->indexFiles($files);
|
yield $this->indexFiles($files);
|
||||||
$index->setStaticComplete();
|
$index->setStaticComplete();
|
||||||
|
|
||||||
// Index dynamic references
|
// Index dynamic references
|
||||||
$this->client->window->logMessage(MessageType::INFO, 'Indexing ' . ($packageKey ?? $packageName) . ' for dynamic references');
|
$this->client->window->logMessage(
|
||||||
|
MessageType::INFO,
|
||||||
|
'Indexing ' . ($packageKey ?? $packageName) . ' for dynamic references'
|
||||||
|
);
|
||||||
yield $this->indexFiles($files);
|
yield $this->indexFiles($files);
|
||||||
$index->setComplete();
|
$index->setComplete();
|
||||||
|
|
||||||
|
@ -182,7 +193,10 @@ class Indexer
|
||||||
$this->client->window->logMessage(MessageType::INFO, "Storing $packageKey in cache");
|
$this->client->window->logMessage(MessageType::INFO, "Storing $packageKey in cache");
|
||||||
$this->cache->set($cacheKey, $index);
|
$this->cache->set($cacheKey, $index);
|
||||||
} else {
|
} else {
|
||||||
$this->client->window->logMessage(MessageType::WARNING, "Could not compute cache key for $packageName");
|
$this->client->window->logMessage(
|
||||||
|
MessageType::WARNING,
|
||||||
|
"Could not compute cache key for $packageName"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,7 +227,7 @@ class Indexer
|
||||||
yield timeout();
|
yield timeout();
|
||||||
$this->client->window->logMessage(MessageType::LOG, "Parsing $uri");
|
$this->client->window->logMessage(MessageType::LOG, "Parsing $uri");
|
||||||
try {
|
try {
|
||||||
$document = yield $this->documentLoader->load($uri);
|
$document = (yield $this->documentLoader->load($uri));
|
||||||
if (!isVendored($document, $this->composerJson)) {
|
if (!isVendored($document, $this->composerJson)) {
|
||||||
$this->client->textDocument->publishDiagnostics($uri, $document->getDiagnostics());
|
$this->client->textDocument->publishDiagnostics($uri, $document->getDiagnostics());
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ class LanguageClient
|
||||||
public function __construct(ProtocolReader $reader, ProtocolWriter $writer)
|
public function __construct(ProtocolReader $reader, ProtocolWriter $writer)
|
||||||
{
|
{
|
||||||
$handler = new ClientHandler($reader, $writer);
|
$handler = new ClientHandler($reader, $writer);
|
||||||
$mapper = new JsonMapper;
|
$mapper = new JsonMapper();
|
||||||
|
|
||||||
$this->textDocument = new Client\TextDocument($handler, $mapper);
|
$this->textDocument = new Client\TextDocument($handler, $mapper);
|
||||||
$this->window = new Client\Window($handler);
|
$this->window = new Client\Window($handler);
|
||||||
|
|
|
@ -119,21 +119,23 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher
|
||||||
$this->exit();
|
$this->exit();
|
||||||
});
|
});
|
||||||
$this->protocolReader->on('message', function (Message $msg) {
|
$this->protocolReader->on('message', function (Message $msg) {
|
||||||
coroutine(function () use ($msg) {
|
|
||||||
// Ignore responses, this is the handler for requests and notifications
|
// Ignore responses, this is the handler for requests and notifications
|
||||||
|
// Invoke the method handler to get a result
|
||||||
|
// If a ResponseError is thrown, send it back in the Response
|
||||||
|
// If an unexpected error occurred, send back an INTERNAL_ERROR error response
|
||||||
|
// Only send a Response for a Request
|
||||||
|
// Notifications do not send Responses
|
||||||
|
coroutine(function () use ($msg) {
|
||||||
if (AdvancedJsonRpc\Response::isResponse($msg->body)) {
|
if (AdvancedJsonRpc\Response::isResponse($msg->body)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$result = null;
|
$result = null;
|
||||||
$error = null;
|
$error = null;
|
||||||
try {
|
try {
|
||||||
// Invoke the method handler to get a result
|
$result = (yield $this->dispatch($msg->body));
|
||||||
$result = yield $this->dispatch($msg->body);
|
|
||||||
} catch (AdvancedJsonRpc\Error $e) {
|
} catch (AdvancedJsonRpc\Error $e) {
|
||||||
// If a ResponseError is thrown, send it back in the Response
|
|
||||||
$error = $e;
|
$error = $e;
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
// If an unexpected error occurred, send back an INTERNAL_ERROR error response
|
|
||||||
$error = new AdvancedJsonRpc\Error(
|
$error = new AdvancedJsonRpc\Error(
|
||||||
(string) $e,
|
(string) $e,
|
||||||
AdvancedJsonRpc\ErrorCode::INTERNAL_ERROR,
|
AdvancedJsonRpc\ErrorCode::INTERNAL_ERROR,
|
||||||
|
@ -141,8 +143,6 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher
|
||||||
$e
|
$e
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Only send a Response for a Request
|
|
||||||
// Notifications do not send Responses
|
|
||||||
if (AdvancedJsonRpc\Request::isRequest($msg->body)) {
|
if (AdvancedJsonRpc\Request::isRequest($msg->body)) {
|
||||||
if ($error !== null) {
|
if ($error !== null) {
|
||||||
$responseBody = new AdvancedJsonRpc\ErrorResponse($msg->body->id, $error);
|
$responseBody = new AdvancedJsonRpc\ErrorResponse($msg->body->id, $error);
|
||||||
|
@ -165,27 +165,30 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher
|
||||||
* @param int|null $processId The process Id of the parent process that started the server. Is null if the process has not been started by another process. If the parent process is not alive then the server should exit (see exit notification) its process.
|
* @param int|null $processId The process Id of the parent process that started the server. Is null if the process has not been started by another process. If the parent process is not alive then the server should exit (see exit notification) its process.
|
||||||
* @return Promise <InitializeResult>
|
* @return Promise <InitializeResult>
|
||||||
*/
|
*/
|
||||||
public function initialize(ClientCapabilities $capabilities, string $rootPath = null, int $processId = null, string $rootUri = null): Promise
|
public function initialize(
|
||||||
{
|
ClientCapabilities $capabilities,
|
||||||
|
string $rootPath = null,
|
||||||
|
int $processId = null,
|
||||||
|
string $rootUri = null
|
||||||
|
): Promise {
|
||||||
if ($rootPath === null && $rootUri !== null) {
|
if ($rootPath === null && $rootUri !== null) {
|
||||||
$rootPath = uriToPath($rootUri);
|
$rootPath = uriToPath($rootUri);
|
||||||
}
|
}
|
||||||
return coroutine(function () use ($capabilities, $rootPath, $processId) {
|
return coroutine(function () use ($capabilities, $rootPath, $processId) {
|
||||||
|
|
||||||
if ($capabilities->xfilesProvider) {
|
if ($capabilities->xfilesProvider) {
|
||||||
$this->filesFinder = new ClientFilesFinder($this->client);
|
$this->filesFinder = new ClientFilesFinder($this->client);
|
||||||
} else {
|
} else {
|
||||||
$this->filesFinder = new FileSystemFilesFinder;
|
$this->filesFinder = new FileSystemFilesFinder();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($capabilities->xcontentProvider) {
|
if ($capabilities->xcontentProvider) {
|
||||||
$this->contentRetriever = new ClientContentRetriever($this->client);
|
$this->contentRetriever = new ClientContentRetriever($this->client);
|
||||||
} else {
|
} else {
|
||||||
$this->contentRetriever = new FileSystemContentRetriever;
|
$this->contentRetriever = new FileSystemContentRetriever();
|
||||||
}
|
}
|
||||||
|
|
||||||
$dependenciesIndex = new DependenciesIndex;
|
$dependenciesIndex = new DependenciesIndex();
|
||||||
$sourceIndex = new Index;
|
$sourceIndex = new Index();
|
||||||
$this->projectIndex = new ProjectIndex($sourceIndex, $dependenciesIndex, $this->composerJson);
|
$this->projectIndex = new ProjectIndex($sourceIndex, $dependenciesIndex, $this->composerJson);
|
||||||
$stubsIndex = StubsIndex::read();
|
$stubsIndex = StubsIndex::read();
|
||||||
$this->globalIndex = new GlobalIndex($stubsIndex, $this->projectIndex);
|
$this->globalIndex = new GlobalIndex($stubsIndex, $this->projectIndex);
|
||||||
|
@ -204,25 +207,33 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher
|
||||||
|
|
||||||
// Find composer.json
|
// Find composer.json
|
||||||
if ($this->composerJson === null) {
|
if ($this->composerJson === null) {
|
||||||
$composerJsonFiles = yield $this->filesFinder->find(Path::makeAbsolute('**/composer.json', $rootPath));
|
$composerJsonFiles = (yield $this->filesFinder->find(
|
||||||
|
Path::makeAbsolute('**/composer.json', $rootPath)
|
||||||
|
));
|
||||||
sortUrisLevelOrder($composerJsonFiles);
|
sortUrisLevelOrder($composerJsonFiles);
|
||||||
|
|
||||||
if (!empty($composerJsonFiles)) {
|
if (!empty($composerJsonFiles)) {
|
||||||
$this->composerJson = json_decode(yield $this->contentRetriever->retrieve($composerJsonFiles[0]));
|
$this->composerJson = json_decode(
|
||||||
|
yield $this->contentRetriever->retrieve($composerJsonFiles[0])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find composer.lock
|
// Find composer.lock
|
||||||
if ($this->composerLock === null) {
|
if ($this->composerLock === null) {
|
||||||
$composerLockFiles = yield $this->filesFinder->find(Path::makeAbsolute('**/composer.lock', $rootPath));
|
$composerLockFiles = (yield $this->filesFinder->find(
|
||||||
|
Path::makeAbsolute('**/composer.lock', $rootPath)
|
||||||
|
));
|
||||||
sortUrisLevelOrder($composerLockFiles);
|
sortUrisLevelOrder($composerLockFiles);
|
||||||
|
|
||||||
if (!empty($composerLockFiles)) {
|
if (!empty($composerLockFiles)) {
|
||||||
$this->composerLock = json_decode(yield $this->contentRetriever->retrieve($composerLockFiles[0]));
|
$this->composerLock = json_decode(
|
||||||
|
yield $this->contentRetriever->retrieve($composerLockFiles[0])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$cache = $capabilities->xcacheProvider ? new ClientCache($this->client) : new FileSystemCache;
|
$cache = $capabilities->xcacheProvider ? new ClientCache($this->client) : new FileSystemCache();
|
||||||
|
|
||||||
// Index in background
|
// Index in background
|
||||||
$indexer = new Indexer(
|
$indexer = new Indexer(
|
||||||
|
@ -239,7 +250,6 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher
|
||||||
$indexer->index()->otherwise('\\LanguageServer\\crash');
|
$indexer->index()->otherwise('\\LanguageServer\\crash');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ($this->textDocument === null) {
|
if ($this->textDocument === null) {
|
||||||
$this->textDocument = new Server\TextDocument(
|
$this->textDocument = new Server\TextDocument(
|
||||||
$this->documentLoader,
|
$this->documentLoader,
|
||||||
|
@ -276,7 +286,7 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher
|
||||||
// Support "Hover"
|
// Support "Hover"
|
||||||
$serverCapabilities->hoverProvider = true;
|
$serverCapabilities->hoverProvider = true;
|
||||||
// Support "Completion"
|
// Support "Completion"
|
||||||
$serverCapabilities->completionProvider = new CompletionOptions;
|
$serverCapabilities->completionProvider = new CompletionOptions();
|
||||||
$serverCapabilities->completionProvider->resolveProvider = false;
|
$serverCapabilities->completionProvider->resolveProvider = false;
|
||||||
$serverCapabilities->completionProvider->triggerCharacters = ['$', '>'];
|
$serverCapabilities->completionProvider->triggerCharacters = ['$', '>'];
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ class Message
|
||||||
*/
|
*/
|
||||||
public static function parse(string $msg): Message
|
public static function parse(string $msg): Message
|
||||||
{
|
{
|
||||||
$obj = new self;
|
$obj = new self();
|
||||||
$parts = explode("\r\n", $msg);
|
$parts = explode("\r\n", $msg);
|
||||||
$obj->body = MessageBody::parse(array_pop($parts));
|
$obj->body = MessageBody::parse(array_pop($parts));
|
||||||
foreach ($parts as $line) {
|
foreach ($parts as $line) {
|
||||||
|
|
|
@ -9,28 +9,22 @@ use Microsoft\PhpParser\Node;
|
||||||
function isConstantFetch(Node $node): bool
|
function isConstantFetch(Node $node): bool
|
||||||
{
|
{
|
||||||
$parent = $node->parent;
|
$parent = $node->parent;
|
||||||
return
|
return $node instanceof Node\QualifiedName &&
|
||||||
(
|
($parent instanceof Node\Expression ||
|
||||||
$node instanceof Node\QualifiedName &&
|
|
||||||
(
|
|
||||||
$parent instanceof Node\Expression ||
|
|
||||||
$parent instanceof Node\DelimitedList\ExpressionList ||
|
$parent instanceof Node\DelimitedList\ExpressionList ||
|
||||||
$parent instanceof Node\ArrayElement ||
|
$parent instanceof Node\ArrayElement ||
|
||||||
($parent instanceof Node\Parameter && $node->parent->default === $node) ||
|
($parent instanceof Node\Parameter && $node->parent->default === $node) ||
|
||||||
$parent instanceof Node\StatementNode ||
|
$parent instanceof Node\StatementNode ||
|
||||||
$parent instanceof Node\CaseStatementNode
|
$parent instanceof Node\CaseStatementNode) &&
|
||||||
) &&
|
|
||||||
!(
|
!(
|
||||||
$parent instanceof Node\Expression\MemberAccessExpression ||
|
$parent instanceof Node\Expression\MemberAccessExpression ||
|
||||||
$parent instanceof Node\Expression\CallExpression ||
|
$parent instanceof Node\Expression\CallExpression ||
|
||||||
$parent instanceof Node\Expression\ObjectCreationExpression ||
|
$parent instanceof Node\Expression\ObjectCreationExpression ||
|
||||||
$parent instanceof Node\Expression\ScopedPropertyAccessExpression ||
|
$parent instanceof Node\Expression\ScopedPropertyAccessExpression ||
|
||||||
$parent instanceof PhpParser\FunctionLike ||
|
$parent instanceof PhpParser\FunctionLike ||
|
||||||
(
|
($parent instanceof Node\Expression\BinaryExpression &&
|
||||||
$parent instanceof Node\Expression\BinaryExpression &&
|
$parent->operator->kind === PhpParser\TokenKind::InstanceOfKeyword)
|
||||||
$parent->operator->kind === PhpParser\TokenKind::InstanceOfKeyword
|
);
|
||||||
)
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFunctionLikeDeclarationFromParameter(Node\Parameter $node)
|
function getFunctionLikeDeclarationFromParameter(Node\Parameter $node)
|
||||||
|
@ -65,7 +59,6 @@ function isBooleanExpression($expression) : bool
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to get the parent property declaration given a Node
|
* Tries to get the parent property declaration given a Node
|
||||||
* @param Node $node
|
* @param Node $node
|
||||||
|
@ -73,7 +66,8 @@ function isBooleanExpression($expression) : bool
|
||||||
*/
|
*/
|
||||||
function tryGetPropertyDeclaration(Node $node)
|
function tryGetPropertyDeclaration(Node $node)
|
||||||
{
|
{
|
||||||
if ($node instanceof Node\Expression\Variable &&
|
if (
|
||||||
|
$node instanceof Node\Expression\Variable &&
|
||||||
(($propertyDeclaration = $node->parent->parent) instanceof Node\PropertyDeclaration ||
|
(($propertyDeclaration = $node->parent->parent) instanceof Node\PropertyDeclaration ||
|
||||||
($propertyDeclaration = $propertyDeclaration->parent) instanceof Node\PropertyDeclaration)
|
($propertyDeclaration = $propertyDeclaration->parent) instanceof Node\PropertyDeclaration)
|
||||||
) {
|
) {
|
||||||
|
@ -90,8 +84,8 @@ function tryGetPropertyDeclaration(Node $node)
|
||||||
function tryGetConstOrClassConstDeclaration(Node $node)
|
function tryGetConstOrClassConstDeclaration(Node $node)
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
$node instanceof Node\ConstElement && (
|
$node instanceof Node\ConstElement &&
|
||||||
($constDeclaration = $node->parent->parent) instanceof Node\ClassConstDeclaration ||
|
(($constDeclaration = $node->parent->parent) instanceof Node\ClassConstDeclaration ||
|
||||||
$constDeclaration instanceof Node\Statement\ConstDeclaration)
|
$constDeclaration instanceof Node\Statement\ConstDeclaration)
|
||||||
) {
|
) {
|
||||||
return $constDeclaration;
|
return $constDeclaration;
|
||||||
|
@ -107,10 +101,10 @@ function tryGetConstOrClassConstDeclaration(Node $node)
|
||||||
*/
|
*/
|
||||||
function isConstDefineExpression(Node $node): bool
|
function isConstDefineExpression(Node $node): bool
|
||||||
{
|
{
|
||||||
return $node instanceof Node\Expression\CallExpression
|
return $node instanceof Node\Expression\CallExpression &&
|
||||||
&& $node->callableExpression instanceof Node\QualifiedName
|
$node->callableExpression instanceof Node\QualifiedName &&
|
||||||
&& strtolower($node->callableExpression->getText()) === 'define'
|
strtolower($node->callableExpression->getText()) === 'define' &&
|
||||||
&& isset($node->argumentExpressionList->children[0])
|
isset($node->argumentExpressionList->children[0]) &&
|
||||||
&& $node->argumentExpressionList->children[0]->expression instanceof Node\StringLiteral
|
$node->argumentExpressionList->children[0]->expression instanceof Node\StringLiteral &&
|
||||||
&& isset($node->argumentExpressionList->children[2]);
|
isset($node->argumentExpressionList->children[2]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,7 @@ declare(strict_types = 1);
|
||||||
namespace LanguageServer;
|
namespace LanguageServer;
|
||||||
|
|
||||||
use LanguageServer\Index\Index;
|
use LanguageServer\Index\Index;
|
||||||
use LanguageServerProtocol\{
|
use LanguageServerProtocol\{Diagnostic, Position, Range};
|
||||||
Diagnostic, Position, Range
|
|
||||||
};
|
|
||||||
use Microsoft\PhpParser;
|
use Microsoft\PhpParser;
|
||||||
use Microsoft\PhpParser\Node;
|
use Microsoft\PhpParser\Node;
|
||||||
use phpDocumentor\Reflection\DocBlockFactory;
|
use phpDocumentor\Reflection\DocBlockFactory;
|
||||||
|
@ -144,7 +142,13 @@ class PhpDocument
|
||||||
$this->definitions = null;
|
$this->definitions = null;
|
||||||
$this->definitionNodes = null;
|
$this->definitionNodes = null;
|
||||||
|
|
||||||
$treeAnalyzer = new TreeAnalyzer($this->parser, $content, $this->docBlockFactory, $this->definitionResolver, $this->uri);
|
$treeAnalyzer = new TreeAnalyzer(
|
||||||
|
$this->parser,
|
||||||
|
$content,
|
||||||
|
$this->docBlockFactory,
|
||||||
|
$this->definitionResolver,
|
||||||
|
$this->uri
|
||||||
|
);
|
||||||
|
|
||||||
$this->diagnostics = $treeAnalyzer->getDiagnostics();
|
$this->diagnostics = $treeAnalyzer->getDiagnostics();
|
||||||
|
|
||||||
|
|
|
@ -105,9 +105,8 @@ class PhpDocumentLoader
|
||||||
public function load(string $uri): Promise
|
public function load(string $uri): Promise
|
||||||
{
|
{
|
||||||
return coroutine(function () use ($uri) {
|
return coroutine(function () use ($uri) {
|
||||||
|
|
||||||
$limit = 150000;
|
$limit = 150000;
|
||||||
$content = yield $this->contentRetriever->retrieve($uri);
|
$content = (yield $this->contentRetriever->retrieve($uri));
|
||||||
$size = strlen($content);
|
$size = strlen($content);
|
||||||
if ($size > $limit) {
|
if ($size > $limit) {
|
||||||
throw new ContentTooLargeException($uri, $size, $limit);
|
throw new ContentTooLargeException($uri, $size, $limit);
|
||||||
|
|
|
@ -13,5 +13,4 @@ use Sabre\Event\EmitterInterface;
|
||||||
*/
|
*/
|
||||||
interface ProtocolReader extends EmitterInterface
|
interface ProtocolReader extends EmitterInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,7 @@ declare(strict_types = 1);
|
||||||
namespace LanguageServer;
|
namespace LanguageServer;
|
||||||
|
|
||||||
use LanguageServer\Message;
|
use LanguageServer\Message;
|
||||||
use Sabre\Event\{
|
use Sabre\Event\{Loop, Promise};
|
||||||
Loop,
|
|
||||||
Promise
|
|
||||||
};
|
|
||||||
|
|
||||||
class ProtocolStreamWriter implements ProtocolWriter
|
class ProtocolStreamWriter implements ProtocolWriter
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,12 @@ declare(strict_types = 1);
|
||||||
namespace LanguageServer\Server;
|
namespace LanguageServer\Server;
|
||||||
|
|
||||||
use LanguageServer\{
|
use LanguageServer\{
|
||||||
CompletionProvider, SignatureHelpProvider, LanguageClient, PhpDocument, PhpDocumentLoader, DefinitionResolver
|
CompletionProvider,
|
||||||
|
SignatureHelpProvider,
|
||||||
|
LanguageClient,
|
||||||
|
PhpDocument,
|
||||||
|
PhpDocumentLoader,
|
||||||
|
DefinitionResolver
|
||||||
};
|
};
|
||||||
use LanguageServer\Index\ReadableIndex;
|
use LanguageServer\Index\ReadableIndex;
|
||||||
use LanguageServer\Factory\LocationFactory;
|
use LanguageServer\Factory\LocationFactory;
|
||||||
|
@ -28,9 +33,7 @@ use LanguageServerProtocol\{
|
||||||
use Microsoft\PhpParser\Node;
|
use Microsoft\PhpParser\Node;
|
||||||
use Sabre\Event\Promise;
|
use Sabre\Event\Promise;
|
||||||
use Sabre\Uri;
|
use Sabre\Uri;
|
||||||
use function LanguageServer\{
|
use function LanguageServer\{isVendored, waitForEvent, getPackageName};
|
||||||
isVendored, waitForEvent, getPackageName
|
|
||||||
};
|
|
||||||
use function Sabre\Event\coroutine;
|
use function Sabre\Event\coroutine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -180,7 +183,7 @@ class TextDocument
|
||||||
Position $position
|
Position $position
|
||||||
): Promise {
|
): Promise {
|
||||||
return coroutine(function () use ($textDocument, $position) {
|
return coroutine(function () use ($textDocument, $position) {
|
||||||
$document = yield $this->documentLoader->getOrLoad($textDocument->uri);
|
$document = (yield $this->documentLoader->getOrLoad($textDocument->uri));
|
||||||
$node = $document->getNodeAtPosition($position);
|
$node = $document->getNodeAtPosition($position);
|
||||||
if ($node === null) {
|
if ($node === null) {
|
||||||
return [];
|
return [];
|
||||||
|
@ -189,10 +192,10 @@ class TextDocument
|
||||||
// Variables always stay in the boundary of the file and need to be searched inside their function scope
|
// Variables always stay in the boundary of the file and need to be searched inside their function scope
|
||||||
// by traversing the AST
|
// by traversing the AST
|
||||||
if (
|
if (
|
||||||
|
($node instanceof Node\Expression\Variable &&
|
||||||
($node instanceof Node\Expression\Variable && !($node->getParent()->getParent() instanceof Node\PropertyDeclaration))
|
!($node->getParent()->getParent() instanceof Node\PropertyDeclaration)) ||
|
||||||
|| $node instanceof Node\Parameter
|
$node instanceof Node\Parameter ||
|
||||||
|| $node instanceof Node\UseVariableName
|
$node instanceof Node\UseVariableName
|
||||||
) {
|
) {
|
||||||
if (isset($node->name) && $node->name instanceof Node\Expression) {
|
if (isset($node->name) && $node->name instanceof Node\Expression) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -200,14 +203,20 @@ class TextDocument
|
||||||
// Find function/method/closure scope
|
// Find function/method/closure scope
|
||||||
$n = $node;
|
$n = $node;
|
||||||
|
|
||||||
$n = $n->getFirstAncestor(Node\Statement\FunctionDeclaration::class, Node\MethodDeclaration::class, Node\Expression\AnonymousFunctionCreationExpression::class, Node\SourceFileNode::class);
|
$n = $n->getFirstAncestor(
|
||||||
|
Node\Statement\FunctionDeclaration::class,
|
||||||
|
Node\MethodDeclaration::class,
|
||||||
|
Node\Expression\AnonymousFunctionCreationExpression::class,
|
||||||
|
Node\SourceFileNode::class
|
||||||
|
);
|
||||||
|
|
||||||
if ($n === null) {
|
if ($n === null) {
|
||||||
$n = $node->getFirstAncestor(Node\Statement\ExpressionStatement::class)->getParent();
|
$n = $node->getFirstAncestor(Node\Statement\ExpressionStatement::class)->getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($n->getDescendantNodes() as $descendantNode) {
|
foreach ($n->getDescendantNodes() as $descendantNode) {
|
||||||
if ($descendantNode instanceof Node\Expression\Variable &&
|
if (
|
||||||
|
$descendantNode instanceof Node\Expression\Variable &&
|
||||||
$descendantNode->getName() === $node->getName()
|
$descendantNode->getName() === $node->getName()
|
||||||
) {
|
) {
|
||||||
$locations[] = LocationFactory::fromNode($descendantNode);
|
$locations[] = LocationFactory::fromNode($descendantNode);
|
||||||
|
@ -231,7 +240,7 @@ class TextDocument
|
||||||
foreach ($this->index->getReferenceUris($fqn) as $uri) {
|
foreach ($this->index->getReferenceUris($fqn) as $uri) {
|
||||||
$refDocumentPromises[] = $this->documentLoader->getOrLoad($uri);
|
$refDocumentPromises[] = $this->documentLoader->getOrLoad($uri);
|
||||||
}
|
}
|
||||||
$refDocuments = yield Promise\all($refDocumentPromises);
|
$refDocuments = (yield Promise\all($refDocumentPromises));
|
||||||
foreach ($refDocuments as $document) {
|
foreach ($refDocuments as $document) {
|
||||||
$refs = $document->getReferenceNodesByFqn($fqn);
|
$refs = $document->getReferenceNodesByFqn($fqn);
|
||||||
if ($refs !== null) {
|
if ($refs !== null) {
|
||||||
|
@ -257,7 +266,7 @@ class TextDocument
|
||||||
public function signatureHelp(TextDocumentIdentifier $textDocument, Position $position): Promise
|
public function signatureHelp(TextDocumentIdentifier $textDocument, Position $position): Promise
|
||||||
{
|
{
|
||||||
return coroutine(function () use ($textDocument, $position) {
|
return coroutine(function () use ($textDocument, $position) {
|
||||||
$document = yield $this->documentLoader->getOrLoad($textDocument->uri);
|
$document = (yield $this->documentLoader->getOrLoad($textDocument->uri));
|
||||||
return $this->signatureHelpProvider->getSignatureHelp($document, $position);
|
return $this->signatureHelpProvider->getSignatureHelp($document, $position);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -273,7 +282,7 @@ class TextDocument
|
||||||
public function definition(TextDocumentIdentifier $textDocument, Position $position): Promise
|
public function definition(TextDocumentIdentifier $textDocument, Position $position): Promise
|
||||||
{
|
{
|
||||||
return coroutine(function () use ($textDocument, $position) {
|
return coroutine(function () use ($textDocument, $position) {
|
||||||
$document = yield $this->documentLoader->getOrLoad($textDocument->uri);
|
$document = (yield $this->documentLoader->getOrLoad($textDocument->uri));
|
||||||
$node = $document->getNodeAtPosition($position);
|
$node = $document->getNodeAtPosition($position);
|
||||||
if ($node === null) {
|
if ($node === null) {
|
||||||
return [];
|
return [];
|
||||||
|
@ -294,9 +303,9 @@ class TextDocument
|
||||||
yield waitForEvent($this->index, 'definition-added');
|
yield waitForEvent($this->index, 'definition-added');
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
$def === null
|
$def === null ||
|
||||||
|| $def->symbolInformation === null
|
$def->symbolInformation === null ||
|
||||||
|| Uri\parse($def->symbolInformation->location->uri)['scheme'] === 'phpstubs'
|
Uri\parse($def->symbolInformation->location->uri)['scheme'] === 'phpstubs'
|
||||||
) {
|
) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -314,7 +323,7 @@ class TextDocument
|
||||||
public function hover(TextDocumentIdentifier $textDocument, Position $position): Promise
|
public function hover(TextDocumentIdentifier $textDocument, Position $position): Promise
|
||||||
{
|
{
|
||||||
return coroutine(function () use ($textDocument, $position) {
|
return coroutine(function () use ($textDocument, $position) {
|
||||||
$document = yield $this->documentLoader->getOrLoad($textDocument->uri);
|
$document = (yield $this->documentLoader->getOrLoad($textDocument->uri));
|
||||||
// Find the node under the cursor
|
// Find the node under the cursor
|
||||||
$node = $document->getNodeAtPosition($position);
|
$node = $document->getNodeAtPosition($position);
|
||||||
if ($node === null) {
|
if ($node === null) {
|
||||||
|
@ -365,10 +374,13 @@ class TextDocument
|
||||||
* @param CompletionContext|null $context The completion context
|
* @param CompletionContext|null $context The completion context
|
||||||
* @return Promise <CompletionItem[]|CompletionList>
|
* @return Promise <CompletionItem[]|CompletionList>
|
||||||
*/
|
*/
|
||||||
public function completion(TextDocumentIdentifier $textDocument, Position $position, CompletionContext $context = null): Promise
|
public function completion(
|
||||||
{
|
TextDocumentIdentifier $textDocument,
|
||||||
|
Position $position,
|
||||||
|
CompletionContext $context = null
|
||||||
|
): Promise {
|
||||||
return coroutine(function () use ($textDocument, $position, $context) {
|
return coroutine(function () use ($textDocument, $position, $context) {
|
||||||
$document = yield $this->documentLoader->getOrLoad($textDocument->uri);
|
$document = (yield $this->documentLoader->getOrLoad($textDocument->uri));
|
||||||
return $this->completionProvider->provideCompletion($document, $position, $context);
|
return $this->completionProvider->provideCompletion($document, $position, $context);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -388,7 +400,7 @@ class TextDocument
|
||||||
public function xdefinition(TextDocumentIdentifier $textDocument, Position $position): Promise
|
public function xdefinition(TextDocumentIdentifier $textDocument, Position $position): Promise
|
||||||
{
|
{
|
||||||
return coroutine(function () use ($textDocument, $position) {
|
return coroutine(function () use ($textDocument, $position) {
|
||||||
$document = yield $this->documentLoader->getOrLoad($textDocument->uri);
|
$document = (yield $this->documentLoader->getOrLoad($textDocument->uri));
|
||||||
$node = $document->getNodeAtPosition($position);
|
$node = $document->getNodeAtPosition($position);
|
||||||
if ($node === null) {
|
if ($node === null) {
|
||||||
return [];
|
return [];
|
||||||
|
@ -409,9 +421,9 @@ class TextDocument
|
||||||
yield waitForEvent($this->index, 'definition-added');
|
yield waitForEvent($this->index, 'definition-added');
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
$def === null
|
$def === null ||
|
||||||
|| $def->symbolInformation === null
|
$def->symbolInformation === null ||
|
||||||
|| Uri\parse($def->symbolInformation->location->uri)['scheme'] === 'phpstubs'
|
Uri\parse($def->symbolInformation->location->uri)['scheme'] === 'phpstubs'
|
||||||
) {
|
) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,8 +64,15 @@ class Workspace
|
||||||
* @param \stdClass $composerLock The parsed composer.lock of the project, if any
|
* @param \stdClass $composerLock The parsed composer.lock of the project, if any
|
||||||
* @param PhpDocumentLoader $documentLoader PhpDocumentLoader instance to load documents
|
* @param PhpDocumentLoader $documentLoader PhpDocumentLoader instance to load documents
|
||||||
*/
|
*/
|
||||||
public function __construct(LanguageClient $client, ProjectIndex $projectIndex, DependenciesIndex $dependenciesIndex, Index $sourceIndex, \stdClass $composerLock = null, PhpDocumentLoader $documentLoader, \stdClass $composerJson = null)
|
public function __construct(
|
||||||
{
|
LanguageClient $client,
|
||||||
|
ProjectIndex $projectIndex,
|
||||||
|
DependenciesIndex $dependenciesIndex,
|
||||||
|
Index $sourceIndex,
|
||||||
|
\stdClass $composerLock = null,
|
||||||
|
PhpDocumentLoader $documentLoader,
|
||||||
|
\stdClass $composerJson = null
|
||||||
|
) {
|
||||||
$this->client = $client;
|
$this->client = $client;
|
||||||
$this->sourceIndex = $sourceIndex;
|
$this->sourceIndex = $sourceIndex;
|
||||||
$this->projectIndex = $projectIndex;
|
$this->projectIndex = $projectIndex;
|
||||||
|
@ -148,9 +155,9 @@ class Workspace
|
||||||
$refInfos = [];
|
$refInfos = [];
|
||||||
foreach ($refs as $uri => $fqns) {
|
foreach ($refs as $uri => $fqns) {
|
||||||
foreach ($fqns as $fqn) {
|
foreach ($fqns as $fqn) {
|
||||||
$doc = yield $this->documentLoader->getOrLoad($uri);
|
$doc = (yield $this->documentLoader->getOrLoad($uri));
|
||||||
foreach ($doc->getReferenceNodesByFqn($fqn) as $node) {
|
foreach ($doc->getReferenceNodesByFqn($fqn) as $node) {
|
||||||
$refInfo = new ReferenceInformation;
|
$refInfo = new ReferenceInformation();
|
||||||
$refInfo->reference = LocationFactory::fromNode($node);
|
$refInfo->reference = LocationFactory::fromNode($node);
|
||||||
$refInfo->symbol = $query;
|
$refInfo->symbol = $query;
|
||||||
$refInfos[] = $refInfo;
|
$refInfos[] = $refInfo;
|
||||||
|
@ -170,7 +177,10 @@ class Workspace
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
$dependencyReferences = [];
|
$dependencyReferences = [];
|
||||||
foreach (array_merge($this->composerLock->packages, (array)$this->composerLock->{'packages-dev'}) as $package) {
|
foreach (
|
||||||
|
array_merge($this->composerLock->packages, (array) $this->composerLock->{'packages-dev'})
|
||||||
|
as $package
|
||||||
|
) {
|
||||||
$dependencyReferences[] = new DependencyReference($package);
|
$dependencyReferences[] = new DependencyReference($package);
|
||||||
}
|
}
|
||||||
return $dependencyReferences;
|
return $dependencyReferences;
|
||||||
|
|
|
@ -4,10 +4,7 @@ declare(strict_types = 1);
|
||||||
namespace LanguageServer;
|
namespace LanguageServer;
|
||||||
|
|
||||||
use LanguageServer\Index\ReadableIndex;
|
use LanguageServer\Index\ReadableIndex;
|
||||||
use LanguageServerProtocol\{
|
use LanguageServerProtocol\{Position, SignatureHelp};
|
||||||
Position,
|
|
||||||
SignatureHelp
|
|
||||||
};
|
|
||||||
use Microsoft\PhpParser\Node;
|
use Microsoft\PhpParser\Node;
|
||||||
use Sabre\Event\Promise;
|
use Sabre\Event\Promise;
|
||||||
use function Sabre\Event\coroutine;
|
use function Sabre\Event\coroutine;
|
||||||
|
@ -30,8 +27,11 @@ class SignatureHelpProvider
|
||||||
* @param ReadableIndex $index
|
* @param ReadableIndex $index
|
||||||
* @param PhpDocumentLoader $documentLoader
|
* @param PhpDocumentLoader $documentLoader
|
||||||
*/
|
*/
|
||||||
public function __construct(DefinitionResolver $definitionResolver, ReadableIndex $index, PhpDocumentLoader $documentLoader)
|
public function __construct(
|
||||||
{
|
DefinitionResolver $definitionResolver,
|
||||||
|
ReadableIndex $index,
|
||||||
|
PhpDocumentLoader $documentLoader
|
||||||
|
) {
|
||||||
$this->definitionResolver = $definitionResolver;
|
$this->definitionResolver = $definitionResolver;
|
||||||
$this->index = $index;
|
$this->index = $index;
|
||||||
$this->documentLoader = $documentLoader;
|
$this->documentLoader = $documentLoader;
|
||||||
|
@ -52,7 +52,7 @@ class SignatureHelpProvider
|
||||||
$node = $doc->getNodeAtPosition($position);
|
$node = $doc->getNodeAtPosition($position);
|
||||||
|
|
||||||
// Find the definition of the item being called
|
// Find the definition of the item being called
|
||||||
list($def, $argumentExpressionList) = yield $this->getCallingInfo($node);
|
list($def, $argumentExpressionList) = (yield $this->getCallingInfo($node));
|
||||||
|
|
||||||
if (!$def || !$def->signatureInformation) {
|
if (!$def || !$def->signatureInformation) {
|
||||||
return new SignatureHelp();
|
return new SignatureHelp();
|
||||||
|
|
|
@ -32,11 +32,7 @@ class SignatureInformationFactory
|
||||||
{
|
{
|
||||||
$params = $this->createParameters($node);
|
$params = $this->createParameters($node);
|
||||||
$label = $this->createLabel($params);
|
$label = $this->createLabel($params);
|
||||||
return new SignatureInformation(
|
return new SignatureInformation($label, $params, $this->definitionResolver->getDocumentationFromNode($node));
|
||||||
$label,
|
|
||||||
$params,
|
|
||||||
$this->definitionResolver->getDocumentationFromNode($node)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -46,8 +46,13 @@ class TreeAnalyzer
|
||||||
* @param DefinitionResolver $definitionResolver
|
* @param DefinitionResolver $definitionResolver
|
||||||
* @param string $uri
|
* @param string $uri
|
||||||
*/
|
*/
|
||||||
public function __construct(PhpParser\Parser $parser, string $content, DocBlockFactory $docBlockFactory, DefinitionResolver $definitionResolver, string $uri)
|
public function __construct(
|
||||||
{
|
PhpParser\Parser $parser,
|
||||||
|
string $content,
|
||||||
|
DocBlockFactory $docBlockFactory,
|
||||||
|
DefinitionResolver $definitionResolver,
|
||||||
|
string $uri
|
||||||
|
) {
|
||||||
$this->parser = $parser;
|
$this->parser = $parser;
|
||||||
$this->docBlockFactory = $docBlockFactory;
|
$this->docBlockFactory = $docBlockFactory;
|
||||||
$this->definitionResolver = $definitionResolver;
|
$this->definitionResolver = $definitionResolver;
|
||||||
|
@ -69,7 +74,11 @@ class TreeAnalyzer
|
||||||
{
|
{
|
||||||
// Get errors from the parser.
|
// Get errors from the parser.
|
||||||
if (($error = PhpParser\DiagnosticsProvider::checkDiagnostics($node)) !== null) {
|
if (($error = PhpParser\DiagnosticsProvider::checkDiagnostics($node)) !== null) {
|
||||||
$range = PhpParser\PositionUtilities::getRangeFromPosition($error->start, $error->length, $this->sourceFileNode->fileContents);
|
$range = PhpParser\PositionUtilities::getRangeFromPosition(
|
||||||
|
$error->start,
|
||||||
|
$error->length,
|
||||||
|
$this->sourceFileNode->fileContents
|
||||||
|
);
|
||||||
|
|
||||||
switch ($error->kind) {
|
switch ($error->kind) {
|
||||||
case PhpParser\DiagnosticKind::Error:
|
case PhpParser\DiagnosticKind::Error:
|
||||||
|
@ -150,24 +159,24 @@ class TreeAnalyzer
|
||||||
*/
|
*/
|
||||||
private function collectDefinitionsAndReferences(Node $node)
|
private function collectDefinitionsAndReferences(Node $node)
|
||||||
{
|
{
|
||||||
$fqn = ($this->definitionResolver)::getDefinedFqn($node);
|
$fqn = $this->definitionResolver::getDefinedFqn($node);
|
||||||
// Only index definitions with an FQN (no variables)
|
// Only index definitions with an FQN (no variables)
|
||||||
if ($fqn !== null) {
|
if ($fqn !== null) {
|
||||||
$this->definitionNodes[$fqn] = $node;
|
$this->definitionNodes[$fqn] = $node;
|
||||||
$this->definitions[$fqn] = $this->definitionResolver->createDefinitionFromNode($node, $fqn);
|
$this->definitions[$fqn] = $this->definitionResolver->createDefinitionFromNode($node, $fqn);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
$parent = $node->parent;
|
$parent = $node->parent;
|
||||||
if (
|
if (
|
||||||
(
|
|
||||||
// $node->parent instanceof Node\Expression\ScopedPropertyAccessExpression ||
|
// $node->parent instanceof Node\Expression\ScopedPropertyAccessExpression ||
|
||||||
($node instanceof Node\Expression\ScopedPropertyAccessExpression ||
|
(($node instanceof Node\Expression\ScopedPropertyAccessExpression ||
|
||||||
$node instanceof Node\Expression\MemberAccessExpression)
|
$node instanceof Node\Expression\MemberAccessExpression) &&
|
||||||
&& !(
|
!(
|
||||||
$node->parent instanceof Node\Expression\CallExpression ||
|
$node->parent instanceof Node\Expression\CallExpression ||
|
||||||
$node->memberName instanceof PhpParser\Token
|
$node->memberName instanceof PhpParser\Token
|
||||||
))
|
)) ||
|
||||||
|| ($parent instanceof Node\Statement\NamespaceDefinition && $parent->name !== null && $parent->name->getStart() === $node->getStart())
|
($parent instanceof Node\Statement\NamespaceDefinition &&
|
||||||
|
$parent->name !== null &&
|
||||||
|
$parent->name->getStart() === $node->getStart())
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -203,9 +212,11 @@ class TreeAnalyzer
|
||||||
$this->addReference($fqn, $node);
|
$this->addReference($fqn, $node);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
$node instanceof Node\QualifiedName
|
$node instanceof Node\QualifiedName &&
|
||||||
&& ($node->isQualifiedName() || $node->parent instanceof Node\NamespaceUseClause)
|
($node->isQualifiedName() || $node->parent instanceof Node\NamespaceUseClause) &&
|
||||||
&& !($parent instanceof Node\Statement\NamespaceDefinition && $parent->name->getStart() === $node->getStart()
|
!(
|
||||||
|
$parent instanceof Node\Statement\NamespaceDefinition &&
|
||||||
|
$parent->name->getStart() === $node->getStart()
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
// Add references for each referenced namespace
|
// Add references for each referenced namespace
|
||||||
|
@ -219,12 +230,14 @@ class TreeAnalyzer
|
||||||
// Namespaced constant access and function calls also need to register a reference
|
// Namespaced constant access and function calls also need to register a reference
|
||||||
// to the global version because PHP falls back to global at runtime
|
// to the global version because PHP falls back to global at runtime
|
||||||
// http://php.net/manual/en/language.namespaces.fallback.php
|
// http://php.net/manual/en/language.namespaces.fallback.php
|
||||||
if (ParserHelpers\isConstantFetch($node) ||
|
if (
|
||||||
($parent instanceof Node\Expression\CallExpression
|
ParserHelpers\isConstantFetch($node) ||
|
||||||
&& !(
|
($parent instanceof Node\Expression\CallExpression &&
|
||||||
|
!(
|
||||||
$node instanceof Node\Expression\ScopedPropertyAccessExpression ||
|
$node instanceof Node\Expression\ScopedPropertyAccessExpression ||
|
||||||
$node instanceof Node\Expression\MemberAccessExpression
|
$node instanceof Node\Expression\MemberAccessExpression
|
||||||
))) {
|
))
|
||||||
|
) {
|
||||||
$parts = explode('\\', $fqn);
|
$parts = explode('\\', $fqn);
|
||||||
if (count($parts) > 1) {
|
if (count($parts) > 1) {
|
||||||
$globalFqn = end($parts);
|
$globalFqn = end($parts);
|
||||||
|
|
|
@ -74,7 +74,7 @@ function crash(Throwable $err)
|
||||||
*/
|
*/
|
||||||
function timeout($seconds = 0): Promise
|
function timeout($seconds = 0): Promise
|
||||||
{
|
{
|
||||||
$promise = new Promise;
|
$promise = new Promise();
|
||||||
Loop\setTimeout([$promise, 'fulfill'], $seconds);
|
Loop\setTimeout([$promise, 'fulfill'], $seconds);
|
||||||
return $promise;
|
return $promise;
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ function timeout($seconds = 0): Promise
|
||||||
*/
|
*/
|
||||||
function waitForEvent(EmitterInterface $emitter, string $event): Promise
|
function waitForEvent(EmitterInterface $emitter, string $event): Promise
|
||||||
{
|
{
|
||||||
$p = new Promise;
|
$p = new Promise();
|
||||||
$emitter->once($event, [$p, 'fulfill']);
|
$emitter->once($event, [$p, 'fulfill']);
|
||||||
return $p;
|
return $p;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,8 @@ class ClientHandlerTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testRequest()
|
public function testRequest()
|
||||||
{
|
{
|
||||||
$reader = new MockProtocolStream;
|
$reader = new MockProtocolStream();
|
||||||
$writer = new MockProtocolStream;
|
$writer = new MockProtocolStream();
|
||||||
$handler = new ClientHandler($reader, $writer);
|
$handler = new ClientHandler($reader, $writer);
|
||||||
$writer->once('message', function (Message $msg) use ($reader) {
|
$writer->once('message', function (Message $msg) use ($reader) {
|
||||||
// Respond to request
|
// Respond to request
|
||||||
|
@ -22,9 +22,12 @@ class ClientHandlerTest extends TestCase
|
||||||
$reader->write(new Message(new AdvancedJsonRpc\SuccessResponse($msg->body->id, 'pong')));
|
$reader->write(new Message(new AdvancedJsonRpc\SuccessResponse($msg->body->id, 'pong')));
|
||||||
}, 0);
|
}, 0);
|
||||||
});
|
});
|
||||||
$handler->request('testMethod', ['ping'])->then(function ($result) {
|
$handler
|
||||||
|
->request('testMethod', ['ping'])
|
||||||
|
->then(function ($result) {
|
||||||
$this->assertEquals('pong', $result);
|
$this->assertEquals('pong', $result);
|
||||||
})->wait();
|
})
|
||||||
|
->wait();
|
||||||
// No event listeners
|
// No event listeners
|
||||||
$this->assertEquals([], $reader->listeners('message'));
|
$this->assertEquals([], $reader->listeners('message'));
|
||||||
$this->assertEquals([], $writer->listeners('message'));
|
$this->assertEquals([], $writer->listeners('message'));
|
||||||
|
@ -32,8 +35,8 @@ class ClientHandlerTest extends TestCase
|
||||||
|
|
||||||
public function testNotify()
|
public function testNotify()
|
||||||
{
|
{
|
||||||
$reader = new MockProtocolStream;
|
$reader = new MockProtocolStream();
|
||||||
$writer = new MockProtocolStream;
|
$writer = new MockProtocolStream();
|
||||||
$handler = new ClientHandler($reader, $writer);
|
$handler = new ClientHandler($reader, $writer);
|
||||||
$handler->notify('testMethod', ['ping'])->wait();
|
$handler->notify('testMethod', ['ping'])->wait();
|
||||||
// No event listeners
|
// No event listeners
|
||||||
|
|
|
@ -12,24 +12,27 @@ class DefinitionResolverTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testCreateDefinitionFromNode()
|
public function testCreateDefinitionFromNode()
|
||||||
{
|
{
|
||||||
$parser = new PhpParser\Parser;
|
$parser = new PhpParser\Parser();
|
||||||
$doc = new MockPhpDocument;
|
$doc = new MockPhpDocument();
|
||||||
$sourceFileNode = $parser->parseSourceFile("<?php\ndefine('TEST_DEFINE', true);", $doc->getUri());
|
$sourceFileNode = $parser->parseSourceFile("<?php\ndefine('TEST_DEFINE', true);", $doc->getUri());
|
||||||
|
|
||||||
$index = new Index;
|
$index = new Index();
|
||||||
$definitionResolver = new DefinitionResolver($index);
|
$definitionResolver = new DefinitionResolver($index);
|
||||||
$def = $definitionResolver->createDefinitionFromNode($sourceFileNode->statementList[1]->expression, '\TEST_DEFINE');
|
$def = $definitionResolver->createDefinitionFromNode(
|
||||||
|
$sourceFileNode->statementList[1]->expression,
|
||||||
|
'\TEST_DEFINE'
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(\phpDocumentor\Reflection\Types\Boolean::class, $def->type);
|
$this->assertInstanceOf(\phpDocumentor\Reflection\Types\Boolean::class, $def->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetTypeFromNode()
|
public function testGetTypeFromNode()
|
||||||
{
|
{
|
||||||
$parser = new PhpParser\Parser;
|
$parser = new PhpParser\Parser();
|
||||||
$doc = new MockPhpDocument;
|
$doc = new MockPhpDocument();
|
||||||
$sourceFileNode = $parser->parseSourceFile("<?php\ndefine('TEST_DEFINE', true);", $doc->getUri());
|
$sourceFileNode = $parser->parseSourceFile("<?php\ndefine('TEST_DEFINE', true);", $doc->getUri());
|
||||||
|
|
||||||
$index = new Index;
|
$index = new Index();
|
||||||
$definitionResolver = new DefinitionResolver($index);
|
$definitionResolver = new DefinitionResolver($index);
|
||||||
$type = $definitionResolver->getTypeFromNode($sourceFileNode->statementList[1]->expression);
|
$type = $definitionResolver->getTypeFromNode($sourceFileNode->statementList[1]->expression);
|
||||||
|
|
||||||
|
@ -39,11 +42,11 @@ class DefinitionResolverTest extends TestCase
|
||||||
public function testGetDefinedFqnForIncompleteDefine()
|
public function testGetDefinedFqnForIncompleteDefine()
|
||||||
{
|
{
|
||||||
// define('XXX') (only one argument) must not introduce a new symbol
|
// define('XXX') (only one argument) must not introduce a new symbol
|
||||||
$parser = new PhpParser\Parser;
|
$parser = new PhpParser\Parser();
|
||||||
$doc = new MockPhpDocument;
|
$doc = new MockPhpDocument();
|
||||||
$sourceFileNode = $parser->parseSourceFile("<?php\ndefine('TEST_DEFINE');", $doc->getUri());
|
$sourceFileNode = $parser->parseSourceFile("<?php\ndefine('TEST_DEFINE');", $doc->getUri());
|
||||||
|
|
||||||
$index = new Index;
|
$index = new Index();
|
||||||
$definitionResolver = new DefinitionResolver($index);
|
$definitionResolver = new DefinitionResolver($index);
|
||||||
$fqn = $definitionResolver->getDefinedFqn($sourceFileNode->statementList[1]->expression);
|
$fqn = $definitionResolver->getDefinedFqn($sourceFileNode->statementList[1]->expression);
|
||||||
|
|
||||||
|
@ -52,11 +55,11 @@ class DefinitionResolverTest extends TestCase
|
||||||
|
|
||||||
public function testGetDefinedFqnForDefine()
|
public function testGetDefinedFqnForDefine()
|
||||||
{
|
{
|
||||||
$parser = new PhpParser\Parser;
|
$parser = new PhpParser\Parser();
|
||||||
$doc = new MockPhpDocument;
|
$doc = new MockPhpDocument();
|
||||||
$sourceFileNode = $parser->parseSourceFile("<?php\ndefine('TEST_DEFINE', true);", $doc->getUri());
|
$sourceFileNode = $parser->parseSourceFile("<?php\ndefine('TEST_DEFINE', true);", $doc->getUri());
|
||||||
|
|
||||||
$index = new Index;
|
$index = new Index();
|
||||||
$definitionResolver = new DefinitionResolver($index);
|
$definitionResolver = new DefinitionResolver($index);
|
||||||
$fqn = $definitionResolver->getDefinedFqn($sourceFileNode->statementList[1]->expression);
|
$fqn = $definitionResolver->getDefinedFqn($sourceFileNode->statementList[1]->expression);
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,9 @@ namespace LanguageServer\Tests\Diagnostics;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use phpDocumentor\Reflection\DocBlockFactory;
|
use phpDocumentor\Reflection\DocBlockFactory;
|
||||||
use LanguageServer\{
|
use LanguageServer\{DefinitionResolver, TreeAnalyzer};
|
||||||
DefinitionResolver, TreeAnalyzer
|
|
||||||
};
|
|
||||||
use LanguageServer\Index\{Index};
|
use LanguageServer\Index\{Index};
|
||||||
use LanguageServerProtocol\{
|
use LanguageServerProtocol\{Diagnostic, DiagnosticSeverity, Position, Range};
|
||||||
Diagnostic, DiagnosticSeverity, Position, Range
|
|
||||||
};
|
|
||||||
use function LanguageServer\pathToUri;
|
use function LanguageServer\pathToUri;
|
||||||
use Microsoft\PhpParser\Parser;
|
use Microsoft\PhpParser\Parser;
|
||||||
|
|
||||||
|
@ -29,7 +25,7 @@ class InvalidThisUsageTest extends TestCase
|
||||||
$parser = new Parser();
|
$parser = new Parser();
|
||||||
|
|
||||||
$docBlockFactory = DocBlockFactory::createInstance();
|
$docBlockFactory = DocBlockFactory::createInstance();
|
||||||
$index = new Index;
|
$index = new Index();
|
||||||
$definitionResolver = new DefinitionResolver($index);
|
$definitionResolver = new DefinitionResolver($index);
|
||||||
$content = file_get_contents($path);
|
$content = file_get_contents($path);
|
||||||
|
|
||||||
|
@ -64,18 +60,13 @@ class InvalidThisUsageTest extends TestCase
|
||||||
$diagnostics[0],
|
$diagnostics[0],
|
||||||
'$this can not be used in static methods.',
|
'$this can not be used in static methods.',
|
||||||
DiagnosticSeverity::ERROR,
|
DiagnosticSeverity::ERROR,
|
||||||
new Range(
|
new Range(new Position(6, 15), new Position(6, 20))
|
||||||
new Position(6, 15),
|
|
||||||
new Position(6, 20)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testThisInMethodProducesNoError()
|
public function testThisInMethodProducesNoError()
|
||||||
{
|
{
|
||||||
$diagnostics = $this->collectDiagnostics(
|
$diagnostics = $this->collectDiagnostics(__DIR__ . '/../../fixtures/diagnostics/baselines/this_in_method.php');
|
||||||
__DIR__ . '/../../fixtures/diagnostics/baselines/this_in_method.php'
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertCount(0, $diagnostics);
|
$this->assertCount(0, $diagnostics);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,19 +10,19 @@ class IndexTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testGetSetMethodDefinition()
|
public function testGetSetMethodDefinition()
|
||||||
{
|
{
|
||||||
$index = new Index;
|
$index = new Index();
|
||||||
$index->setDefinition('SomeNamespace\SomeClass', new Definition);
|
$index->setDefinition('SomeNamespace\SomeClass', new Definition());
|
||||||
$methodDefinition = new Definition;
|
$methodDefinition = new Definition();
|
||||||
$methodFqn = 'SomeNamespace\SomeClass->someMethod()';
|
$methodFqn = 'SomeNamespace\SomeClass->someMethod()';
|
||||||
$index->setDefinition($methodFqn, $methodDefinition);
|
$index->setDefinition($methodFqn, $methodDefinition);
|
||||||
$index->setDefinition('SomeNamespace\SomeClass->someProperty', new Definition);
|
$index->setDefinition('SomeNamespace\SomeClass->someProperty', new Definition());
|
||||||
$this->assertSame($methodDefinition, $index->getDefinition($methodFqn));
|
$this->assertSame($methodDefinition, $index->getDefinition($methodFqn));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetSetClassDefinition()
|
public function testGetSetClassDefinition()
|
||||||
{
|
{
|
||||||
$index = new Index;
|
$index = new Index();
|
||||||
$definition = new Definition;
|
$definition = new Definition();
|
||||||
$fqn = 'SomeNamespace\SomeClass';
|
$fqn = 'SomeNamespace\SomeClass';
|
||||||
$index->setDefinition($fqn, $definition);
|
$index->setDefinition($fqn, $definition);
|
||||||
$this->assertSame($definition, $index->getDefinition($fqn));
|
$this->assertSame($definition, $index->getDefinition($fqn));
|
||||||
|
|
|
@ -28,8 +28,8 @@ class LanguageServerTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testInitialize()
|
public function testInitialize()
|
||||||
{
|
{
|
||||||
$server = new LanguageServer(new MockProtocolStream, new MockProtocolStream);
|
$server = new LanguageServer(new MockProtocolStream(), new MockProtocolStream());
|
||||||
$result = $server->initialize(new ClientCapabilities, __DIR__, getmypid())->wait();
|
$result = $server->initialize(new ClientCapabilities(), __DIR__, getmypid())->wait();
|
||||||
|
|
||||||
$serverCapabilities = new ServerCapabilities();
|
$serverCapabilities = new ServerCapabilities();
|
||||||
$serverCapabilities->textDocumentSync = TextDocumentSyncKind::FULL;
|
$serverCapabilities->textDocumentSync = TextDocumentSyncKind::FULL;
|
||||||
|
@ -38,10 +38,10 @@ class LanguageServerTest extends TestCase
|
||||||
$serverCapabilities->definitionProvider = true;
|
$serverCapabilities->definitionProvider = true;
|
||||||
$serverCapabilities->referencesProvider = true;
|
$serverCapabilities->referencesProvider = true;
|
||||||
$serverCapabilities->hoverProvider = true;
|
$serverCapabilities->hoverProvider = true;
|
||||||
$serverCapabilities->completionProvider = new CompletionOptions;
|
$serverCapabilities->completionProvider = new CompletionOptions();
|
||||||
$serverCapabilities->completionProvider->resolveProvider = false;
|
$serverCapabilities->completionProvider->resolveProvider = false;
|
||||||
$serverCapabilities->completionProvider->triggerCharacters = ['$', '>'];
|
$serverCapabilities->completionProvider->triggerCharacters = ['$', '>'];
|
||||||
$serverCapabilities->signatureHelpProvider = new SignatureHelpOptions;
|
$serverCapabilities->signatureHelpProvider = new SignatureHelpOptions();
|
||||||
$serverCapabilities->signatureHelpProvider->triggerCharacters = ['(', ','];
|
$serverCapabilities->signatureHelpProvider->triggerCharacters = ['(', ','];
|
||||||
$serverCapabilities->xworkspaceReferencesProvider = true;
|
$serverCapabilities->xworkspaceReferencesProvider = true;
|
||||||
$serverCapabilities->xdefinitionProvider = true;
|
$serverCapabilities->xdefinitionProvider = true;
|
||||||
|
@ -52,9 +52,9 @@ class LanguageServerTest extends TestCase
|
||||||
|
|
||||||
public function testIndexingWithDirectFileAccess()
|
public function testIndexingWithDirectFileAccess()
|
||||||
{
|
{
|
||||||
$promise = new Promise;
|
$promise = new Promise();
|
||||||
$input = new MockProtocolStream;
|
$input = new MockProtocolStream();
|
||||||
$output = new MockProtocolStream;
|
$output = new MockProtocolStream();
|
||||||
$output->on('message', function (Message $msg) use ($promise) {
|
$output->on('message', function (Message $msg) use ($promise) {
|
||||||
if ($msg->body->method === 'window/logMessage' && $promise->state === Promise::PENDING) {
|
if ($msg->body->method === 'window/logMessage' && $promise->state === Promise::PENDING) {
|
||||||
if ($msg->body->params->type === MessageType::ERROR) {
|
if ($msg->body->params->type === MessageType::ERROR) {
|
||||||
|
@ -65,25 +65,32 @@ class LanguageServerTest extends TestCase
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$server = new LanguageServer($input, $output);
|
$server = new LanguageServer($input, $output);
|
||||||
$capabilities = new ClientCapabilities;
|
$capabilities = new ClientCapabilities();
|
||||||
$server->initialize($capabilities, realpath(__DIR__ . '/../fixtures'), getmypid());
|
$server->initialize($capabilities, realpath(__DIR__ . '/../fixtures'), getmypid());
|
||||||
$promise->wait();
|
$promise->wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIndexingWithFilesAndContentRequests()
|
public function testIndexingWithFilesAndContentRequests()
|
||||||
{
|
{
|
||||||
$promise = new Promise;
|
$promise = new Promise();
|
||||||
$filesCalled = false;
|
$filesCalled = false;
|
||||||
$contentCalled = false;
|
$contentCalled = false;
|
||||||
$rootPath = realpath(__DIR__ . '/../fixtures');
|
$rootPath = realpath(__DIR__ . '/../fixtures');
|
||||||
$input = new MockProtocolStream;
|
$input = new MockProtocolStream();
|
||||||
$output = new MockProtocolStream;
|
$output = new MockProtocolStream();
|
||||||
$run = 1;
|
$run = 1;
|
||||||
$output->on('message', function (Message $msg) use ($promise, $input, $rootPath, &$filesCalled, &$contentCalled, &$run) {
|
$output->on('message', function (Message $msg) use (
|
||||||
|
$promise,
|
||||||
|
$input,
|
||||||
|
$rootPath,
|
||||||
|
&$filesCalled,
|
||||||
|
&$contentCalled,
|
||||||
|
&$run
|
||||||
|
) {
|
||||||
if ($msg->body->method === 'textDocument/xcontent') {
|
if ($msg->body->method === 'textDocument/xcontent') {
|
||||||
// Document content requested
|
// Document content requested
|
||||||
$contentCalled = true;
|
$contentCalled = true;
|
||||||
$textDocumentItem = new TextDocumentItem;
|
$textDocumentItem = new TextDocumentItem();
|
||||||
$textDocumentItem->uri = $msg->body->params->textDocument->uri;
|
$textDocumentItem->uri = $msg->body->params->textDocument->uri;
|
||||||
$textDocumentItem->version = 1;
|
$textDocumentItem->version = 1;
|
||||||
$textDocumentItem->languageId = 'php';
|
$textDocumentItem->languageId = 'php';
|
||||||
|
@ -111,7 +118,7 @@ class LanguageServerTest extends TestCase
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$server = new LanguageServer($input, $output);
|
$server = new LanguageServer($input, $output);
|
||||||
$capabilities = new ClientCapabilities;
|
$capabilities = new ClientCapabilities();
|
||||||
$capabilities->xfilesProvider = true;
|
$capabilities->xfilesProvider = true;
|
||||||
$capabilities->xcontentProvider = true;
|
$capabilities->xcontentProvider = true;
|
||||||
$server->initialize($capabilities, $rootPath, getmypid());
|
$server->initialize($capabilities, $rootPath, getmypid());
|
||||||
|
|
|
@ -5,9 +5,7 @@ namespace LanguageServer\Tests\Server\TextDocument;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use phpDocumentor\Reflection\DocBlockFactory;
|
use phpDocumentor\Reflection\DocBlockFactory;
|
||||||
use LanguageServer\{
|
use LanguageServer\{DefinitionResolver, TreeAnalyzer};
|
||||||
DefinitionResolver, TreeAnalyzer
|
|
||||||
};
|
|
||||||
use LanguageServer\Index\{Index};
|
use LanguageServer\Index\{Index};
|
||||||
use function LanguageServer\pathToUri;
|
use function LanguageServer\pathToUri;
|
||||||
use Microsoft\PhpParser;
|
use Microsoft\PhpParser;
|
||||||
|
@ -20,7 +18,8 @@ class DefinitionCollectorTest extends TestCase
|
||||||
$path = realpath(__DIR__ . '/../../fixtures/symbols.php');
|
$path = realpath(__DIR__ . '/../../fixtures/symbols.php');
|
||||||
$defNodes = $this->collectDefinitions($path);
|
$defNodes = $this->collectDefinitions($path);
|
||||||
|
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
|
[
|
||||||
'TestNamespace',
|
'TestNamespace',
|
||||||
'TestNamespace\\TEST_CONST',
|
'TestNamespace\\TEST_CONST',
|
||||||
'TestNamespace\\TestClass',
|
'TestNamespace\\TestClass',
|
||||||
|
@ -37,16 +36,24 @@ class DefinitionCollectorTest extends TestCase
|
||||||
'TestNamespace\\Example->__construct()',
|
'TestNamespace\\Example->__construct()',
|
||||||
'TestNamespace\\Example->__destruct()',
|
'TestNamespace\\Example->__destruct()',
|
||||||
'TestNamespace\\InnerNamespace',
|
'TestNamespace\\InnerNamespace',
|
||||||
'TestNamespace\\InnerNamespace\\InnerClass',
|
'TestNamespace\\InnerNamespace\\InnerClass'
|
||||||
], array_keys($defNodes));
|
],
|
||||||
|
array_keys($defNodes)
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(Node\ConstElement::class, $defNodes['TestNamespace\\TEST_CONST']);
|
$this->assertInstanceOf(Node\ConstElement::class, $defNodes['TestNamespace\\TEST_CONST']);
|
||||||
$this->assertInstanceOf(Node\Statement\ClassDeclaration::class, $defNodes['TestNamespace\\TestClass']);
|
$this->assertInstanceOf(Node\Statement\ClassDeclaration::class, $defNodes['TestNamespace\\TestClass']);
|
||||||
$this->assertInstanceOf(Node\ConstElement::class, $defNodes['TestNamespace\\TestClass::TEST_CLASS_CONST']);
|
$this->assertInstanceOf(Node\ConstElement::class, $defNodes['TestNamespace\\TestClass::TEST_CLASS_CONST']);
|
||||||
// TODO - should we parse properties more strictly?
|
// TODO - should we parse properties more strictly?
|
||||||
$this->assertInstanceOf(Node\Expression\Variable::class, $defNodes['TestNamespace\\TestClass::$staticTestProperty']);
|
$this->assertInstanceOf(
|
||||||
|
Node\Expression\Variable::class,
|
||||||
|
$defNodes['TestNamespace\\TestClass::$staticTestProperty']
|
||||||
|
);
|
||||||
$this->assertInstanceOf(Node\Expression\Variable::class, $defNodes['TestNamespace\\TestClass->testProperty']);
|
$this->assertInstanceOf(Node\Expression\Variable::class, $defNodes['TestNamespace\\TestClass->testProperty']);
|
||||||
$this->assertInstanceOf(Node\MethodDeclaration::class, $defNodes['TestNamespace\\TestClass::staticTestMethod()']);
|
$this->assertInstanceOf(
|
||||||
|
Node\MethodDeclaration::class,
|
||||||
|
$defNodes['TestNamespace\\TestClass::staticTestMethod()']
|
||||||
|
);
|
||||||
$this->assertInstanceOf(Node\MethodDeclaration::class, $defNodes['TestNamespace\\TestClass->testMethod()']);
|
$this->assertInstanceOf(Node\MethodDeclaration::class, $defNodes['TestNamespace\\TestClass->testMethod()']);
|
||||||
$this->assertInstanceOf(Node\Statement\TraitDeclaration::class, $defNodes['TestNamespace\\TestTrait']);
|
$this->assertInstanceOf(Node\Statement\TraitDeclaration::class, $defNodes['TestNamespace\\TestTrait']);
|
||||||
$this->assertInstanceOf(Node\Statement\InterfaceDeclaration::class, $defNodes['TestNamespace\\TestInterface']);
|
$this->assertInstanceOf(Node\Statement\InterfaceDeclaration::class, $defNodes['TestNamespace\\TestInterface']);
|
||||||
|
@ -55,7 +62,10 @@ class DefinitionCollectorTest extends TestCase
|
||||||
$this->assertInstanceOf(Node\Statement\ClassDeclaration::class, $defNodes['TestNamespace\\Example']);
|
$this->assertInstanceOf(Node\Statement\ClassDeclaration::class, $defNodes['TestNamespace\\Example']);
|
||||||
$this->assertInstanceOf(Node\MethodDeclaration::class, $defNodes['TestNamespace\\Example->__construct()']);
|
$this->assertInstanceOf(Node\MethodDeclaration::class, $defNodes['TestNamespace\\Example->__construct()']);
|
||||||
$this->assertInstanceOf(Node\MethodDeclaration::class, $defNodes['TestNamespace\\Example->__destruct()']);
|
$this->assertInstanceOf(Node\MethodDeclaration::class, $defNodes['TestNamespace\\Example->__destruct()']);
|
||||||
$this->assertInstanceOf(Node\Statement\ClassDeclaration::class, $defNodes['TestNamespace\\InnerNamespace\\InnerClass']);
|
$this->assertInstanceOf(
|
||||||
|
Node\Statement\ClassDeclaration::class,
|
||||||
|
$defNodes['TestNamespace\\InnerNamespace\\InnerClass']
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDoesNotCollectReferences()
|
public function testDoesNotCollectReferences()
|
||||||
|
@ -77,7 +87,7 @@ class DefinitionCollectorTest extends TestCase
|
||||||
$parser = new PhpParser\Parser();
|
$parser = new PhpParser\Parser();
|
||||||
|
|
||||||
$docBlockFactory = DocBlockFactory::createInstance();
|
$docBlockFactory = DocBlockFactory::createInstance();
|
||||||
$index = new Index;
|
$index = new Index();
|
||||||
$definitionResolver = new DefinitionResolver($index);
|
$definitionResolver = new DefinitionResolver($index);
|
||||||
$content = file_get_contents($path);
|
$content = file_get_contents($path);
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,9 @@ declare(strict_types = 1);
|
||||||
|
|
||||||
namespace LanguageServer\Tests\Server;
|
namespace LanguageServer\Tests\Server;
|
||||||
|
|
||||||
use LanguageServer\{
|
use LanguageServer\{PhpDocument, PhpDocumentLoader, Project, DefinitionResolver};
|
||||||
PhpDocument, PhpDocumentLoader, Project, DefinitionResolver
|
|
||||||
};
|
|
||||||
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
||||||
use LanguageServer\Index\{
|
use LanguageServer\Index\{DependenciesIndex, Index, ProjectIndex};
|
||||||
DependenciesIndex, Index, ProjectIndex
|
|
||||||
};
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use function LanguageServer\pathToUri;
|
use function LanguageServer\pathToUri;
|
||||||
|
|
||||||
|
@ -22,9 +18,9 @@ class PhpDocumentLoaderTest extends TestCase
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
$projectIndex = new ProjectIndex(new Index, new DependenciesIndex);
|
$projectIndex = new ProjectIndex(new Index(), new DependenciesIndex());
|
||||||
$this->loader = new PhpDocumentLoader(
|
$this->loader = new PhpDocumentLoader(
|
||||||
new FileSystemContentRetriever,
|
new FileSystemContentRetriever(),
|
||||||
$projectIndex,
|
$projectIndex,
|
||||||
new DefinitionResolver($projectIndex)
|
new DefinitionResolver($projectIndex)
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,15 +3,9 @@ declare(strict_types = 1);
|
||||||
|
|
||||||
namespace LanguageServer\Tests\Server;
|
namespace LanguageServer\Tests\Server;
|
||||||
|
|
||||||
use LanguageServer\{
|
use LanguageServer\{PhpDocument, DefinitionResolver};
|
||||||
PhpDocument, DefinitionResolver
|
use LanguageServer\Index\{Index};
|
||||||
};
|
use LanguageServerProtocol\{Position};
|
||||||
use LanguageServer\Index\{
|
|
||||||
Index
|
|
||||||
};
|
|
||||||
use LanguageServerProtocol\{
|
|
||||||
Position
|
|
||||||
};
|
|
||||||
use Microsoft\PhpParser;
|
use Microsoft\PhpParser;
|
||||||
use Microsoft\PhpParser\Node;
|
use Microsoft\PhpParser\Node;
|
||||||
use phpDocumentor\Reflection\DocBlockFactory;
|
use phpDocumentor\Reflection\DocBlockFactory;
|
||||||
|
@ -24,7 +18,7 @@ class PhpDocumentTest extends TestCase
|
||||||
{
|
{
|
||||||
$parser = new PhpParser\Parser();
|
$parser = new PhpParser\Parser();
|
||||||
$docBlockFactory = DocBlockFactory::createInstance();
|
$docBlockFactory = DocBlockFactory::createInstance();
|
||||||
$index = new Index;
|
$index = new Index();
|
||||||
$definitionResolver = new DefinitionResolver($index);
|
$definitionResolver = new DefinitionResolver($index);
|
||||||
return new PhpDocument($uri, $content, $index, $parser, $docBlockFactory, $definitionResolver);
|
return new PhpDocument($uri, $content, $index, $parser, $docBlockFactory, $definitionResolver);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,7 @@ namespace LanguageServer\Tests\Server;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use LanguageServer\Tests\MockProtocolStream;
|
use LanguageServer\Tests\MockProtocolStream;
|
||||||
use LanguageServer\{
|
use LanguageServer\{Server, LanguageClient, PhpDocumentLoader, DefinitionResolver};
|
||||||
Server, LanguageClient, PhpDocumentLoader, DefinitionResolver
|
|
||||||
};
|
|
||||||
use LanguageServer\Index\{ProjectIndex, DependenciesIndex, Index};
|
use LanguageServer\Index\{ProjectIndex, DependenciesIndex, Index};
|
||||||
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
||||||
use LanguageServerProtocol\{Position, Location, Range};
|
use LanguageServerProtocol\{Position, Location, Range};
|
||||||
|
@ -46,16 +44,32 @@ abstract class ServerTestCase extends TestCase
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
$sourceIndex = new Index;
|
$sourceIndex = new Index();
|
||||||
$dependenciesIndex = new DependenciesIndex;
|
$dependenciesIndex = new DependenciesIndex();
|
||||||
$projectIndex = new ProjectIndex($sourceIndex, $dependenciesIndex);
|
$projectIndex = new ProjectIndex($sourceIndex, $dependenciesIndex);
|
||||||
$projectIndex->setComplete();
|
$projectIndex->setComplete();
|
||||||
|
|
||||||
$definitionResolver = new DefinitionResolver($projectIndex);
|
$definitionResolver = new DefinitionResolver($projectIndex);
|
||||||
$client = new LanguageClient(new MockProtocolStream, new MockProtocolStream);
|
$client = new LanguageClient(new MockProtocolStream(), new MockProtocolStream());
|
||||||
$this->documentLoader = new PhpDocumentLoader(new FileSystemContentRetriever, $projectIndex, $definitionResolver);
|
$this->documentLoader = new PhpDocumentLoader(
|
||||||
$this->textDocument = new Server\TextDocument($this->documentLoader, $definitionResolver, $client, $projectIndex);
|
new FileSystemContentRetriever(),
|
||||||
$this->workspace = new Server\Workspace($client, $projectIndex, $dependenciesIndex, $sourceIndex, null, $this->documentLoader);
|
$projectIndex,
|
||||||
|
$definitionResolver
|
||||||
|
);
|
||||||
|
$this->textDocument = new Server\TextDocument(
|
||||||
|
$this->documentLoader,
|
||||||
|
$definitionResolver,
|
||||||
|
$client,
|
||||||
|
$projectIndex
|
||||||
|
);
|
||||||
|
$this->workspace = new Server\Workspace(
|
||||||
|
$client,
|
||||||
|
$projectIndex,
|
||||||
|
$dependenciesIndex,
|
||||||
|
$sourceIndex,
|
||||||
|
null,
|
||||||
|
$this->documentLoader
|
||||||
|
);
|
||||||
|
|
||||||
$globalSymbolsUri = pathToUri(realpath(__DIR__ . '/../../fixtures/global_symbols.php'));
|
$globalSymbolsUri = pathToUri(realpath(__DIR__ . '/../../fixtures/global_symbols.php'));
|
||||||
$globalReferencesUri = pathToUri(realpath(__DIR__ . '/../../fixtures/global_references.php'));
|
$globalReferencesUri = pathToUri(realpath(__DIR__ . '/../../fixtures/global_references.php'));
|
||||||
|
@ -71,49 +85,122 @@ abstract class ServerTestCase extends TestCase
|
||||||
|
|
||||||
// @codingStandardsIgnoreStart
|
// @codingStandardsIgnoreStart
|
||||||
$this->definitionLocations = [
|
$this->definitionLocations = [
|
||||||
|
|
||||||
// Global
|
// Global
|
||||||
'TEST_DEFINE_CONSTANT' => new Location($globalSymbolsUri, new Range(new Position(104, 0), new Position(104, 37))),
|
'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))),
|
'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))),
|
'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))),
|
'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))),
|
'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))),
|
'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::TEST_CLASS_CONST' => new Location(
|
||||||
'TestClass::testProperty' => new Location($globalSymbolsUri, new Range(new Position(41, 11), new Position(41, 24))),
|
$globalSymbolsUri,
|
||||||
'TestClass::staticTestProperty' => new Location($globalSymbolsUri, new Range(new Position(34, 18), new Position(34, 37))),
|
new Range(new Position(27, 10), new Position(27, 32))
|
||||||
'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))),
|
'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))),
|
'test_function()' => new Location($globalSymbolsUri, new Range(new Position(78, 0), new Position(81, 1))),
|
||||||
'UnusedClass' => new Location($globalSymbolsUri, new Range(new Position(111, 0), new Position(118, 1))),
|
'UnusedClass' => new Location($globalSymbolsUri, new Range(new Position(111, 0), new Position(118, 1))),
|
||||||
'UnusedClass::unusedProperty' => new Location($globalSymbolsUri, new Range(new Position(113,11), new Position(113, 26))),
|
'UnusedClass::unusedProperty' => new Location(
|
||||||
'UnusedClass::unusedMethod' => new Location($globalSymbolsUri, new Range(new Position(115, 4), new Position(117, 5))),
|
$globalSymbolsUri,
|
||||||
|
new Range(new Position(113, 11), new Position(113, 26))
|
||||||
|
),
|
||||||
|
'UnusedClass::unusedMethod' => new Location(
|
||||||
|
$globalSymbolsUri,
|
||||||
|
new Range(new Position(115, 4), new Position(117, 5))
|
||||||
|
),
|
||||||
'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))),
|
||||||
|
|
||||||
// Namespaced
|
// Namespaced
|
||||||
'TestNamespace' => new Location($symbolsUri, new Range(new Position(2, 0), new Position(2, 24))),
|
'TestNamespace' => new Location($symbolsUri, new Range(new Position(2, 0), new Position(2, 24))),
|
||||||
'SecondTestNamespace' => new Location($useUri, new Range(new Position(2, 0), new Position(2, 30))),
|
'SecondTestNamespace' => new Location($useUri, new Range(new Position(2, 0), new Position(2, 30))),
|
||||||
'TestNamespace\\TEST_CONST' => new Location($symbolsUri, new Range(new Position( 9, 6), new Position( 9, 22))),
|
'TestNamespace\\TEST_CONST' => new Location(
|
||||||
'TestNamespace\\TestClass' => new Location($symbolsUri, new Range(new Position(20, 0), new Position(61, 1))),
|
$symbolsUri,
|
||||||
'TestNamespace\\ChildClass' => new Location($symbolsUri, new Range(new Position(99, 0), new Position(99, 37))),
|
new Range(new Position(9, 6), new Position(9, 22))
|
||||||
'TestNamespace\\TestTrait' => new Location($symbolsUri, new Range(new Position(63, 0), new Position(66, 1))),
|
),
|
||||||
'TestNamespace\\TestInterface' => new Location($symbolsUri, new Range(new Position(68, 0), new Position(71, 1))),
|
'TestNamespace\\TestClass' => new Location(
|
||||||
'TestNamespace\\TestClass::TEST_CLASS_CONST' => new Location($symbolsUri, new Range(new Position(27, 10), new Position(27, 32))),
|
$symbolsUri,
|
||||||
'TestNamespace\\TestClass::testProperty' => new Location($symbolsUri, new Range(new Position(41, 11), new Position(41, 24))),
|
new Range(new Position(20, 0), new Position(61, 1))
|
||||||
'TestNamespace\\TestClass::staticTestProperty' => new Location($symbolsUri, new Range(new Position(34, 18), new Position(34, 37))),
|
),
|
||||||
'TestNamespace\\TestClass::staticTestMethod()' => new Location($symbolsUri, new Range(new Position(46, 4), new Position(49, 5))),
|
'TestNamespace\\ChildClass' => new Location(
|
||||||
'TestNamespace\\TestClass::testMethod()' => new Location($symbolsUri, new Range(new Position(57, 4), new Position(60, 5))),
|
$symbolsUri,
|
||||||
'TestNamespace\\test_function()' => new Location($symbolsUri, new Range(new Position(78, 0), new Position(81, 1))),
|
new Range(new Position(99, 0), new Position(99, 37))
|
||||||
'TestNamespace\\whatever()' => new Location($referencesUri, new Range(new Position(21, 0), new Position(23, 1))),
|
),
|
||||||
'TestNamespace\\Example' => new Location($symbolsUri, new Range(new Position(101, 0), new Position(104, 1))),
|
'TestNamespace\\TestTrait' => new Location(
|
||||||
'TestNamespace\\Example::__construct' => new Location($symbolsUri, new Range(new Position(102, 4), new Position(102, 36))),
|
$symbolsUri,
|
||||||
'TestNamespace\\Example::__destruct' => new Location($symbolsUri, new Range(new Position(103, 4), new Position(103, 35))),
|
new Range(new Position(63, 0), new Position(66, 1))
|
||||||
'TestNamespace\\InnerNamespace' => new Location($symbolsUri, new Range(new Position(106, 0), new Position(106, 39))),
|
),
|
||||||
'TestNamespace\\InnerNamespace\\InnerClass' => new Location($symbolsUri, new Range(new Position(108, 0), new Position(109, 1))),
|
'TestNamespace\\TestInterface' => new Location(
|
||||||
|
$symbolsUri,
|
||||||
|
new Range(new Position(68, 0), new Position(71, 1))
|
||||||
|
),
|
||||||
|
'TestNamespace\\TestClass::TEST_CLASS_CONST' => new Location(
|
||||||
|
$symbolsUri,
|
||||||
|
new Range(new Position(27, 10), new Position(27, 32))
|
||||||
|
),
|
||||||
|
'TestNamespace\\TestClass::testProperty' => new Location(
|
||||||
|
$symbolsUri,
|
||||||
|
new Range(new Position(41, 11), new Position(41, 24))
|
||||||
|
),
|
||||||
|
'TestNamespace\\TestClass::staticTestProperty' => new Location(
|
||||||
|
$symbolsUri,
|
||||||
|
new Range(new Position(34, 18), new Position(34, 37))
|
||||||
|
),
|
||||||
|
'TestNamespace\\TestClass::staticTestMethod()' => new Location(
|
||||||
|
$symbolsUri,
|
||||||
|
new Range(new Position(46, 4), new Position(49, 5))
|
||||||
|
),
|
||||||
|
'TestNamespace\\TestClass::testMethod()' => new Location(
|
||||||
|
$symbolsUri,
|
||||||
|
new Range(new Position(57, 4), new Position(60, 5))
|
||||||
|
),
|
||||||
|
'TestNamespace\\test_function()' => new Location(
|
||||||
|
$symbolsUri,
|
||||||
|
new Range(new Position(78, 0), new Position(81, 1))
|
||||||
|
),
|
||||||
|
'TestNamespace\\whatever()' => new Location(
|
||||||
|
$referencesUri,
|
||||||
|
new Range(new Position(21, 0), new Position(23, 1))
|
||||||
|
),
|
||||||
|
'TestNamespace\\Example' => new Location(
|
||||||
|
$symbolsUri,
|
||||||
|
new Range(new Position(101, 0), new Position(104, 1))
|
||||||
|
),
|
||||||
|
'TestNamespace\\Example::__construct' => new Location(
|
||||||
|
$symbolsUri,
|
||||||
|
new Range(new Position(102, 4), new Position(102, 36))
|
||||||
|
),
|
||||||
|
'TestNamespace\\Example::__destruct' => new Location(
|
||||||
|
$symbolsUri,
|
||||||
|
new Range(new Position(103, 4), new Position(103, 35))
|
||||||
|
),
|
||||||
|
'TestNamespace\\InnerNamespace' => new Location(
|
||||||
|
$symbolsUri,
|
||||||
|
new Range(new Position(106, 0), new Position(106, 39))
|
||||||
|
),
|
||||||
|
'TestNamespace\\InnerNamespace\\InnerClass' => new Location(
|
||||||
|
$symbolsUri,
|
||||||
|
new Range(new Position(108, 0), new Position(109, 1))
|
||||||
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->referenceLocations = [
|
$this->referenceLocations = [
|
||||||
|
|
||||||
// Namespaced
|
// Namespaced
|
||||||
'TestNamespace' => [
|
'TestNamespace' => [
|
||||||
0 => new Location($referencesUri, new Range(new Position(31, 13), new Position(31, 40))), // use function TestNamespace\test_function;
|
0 => new Location($referencesUri, new Range(new Position(31, 13), new Position(31, 40))), // use function TestNamespace\test_function;
|
||||||
|
@ -133,10 +220,10 @@ abstract class ServerTestCase extends TestCase
|
||||||
6 => new Location($referencesUri, new Range(new Position(21, 18), new Position(21, 27))), // function whatever(TestClass $param)
|
6 => new Location($referencesUri, new Range(new Position(21, 18), new Position(21, 27))), // function whatever(TestClass $param)
|
||||||
7 => new Location($referencesUri, new Range(new Position(21, 37), new Position(21, 46))), // function whatever(TestClass $param): TestClass
|
7 => new Location($referencesUri, new Range(new Position(21, 37), new Position(21, 46))), // function whatever(TestClass $param): TestClass
|
||||||
8 => new Location($referencesUri, new Range(new Position(39, 0), new Position(39, 9))), // TestClass::$staticTestProperty[123]->testProperty;
|
8 => new Location($referencesUri, new Range(new Position(39, 0), new Position(39, 9))), // TestClass::$staticTestProperty[123]->testProperty;
|
||||||
9 => new Location($useUri, new Range(new Position( 4, 4), new Position( 4, 27))), // use TestNamespace\TestClass;
|
9 => new Location($useUri, new Range(new Position(4, 4), new Position(4, 27))) // use TestNamespace\TestClass;
|
||||||
],
|
],
|
||||||
'TestNamespace\\TestChild' => [
|
'TestNamespace\\TestChild' => [
|
||||||
0 => new Location($referencesUri, new Range(new Position(42, 5), new Position(42, 25))), // echo $child->testProperty;
|
0 => new Location($referencesUri, new Range(new Position(42, 5), new Position(42, 25))) // echo $child->testProperty;
|
||||||
],
|
],
|
||||||
'TestNamespace\\TestInterface' => [
|
'TestNamespace\\TestInterface' => [
|
||||||
0 => new Location($symbolsUri, new Range(new Position(20, 27), new Position(20, 40))), // class TestClass implements TestInterface
|
0 => new Location($symbolsUri, new Range(new Position(20, 27), new Position(20, 40))), // class TestClass implements TestInterface
|
||||||
|
@ -187,10 +274,10 @@ abstract class ServerTestCase extends TestCase
|
||||||
5 => new Location($globalReferencesUri, new Range(new Position(9, 5), new Position(9, 14))), // TestClass::TEST_CLASS_CONST;
|
5 => new Location($globalReferencesUri, new Range(new Position(9, 5), new Position(9, 14))), // TestClass::TEST_CLASS_CONST;
|
||||||
6 => new Location($globalReferencesUri, new Range(new Position(21, 18), new Position(21, 27))), // function whatever(TestClass $param)
|
6 => new Location($globalReferencesUri, new Range(new Position(21, 18), new Position(21, 27))), // function whatever(TestClass $param)
|
||||||
7 => new Location($globalReferencesUri, new Range(new Position(21, 37), new Position(21, 46))), // function whatever(TestClass $param): TestClass
|
7 => new Location($globalReferencesUri, new Range(new Position(21, 37), new Position(21, 46))), // function whatever(TestClass $param): TestClass
|
||||||
8 => new Location($globalReferencesUri, new Range(new Position(39, 0), new Position(39, 9))), // TestClass::$staticTestProperty[123]->testProperty;
|
8 => new Location($globalReferencesUri, new Range(new Position(39, 0), new Position(39, 9))) // TestClass::$staticTestProperty[123]->testProperty;
|
||||||
],
|
],
|
||||||
'TestChild' => [
|
'TestChild' => [
|
||||||
0 => new Location($globalReferencesUri, new Range(new Position(42, 5), new Position(42, 25))), // echo $child->testProperty;
|
0 => new Location($globalReferencesUri, new Range(new Position(42, 5), new Position(42, 25))) // echo $child->testProperty;
|
||||||
],
|
],
|
||||||
'TestInterface' => [
|
'TestInterface' => [
|
||||||
0 => new Location($globalSymbolsUri, new Range(new Position(20, 27), new Position(20, 40))), // class TestClass implements TestInterface
|
0 => new Location($globalSymbolsUri, new Range(new Position(20, 27), new Position(20, 40))), // class TestClass implements TestInterface
|
||||||
|
|
|
@ -5,9 +5,7 @@ namespace LanguageServer\Tests\Server\TextDocument;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use LanguageServer\Tests\MockProtocolStream;
|
use LanguageServer\Tests\MockProtocolStream;
|
||||||
use LanguageServer\{
|
use LanguageServer\{Server, LanguageClient, PhpDocumentLoader, DefinitionResolver};
|
||||||
Server, LanguageClient, PhpDocumentLoader, DefinitionResolver
|
|
||||||
};
|
|
||||||
use LanguageServer\Index\{Index, ProjectIndex, DependenciesIndex};
|
use LanguageServer\Index\{Index, ProjectIndex, DependenciesIndex};
|
||||||
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
||||||
use LanguageServerProtocol\{
|
use LanguageServerProtocol\{
|
||||||
|
@ -37,10 +35,10 @@ class CompletionTest extends TestCase
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
$client = new LanguageClient(new MockProtocolStream, new MockProtocolStream);
|
$client = new LanguageClient(new MockProtocolStream(), new MockProtocolStream());
|
||||||
$projectIndex = new ProjectIndex(new Index, new DependenciesIndex);
|
$projectIndex = new ProjectIndex(new Index(), new DependenciesIndex());
|
||||||
$definitionResolver = new DefinitionResolver($projectIndex);
|
$definitionResolver = new DefinitionResolver($projectIndex);
|
||||||
$contentRetriever = new FileSystemContentRetriever;
|
$contentRetriever = new FileSystemContentRetriever();
|
||||||
$this->loader = new PhpDocumentLoader($contentRetriever, $projectIndex, $definitionResolver);
|
$this->loader = new PhpDocumentLoader($contentRetriever, $projectIndex, $definitionResolver);
|
||||||
$this->loader->load(pathToUri(__DIR__ . '/../../../fixtures/global_symbols.php'))->wait();
|
$this->loader->load(pathToUri(__DIR__ . '/../../../fixtures/global_symbols.php'))->wait();
|
||||||
$this->loader->load(pathToUri(__DIR__ . '/../../../fixtures/symbols.php'))->wait();
|
$this->loader->load(pathToUri(__DIR__ . '/../../../fixtures/symbols.php'))->wait();
|
||||||
|
@ -54,11 +52,12 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/property_with_prefix.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/property_with_prefix.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(3, 7))
|
||||||
new Position(3, 7)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'testProperty',
|
'testProperty',
|
||||||
CompletionItemKind::PROPERTY,
|
CompletionItemKind::PROPERTY,
|
||||||
|
@ -71,7 +70,11 @@ class CompletionTest extends TestCase
|
||||||
'\TestClass', // Return type of the method
|
'\TestClass', // Return type of the method
|
||||||
'Non culpa nostrud mollit esse sunt laboris in irure ullamco cupidatat amet.'
|
'Non culpa nostrud mollit esse sunt laboris in irure ullamco cupidatat amet.'
|
||||||
)
|
)
|
||||||
], true), $items);
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -81,11 +84,12 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/inside_namespace_and_method.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/inside_namespace_and_method.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(8, 11))
|
||||||
new Position(8, 11)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'test_function',
|
'test_function',
|
||||||
CompletionItemKind::FUNCTION,
|
CompletionItemKind::FUNCTION,
|
||||||
|
@ -95,7 +99,11 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
'\test_function'
|
'\test_function'
|
||||||
)
|
)
|
||||||
], true), $items);
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -105,11 +113,12 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/property.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/property.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(3, 6))
|
||||||
new Position(3, 6)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'testProperty',
|
'testProperty',
|
||||||
CompletionItemKind::PROPERTY,
|
CompletionItemKind::PROPERTY,
|
||||||
|
@ -122,7 +131,11 @@ class CompletionTest extends TestCase
|
||||||
'\TestClass', // Return type of the method
|
'\TestClass', // Return type of the method
|
||||||
'Non culpa nostrud mollit esse sunt laboris in irure ullamco cupidatat amet.'
|
'Non culpa nostrud mollit esse sunt laboris in irure ullamco cupidatat amet.'
|
||||||
)
|
)
|
||||||
], true), $items);
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -132,11 +145,12 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/variable.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/variable.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(8, 5))
|
||||||
new Position(8, 5)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'$var',
|
'$var',
|
||||||
CompletionItemKind::VARIABLE,
|
CompletionItemKind::VARIABLE,
|
||||||
|
@ -157,7 +171,11 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
new TextEdit(new Range(new Position(8, 5), new Position(8, 5)), 'param')
|
new TextEdit(new Range(new Position(8, 5), new Position(8, 5)), 'param')
|
||||||
)
|
)
|
||||||
], true), $items);
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -167,11 +185,12 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/variable_with_prefix.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/variable_with_prefix.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(8, 6))
|
||||||
new Position(8, 6)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'$param',
|
'$param',
|
||||||
CompletionItemKind::VARIABLE,
|
CompletionItemKind::VARIABLE,
|
||||||
|
@ -182,7 +201,11 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
new TextEdit(new Range(new Position(8, 6), new Position(8, 6)), 'aram')
|
new TextEdit(new Range(new Position(8, 6), new Position(8, 6)), 'aram')
|
||||||
)
|
)
|
||||||
], true), $items);
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -192,51 +215,58 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/used_new.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/used_new.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(6, 10))
|
||||||
new Position(6, 10)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
// Global TestClass definition (inserted as \TestClass)
|
// Global TestClass definition (inserted as \TestClass)
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'TestClass',
|
'TestClass',
|
||||||
CompletionItemKind::CLASS_,
|
CompletionItemKind::CLASS_,
|
||||||
null,
|
null,
|
||||||
'Pariatur ut laborum tempor voluptate consequat ea deserunt.' . "\n\n" .
|
'Pariatur ut laborum tempor voluptate consequat ea deserunt.' .
|
||||||
'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' . "\n" .
|
"\n\n" .
|
||||||
'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' . "\n" .
|
'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' .
|
||||||
'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' . "\n" .
|
"\n" .
|
||||||
'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' . "\n" .
|
'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' .
|
||||||
|
"\n" .
|
||||||
|
'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' .
|
||||||
|
"\n" .
|
||||||
|
'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' .
|
||||||
|
"\n" .
|
||||||
'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.',
|
'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.',
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
'\TestClass'
|
'\TestClass'
|
||||||
),
|
),
|
||||||
new CompletionItem(
|
new CompletionItem('ChildClass', CompletionItemKind::CLASS_, null, null, null, null, '\ChildClass'),
|
||||||
'ChildClass',
|
|
||||||
CompletionItemKind::CLASS_,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
'\ChildClass'
|
|
||||||
),
|
|
||||||
// Namespaced, `use`d TestClass definition (inserted as TestClass)
|
// Namespaced, `use`d TestClass definition (inserted as TestClass)
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'TestClass',
|
'TestClass',
|
||||||
CompletionItemKind::CLASS_,
|
CompletionItemKind::CLASS_,
|
||||||
'TestNamespace',
|
'TestNamespace',
|
||||||
'Pariatur ut laborum tempor voluptate consequat ea deserunt.' . "\n\n" .
|
'Pariatur ut laborum tempor voluptate consequat ea deserunt.' .
|
||||||
'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' . "\n" .
|
"\n\n" .
|
||||||
'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' . "\n" .
|
'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' .
|
||||||
'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' . "\n" .
|
"\n" .
|
||||||
'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' . "\n" .
|
'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' .
|
||||||
|
"\n" .
|
||||||
|
'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' .
|
||||||
|
"\n" .
|
||||||
|
'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' .
|
||||||
|
"\n" .
|
||||||
'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.',
|
'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.',
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
'TestClass'
|
'TestClass'
|
||||||
|
)
|
||||||
|
],
|
||||||
|
true
|
||||||
),
|
),
|
||||||
], true), $items);
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -246,26 +276,36 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/used_class.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/used_class.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(6, 5))
|
||||||
new Position(6, 5)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'TestClass',
|
'TestClass',
|
||||||
CompletionItemKind::CLASS_,
|
CompletionItemKind::CLASS_,
|
||||||
'TestNamespace',
|
'TestNamespace',
|
||||||
'Pariatur ut laborum tempor voluptate consequat ea deserunt.' . "\n\n" .
|
'Pariatur ut laborum tempor voluptate consequat ea deserunt.' .
|
||||||
'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' . "\n" .
|
"\n\n" .
|
||||||
'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' . "\n" .
|
'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' .
|
||||||
'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' . "\n" .
|
"\n" .
|
||||||
'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' . "\n" .
|
'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' .
|
||||||
|
"\n" .
|
||||||
|
'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' .
|
||||||
|
"\n" .
|
||||||
|
'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' .
|
||||||
|
"\n" .
|
||||||
'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.',
|
'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.',
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
'TestClass'
|
'TestClass'
|
||||||
)
|
)
|
||||||
], true), $items);
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
$items
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertCompletionsListDoesNotContainLabel('OtherClass', $items);
|
$this->assertCompletionsListDoesNotContainLabel('OtherClass', $items);
|
||||||
$this->assertCompletionsListDoesNotContainLabel('TestInterface', $items);
|
$this->assertCompletionsListDoesNotContainLabel('TestInterface', $items);
|
||||||
|
@ -278,12 +318,12 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/used_namespace.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/used_namespace.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(8, 16))
|
||||||
new Position(8, 16)
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'InnerClass',
|
'InnerClass',
|
||||||
CompletionItemKind::CLASS_,
|
CompletionItemKind::CLASS_,
|
||||||
|
@ -293,7 +333,9 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
'AliasNamespace\\InnerClass'
|
'AliasNamespace\\InnerClass'
|
||||||
)
|
)
|
||||||
], true),
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
$items
|
$items
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -305,12 +347,12 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/used_namespace.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/used_namespace.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(9, 15))
|
||||||
new Position(9, 15)
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'InnerClass',
|
'InnerClass',
|
||||||
CompletionItemKind::CLASS_,
|
CompletionItemKind::CLASS_,
|
||||||
|
@ -319,8 +361,10 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
'AliasNamespace\InnerClass'
|
'AliasNamespace\InnerClass'
|
||||||
|
)
|
||||||
|
],
|
||||||
|
true
|
||||||
),
|
),
|
||||||
], true),
|
|
||||||
$items
|
$items
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -332,11 +376,12 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/static_property_with_prefix.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/static_property_with_prefix.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(2, 14))
|
||||||
new Position(2, 14)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'staticTestProperty',
|
'staticTestProperty',
|
||||||
CompletionItemKind::PROPERTY,
|
CompletionItemKind::PROPERTY,
|
||||||
|
@ -346,7 +391,11 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
'$staticTestProperty'
|
'$staticTestProperty'
|
||||||
)
|
)
|
||||||
], true), $items);
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -356,11 +405,12 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/static.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/static.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(2, 11))
|
||||||
new Position(2, 11)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'TEST_CLASS_CONST',
|
'TEST_CLASS_CONST',
|
||||||
CompletionItemKind::VARIABLE,
|
CompletionItemKind::VARIABLE,
|
||||||
|
@ -382,7 +432,11 @@ class CompletionTest extends TestCase
|
||||||
'mixed', // Method return type
|
'mixed', // Method return type
|
||||||
'Do magna consequat veniam minim proident eiusmod incididunt aute proident.'
|
'Do magna consequat veniam minim proident eiusmod incididunt aute proident.'
|
||||||
)
|
)
|
||||||
], true), $items);
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -392,18 +446,23 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/static_method_with_prefix.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/static_method_with_prefix.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(2, 13))
|
||||||
new Position(2, 13)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'staticTestMethod',
|
'staticTestMethod',
|
||||||
CompletionItemKind::METHOD,
|
CompletionItemKind::METHOD,
|
||||||
'mixed',
|
'mixed',
|
||||||
'Do magna consequat veniam minim proident eiusmod incididunt aute proident.'
|
'Do magna consequat veniam minim proident eiusmod incididunt aute proident.'
|
||||||
)
|
)
|
||||||
], true), $items);
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -413,18 +472,23 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/class_const_with_prefix.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/class_const_with_prefix.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(2, 13))
|
||||||
new Position(2, 13)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'TEST_CLASS_CONST',
|
'TEST_CLASS_CONST',
|
||||||
CompletionItemKind::VARIABLE,
|
CompletionItemKind::VARIABLE,
|
||||||
'int',
|
'int',
|
||||||
'Anim labore veniam consectetur laboris minim quis aute aute esse nulla ad.'
|
'Anim labore veniam consectetur laboris minim quis aute aute esse nulla ad.'
|
||||||
)
|
)
|
||||||
], true), $items);
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -434,23 +498,33 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/fully_qualified_class.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/fully_qualified_class.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(6, 6))
|
||||||
new Position(6, 6)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'TestClass',
|
'TestClass',
|
||||||
CompletionItemKind::CLASS_,
|
CompletionItemKind::CLASS_,
|
||||||
null,
|
null,
|
||||||
'Pariatur ut laborum tempor voluptate consequat ea deserunt.' . "\n\n" .
|
'Pariatur ut laborum tempor voluptate consequat ea deserunt.' .
|
||||||
'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' . "\n" .
|
"\n\n" .
|
||||||
'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' . "\n" .
|
'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' .
|
||||||
'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' . "\n" .
|
"\n" .
|
||||||
'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' . "\n" .
|
'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' .
|
||||||
|
"\n" .
|
||||||
|
'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' .
|
||||||
|
"\n" .
|
||||||
|
'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' .
|
||||||
|
"\n" .
|
||||||
'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.'
|
'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.'
|
||||||
)
|
)
|
||||||
], true), $items);
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
$items
|
||||||
|
);
|
||||||
// Assert that all results are non-namespaced.
|
// Assert that all results are non-namespaced.
|
||||||
foreach ($items->items as $item) {
|
foreach ($items->items as $item) {
|
||||||
$this->assertSame($item->detail, null);
|
$this->assertSame($item->detail, null);
|
||||||
|
@ -464,14 +538,19 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/keywords.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/keywords.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(2, 1))
|
||||||
new Position(2, 1)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem('class', CompletionItemKind::KEYWORD, null, null, null, null, 'class'),
|
new CompletionItem('class', CompletionItemKind::KEYWORD, null, null, null, null, 'class'),
|
||||||
new CompletionItem('clone', CompletionItemKind::KEYWORD, null, null, null, null, 'clone')
|
new CompletionItem('clone', CompletionItemKind::KEYWORD, null, null, null, null, 'clone')
|
||||||
], true), $items);
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -481,11 +560,12 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/html.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/html.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(0, 0))
|
||||||
new Position(0, 0)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'<?php',
|
'<?php',
|
||||||
CompletionItemKind::KEYWORD,
|
CompletionItemKind::KEYWORD,
|
||||||
|
@ -496,7 +576,11 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
new TextEdit(new Range(new Position(0, 0), new Position(0, 0)), '<?php')
|
new TextEdit(new Range(new Position(0, 0), new Position(0, 0)), '<?php')
|
||||||
)
|
)
|
||||||
], true), $items);
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -506,10 +590,9 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/html_with_prefix.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/html_with_prefix.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(0, 1))
|
||||||
new Position(0, 1)
|
->wait();
|
||||||
)->wait();
|
|
||||||
|
|
||||||
$this->assertEquals(new CompletionList([], true), $items);
|
$this->assertEquals(new CompletionList([], true), $items);
|
||||||
}
|
}
|
||||||
|
@ -521,13 +604,17 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/html_with_prefix.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/html_with_prefix.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
|
->completion(
|
||||||
new TextDocumentIdentifier($completionUri),
|
new TextDocumentIdentifier($completionUri),
|
||||||
new Position(0, 1),
|
new Position(0, 1),
|
||||||
new CompletionContext(CompletionTriggerKind::TRIGGER_CHARACTER, '<')
|
new CompletionContext(CompletionTriggerKind::TRIGGER_CHARACTER, '<')
|
||||||
)->wait();
|
)
|
||||||
|
->wait();
|
||||||
|
|
||||||
$this->assertEquals(new CompletionList([
|
$this->assertEquals(
|
||||||
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'<?php',
|
'<?php',
|
||||||
CompletionItemKind::KEYWORD,
|
CompletionItemKind::KEYWORD,
|
||||||
|
@ -538,7 +625,11 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
new TextEdit(new Range(new Position(0, 1), new Position(0, 1)), '?php')
|
new TextEdit(new Range(new Position(0, 1), new Position(0, 1)), '?php')
|
||||||
)
|
)
|
||||||
], true), $items);
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -548,11 +639,13 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/html_no_completion.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/html_no_completion.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
|
->completion(
|
||||||
new TextDocumentIdentifier($completionUri),
|
new TextDocumentIdentifier($completionUri),
|
||||||
new Position(0, 1),
|
new Position(0, 1),
|
||||||
new CompletionContext(CompletionTriggerKind::TRIGGER_CHARACTER, '>')
|
new CompletionContext(CompletionTriggerKind::TRIGGER_CHARACTER, '>')
|
||||||
)->wait();
|
)
|
||||||
|
->wait();
|
||||||
$this->assertEquals(new CompletionList([], true), $items);
|
$this->assertEquals(new CompletionList([], true), $items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,12 +656,16 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/html_no_completion.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/html_no_completion.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
|
->completion(
|
||||||
new TextDocumentIdentifier($completionUri),
|
new TextDocumentIdentifier($completionUri),
|
||||||
new Position(0, 1),
|
new Position(0, 1),
|
||||||
new CompletionContext(CompletionTriggerKind::INVOKED)
|
new CompletionContext(CompletionTriggerKind::INVOKED)
|
||||||
)->wait();
|
)
|
||||||
$this->assertEquals(new CompletionList([
|
->wait();
|
||||||
|
$this->assertEquals(
|
||||||
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'<?php',
|
'<?php',
|
||||||
CompletionItemKind::KEYWORD,
|
CompletionItemKind::KEYWORD,
|
||||||
|
@ -579,7 +676,11 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
new TextEdit(new Range(new Position(0, 1), new Position(0, 1)), '?php')
|
new TextEdit(new Range(new Position(0, 1), new Position(0, 1)), '?php')
|
||||||
)
|
)
|
||||||
], true), $items);
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -589,16 +690,13 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/namespace.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/namespace.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(4, 6))
|
||||||
new Position(4, 6)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList([new CompletionItem('SomeNamespace', CompletionItemKind::MODULE)], true),
|
||||||
new CompletionItem(
|
$items
|
||||||
'SomeNamespace',
|
);
|
||||||
CompletionItemKind::MODULE
|
|
||||||
)
|
|
||||||
], true), $items);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -608,11 +706,12 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/bare_php.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/bare_php.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(4, 8))
|
||||||
new Position(4, 8)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'$abc2',
|
'$abc2',
|
||||||
CompletionItemKind::VARIABLE,
|
CompletionItemKind::VARIABLE,
|
||||||
|
@ -633,7 +732,11 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
new TextEdit(new Range(new Position(4, 8), new Position(4, 8)), 'c')
|
new TextEdit(new Range(new Position(4, 8), new Position(4, 8)), 'c')
|
||||||
)
|
)
|
||||||
], true), $items);
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -643,10 +746,7 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/foreach.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/foreach.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument->completion(new TextDocumentIdentifier($completionUri), $position)->wait();
|
||||||
new TextDocumentIdentifier($completionUri),
|
|
||||||
$position
|
|
||||||
)->wait();
|
|
||||||
$this->assertCompletionsListSubset(new CompletionList($expectedItems, true), $items);
|
$this->assertCompletionsListSubset(new CompletionList($expectedItems, true), $items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -665,22 +765,14 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
new TextEdit(new Range(new Position(18, 6), new Position(18, 6)), 'alue')
|
new TextEdit(new Range(new Position(18, 6), new Position(18, 6)), 'alue')
|
||||||
),
|
)
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'foreach value resolved' => [
|
'foreach value resolved' => [
|
||||||
new Position(19, 12),
|
new Position(19, 12),
|
||||||
[
|
[
|
||||||
new CompletionItem(
|
new CompletionItem('foo', CompletionItemKind::PROPERTY, 'mixed'),
|
||||||
'foo',
|
new CompletionItem('test', CompletionItemKind::METHOD, '\\Foo\\Bar[]')
|
||||||
CompletionItemKind::PROPERTY,
|
|
||||||
'mixed'
|
|
||||||
),
|
|
||||||
new CompletionItem(
|
|
||||||
'test',
|
|
||||||
CompletionItemKind::METHOD,
|
|
||||||
'\\Foo\\Bar[]'
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'array creation with multiple objects' => [
|
'array creation with multiple objects' => [
|
||||||
|
@ -705,7 +797,7 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
new TextEdit(new Range(new Position(23, 5), new Position(23, 5)), 'key')
|
new TextEdit(new Range(new Position(23, 5), new Position(23, 5)), 'key')
|
||||||
),
|
)
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'array creation with string/int keys and object values' => [
|
'array creation with string/int keys and object values' => [
|
||||||
|
@ -730,7 +822,7 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
new TextEdit(new Range(new Position(27, 5), new Position(27, 5)), 'key')
|
new TextEdit(new Range(new Position(27, 5), new Position(27, 5)), 'key')
|
||||||
),
|
)
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'array creation with only string keys' => [
|
'array creation with only string keys' => [
|
||||||
|
@ -755,7 +847,7 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
new TextEdit(new Range(new Position(31, 5), new Position(31, 5)), 'key')
|
new TextEdit(new Range(new Position(31, 5), new Position(31, 5)), 'key')
|
||||||
),
|
)
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'foreach function call' => [
|
'foreach function call' => [
|
||||||
|
@ -770,7 +862,7 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
new TextEdit(new Range(new Position(35, 5), new Position(35, 5)), 'value')
|
new TextEdit(new Range(new Position(35, 5), new Position(35, 5)), 'value')
|
||||||
),
|
)
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'foreach unknown type' => [
|
'foreach unknown type' => [
|
||||||
|
@ -785,9 +877,9 @@ class CompletionTest extends TestCase
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
new TextEdit(new Range(new Position(39, 10), new Position(39, 10)), 'wn')
|
new TextEdit(new Range(new Position(39, 10), new Position(39, 10)), 'wn')
|
||||||
),
|
)
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -795,44 +887,32 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/method_return_type.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/method_return_type.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(10, 6))
|
||||||
new Position(10, 6)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList(
|
||||||
new CompletionItem(
|
[new CompletionItem('foo', CompletionItemKind::METHOD, '\FooClass', null, null, null, null, null)],
|
||||||
'foo',
|
true
|
||||||
CompletionItemKind::METHOD,
|
),
|
||||||
'\FooClass',
|
$items
|
||||||
null,
|
);
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null
|
|
||||||
)
|
|
||||||
], true), $items);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testStaticMethodReturnType()
|
public function testStaticMethodReturnType()
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/static_method_return_type.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/static_method_return_type.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(11, 6))
|
||||||
new Position(11, 6)
|
->wait();
|
||||||
)->wait();
|
$this->assertCompletionsListSubset(
|
||||||
$this->assertCompletionsListSubset(new CompletionList([
|
new CompletionList(
|
||||||
new CompletionItem(
|
[new CompletionItem('bar', CompletionItemKind::METHOD, 'mixed', null, null, null, null, null)],
|
||||||
'bar',
|
true
|
||||||
CompletionItemKind::METHOD,
|
),
|
||||||
'mixed',
|
$items
|
||||||
null,
|
);
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null
|
|
||||||
)
|
|
||||||
], true), $items);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function assertCompletionsListSubset(CompletionList $subsetList, CompletionList $list)
|
private function assertCompletionsListSubset(CompletionList $subsetList, CompletionList $list)
|
||||||
|
@ -858,11 +938,12 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/this.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/this.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(12, 15))
|
||||||
new Position(12, 15)
|
->wait();
|
||||||
)->wait();
|
$this->assertEquals(
|
||||||
$this->assertEquals(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'foo',
|
'foo',
|
||||||
CompletionItemKind::PROPERTY,
|
CompletionItemKind::PROPERTY,
|
||||||
|
@ -887,7 +968,11 @@ class CompletionTest extends TestCase
|
||||||
'mixed', // Return type of the method
|
'mixed', // Return type of the method
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
], true), $items);
|
],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -897,11 +982,12 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/this_with_prefix.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/this_with_prefix.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(12, 16))
|
||||||
new Position(12, 16)
|
->wait();
|
||||||
)->wait();
|
$this->assertEquals(
|
||||||
$this->assertEquals(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'foo',
|
'foo',
|
||||||
CompletionItemKind::PROPERTY,
|
CompletionItemKind::PROPERTY,
|
||||||
|
@ -937,8 +1023,12 @@ class CompletionTest extends TestCase
|
||||||
CompletionItemKind::METHOD,
|
CompletionItemKind::METHOD,
|
||||||
'\TestClass', // Return type of the method
|
'\TestClass', // Return type of the method
|
||||||
'Non culpa nostrud mollit esse sunt laboris in irure ullamco cupidatat amet.'
|
'Non culpa nostrud mollit esse sunt laboris in irure ullamco cupidatat amet.'
|
||||||
|
)
|
||||||
|
],
|
||||||
|
true
|
||||||
),
|
),
|
||||||
], true), $items);
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -948,11 +1038,12 @@ class CompletionTest extends TestCase
|
||||||
{
|
{
|
||||||
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/this_return_value.php');
|
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/this_return_value.php');
|
||||||
$this->loader->open($completionUri, file_get_contents($completionUri));
|
$this->loader->open($completionUri, file_get_contents($completionUri));
|
||||||
$items = $this->textDocument->completion(
|
$items = $this->textDocument
|
||||||
new TextDocumentIdentifier($completionUri),
|
->completion(new TextDocumentIdentifier($completionUri), new Position(17, 23))
|
||||||
new Position(17, 23)
|
->wait();
|
||||||
)->wait();
|
$this->assertEquals(
|
||||||
$this->assertEquals(new CompletionList([
|
new CompletionList(
|
||||||
|
[
|
||||||
new CompletionItem(
|
new CompletionItem(
|
||||||
'bar',
|
'bar',
|
||||||
CompletionItemKind::METHOD,
|
CompletionItemKind::METHOD,
|
||||||
|
@ -967,7 +1058,11 @@ class CompletionTest extends TestCase
|
||||||
'foo',
|
'foo',
|
||||||
CompletionItemKind::METHOD,
|
CompletionItemKind::METHOD,
|
||||||
'$this' // Return type of the method
|
'$this' // Return type of the method
|
||||||
|
)
|
||||||
|
],
|
||||||
|
true
|
||||||
),
|
),
|
||||||
], true), $items);
|
$items
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,7 @@ namespace LanguageServer\Tests\Server\TextDocument\Definition;
|
||||||
|
|
||||||
use LanguageServer\Tests\MockProtocolStream;
|
use LanguageServer\Tests\MockProtocolStream;
|
||||||
use LanguageServer\Tests\Server\ServerTestCase;
|
use LanguageServer\Tests\Server\ServerTestCase;
|
||||||
use LanguageServer\{
|
use LanguageServer\{Server, LanguageClient, PhpDocumentLoader, DefinitionResolver};
|
||||||
Server, LanguageClient, PhpDocumentLoader, DefinitionResolver
|
|
||||||
};
|
|
||||||
use LanguageServer\Index\{Index, ProjectIndex, DependenciesIndex};
|
use LanguageServer\Index\{Index, ProjectIndex, DependenciesIndex};
|
||||||
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
||||||
use LanguageServerProtocol\{TextDocumentIdentifier, Position, Range, Location};
|
use LanguageServerProtocol\{TextDocumentIdentifier, Position, Range, Location};
|
||||||
|
@ -16,11 +14,11 @@ class GlobalFallbackTest extends ServerTestCase
|
||||||
{
|
{
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
$projectIndex = new ProjectIndex(new Index, new DependenciesIndex);
|
$projectIndex = new ProjectIndex(new Index(), new DependenciesIndex());
|
||||||
$projectIndex->setComplete();
|
$projectIndex->setComplete();
|
||||||
$client = new LanguageClient(new MockProtocolStream, new MockProtocolStream);
|
$client = new LanguageClient(new MockProtocolStream(), new MockProtocolStream());
|
||||||
$definitionResolver = new DefinitionResolver($projectIndex);
|
$definitionResolver = new DefinitionResolver($projectIndex);
|
||||||
$contentRetriever = new FileSystemContentRetriever;
|
$contentRetriever = new FileSystemContentRetriever();
|
||||||
$loader = new PhpDocumentLoader($contentRetriever, $projectIndex, $definitionResolver);
|
$loader = new PhpDocumentLoader($contentRetriever, $projectIndex, $definitionResolver);
|
||||||
$this->textDocument = new Server\TextDocument($loader, $definitionResolver, $client, $projectIndex);
|
$this->textDocument = new Server\TextDocument($loader, $definitionResolver, $client, $projectIndex);
|
||||||
$loader->open('global_fallback', file_get_contents(__DIR__ . '/../../../../fixtures/global_fallback.php'));
|
$loader->open('global_fallback', file_get_contents(__DIR__ . '/../../../../fixtures/global_fallback.php'));
|
||||||
|
@ -31,10 +29,9 @@ class GlobalFallbackTest extends ServerTestCase
|
||||||
{
|
{
|
||||||
// $obj = new TestClass();
|
// $obj = new TestClass();
|
||||||
// Get definition for TestClass should not fall back to global
|
// Get definition for TestClass should not fall back to global
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier('global_fallback'),
|
->definition(new TextDocumentIdentifier('global_fallback'), new Position(9, 16))
|
||||||
new Position(9, 16)
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals([], $result);
|
$this->assertEquals([], $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,21 +39,25 @@ class GlobalFallbackTest extends ServerTestCase
|
||||||
{
|
{
|
||||||
// echo TEST_CONST;
|
// echo TEST_CONST;
|
||||||
// Get definition for TEST_CONST
|
// Get definition for TEST_CONST
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier('global_fallback'),
|
->definition(new TextDocumentIdentifier('global_fallback'), new Position(6, 10))
|
||||||
new Position(6, 10)
|
->wait();
|
||||||
)->wait();
|
$this->assertEquals(
|
||||||
$this->assertEquals(new Location('global_symbols', new Range(new Position(9, 6), new Position(9, 22))), $result);
|
new Location('global_symbols', new Range(new Position(9, 6), new Position(9, 22))),
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testFallsBackForFunctions()
|
public function testFallsBackForFunctions()
|
||||||
{
|
{
|
||||||
// test_function();
|
// test_function();
|
||||||
// Get definition for test_function
|
// Get definition for test_function
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier('global_fallback'),
|
->definition(new TextDocumentIdentifier('global_fallback'), new Position(5, 6))
|
||||||
new Position(5, 6)
|
->wait();
|
||||||
)->wait();
|
$this->assertEquals(
|
||||||
$this->assertEquals(new Location('global_symbols', new Range(new Position(78, 0), new Position(81, 1))), $result);
|
new Location('global_symbols', new Range(new Position(78, 0), new Position(81, 1))),
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,20 +12,24 @@ class GlobalTest extends ServerTestCase
|
||||||
public function testDefinitionFileBeginning()
|
public function testDefinitionFileBeginning()
|
||||||
{
|
{
|
||||||
// |<?php
|
// |<?php
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
|
->definition(
|
||||||
new TextDocumentIdentifier(pathToUri(realpath(__DIR__ . '/../../../../fixtures/references.php'))),
|
new TextDocumentIdentifier(pathToUri(realpath(__DIR__ . '/../../../../fixtures/references.php'))),
|
||||||
new Position(0, 0)
|
new Position(0, 0)
|
||||||
)->wait();
|
)
|
||||||
|
->wait();
|
||||||
$this->assertEquals([], $result);
|
$this->assertEquals([], $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDefinitionEmptyResult()
|
public function testDefinitionEmptyResult()
|
||||||
{
|
{
|
||||||
// namespace keyword
|
// namespace keyword
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
|
->definition(
|
||||||
new TextDocumentIdentifier(pathToUri(realpath(__DIR__ . '/../../../../fixtures/references.php'))),
|
new TextDocumentIdentifier(pathToUri(realpath(__DIR__ . '/../../../../fixtures/references.php'))),
|
||||||
new Position(1, 0)
|
new Position(1, 0)
|
||||||
)->wait();
|
)
|
||||||
|
->wait();
|
||||||
$this->assertEquals([], $result);
|
$this->assertEquals([], $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,10 +38,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// echo self::TEST_CLASS_CONST;
|
// echo self::TEST_CLASS_CONST;
|
||||||
// Get definition for self
|
// Get definition for self
|
||||||
$reference = $this->getReferenceLocations('TestClass')[0];
|
$reference = $this->getReferenceLocations('TestClass')[0];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
$reference->range->start
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,10 +49,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// $obj = new TestClass();
|
// $obj = new TestClass();
|
||||||
// Get definition for TestClass
|
// Get definition for TestClass
|
||||||
$reference = $this->getReferenceLocations('TestClass')[1];
|
$reference = $this->getReferenceLocations('TestClass')[1];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
$reference->range->start
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,10 +60,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// TestClass::staticTestMethod();
|
// TestClass::staticTestMethod();
|
||||||
// Get definition for TestClass
|
// Get definition for TestClass
|
||||||
$reference = $this->getReferenceLocations('TestClass')[2];
|
$reference = $this->getReferenceLocations('TestClass')[2];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
$reference->range->start
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,10 +71,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// echo TestClass::$staticTestProperty;
|
// echo TestClass::$staticTestProperty;
|
||||||
// Get definition for TestClass
|
// Get definition for TestClass
|
||||||
$reference = $this->getReferenceLocations('TestClass')[3];
|
$reference = $this->getReferenceLocations('TestClass')[3];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
$reference->range->start
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,10 +82,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// TestClass::TEST_CLASS_CONST;
|
// TestClass::TEST_CLASS_CONST;
|
||||||
// Get definition for TestClass
|
// Get definition for TestClass
|
||||||
$reference = $this->getReferenceLocations('TestClass')[4];
|
$reference = $this->getReferenceLocations('TestClass')[4];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
$reference->range->start
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,10 +93,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// class TestClass implements TestInterface
|
// class TestClass implements TestInterface
|
||||||
// Get definition for TestInterface
|
// Get definition for TestInterface
|
||||||
$reference = $this->getReferenceLocations('TestInterface')[0];
|
$reference = $this->getReferenceLocations('TestInterface')[0];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
$reference->range->start
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestInterface'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestInterface'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,10 +104,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// echo TestClass::TEST_CLASS_CONST;
|
// echo TestClass::TEST_CLASS_CONST;
|
||||||
// Get definition for TEST_CLASS_CONST
|
// Get definition for TEST_CLASS_CONST
|
||||||
$reference = $this->getReferenceLocations('TestClass::TEST_CLASS_CONST')[1];
|
$reference = $this->getReferenceLocations('TestClass::TEST_CLASS_CONST')[1];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass::TEST_CLASS_CONST'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass::TEST_CLASS_CONST'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,10 +115,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// echo self::TEST_CLASS_CONST;
|
// echo self::TEST_CLASS_CONST;
|
||||||
// Get definition for TEST_CLASS_CONST
|
// Get definition for TEST_CLASS_CONST
|
||||||
$reference = $this->getReferenceLocations('TestClass::TEST_CLASS_CONST')[0];
|
$reference = $this->getReferenceLocations('TestClass::TEST_CLASS_CONST')[0];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass::TEST_CLASS_CONST'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass::TEST_CLASS_CONST'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,10 +126,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// echo TEST_CONST;
|
// echo TEST_CONST;
|
||||||
// Get definition for TEST_CONST
|
// Get definition for TEST_CONST
|
||||||
$reference = $this->getReferenceLocations('TEST_CONST')[1];
|
$reference = $this->getReferenceLocations('TEST_CONST')[1];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
$reference->range->start
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TEST_CONST'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TEST_CONST'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,10 +137,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// TestClass::staticTestMethod();
|
// TestClass::staticTestMethod();
|
||||||
// Get definition for staticTestMethod
|
// Get definition for staticTestMethod
|
||||||
$reference = $this->getReferenceLocations('TestClass::staticTestMethod()')[0];
|
$reference = $this->getReferenceLocations('TestClass::staticTestMethod()')[0];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass::staticTestMethod()'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass::staticTestMethod()'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,10 +148,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// echo TestClass::$staticTestProperty;
|
// echo TestClass::$staticTestProperty;
|
||||||
// Get definition for staticTestProperty
|
// Get definition for staticTestProperty
|
||||||
$reference = $this->getReferenceLocations('TestClass::staticTestProperty')[0];
|
$reference = $this->getReferenceLocations('TestClass::staticTestProperty')[0];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass::staticTestProperty'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass::staticTestProperty'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,10 +159,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// $obj->testMethod();
|
// $obj->testMethod();
|
||||||
// Get definition for testMethod
|
// Get definition for testMethod
|
||||||
$reference = $this->getReferenceLocations('TestClass::testMethod()')[0];
|
$reference = $this->getReferenceLocations('TestClass::testMethod()')[0];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass::testMethod()'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass::testMethod()'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,10 +170,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// $child->testMethod();
|
// $child->testMethod();
|
||||||
// Get definition for testMethod
|
// Get definition for testMethod
|
||||||
$reference = $this->getReferenceLocations('TestClass::testMethod()')[2];
|
$reference = $this->getReferenceLocations('TestClass::testMethod()')[2];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass::testMethod()'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass::testMethod()'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,10 +181,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// echo $obj->testProperty;
|
// echo $obj->testProperty;
|
||||||
// Get definition for testProperty
|
// Get definition for testProperty
|
||||||
$reference = $this->getReferenceLocations('TestClass::testProperty')[1];
|
$reference = $this->getReferenceLocations('TestClass::testProperty')[1];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass::testProperty'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass::testProperty'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,10 +192,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// $this->testProperty = $testParameter;
|
// $this->testProperty = $testParameter;
|
||||||
// Get definition for testProperty
|
// Get definition for testProperty
|
||||||
$reference = $this->getReferenceLocations('TestClass::testProperty')[0];
|
$reference = $this->getReferenceLocations('TestClass::testProperty')[0];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass::testProperty'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass::testProperty'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,10 +203,7 @@ class GlobalTest extends ServerTestCase
|
||||||
// echo $var;
|
// echo $var;
|
||||||
// Get definition for $var
|
// Get definition for $var
|
||||||
$uri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/references.php'));
|
$uri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/references.php'));
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument->definition(new TextDocumentIdentifier($uri), new Position(13, 7))->wait();
|
||||||
new TextDocumentIdentifier($uri),
|
|
||||||
new Position(13, 7)
|
|
||||||
)->wait();
|
|
||||||
$this->assertEquals(new Location($uri, new Range(new Position(12, 0), new Position(12, 10))), $result);
|
$this->assertEquals(new Location($uri, new Range(new Position(12, 0), new Position(12, 10))), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,10 +212,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// function whatever(TestClass $param) {
|
// function whatever(TestClass $param) {
|
||||||
// Get definition for TestClass
|
// Get definition for TestClass
|
||||||
$reference = $this->getReferenceLocations('TestClass')[5];
|
$reference = $this->getReferenceLocations('TestClass')[5];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
$reference->range->start
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,10 +223,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// function whatever(TestClass $param): TestClass {
|
// function whatever(TestClass $param): TestClass {
|
||||||
// Get definition for TestClass
|
// Get definition for TestClass
|
||||||
$reference = $this->getReferenceLocations('TestClass')[6];
|
$reference = $this->getReferenceLocations('TestClass')[6];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
$reference->range->start
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,10 +234,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// public function testMethod($testParameter): TestInterface
|
// public function testMethod($testParameter): TestInterface
|
||||||
// Get definition for TestInterface
|
// Get definition for TestInterface
|
||||||
$reference = $this->getReferenceLocations('TestInterface')[1];
|
$reference = $this->getReferenceLocations('TestInterface')[1];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
$reference->range->start
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestInterface'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestInterface'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,10 +245,7 @@ class GlobalTest extends ServerTestCase
|
||||||
// echo $param;
|
// echo $param;
|
||||||
// Get definition for $param
|
// Get definition for $param
|
||||||
$uri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/references.php'));
|
$uri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/references.php'));
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument->definition(new TextDocumentIdentifier($uri), new Position(22, 13))->wait();
|
||||||
new TextDocumentIdentifier($uri),
|
|
||||||
new Position(22, 13)
|
|
||||||
)->wait();
|
|
||||||
$this->assertEquals(new Location($uri, new Range(new Position(21, 18), new Position(21, 34))), $result);
|
$this->assertEquals(new Location($uri, new Range(new Position(21, 18), new Position(21, 34))), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,10 +254,7 @@ class GlobalTest extends ServerTestCase
|
||||||
// echo $var;
|
// echo $var;
|
||||||
// Get definition for $var
|
// Get definition for $var
|
||||||
$uri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/references.php'));
|
$uri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/references.php'));
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument->definition(new TextDocumentIdentifier($uri), new Position(26, 11))->wait();
|
||||||
new TextDocumentIdentifier($uri),
|
|
||||||
new Position(26, 11)
|
|
||||||
)->wait();
|
|
||||||
$this->assertEquals(new Location($uri, new Range(new Position(25, 22), new Position(25, 26))), $result);
|
$this->assertEquals(new Location($uri, new Range(new Position(25, 22), new Position(25, 26))), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,10 +263,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// test_function();
|
// test_function();
|
||||||
// Get definition for test_function
|
// Get definition for test_function
|
||||||
$reference = $this->getReferenceLocations('test_function()')[0];
|
$reference = $this->getReferenceLocations('test_function()')[0];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
$reference->range->start
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('test_function()'), $result);
|
$this->assertEquals($this->getDefinitionLocation('test_function()'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,10 +274,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// use function test_function;
|
// use function test_function;
|
||||||
// Get definition for test_function
|
// Get definition for test_function
|
||||||
$reference = $this->getReferenceLocations('test_function()')[1];
|
$reference = $this->getReferenceLocations('test_function()')[1];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
$reference->range->start
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('test_function()'), $result);
|
$this->assertEquals($this->getDefinitionLocation('test_function()'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,10 +285,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// if ($abc instanceof TestInterface) {
|
// if ($abc instanceof TestInterface) {
|
||||||
// Get definition for TestInterface
|
// Get definition for TestInterface
|
||||||
$reference = $this->getReferenceLocations('TestInterface')[2];
|
$reference = $this->getReferenceLocations('TestInterface')[2];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
$reference->range->start
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestInterface'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestInterface'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,10 +296,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// $obj->testProperty->testMethod();
|
// $obj->testProperty->testMethod();
|
||||||
// Get definition for testMethod
|
// Get definition for testMethod
|
||||||
$reference = $this->getReferenceLocations('TestClass::testMethod()')[1];
|
$reference = $this->getReferenceLocations('TestClass::testMethod()')[1];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass::testMethod()'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass::testMethod()'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,10 +307,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// TestClass::$staticTestProperty[123]->testProperty;
|
// TestClass::$staticTestProperty[123]->testProperty;
|
||||||
// Get definition for testProperty
|
// Get definition for testProperty
|
||||||
$reference = $this->getReferenceLocations('TestClass::testProperty')[3];
|
$reference = $this->getReferenceLocations('TestClass::testProperty')[3];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass::testProperty'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass::testProperty'), $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,9 @@ class NamespacedTest extends GlobalTest
|
||||||
// echo TEST_CONST;
|
// echo TEST_CONST;
|
||||||
// Get definition for TEST_CONST
|
// Get definition for TEST_CONST
|
||||||
$reference = $this->getReferenceLocations('TEST_CONST')[0];
|
$reference = $this->getReferenceLocations('TEST_CONST')[0];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
$reference->range->start
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TEST_CONST'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TEST_CONST'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,10 +34,9 @@ class NamespacedTest extends GlobalTest
|
||||||
// use TestNamespace\TestClass;
|
// use TestNamespace\TestClass;
|
||||||
// Get definition for TestClass
|
// Get definition for TestClass
|
||||||
$reference = $this->getReferenceLocations('TestClass')[7];
|
$reference = $this->getReferenceLocations('TestClass')[7];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
$reference->range->start
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,10 +45,9 @@ class NamespacedTest extends GlobalTest
|
||||||
// use TestNamespace\{TestTrait, TestInterface};
|
// use TestNamespace\{TestTrait, TestInterface};
|
||||||
// Get definition for TestInterface
|
// Get definition for TestInterface
|
||||||
$reference = $this->getReferenceLocations('TestClass')[1];
|
$reference = $this->getReferenceLocations('TestClass')[1];
|
||||||
$result = $this->textDocument->definition(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->definition(new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
$reference->range->start
|
->wait();
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,26 +5,19 @@ namespace LanguageServer\Tests\Server\TextDocument;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use LanguageServer\Tests\MockProtocolStream;
|
use LanguageServer\Tests\MockProtocolStream;
|
||||||
use LanguageServer\{
|
use LanguageServer\{Server, LanguageClient, PhpDocumentLoader, DefinitionResolver};
|
||||||
Server, LanguageClient, PhpDocumentLoader, DefinitionResolver
|
|
||||||
};
|
|
||||||
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
||||||
use LanguageServer\Index\{Index, ProjectIndex, DependenciesIndex};
|
use LanguageServer\Index\{Index, ProjectIndex, DependenciesIndex};
|
||||||
use LanguageServerProtocol\{
|
use LanguageServerProtocol\{VersionedTextDocumentIdentifier, TextDocumentContentChangeEvent, Range, Position};
|
||||||
VersionedTextDocumentIdentifier,
|
|
||||||
TextDocumentContentChangeEvent,
|
|
||||||
Range,
|
|
||||||
Position
|
|
||||||
};
|
|
||||||
|
|
||||||
class DidChangeTest extends TestCase
|
class DidChangeTest extends TestCase
|
||||||
{
|
{
|
||||||
public function test()
|
public function test()
|
||||||
{
|
{
|
||||||
$projectIndex = new ProjectIndex(new Index, new DependenciesIndex);
|
$projectIndex = new ProjectIndex(new Index(), new DependenciesIndex());
|
||||||
$client = new LanguageClient(new MockProtocolStream, new MockProtocolStream);
|
$client = new LanguageClient(new MockProtocolStream(), new MockProtocolStream());
|
||||||
$definitionResolver = new DefinitionResolver($projectIndex);
|
$definitionResolver = new DefinitionResolver($projectIndex);
|
||||||
$loader = new PhpDocumentLoader(new FileSystemContentRetriever, $projectIndex, $definitionResolver);
|
$loader = new PhpDocumentLoader(new FileSystemContentRetriever(), $projectIndex, $definitionResolver);
|
||||||
$textDocument = new Server\TextDocument($loader, $definitionResolver, $client, $projectIndex);
|
$textDocument = new Server\TextDocument($loader, $definitionResolver, $client, $projectIndex);
|
||||||
$phpDocument = $loader->open('whatever', "<?php\necho 'Hello, World'\n");
|
$phpDocument = $loader->open('whatever', "<?php\necho 'Hello, World'\n");
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,7 @@ namespace LanguageServer\Tests\Server\TextDocument;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use LanguageServer\Tests\MockProtocolStream;
|
use LanguageServer\Tests\MockProtocolStream;
|
||||||
use LanguageServer\{
|
use LanguageServer\{Server, LanguageClient, PhpDocumentLoader, DefinitionResolver};
|
||||||
Server, LanguageClient, PhpDocumentLoader, DefinitionResolver
|
|
||||||
};
|
|
||||||
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
||||||
use LanguageServer\Index\{Index, ProjectIndex, DependenciesIndex};
|
use LanguageServer\Index\{Index, ProjectIndex, DependenciesIndex};
|
||||||
use LanguageServerProtocol\{TextDocumentItem, TextDocumentIdentifier};
|
use LanguageServerProtocol\{TextDocumentItem, TextDocumentIdentifier};
|
||||||
|
@ -16,10 +14,10 @@ class DidCloseTest extends TestCase
|
||||||
{
|
{
|
||||||
public function test()
|
public function test()
|
||||||
{
|
{
|
||||||
$projectIndex = new ProjectIndex(new Index, new DependenciesIndex);
|
$projectIndex = new ProjectIndex(new Index(), new DependenciesIndex());
|
||||||
$client = new LanguageClient(new MockProtocolStream, new MockProtocolStream);
|
$client = new LanguageClient(new MockProtocolStream(), new MockProtocolStream());
|
||||||
$definitionResolver = new DefinitionResolver($projectIndex);
|
$definitionResolver = new DefinitionResolver($projectIndex);
|
||||||
$loader = new PhpDocumentLoader(new FileSystemContentRetriever, $projectIndex, $definitionResolver);
|
$loader = new PhpDocumentLoader(new FileSystemContentRetriever(), $projectIndex, $definitionResolver);
|
||||||
$textDocument = new Server\TextDocument($loader, $definitionResolver, $client, $projectIndex);
|
$textDocument = new Server\TextDocument($loader, $definitionResolver, $client, $projectIndex);
|
||||||
$phpDocument = $loader->open('whatever', "<?php\necho 'Hello, World'\n");
|
$phpDocument = $loader->open('whatever', "<?php\necho 'Hello, World'\n");
|
||||||
|
|
||||||
|
|
|
@ -17,25 +17,113 @@ class DocumentSymbolTest extends ServerTestCase
|
||||||
$uri = pathToUri(realpath(__DIR__ . '/../../../fixtures/symbols.php'));
|
$uri = pathToUri(realpath(__DIR__ . '/../../../fixtures/symbols.php'));
|
||||||
$result = $this->textDocument->documentSymbol(new TextDocumentIdentifier($uri))->wait();
|
$result = $this->textDocument->documentSymbol(new TextDocumentIdentifier($uri))->wait();
|
||||||
// @codingStandardsIgnoreStart
|
// @codingStandardsIgnoreStart
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
new SymbolInformation('TestNamespace', SymbolKind::NAMESPACE, $this->getDefinitionLocation('TestNamespace'), ''),
|
[
|
||||||
new SymbolInformation('TEST_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestNamespace\\TEST_CONST'), 'TestNamespace'),
|
new SymbolInformation(
|
||||||
new SymbolInformation('TestClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\TestClass'), 'TestNamespace'),
|
'TestNamespace',
|
||||||
new SymbolInformation('TEST_CLASS_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestNamespace\\TestClass::TEST_CLASS_CONST'), 'TestNamespace\\TestClass'),
|
SymbolKind::NAMESPACE,
|
||||||
new SymbolInformation('staticTestProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestNamespace\\TestClass::staticTestProperty'), 'TestNamespace\\TestClass'),
|
$this->getDefinitionLocation('TestNamespace'),
|
||||||
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(
|
||||||
new SymbolInformation('TestTrait', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\TestTrait'), 'TestNamespace'),
|
'TEST_CONST',
|
||||||
new SymbolInformation('TestInterface', SymbolKind::INTERFACE, $this->getDefinitionLocation('TestNamespace\\TestInterface'), 'TestNamespace'),
|
SymbolKind::CONSTANT,
|
||||||
new SymbolInformation('test_function', SymbolKind::FUNCTION, $this->getDefinitionLocation('TestNamespace\\test_function()'), 'TestNamespace'),
|
$this->getDefinitionLocation('TestNamespace\\TEST_CONST'),
|
||||||
new SymbolInformation('ChildClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\ChildClass'), 'TestNamespace'),
|
'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(
|
||||||
new SymbolInformation('__destruct', SymbolKind::CONSTRUCTOR, $this->getDefinitionLocation('TestNamespace\\Example::__destruct'), 'TestNamespace\\Example'),
|
'TestClass',
|
||||||
new SymbolInformation('TestNamespace\\InnerNamespace', SymbolKind::NAMESPACE, $this->getDefinitionLocation('TestNamespace\\InnerNamespace'), 'TestNamespace'),
|
SymbolKind::CLASS_,
|
||||||
new SymbolInformation('InnerClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\InnerNamespace\\InnerClass'), 'TestNamespace\\InnerNamespace'),
|
$this->getDefinitionLocation('TestNamespace\\TestClass'),
|
||||||
], $result);
|
'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(
|
||||||
|
'TestNamespace\\InnerNamespace',
|
||||||
|
SymbolKind::NAMESPACE,
|
||||||
|
$this->getDefinitionLocation('TestNamespace\\InnerNamespace'),
|
||||||
|
'TestNamespace'
|
||||||
|
),
|
||||||
|
new SymbolInformation(
|
||||||
|
'InnerClass',
|
||||||
|
SymbolKind::CLASS_,
|
||||||
|
$this->getDefinitionLocation('TestNamespace\\InnerNamespace\\InnerClass'),
|
||||||
|
'TestNamespace\\InnerNamespace'
|
||||||
|
)
|
||||||
|
],
|
||||||
|
$result
|
||||||
|
);
|
||||||
// @codingStandardsIgnoreEnd
|
// @codingStandardsIgnoreEnd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,19 +16,29 @@ class HoverTest extends ServerTestCase
|
||||||
// $obj = new TestClass();
|
// $obj = new TestClass();
|
||||||
// Get hover for TestClass
|
// Get hover for TestClass
|
||||||
$reference = $this->getReferenceLocations('TestClass')[1];
|
$reference = $this->getReferenceLocations('TestClass')[1];
|
||||||
$result = $this->textDocument->hover(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->hover(new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
$reference->range->start
|
->wait();
|
||||||
)->wait();
|
$this->assertEquals(
|
||||||
$this->assertEquals(new Hover([
|
new Hover(
|
||||||
|
[
|
||||||
new MarkedString('php', "<?php\nclass TestClass implements TestInterface"),
|
new MarkedString('php', "<?php\nclass TestClass implements TestInterface"),
|
||||||
'Pariatur ut laborum tempor voluptate consequat ea deserunt.' . "\n\n" .
|
'Pariatur ut laborum tempor voluptate consequat ea deserunt.' .
|
||||||
'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' . "\n" .
|
"\n\n" .
|
||||||
'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' . "\n" .
|
'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' .
|
||||||
'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' . "\n" .
|
"\n" .
|
||||||
'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' . "\n" .
|
'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' .
|
||||||
|
"\n" .
|
||||||
|
'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' .
|
||||||
|
"\n" .
|
||||||
|
'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' .
|
||||||
|
"\n" .
|
||||||
'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.'
|
'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.'
|
||||||
], $reference->range), $result);
|
],
|
||||||
|
$reference->range
|
||||||
|
),
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHoverForClassLikeDefinition()
|
public function testHoverForClassLikeDefinition()
|
||||||
|
@ -36,19 +46,29 @@ class HoverTest extends ServerTestCase
|
||||||
// class TestClass implements TestInterface
|
// class TestClass implements TestInterface
|
||||||
// Get hover for TestClass
|
// Get hover for TestClass
|
||||||
$definition = $this->getDefinitionLocation('TestClass');
|
$definition = $this->getDefinitionLocation('TestClass');
|
||||||
$result = $this->textDocument->hover(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($definition->uri),
|
->hover(new TextDocumentIdentifier($definition->uri), $definition->range->start)
|
||||||
$definition->range->start
|
->wait();
|
||||||
)->wait();
|
$this->assertEquals(
|
||||||
$this->assertEquals(new Hover([
|
new Hover(
|
||||||
|
[
|
||||||
new MarkedString('php', "<?php\nclass TestClass implements TestInterface"),
|
new MarkedString('php', "<?php\nclass TestClass implements TestInterface"),
|
||||||
'Pariatur ut laborum tempor voluptate consequat ea deserunt.' . "\n\n" .
|
'Pariatur ut laborum tempor voluptate consequat ea deserunt.' .
|
||||||
'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' . "\n" .
|
"\n\n" .
|
||||||
'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' . "\n" .
|
'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' .
|
||||||
'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' . "\n" .
|
"\n" .
|
||||||
'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' . "\n" .
|
'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' .
|
||||||
|
"\n" .
|
||||||
|
'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' .
|
||||||
|
"\n" .
|
||||||
|
'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' .
|
||||||
|
"\n" .
|
||||||
'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.'
|
'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.'
|
||||||
], $definition->range), $result);
|
],
|
||||||
|
$definition->range
|
||||||
|
),
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHoverForMethod()
|
public function testHoverForMethod()
|
||||||
|
@ -56,14 +76,19 @@ class HoverTest extends ServerTestCase
|
||||||
// $obj->testMethod();
|
// $obj->testMethod();
|
||||||
// Get hover for testMethod
|
// Get hover for testMethod
|
||||||
$reference = $this->getReferenceLocations('TestClass::testMethod()')[0];
|
$reference = $this->getReferenceLocations('TestClass::testMethod()')[0];
|
||||||
$result = $this->textDocument->hover(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->hover(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
$this->assertEquals(
|
||||||
$this->assertEquals(new Hover([
|
new Hover(
|
||||||
|
[
|
||||||
new MarkedString('php', "<?php\npublic function testMethod(\$testParameter): TestInterface"),
|
new MarkedString('php', "<?php\npublic function testMethod(\$testParameter): TestInterface"),
|
||||||
'Non culpa nostrud mollit esse sunt laboris in irure ullamco cupidatat amet.'
|
'Non culpa nostrud mollit esse sunt laboris in irure ullamco cupidatat amet.'
|
||||||
], $reference->range), $result);
|
],
|
||||||
|
$reference->range
|
||||||
|
),
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHoverForProperty()
|
public function testHoverForProperty()
|
||||||
|
@ -71,14 +96,19 @@ class HoverTest extends ServerTestCase
|
||||||
// echo $obj->testProperty;
|
// echo $obj->testProperty;
|
||||||
// Get hover for testProperty
|
// Get hover for testProperty
|
||||||
$reference = $this->getReferenceLocations('TestClass::testProperty')[0];
|
$reference = $this->getReferenceLocations('TestClass::testProperty')[0];
|
||||||
$result = $this->textDocument->hover(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->hover(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
$this->assertEquals(
|
||||||
$this->assertEquals(new Hover([
|
new Hover(
|
||||||
|
[
|
||||||
new MarkedString('php', "<?php\npublic \$testProperty;"),
|
new MarkedString('php', "<?php\npublic \$testProperty;"),
|
||||||
'Reprehenderit magna velit mollit ipsum do.'
|
'Reprehenderit magna velit mollit ipsum do.'
|
||||||
], $reference->range), $result);
|
],
|
||||||
|
$reference->range
|
||||||
|
),
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHoverForStaticMethod()
|
public function testHoverForStaticMethod()
|
||||||
|
@ -86,14 +116,19 @@ class HoverTest extends ServerTestCase
|
||||||
// TestClass::staticTestMethod();
|
// TestClass::staticTestMethod();
|
||||||
// Get hover for staticTestMethod
|
// Get hover for staticTestMethod
|
||||||
$reference = $this->getReferenceLocations('TestClass::staticTestMethod()')[0];
|
$reference = $this->getReferenceLocations('TestClass::staticTestMethod()')[0];
|
||||||
$result = $this->textDocument->hover(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->hover(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
$this->assertEquals(
|
||||||
$this->assertEquals(new Hover([
|
new Hover(
|
||||||
|
[
|
||||||
new MarkedString('php', "<?php\npublic static function staticTestMethod()"),
|
new MarkedString('php', "<?php\npublic static function staticTestMethod()"),
|
||||||
'Do magna consequat veniam minim proident eiusmod incididunt aute proident.'
|
'Do magna consequat veniam minim proident eiusmod incididunt aute proident.'
|
||||||
], $reference->range), $result);
|
],
|
||||||
|
$reference->range
|
||||||
|
),
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHoverForStaticProperty()
|
public function testHoverForStaticProperty()
|
||||||
|
@ -101,14 +136,19 @@ class HoverTest extends ServerTestCase
|
||||||
// echo TestClass::staticTestProperty;
|
// echo TestClass::staticTestProperty;
|
||||||
// Get hover for staticTestProperty
|
// Get hover for staticTestProperty
|
||||||
$reference = $this->getReferenceLocations('TestClass::staticTestProperty')[0];
|
$reference = $this->getReferenceLocations('TestClass::staticTestProperty')[0];
|
||||||
$result = $this->textDocument->hover(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->hover(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
$this->assertEquals(
|
||||||
$this->assertEquals(new Hover([
|
new Hover(
|
||||||
|
[
|
||||||
new MarkedString('php', "<?php\npublic static \$staticTestProperty;"),
|
new MarkedString('php', "<?php\npublic static \$staticTestProperty;"),
|
||||||
'Lorem excepteur officia sit anim velit veniam enim.'
|
'Lorem excepteur officia sit anim velit veniam enim.'
|
||||||
], $reference->range), $result);
|
],
|
||||||
|
$reference->range
|
||||||
|
),
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHoverForClassConstant()
|
public function testHoverForClassConstant()
|
||||||
|
@ -116,14 +156,19 @@ class HoverTest extends ServerTestCase
|
||||||
// echo TestClass::TEST_CLASS_CONST;
|
// echo TestClass::TEST_CLASS_CONST;
|
||||||
// Get hover for TEST_CLASS_CONST
|
// Get hover for TEST_CLASS_CONST
|
||||||
$reference = $this->getReferenceLocations('TestClass::TEST_CLASS_CONST')[0];
|
$reference = $this->getReferenceLocations('TestClass::TEST_CLASS_CONST')[0];
|
||||||
$result = $this->textDocument->hover(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->hover(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
$this->assertEquals(
|
||||||
$this->assertEquals(new Hover([
|
new Hover(
|
||||||
|
[
|
||||||
new MarkedString('php', "<?php\nconst TEST_CLASS_CONST = 123;"),
|
new MarkedString('php', "<?php\nconst TEST_CLASS_CONST = 123;"),
|
||||||
'Anim labore veniam consectetur laboris minim quis aute aute esse nulla ad.'
|
'Anim labore veniam consectetur laboris minim quis aute aute esse nulla ad.'
|
||||||
], $reference->range), $result);
|
],
|
||||||
|
$reference->range
|
||||||
|
),
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHoverForFunction()
|
public function testHoverForFunction()
|
||||||
|
@ -131,14 +176,19 @@ class HoverTest extends ServerTestCase
|
||||||
// test_function();
|
// test_function();
|
||||||
// Get hover for test_function
|
// Get hover for test_function
|
||||||
$reference = $this->getReferenceLocations('test_function()')[0];
|
$reference = $this->getReferenceLocations('test_function()')[0];
|
||||||
$result = $this->textDocument->hover(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->hover(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
$this->assertEquals(
|
||||||
$this->assertEquals(new Hover([
|
new Hover(
|
||||||
|
[
|
||||||
new MarkedString('php', "<?php\nfunction test_function()"),
|
new MarkedString('php', "<?php\nfunction test_function()"),
|
||||||
'Officia aliquip adipisicing et nulla et laboris dolore labore.'
|
'Officia aliquip adipisicing et nulla et laboris dolore labore.'
|
||||||
], $reference->range), $result);
|
],
|
||||||
|
$reference->range
|
||||||
|
),
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHoverForConstant()
|
public function testHoverForConstant()
|
||||||
|
@ -146,14 +196,19 @@ class HoverTest extends ServerTestCase
|
||||||
// echo TEST_CONST;
|
// echo TEST_CONST;
|
||||||
// Get hover for TEST_CONST
|
// Get hover for TEST_CONST
|
||||||
$reference = $this->getReferenceLocations('TEST_CONST')[0];
|
$reference = $this->getReferenceLocations('TEST_CONST')[0];
|
||||||
$result = $this->textDocument->hover(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->hover(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
$this->assertEquals(
|
||||||
$this->assertEquals(new Hover([
|
new Hover(
|
||||||
|
[
|
||||||
new MarkedString('php', "<?php\nconst TEST_CONST = 123;"),
|
new MarkedString('php', "<?php\nconst TEST_CONST = 123;"),
|
||||||
'Esse commodo excepteur pariatur Lorem est aute incididunt reprehenderit.'
|
'Esse commodo excepteur pariatur Lorem est aute incididunt reprehenderit.'
|
||||||
], $reference->range), $result);
|
],
|
||||||
|
$reference->range
|
||||||
|
),
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHoverForGlobalConstant()
|
public function testHoverForGlobalConstant()
|
||||||
|
@ -161,15 +216,20 @@ class HoverTest extends ServerTestCase
|
||||||
// print TEST_DEFINE_CONSTANT ? 'true' : 'false';
|
// print TEST_DEFINE_CONSTANT ? 'true' : 'false';
|
||||||
// Get hover for TEST_DEFINE_CONSTANT
|
// Get hover for TEST_DEFINE_CONSTANT
|
||||||
$reference = $this->getReferenceLocations('TEST_DEFINE_CONSTANT')[0];
|
$reference = $this->getReferenceLocations('TEST_DEFINE_CONSTANT')[0];
|
||||||
$result = $this->textDocument->hover(
|
$result = $this->textDocument
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->hover(new TextDocumentIdentifier($reference->uri), $reference->range->end)
|
||||||
$reference->range->end
|
->wait();
|
||||||
)->wait();
|
|
||||||
// TODO - should pretty print with fqns, like \define, \false. Not yet supported by tolerant-php-parser
|
// TODO - should pretty print with fqns, like \define, \false. Not yet supported by tolerant-php-parser
|
||||||
$this->assertEquals(new Hover([
|
$this->assertEquals(
|
||||||
|
new Hover(
|
||||||
|
[
|
||||||
new MarkedString('php', "<?php\ndefine('TEST_DEFINE_CONSTANT', false)"),
|
new MarkedString('php', "<?php\ndefine('TEST_DEFINE_CONSTANT', false)"),
|
||||||
'Lorem ipsum dolor sit amet, consectetur.'
|
'Lorem ipsum dolor sit amet, consectetur.'
|
||||||
], $reference->range), $result);
|
],
|
||||||
|
$reference->range
|
||||||
|
),
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHoverForVariable()
|
public function testHoverForVariable()
|
||||||
|
@ -178,10 +238,13 @@ class HoverTest extends ServerTestCase
|
||||||
// Get hover for $var
|
// Get hover for $var
|
||||||
$uri = pathToUri(realpath(__DIR__ . '/../../../fixtures/references.php'));
|
$uri = pathToUri(realpath(__DIR__ . '/../../../fixtures/references.php'));
|
||||||
$result = $this->textDocument->hover(new TextDocumentIdentifier($uri), new Position(13, 7))->wait();
|
$result = $this->textDocument->hover(new TextDocumentIdentifier($uri), new Position(13, 7))->wait();
|
||||||
$this->assertEquals(new Hover(
|
$this->assertEquals(
|
||||||
|
new Hover(
|
||||||
[new MarkedString('php', "<?php\n\$var = 123")],
|
[new MarkedString('php', "<?php\n\$var = 123")],
|
||||||
new Range(new Position(13, 5), new Position(13, 9))
|
new Range(new Position(13, 5), new Position(13, 9))
|
||||||
), $result);
|
),
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHoverForParam()
|
public function testHoverForParam()
|
||||||
|
@ -190,13 +253,16 @@ class HoverTest extends ServerTestCase
|
||||||
// Get hover for $param
|
// Get hover for $param
|
||||||
$uri = pathToUri(realpath(__DIR__ . '/../../../fixtures/references.php'));
|
$uri = pathToUri(realpath(__DIR__ . '/../../../fixtures/references.php'));
|
||||||
$result = $this->textDocument->hover(new TextDocumentIdentifier($uri), new Position(22, 11))->wait();
|
$result = $this->textDocument->hover(new TextDocumentIdentifier($uri), new Position(22, 11))->wait();
|
||||||
$this->assertEquals(new Hover(
|
$this->assertEquals(
|
||||||
|
new Hover(
|
||||||
[
|
[
|
||||||
new MarkedString('php', "<?php\nTestClass \$param"),
|
new MarkedString('php', "<?php\nTestClass \$param"),
|
||||||
'Adipisicing non non cillum sint incididunt cillum enim mollit.'
|
'Adipisicing non non cillum sint incididunt cillum enim mollit.'
|
||||||
],
|
],
|
||||||
new Range(new Position(22, 9), new Position(22, 15))
|
new Range(new Position(22, 9), new Position(22, 15))
|
||||||
), $result);
|
),
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHoverForThis()
|
public function testHoverForThis()
|
||||||
|
@ -205,14 +271,25 @@ class HoverTest extends ServerTestCase
|
||||||
// Get hover for $this
|
// Get hover for $this
|
||||||
$uri = pathToUri(realpath(__DIR__ . '/../../../fixtures/global_symbols.php'));
|
$uri = pathToUri(realpath(__DIR__ . '/../../../fixtures/global_symbols.php'));
|
||||||
$result = $this->textDocument->hover(new TextDocumentIdentifier($uri), new Position(59, 11))->wait();
|
$result = $this->textDocument->hover(new TextDocumentIdentifier($uri), new Position(59, 11))->wait();
|
||||||
$this->assertEquals(new Hover([
|
$this->assertEquals(
|
||||||
|
new Hover(
|
||||||
|
[
|
||||||
new MarkedString('php', "<?php\nclass TestClass implements TestInterface"),
|
new MarkedString('php', "<?php\nclass TestClass implements TestInterface"),
|
||||||
'Pariatur ut laborum tempor voluptate consequat ea deserunt.' . "\n\n" .
|
'Pariatur ut laborum tempor voluptate consequat ea deserunt.' .
|
||||||
'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' . "\n" .
|
"\n\n" .
|
||||||
'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' . "\n" .
|
'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' .
|
||||||
'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' . "\n" .
|
"\n" .
|
||||||
'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' . "\n" .
|
'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' .
|
||||||
|
"\n" .
|
||||||
|
'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' .
|
||||||
|
"\n" .
|
||||||
|
'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' .
|
||||||
|
"\n" .
|
||||||
'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.'
|
'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.'
|
||||||
], new Range(new Position(59, 8), new Position(59, 13))), $result);
|
],
|
||||||
|
new Range(new Position(59, 8), new Position(59, 13))
|
||||||
|
),
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,7 @@ namespace LanguageServer\Tests\Server\TextDocument;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use LanguageServer\Tests\MockProtocolStream;
|
use LanguageServer\Tests\MockProtocolStream;
|
||||||
use LanguageServer\{
|
use LanguageServer\{Server, Client, LanguageClient, ClientHandler, PhpDocumentLoader, DefinitionResolver};
|
||||||
Server, Client, LanguageClient, ClientHandler, PhpDocumentLoader, DefinitionResolver
|
|
||||||
};
|
|
||||||
use LanguageServer\Index\{Index, ProjectIndex, DependenciesIndex};
|
use LanguageServer\Index\{Index, ProjectIndex, DependenciesIndex};
|
||||||
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
||||||
use LanguageServerProtocol\{TextDocumentItem, DiagnosticSeverity};
|
use LanguageServerProtocol\{TextDocumentItem, DiagnosticSeverity};
|
||||||
|
@ -25,12 +23,15 @@ class ParseErrorsTest extends TestCase
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
$client = new LanguageClient(new MockProtocolStream, new MockProtocolStream);
|
$client = new LanguageClient(new MockProtocolStream(), new MockProtocolStream());
|
||||||
$client->textDocument = new class($this->args) extends Client\TextDocument {
|
$client->textDocument = new class($this->args) extends Client\TextDocument {
|
||||||
private $args;
|
private $args;
|
||||||
public function __construct(&$args)
|
public function __construct(&$args)
|
||||||
{
|
{
|
||||||
parent::__construct(new ClientHandler(new MockProtocolStream, new MockProtocolStream), new JsonMapper);
|
parent::__construct(
|
||||||
|
new ClientHandler(new MockProtocolStream(), new MockProtocolStream()),
|
||||||
|
new JsonMapper()
|
||||||
|
);
|
||||||
$this->args = &$args;
|
$this->args = &$args;
|
||||||
}
|
}
|
||||||
public function publishDiagnostics(string $uri, array $diagnostics): Promise
|
public function publishDiagnostics(string $uri, array $diagnostics): Promise
|
||||||
|
@ -39,9 +40,9 @@ class ParseErrorsTest extends TestCase
|
||||||
return Promise\resolve(null);
|
return Promise\resolve(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
$projectIndex = new ProjectIndex(new Index, new DependenciesIndex);
|
$projectIndex = new ProjectIndex(new Index(), new DependenciesIndex());
|
||||||
$definitionResolver = new DefinitionResolver($projectIndex);
|
$definitionResolver = new DefinitionResolver($projectIndex);
|
||||||
$loader = new PhpDocumentLoader(new FileSystemContentRetriever, $projectIndex, $definitionResolver);
|
$loader = new PhpDocumentLoader(new FileSystemContentRetriever(), $projectIndex, $definitionResolver);
|
||||||
$this->textDocument = new Server\TextDocument($loader, $definitionResolver, $client, $projectIndex);
|
$this->textDocument = new Server\TextDocument($loader, $definitionResolver, $client, $projectIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,9 +59,11 @@ class ParseErrorsTest extends TestCase
|
||||||
public function testParseErrorsArePublishedAsDiagnostics()
|
public function testParseErrorsArePublishedAsDiagnostics()
|
||||||
{
|
{
|
||||||
$this->openFile(__DIR__ . '/../../../fixtures/invalid_file.php');
|
$this->openFile(__DIR__ . '/../../../fixtures/invalid_file.php');
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
|
[
|
||||||
'whatever',
|
'whatever',
|
||||||
[[
|
[
|
||||||
|
[
|
||||||
'range' => [
|
'range' => [
|
||||||
'start' => [
|
'start' => [
|
||||||
'line' => 2,
|
'line' => 2,
|
||||||
|
@ -123,17 +126,22 @@ class ParseErrorsTest extends TestCase
|
||||||
'code' => null,
|
'code' => null,
|
||||||
'source' => 'php',
|
'source' => 'php',
|
||||||
'message' => "'Name' expected."
|
'message' => "'Name' expected."
|
||||||
]]
|
]
|
||||||
], json_decode(json_encode($this->args), true));
|
]
|
||||||
|
],
|
||||||
|
json_decode(json_encode($this->args), true)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testParseErrorsWithOnlyStartLine()
|
public function testParseErrorsWithOnlyStartLine()
|
||||||
{
|
{
|
||||||
$this->markTestIncomplete('This diagnostic not yet implemented in tolerant-php-parser');
|
$this->markTestIncomplete('This diagnostic not yet implemented in tolerant-php-parser');
|
||||||
$this->openFile(__DIR__ . '/../../../fixtures/namespace_not_first.php');
|
$this->openFile(__DIR__ . '/../../../fixtures/namespace_not_first.php');
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
|
[
|
||||||
'whatever',
|
'whatever',
|
||||||
[[
|
[
|
||||||
|
[
|
||||||
'range' => [
|
'range' => [
|
||||||
'start' => [
|
'start' => [
|
||||||
'line' => 4,
|
'line' => 4,
|
||||||
|
@ -148,7 +156,10 @@ class ParseErrorsTest extends TestCase
|
||||||
'code' => null,
|
'code' => null,
|
||||||
'source' => 'php',
|
'source' => 'php',
|
||||||
'message' => "Namespace declaration statement has to be the very first statement in the script"
|
'message' => "Namespace declaration statement has to be the very first statement in the script"
|
||||||
]]
|
]
|
||||||
], json_decode(json_encode($this->args), true));
|
]
|
||||||
|
],
|
||||||
|
json_decode(json_encode($this->args), true)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,16 +3,10 @@ declare(strict_types = 1);
|
||||||
|
|
||||||
namespace LanguageServer\Tests\Server\TextDocument\References;
|
namespace LanguageServer\Tests\Server\TextDocument\References;
|
||||||
|
|
||||||
use LanguageServer\{
|
use LanguageServer\{LanguageClient, PhpDocumentLoader, Server, DefinitionResolver};
|
||||||
LanguageClient, PhpDocumentLoader, Server, DefinitionResolver
|
|
||||||
};
|
|
||||||
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
||||||
use LanguageServer\Index\{
|
use LanguageServer\Index\{DependenciesIndex, Index, ProjectIndex};
|
||||||
DependenciesIndex, Index, ProjectIndex
|
use LanguageServerProtocol\{Location, Position, Range, ReferenceContext, TextDocumentIdentifier};
|
||||||
};
|
|
||||||
use LanguageServerProtocol\{
|
|
||||||
Location, Position, Range, ReferenceContext, TextDocumentIdentifier
|
|
||||||
};
|
|
||||||
use LanguageServer\Tests\MockProtocolStream;
|
use LanguageServer\Tests\MockProtocolStream;
|
||||||
use LanguageServer\Tests\Server\ServerTestCase;
|
use LanguageServer\Tests\Server\ServerTestCase;
|
||||||
|
|
||||||
|
@ -20,25 +14,38 @@ class GlobalFallbackTest extends ServerTestCase
|
||||||
{
|
{
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
$projectIndex = new ProjectIndex(new Index, new DependenciesIndex);
|
$projectIndex = new ProjectIndex(new Index(), new DependenciesIndex());
|
||||||
$projectIndex->setComplete();
|
$projectIndex->setComplete();
|
||||||
$definitionResolver = new DefinitionResolver($projectIndex);
|
$definitionResolver = new DefinitionResolver($projectIndex);
|
||||||
$client = new LanguageClient(new MockProtocolStream, new MockProtocolStream);
|
$client = new LanguageClient(new MockProtocolStream(), new MockProtocolStream());
|
||||||
$this->documentLoader = new PhpDocumentLoader(new FileSystemContentRetriever, $projectIndex, $definitionResolver);
|
$this->documentLoader = new PhpDocumentLoader(
|
||||||
$this->textDocument = new Server\TextDocument($this->documentLoader, $definitionResolver, $client, $projectIndex);
|
new FileSystemContentRetriever(),
|
||||||
$this->documentLoader->open('global_fallback', file_get_contents(__DIR__ . '/../../../../fixtures/global_fallback.php'));
|
$projectIndex,
|
||||||
$this->documentLoader->open('global_symbols', file_get_contents(__DIR__ . '/../../../../fixtures/global_symbols.php'));
|
$definitionResolver
|
||||||
|
);
|
||||||
|
$this->textDocument = new Server\TextDocument(
|
||||||
|
$this->documentLoader,
|
||||||
|
$definitionResolver,
|
||||||
|
$client,
|
||||||
|
$projectIndex
|
||||||
|
);
|
||||||
|
$this->documentLoader->open(
|
||||||
|
'global_fallback',
|
||||||
|
file_get_contents(__DIR__ . '/../../../../fixtures/global_fallback.php')
|
||||||
|
);
|
||||||
|
$this->documentLoader->open(
|
||||||
|
'global_symbols',
|
||||||
|
file_get_contents(__DIR__ . '/../../../../fixtures/global_symbols.php')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testClassDoesNotFallback()
|
public function testClassDoesNotFallback()
|
||||||
{
|
{
|
||||||
// class TestClass implements TestInterface
|
// class TestClass implements TestInterface
|
||||||
// Get references for TestClass
|
// Get references for TestClass
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(new ReferenceContext(), new TextDocumentIdentifier('global_symbols'), new Position(6, 9))
|
||||||
new TextDocumentIdentifier('global_symbols'),
|
->wait();
|
||||||
new Position(6, 9)
|
|
||||||
)->wait();
|
|
||||||
$this->assertEquals([], $result);
|
$this->assertEquals([], $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,23 +53,25 @@ class GlobalFallbackTest extends ServerTestCase
|
||||||
{
|
{
|
||||||
// const TEST_CONST = 123;
|
// const TEST_CONST = 123;
|
||||||
// Get references for TEST_CONST
|
// Get references for TEST_CONST
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(new ReferenceContext(), new TextDocumentIdentifier('global_symbols'), new Position(9, 13))
|
||||||
new TextDocumentIdentifier('global_symbols'),
|
->wait();
|
||||||
new Position(9, 13)
|
$this->assertEquals(
|
||||||
)->wait();
|
[new Location('global_fallback', new Range(new Position(6, 5), new Position(6, 15)))],
|
||||||
$this->assertEquals([new Location('global_fallback', new Range(new Position(6, 5), new Position(6, 15)))], $result);
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testFallsBackForFunctions()
|
public function testFallsBackForFunctions()
|
||||||
{
|
{
|
||||||
// function test_function()
|
// function test_function()
|
||||||
// Get references for test_function
|
// Get references for test_function
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(new ReferenceContext(), new TextDocumentIdentifier('global_symbols'), new Position(78, 16))
|
||||||
new TextDocumentIdentifier('global_symbols'),
|
->wait();
|
||||||
new Position(78, 16)
|
$this->assertEquals(
|
||||||
)->wait();
|
[new Location('global_fallback', new Range(new Position(5, 0), new Position(5, 13)))],
|
||||||
$this->assertEquals([new Location('global_fallback', new Range(new Position(5, 0), new Position(5, 13)))], $result);
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,13 @@ class GlobalTest extends ServerTestCase
|
||||||
// class TestClass implements TestInterface
|
// class TestClass implements TestInterface
|
||||||
// Get references for TestClass
|
// Get references for TestClass
|
||||||
$definition = $this->getDefinitionLocation('TestClass');
|
$definition = $this->getDefinitionLocation('TestClass');
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(
|
||||||
|
new ReferenceContext(),
|
||||||
new TextDocumentIdentifier($definition->uri),
|
new TextDocumentIdentifier($definition->uri),
|
||||||
$definition->range->start
|
$definition->range->start
|
||||||
)->wait();
|
)
|
||||||
|
->wait();
|
||||||
$this->assertEquals($this->getReferenceLocations('TestClass'), $result);
|
$this->assertEquals($this->getReferenceLocations('TestClass'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,11 +29,13 @@ class GlobalTest extends ServerTestCase
|
||||||
// const TEST_CLASS_CONST = 123;
|
// const TEST_CLASS_CONST = 123;
|
||||||
// Get references for TEST_CLASS_CONST
|
// Get references for TEST_CLASS_CONST
|
||||||
$definition = $this->getDefinitionLocation('TestClass::TEST_CLASS_CONST');
|
$definition = $this->getDefinitionLocation('TestClass::TEST_CLASS_CONST');
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(
|
||||||
|
new ReferenceContext(),
|
||||||
new TextDocumentIdentifier($definition->uri),
|
new TextDocumentIdentifier($definition->uri),
|
||||||
$definition->range->start
|
$definition->range->start
|
||||||
)->wait();
|
)
|
||||||
|
->wait();
|
||||||
$this->assertEquals($this->getReferenceLocations('TestClass::TEST_CLASS_CONST'), $result);
|
$this->assertEquals($this->getReferenceLocations('TestClass::TEST_CLASS_CONST'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,11 +44,13 @@ class GlobalTest extends ServerTestCase
|
||||||
// const TEST_CONST = 123;
|
// const TEST_CONST = 123;
|
||||||
// Get references for TEST_CONST
|
// Get references for TEST_CONST
|
||||||
$definition = $this->getDefinitionLocation('TEST_CONST');
|
$definition = $this->getDefinitionLocation('TEST_CONST');
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(
|
||||||
|
new ReferenceContext(),
|
||||||
new TextDocumentIdentifier($definition->uri),
|
new TextDocumentIdentifier($definition->uri),
|
||||||
$definition->range->start
|
$definition->range->start
|
||||||
)->wait();
|
)
|
||||||
|
->wait();
|
||||||
$this->assertEquals($this->getReferenceLocations('TEST_CONST'), $result);
|
$this->assertEquals($this->getReferenceLocations('TEST_CONST'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,11 +59,13 @@ class GlobalTest extends ServerTestCase
|
||||||
// public static function staticTestMethod()
|
// public static function staticTestMethod()
|
||||||
// Get references for staticTestMethod
|
// Get references for staticTestMethod
|
||||||
$definition = $this->getDefinitionLocation('TestClass::staticTestMethod()');
|
$definition = $this->getDefinitionLocation('TestClass::staticTestMethod()');
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(
|
||||||
|
new ReferenceContext(),
|
||||||
new TextDocumentIdentifier($definition->uri),
|
new TextDocumentIdentifier($definition->uri),
|
||||||
$definition->range->start
|
$definition->range->start
|
||||||
)->wait();
|
)
|
||||||
|
->wait();
|
||||||
$this->assertEquals($this->getReferenceLocations('TestClass::staticTestMethod()'), $result);
|
$this->assertEquals($this->getReferenceLocations('TestClass::staticTestMethod()'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,11 +74,13 @@ class GlobalTest extends ServerTestCase
|
||||||
// public static $staticTestProperty;
|
// public static $staticTestProperty;
|
||||||
// Get references for $staticTestProperty
|
// Get references for $staticTestProperty
|
||||||
$definition = $this->getDefinitionLocation('TestClass::staticTestProperty');
|
$definition = $this->getDefinitionLocation('TestClass::staticTestProperty');
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(
|
||||||
|
new ReferenceContext(),
|
||||||
new TextDocumentIdentifier($definition->uri),
|
new TextDocumentIdentifier($definition->uri),
|
||||||
$definition->range->start
|
$definition->range->start
|
||||||
)->wait();
|
)
|
||||||
|
->wait();
|
||||||
$this->assertEquals($this->getReferenceLocations('TestClass::staticTestProperty'), $result);
|
$this->assertEquals($this->getReferenceLocations('TestClass::staticTestProperty'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,11 +89,13 @@ class GlobalTest extends ServerTestCase
|
||||||
// public function testMethod($testParameter)
|
// public function testMethod($testParameter)
|
||||||
// Get references for testMethod
|
// Get references for testMethod
|
||||||
$definition = $this->getDefinitionLocation('TestClass::testMethod()');
|
$definition = $this->getDefinitionLocation('TestClass::testMethod()');
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(
|
||||||
|
new ReferenceContext(),
|
||||||
new TextDocumentIdentifier($definition->uri),
|
new TextDocumentIdentifier($definition->uri),
|
||||||
$definition->range->start
|
$definition->range->start
|
||||||
)->wait();
|
)
|
||||||
|
->wait();
|
||||||
$this->assertEquals($this->getReferenceLocations('TestClass::testMethod()'), $result);
|
$this->assertEquals($this->getReferenceLocations('TestClass::testMethod()'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,11 +104,13 @@ class GlobalTest extends ServerTestCase
|
||||||
// public $testProperty;
|
// public $testProperty;
|
||||||
// Get references for testProperty
|
// Get references for testProperty
|
||||||
$definition = $this->getDefinitionLocation('TestClass::testProperty');
|
$definition = $this->getDefinitionLocation('TestClass::testProperty');
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(
|
||||||
|
new ReferenceContext(),
|
||||||
new TextDocumentIdentifier($definition->uri),
|
new TextDocumentIdentifier($definition->uri),
|
||||||
$definition->range->start
|
$definition->range->start
|
||||||
)->wait();
|
)
|
||||||
|
->wait();
|
||||||
$this->assertEquals($this->getReferenceLocations('TestClass::testProperty'), $result);
|
$this->assertEquals($this->getReferenceLocations('TestClass::testProperty'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,16 +119,17 @@ class GlobalTest extends ServerTestCase
|
||||||
// $var = 123;
|
// $var = 123;
|
||||||
// Get definition for $var
|
// Get definition for $var
|
||||||
$uri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/references.php'));
|
$uri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/references.php'));
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(new ReferenceContext(), new TextDocumentIdentifier($uri), new Position(12, 3))
|
||||||
new TextDocumentIdentifier($uri),
|
->wait();
|
||||||
new Position(12, 3)
|
$this->assertEquals(
|
||||||
)->wait();
|
[
|
||||||
$this->assertEquals([
|
|
||||||
new Location($uri, new Range(new Position(12, 0), new Position(12, 4))),
|
new Location($uri, new Range(new Position(12, 0), new Position(12, 4))),
|
||||||
new Location($uri, new Range(new Position(13, 5), new Position(13, 9))),
|
new Location($uri, new Range(new Position(13, 5), new Position(13, 9))),
|
||||||
new Location($uri, new Range(new Position(26, 9), new Position(26, 13)))
|
new Location($uri, new Range(new Position(26, 9), new Position(26, 13)))
|
||||||
], $result);
|
],
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testReferencesForFunctionParams()
|
public function testReferencesForFunctionParams()
|
||||||
|
@ -122,11 +137,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// function whatever(TestClass $param): TestClass
|
// function whatever(TestClass $param): TestClass
|
||||||
// Get references for $param
|
// Get references for $param
|
||||||
$uri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/references.php'));
|
$uri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/references.php'));
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(new ReferenceContext(), new TextDocumentIdentifier($uri), new Position(21, 32))
|
||||||
new TextDocumentIdentifier($uri),
|
->wait();
|
||||||
new Position(21, 32)
|
|
||||||
)->wait();
|
|
||||||
$this->assertEquals([new Location($uri, new Range(new Position(22, 9), new Position(22, 15)))], $result);
|
$this->assertEquals([new Location($uri, new Range(new Position(22, 9), new Position(22, 15)))], $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,15 +149,16 @@ class GlobalTest extends ServerTestCase
|
||||||
// Get references for test_function
|
// Get references for test_function
|
||||||
$referencesUri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/references.php'));
|
$referencesUri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/references.php'));
|
||||||
$symbolsUri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/symbols.php'));
|
$symbolsUri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/symbols.php'));
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(new ReferenceContext(), new TextDocumentIdentifier($symbolsUri), new Position(78, 16))
|
||||||
new TextDocumentIdentifier($symbolsUri),
|
->wait();
|
||||||
new Position(78, 16)
|
$this->assertEquals(
|
||||||
)->wait();
|
[
|
||||||
$this->assertEquals([
|
|
||||||
new Location($referencesUri, new Range(new Position(10, 0), new Position(10, 13))),
|
new Location($referencesUri, new Range(new Position(10, 0), new Position(10, 13))),
|
||||||
new Location($referencesUri, new Range(new Position(31, 13), new Position(31, 40)))
|
new Location($referencesUri, new Range(new Position(31, 13), new Position(31, 40)))
|
||||||
], $result);
|
],
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testReferencesForReference()
|
public function testReferencesForReference()
|
||||||
|
@ -152,11 +166,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// $obj = new TestClass();
|
// $obj = new TestClass();
|
||||||
// Get references for TestClass
|
// Get references for TestClass
|
||||||
$reference = $this->getReferenceLocations('TestClass')[1];
|
$reference = $this->getReferenceLocations('TestClass')[1];
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(new ReferenceContext(), new TextDocumentIdentifier($reference->uri), $reference->range->start)
|
||||||
new TextDocumentIdentifier($reference->uri),
|
->wait();
|
||||||
$reference->range->start
|
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($this->getReferenceLocations('TestClass'), $result);
|
$this->assertEquals($this->getReferenceLocations('TestClass'), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,11 +177,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// class UnusedClass
|
// class UnusedClass
|
||||||
// Get references for UnusedClass
|
// Get references for UnusedClass
|
||||||
$symbolsUri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/global_symbols.php'));
|
$symbolsUri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/global_symbols.php'));
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(new ReferenceContext(), new TextDocumentIdentifier($symbolsUri), new Position(111, 10))
|
||||||
new TextDocumentIdentifier($symbolsUri),
|
->wait();
|
||||||
new Position(111, 10)
|
|
||||||
)->wait();
|
|
||||||
$this->assertEquals([], $result);
|
$this->assertEquals([], $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,11 +188,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// public $unusedProperty
|
// public $unusedProperty
|
||||||
// Get references for unusedProperty
|
// Get references for unusedProperty
|
||||||
$symbolsUri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/global_symbols.php'));
|
$symbolsUri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/global_symbols.php'));
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(new ReferenceContext(), new TextDocumentIdentifier($symbolsUri), new Position(113, 18))
|
||||||
new TextDocumentIdentifier($symbolsUri),
|
->wait();
|
||||||
new Position(113, 18)
|
|
||||||
)->wait();
|
|
||||||
$this->assertEquals([], $result);
|
$this->assertEquals([], $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,11 +199,9 @@ class GlobalTest extends ServerTestCase
|
||||||
// public function unusedMethod()
|
// public function unusedMethod()
|
||||||
// Get references for unusedMethod
|
// Get references for unusedMethod
|
||||||
$symbolsUri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/global_symbols.php'));
|
$symbolsUri = pathToUri(realpath(__DIR__ . '/../../../../fixtures/global_symbols.php'));
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(new ReferenceContext(), new TextDocumentIdentifier($symbolsUri), new Position(115, 26))
|
||||||
new TextDocumentIdentifier($symbolsUri),
|
->wait();
|
||||||
new Position(115, 26)
|
|
||||||
)->wait();
|
|
||||||
$this->assertEquals([], $result);
|
$this->assertEquals([], $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,9 @@ class NamespacedTest extends GlobalTest
|
||||||
// namespace TestNamespace;
|
// namespace TestNamespace;
|
||||||
// Get references for TestNamespace
|
// Get references for TestNamespace
|
||||||
$definition = parent::getDefinitionLocation('TestNamespace');
|
$definition = parent::getDefinitionLocation('TestNamespace');
|
||||||
$result = $this->textDocument->references(
|
$result = $this->textDocument
|
||||||
new ReferenceContext,
|
->references(new ReferenceContext(), new TextDocumentIdentifier($definition->uri), $definition->range->end)
|
||||||
new TextDocumentIdentifier($definition->uri),
|
->wait();
|
||||||
$definition->range->end
|
|
||||||
)->wait();
|
|
||||||
$this->assertEquals(parent::getReferenceLocations('TestNamespace'), $result);
|
$this->assertEquals(parent::getReferenceLocations('TestNamespace'), $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,7 @@ namespace LanguageServer\Tests\Server\TextDocument;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use LanguageServer\Tests\MockProtocolStream;
|
use LanguageServer\Tests\MockProtocolStream;
|
||||||
use LanguageServer\{
|
use LanguageServer\{Server, LanguageClient, PhpDocumentLoader, DefinitionResolver};
|
||||||
Server, LanguageClient, PhpDocumentLoader, DefinitionResolver
|
|
||||||
};
|
|
||||||
use LanguageServer\Index\{Index, ProjectIndex, DependenciesIndex};
|
use LanguageServer\Index\{Index, ProjectIndex, DependenciesIndex};
|
||||||
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
||||||
use LanguageServerProtocol\{
|
use LanguageServerProtocol\{
|
||||||
|
@ -35,11 +33,11 @@ class SignatureHelpTest extends TestCase
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
$client = new LanguageClient(new MockProtocolStream, new MockProtocolStream);
|
$client = new LanguageClient(new MockProtocolStream(), new MockProtocolStream());
|
||||||
$index = new Index();
|
$index = new Index();
|
||||||
$projectIndex = new ProjectIndex($index, new DependenciesIndex);
|
$projectIndex = new ProjectIndex($index, new DependenciesIndex());
|
||||||
$definitionResolver = new DefinitionResolver($projectIndex);
|
$definitionResolver = new DefinitionResolver($projectIndex);
|
||||||
$contentRetriever = new FileSystemContentRetriever;
|
$contentRetriever = new FileSystemContentRetriever();
|
||||||
$this->loader = new PhpDocumentLoader($contentRetriever, $projectIndex, $definitionResolver);
|
$this->loader = new PhpDocumentLoader($contentRetriever, $projectIndex, $definitionResolver);
|
||||||
$this->textDocument = new Server\TextDocument($this->loader, $definitionResolver, $client, $projectIndex);
|
$this->textDocument = new Server\TextDocument($this->loader, $definitionResolver, $client, $projectIndex);
|
||||||
$index->setComplete();
|
$index->setComplete();
|
||||||
|
@ -52,10 +50,7 @@ class SignatureHelpTest extends TestCase
|
||||||
{
|
{
|
||||||
$callsUri = pathToUri(__DIR__ . '/../../../fixtures/signature_help/calls.php');
|
$callsUri = pathToUri(__DIR__ . '/../../../fixtures/signature_help/calls.php');
|
||||||
$this->loader->open($callsUri, file_get_contents($callsUri));
|
$this->loader->open($callsUri, file_get_contents($callsUri));
|
||||||
$signatureHelp = $this->textDocument->signatureHelp(
|
$signatureHelp = $this->textDocument->signatureHelp(new TextDocumentIdentifier($callsUri), $position)->wait();
|
||||||
new TextDocumentIdentifier($callsUri),
|
|
||||||
$position
|
|
||||||
)->wait();
|
|
||||||
$this->assertEquals($expectedSignature, $signatureHelp);
|
$this->assertEquals($expectedSignature, $signatureHelp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,15 +64,18 @@ class SignatureHelpTest extends TestCase
|
||||||
new SignatureInformation(
|
new SignatureInformation(
|
||||||
'(\\Foo\\SomethingElse $a, int|null $b = null)',
|
'(\\Foo\\SomethingElse $a, int|null $b = null)',
|
||||||
[
|
[
|
||||||
new ParameterInformation('\\Foo\\SomethingElse $a', 'A param with a different doc type'),
|
new ParameterInformation(
|
||||||
new ParameterInformation('int|null $b = null', 'Param with default value'),
|
'\\Foo\\SomethingElse $a',
|
||||||
|
'A param with a different doc type'
|
||||||
|
),
|
||||||
|
new ParameterInformation('int|null $b = null', 'Param with default value')
|
||||||
],
|
],
|
||||||
'Function doc'
|
'Function doc'
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
0,
|
0,
|
||||||
0
|
0
|
||||||
),
|
)
|
||||||
],
|
],
|
||||||
'member call 2nd param active' => [
|
'member call 2nd param active' => [
|
||||||
new Position(51, 12),
|
new Position(51, 12),
|
||||||
|
@ -86,15 +84,18 @@ class SignatureHelpTest extends TestCase
|
||||||
new SignatureInformation(
|
new SignatureInformation(
|
||||||
'(\\Foo\\SomethingElse $a, int|null $b = null)',
|
'(\\Foo\\SomethingElse $a, int|null $b = null)',
|
||||||
[
|
[
|
||||||
new ParameterInformation('\\Foo\\SomethingElse $a', 'A param with a different doc type'),
|
new ParameterInformation(
|
||||||
new ParameterInformation('int|null $b = null', 'Param with default value'),
|
'\\Foo\\SomethingElse $a',
|
||||||
|
'A param with a different doc type'
|
||||||
|
),
|
||||||
|
new ParameterInformation('int|null $b = null', 'Param with default value')
|
||||||
],
|
],
|
||||||
'Function doc'
|
'Function doc'
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
0,
|
0,
|
||||||
1
|
1
|
||||||
),
|
)
|
||||||
],
|
],
|
||||||
'member call 2nd param active and closing )' => [
|
'member call 2nd param active and closing )' => [
|
||||||
new Position(52, 11),
|
new Position(52, 11),
|
||||||
|
@ -103,19 +104,22 @@ class SignatureHelpTest extends TestCase
|
||||||
new SignatureInformation(
|
new SignatureInformation(
|
||||||
'(\\Foo\\SomethingElse $a, int|null $b = null)',
|
'(\\Foo\\SomethingElse $a, int|null $b = null)',
|
||||||
[
|
[
|
||||||
new ParameterInformation('\\Foo\\SomethingElse $a', 'A param with a different doc type'),
|
new ParameterInformation(
|
||||||
new ParameterInformation('int|null $b = null', 'Param with default value'),
|
'\\Foo\\SomethingElse $a',
|
||||||
|
'A param with a different doc type'
|
||||||
|
),
|
||||||
|
new ParameterInformation('int|null $b = null', 'Param with default value')
|
||||||
],
|
],
|
||||||
'Function doc'
|
'Function doc'
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
0,
|
0,
|
||||||
1
|
1
|
||||||
),
|
)
|
||||||
],
|
],
|
||||||
'method with no params' => [
|
'method with no params' => [
|
||||||
new Position(53, 9),
|
new Position(53, 9),
|
||||||
new SignatureHelp([new SignatureInformation('()', [], 'Method with no params', 0, 0)]),
|
new SignatureHelp([new SignatureInformation('()', [], 'Method with no params', 0, 0)])
|
||||||
],
|
],
|
||||||
'constructor' => [
|
'constructor' => [
|
||||||
new Position(48, 14),
|
new Position(48, 14),
|
||||||
|
@ -126,14 +130,14 @@ class SignatureHelpTest extends TestCase
|
||||||
[
|
[
|
||||||
new ParameterInformation('string $first', 'First param'),
|
new ParameterInformation('string $first', 'First param'),
|
||||||
new ParameterInformation('int $second', 'Second param'),
|
new ParameterInformation('int $second', 'Second param'),
|
||||||
new ParameterInformation('\Foo\Test $third', 'Third param with a longer description'),
|
new ParameterInformation('\Foo\Test $third', 'Third param with a longer description')
|
||||||
],
|
],
|
||||||
'Constructor comment goes here'
|
'Constructor comment goes here'
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
0,
|
0,
|
||||||
0
|
0
|
||||||
),
|
)
|
||||||
],
|
],
|
||||||
'constructor argument expression list' => [
|
'constructor argument expression list' => [
|
||||||
new Position(49, 16),
|
new Position(49, 16),
|
||||||
|
@ -144,27 +148,24 @@ class SignatureHelpTest extends TestCase
|
||||||
[
|
[
|
||||||
new ParameterInformation('string $first', 'First param'),
|
new ParameterInformation('string $first', 'First param'),
|
||||||
new ParameterInformation('int $second', 'Second param'),
|
new ParameterInformation('int $second', 'Second param'),
|
||||||
new ParameterInformation('\Foo\Test $third', 'Third param with a longer description'),
|
new ParameterInformation('\Foo\Test $third', 'Third param with a longer description')
|
||||||
],
|
],
|
||||||
'Constructor comment goes here'
|
'Constructor comment goes here'
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
0,
|
0,
|
||||||
1
|
1
|
||||||
),
|
)
|
||||||
],
|
],
|
||||||
'global function' => [
|
'global function' => [
|
||||||
new Position(57, 15),
|
new Position(57, 15),
|
||||||
new SignatureHelp(
|
new SignatureHelp(
|
||||||
[
|
[
|
||||||
new SignatureInformation(
|
new SignatureInformation('(int $i, bool $b = false, \Foo\Test|null ...$things = null)', [
|
||||||
'(int $i, bool $b = false, \Foo\Test|null ...$things = null)',
|
|
||||||
[
|
|
||||||
new ParameterInformation('int $i', 'Global function param one'),
|
new ParameterInformation('int $i', 'Global function param one'),
|
||||||
new ParameterInformation('bool $b = false', 'Default false param'),
|
new ParameterInformation('bool $b = false', 'Default false param'),
|
||||||
new ParameterInformation('\Foo\Test|null ...$things = null', 'Test things'),
|
new ParameterInformation('\Foo\Test|null ...$things = null', 'Test things')
|
||||||
]
|
])
|
||||||
),
|
|
||||||
],
|
],
|
||||||
0,
|
0,
|
||||||
2
|
2
|
||||||
|
@ -176,24 +177,15 @@ class SignatureHelpTest extends TestCase
|
||||||
[new SignatureInformation('(mixed $a)', [new ParameterInformation('mixed $a')])],
|
[new SignatureInformation('(mixed $a)', [new ParameterInformation('mixed $a')])],
|
||||||
0,
|
0,
|
||||||
0
|
0
|
||||||
),
|
)
|
||||||
],
|
|
||||||
'no signature help' => [
|
|
||||||
new Position(0, 0),
|
|
||||||
new SignatureHelp([]),
|
|
||||||
],
|
|
||||||
'construct from non fqn (not supported)' => [
|
|
||||||
new Position(62, 9),
|
|
||||||
new SignatureHelp([]),
|
|
||||||
],
|
],
|
||||||
|
'no signature help' => [new Position(0, 0), new SignatureHelp([])],
|
||||||
|
'construct from non fqn (not supported)' => [new Position(62, 9), new SignatureHelp([])],
|
||||||
'construct from non fqn (not supported) argument expression' => [
|
'construct from non fqn (not supported) argument expression' => [
|
||||||
new Position(63, 11),
|
new Position(63, 11),
|
||||||
new SignatureHelp([]),
|
new SignatureHelp([])
|
||||||
],
|
|
||||||
'invalid var' => [
|
|
||||||
new Position(65, 13),
|
|
||||||
new SignatureHelp([]),
|
|
||||||
],
|
],
|
||||||
|
'invalid var' => [new Position(65, 13), new SignatureHelp([])]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,19 @@ class DidChangeWatchedFilesTest extends ServerTestCase
|
||||||
{
|
{
|
||||||
public function testDeletingFileClearsAllDiagnostics()
|
public function testDeletingFileClearsAllDiagnostics()
|
||||||
{
|
{
|
||||||
$client = new LanguageClient(new MockProtocolStream(), $writer = new MockProtocolStream());
|
$client = new LanguageClient(new MockProtocolStream(), ($writer = new MockProtocolStream()));
|
||||||
$projectIndex = new ProjectIndex($sourceIndex = new Index(), $dependenciesIndex = new DependenciesIndex());
|
$projectIndex = new ProjectIndex(($sourceIndex = new Index()), ($dependenciesIndex = new DependenciesIndex()));
|
||||||
$definitionResolver = new DefinitionResolver($projectIndex);
|
$definitionResolver = new DefinitionResolver($projectIndex);
|
||||||
$loader = new PhpDocumentLoader(new FileSystemContentRetriever(), $projectIndex, $definitionResolver);
|
$loader = new PhpDocumentLoader(new FileSystemContentRetriever(), $projectIndex, $definitionResolver);
|
||||||
$workspace = new Server\Workspace($client, $projectIndex, $dependenciesIndex, $sourceIndex, null, $loader, null);
|
$workspace = new Server\Workspace(
|
||||||
|
$client,
|
||||||
|
$projectIndex,
|
||||||
|
$dependenciesIndex,
|
||||||
|
$sourceIndex,
|
||||||
|
null,
|
||||||
|
$loader,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
$fileEvent = new FileEvent('my uri', FileChangeType::DELETED);
|
$fileEvent = new FileEvent('my uri', FileChangeType::DELETED);
|
||||||
|
|
||||||
|
|
|
@ -29,46 +29,204 @@ class SymbolTest extends ServerTestCase
|
||||||
$referencesUri = pathToUri(realpath(__DIR__ . '/../../../fixtures/references.php'));
|
$referencesUri = pathToUri(realpath(__DIR__ . '/../../../fixtures/references.php'));
|
||||||
|
|
||||||
// @codingStandardsIgnoreStart
|
// @codingStandardsIgnoreStart
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
new SymbolInformation('TestNamespace', SymbolKind::NAMESPACE, new Location($referencesUri, new Range(new Position(2, 0), new Position(2, 24))), ''),
|
[
|
||||||
|
new SymbolInformation(
|
||||||
|
'TestNamespace',
|
||||||
|
SymbolKind::NAMESPACE,
|
||||||
|
new Location($referencesUri, new Range(new Position(2, 0), new Position(2, 24))),
|
||||||
|
''
|
||||||
|
),
|
||||||
// Namespaced
|
// Namespaced
|
||||||
new SymbolInformation('TEST_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestNamespace\\TEST_CONST'), 'TestNamespace'),
|
new SymbolInformation(
|
||||||
new SymbolInformation('TestClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\TestClass'), 'TestNamespace'),
|
'TEST_CONST',
|
||||||
new SymbolInformation('TEST_CLASS_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestNamespace\\TestClass::TEST_CLASS_CONST'), 'TestNamespace\\TestClass'),
|
SymbolKind::CONSTANT,
|
||||||
new SymbolInformation('staticTestProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestNamespace\\TestClass::staticTestProperty'), 'TestNamespace\\TestClass'),
|
$this->getDefinitionLocation('TestNamespace\\TEST_CONST'),
|
||||||
new SymbolInformation('testProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestNamespace\\TestClass::testProperty'), 'TestNamespace\\TestClass'),
|
'TestNamespace'
|
||||||
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(
|
||||||
new SymbolInformation('TestTrait', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\TestTrait'), 'TestNamespace'),
|
'TestClass',
|
||||||
new SymbolInformation('TestInterface', SymbolKind::INTERFACE, $this->getDefinitionLocation('TestNamespace\\TestInterface'), 'TestNamespace'),
|
SymbolKind::CLASS_,
|
||||||
new SymbolInformation('test_function', SymbolKind::FUNCTION, $this->getDefinitionLocation('TestNamespace\\test_function()'), 'TestNamespace'),
|
$this->getDefinitionLocation('TestNamespace\\TestClass'),
|
||||||
new SymbolInformation('ChildClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\ChildClass'), 'TestNamespace'),
|
'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(
|
||||||
new SymbolInformation('__destruct', SymbolKind::CONSTRUCTOR, $this->getDefinitionLocation('TestNamespace\\Example::__destruct'), 'TestNamespace\\Example'),
|
'TEST_CLASS_CONST',
|
||||||
new SymbolInformation('TestNamespace\\InnerNamespace', SymbolKind::NAMESPACE, $this->getDefinitionLocation('TestNamespace\\InnerNamespace'), 'TestNamespace'),
|
SymbolKind::CONSTANT,
|
||||||
new SymbolInformation('InnerClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\InnerNamespace\\InnerClass'), 'TestNamespace\\InnerNamespace'),
|
$this->getDefinitionLocation('TestNamespace\\TestClass::TEST_CLASS_CONST'),
|
||||||
new SymbolInformation('whatever', SymbolKind::FUNCTION, $this->getDefinitionLocation('TestNamespace\\whatever()'), 'TestNamespace'),
|
'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(
|
||||||
|
'TestNamespace\\InnerNamespace',
|
||||||
|
SymbolKind::NAMESPACE,
|
||||||
|
$this->getDefinitionLocation('TestNamespace\\InnerNamespace'),
|
||||||
|
'TestNamespace'
|
||||||
|
),
|
||||||
|
new SymbolInformation(
|
||||||
|
'InnerClass',
|
||||||
|
SymbolKind::CLASS_,
|
||||||
|
$this->getDefinitionLocation('TestNamespace\\InnerNamespace\\InnerClass'),
|
||||||
|
'TestNamespace\\InnerNamespace'
|
||||||
|
),
|
||||||
|
new SymbolInformation(
|
||||||
|
'whatever',
|
||||||
|
SymbolKind::FUNCTION,
|
||||||
|
$this->getDefinitionLocation('TestNamespace\\whatever()'),
|
||||||
|
'TestNamespace'
|
||||||
|
),
|
||||||
// Global
|
// Global
|
||||||
new SymbolInformation('TEST_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TEST_CONST'), ''),
|
new SymbolInformation(
|
||||||
|
'TEST_CONST',
|
||||||
|
SymbolKind::CONSTANT,
|
||||||
|
$this->getDefinitionLocation('TEST_CONST'),
|
||||||
|
''
|
||||||
|
),
|
||||||
new SymbolInformation('TestClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestClass'), ''),
|
new SymbolInformation('TestClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestClass'), ''),
|
||||||
new SymbolInformation('TEST_CLASS_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestClass::TEST_CLASS_CONST'), 'TestClass'),
|
new SymbolInformation(
|
||||||
new SymbolInformation('staticTestProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestClass::staticTestProperty'), 'TestClass'),
|
'TEST_CLASS_CONST',
|
||||||
new SymbolInformation('testProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('TestClass::testProperty'), 'TestClass'),
|
SymbolKind::CONSTANT,
|
||||||
new SymbolInformation('staticTestMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestClass::staticTestMethod()'), 'TestClass'),
|
$this->getDefinitionLocation('TestClass::TEST_CLASS_CONST'),
|
||||||
new SymbolInformation('testMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestClass::testMethod()'), 'TestClass'),
|
'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('TestTrait', SymbolKind::CLASS_, $this->getDefinitionLocation('TestTrait'), ''),
|
||||||
new SymbolInformation('TestInterface', SymbolKind::INTERFACE, $this->getDefinitionLocation('TestInterface'), ''),
|
new SymbolInformation(
|
||||||
new SymbolInformation('test_function', SymbolKind::FUNCTION, $this->getDefinitionLocation('test_function()'), ''),
|
'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('ChildClass', SymbolKind::CLASS_, $this->getDefinitionLocation('ChildClass'), ''),
|
||||||
new SymbolInformation('TEST_DEFINE_CONSTANT', SymbolKind::CONSTANT, $this->getDefinitionLocation('TEST_DEFINE_CONSTANT'), ''),
|
new SymbolInformation(
|
||||||
new SymbolInformation('UnusedClass', SymbolKind::CLASS_, $this->getDefinitionLocation('UnusedClass'), ''),
|
'TEST_DEFINE_CONSTANT',
|
||||||
new SymbolInformation('unusedProperty', SymbolKind::PROPERTY, $this->getDefinitionLocation('UnusedClass::unusedProperty'), 'UnusedClass'),
|
SymbolKind::CONSTANT,
|
||||||
new SymbolInformation('unusedMethod', SymbolKind::METHOD, $this->getDefinitionLocation('UnusedClass::unusedMethod'), 'UnusedClass'),
|
$this->getDefinitionLocation('TEST_DEFINE_CONSTANT'),
|
||||||
|
''
|
||||||
|
),
|
||||||
|
new SymbolInformation(
|
||||||
|
'UnusedClass',
|
||||||
|
SymbolKind::CLASS_,
|
||||||
|
$this->getDefinitionLocation('UnusedClass'),
|
||||||
|
''
|
||||||
|
),
|
||||||
|
new SymbolInformation(
|
||||||
|
'unusedProperty',
|
||||||
|
SymbolKind::PROPERTY,
|
||||||
|
$this->getDefinitionLocation('UnusedClass::unusedProperty'),
|
||||||
|
'UnusedClass'
|
||||||
|
),
|
||||||
|
new SymbolInformation(
|
||||||
|
'unusedMethod',
|
||||||
|
SymbolKind::METHOD,
|
||||||
|
$this->getDefinitionLocation('UnusedClass::unusedMethod'),
|
||||||
|
'UnusedClass'
|
||||||
|
),
|
||||||
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(
|
||||||
], $result);
|
'SecondTestNamespace',
|
||||||
|
SymbolKind::NAMESPACE,
|
||||||
|
$this->getDefinitionLocation('SecondTestNamespace'),
|
||||||
|
''
|
||||||
|
)
|
||||||
|
],
|
||||||
|
$result
|
||||||
|
);
|
||||||
// @codingStandardsIgnoreEnd
|
// @codingStandardsIgnoreEnd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,12 +235,35 @@ class SymbolTest extends ServerTestCase
|
||||||
// Request symbols
|
// Request symbols
|
||||||
$result = $this->workspace->symbol('testmethod')->wait();
|
$result = $this->workspace->symbol('testmethod')->wait();
|
||||||
// @codingStandardsIgnoreStart
|
// @codingStandardsIgnoreStart
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
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(
|
||||||
new SymbolInformation('staticTestMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestClass::staticTestMethod()'), 'TestClass'),
|
'staticTestMethod',
|
||||||
new SymbolInformation('testMethod', SymbolKind::METHOD, $this->getDefinitionLocation('TestClass::testMethod()'), 'TestClass')
|
SymbolKind::METHOD,
|
||||||
], $result);
|
$this->getDefinitionLocation('TestNamespace\\TestClass::staticTestMethod()'),
|
||||||
|
'TestNamespace\\TestClass'
|
||||||
|
),
|
||||||
|
new SymbolInformation(
|
||||||
|
'testMethod',
|
||||||
|
SymbolKind::METHOD,
|
||||||
|
$this->getDefinitionLocation('TestNamespace\\TestClass::testMethod()'),
|
||||||
|
'TestNamespace\\TestClass'
|
||||||
|
),
|
||||||
|
new SymbolInformation(
|
||||||
|
'staticTestMethod',
|
||||||
|
SymbolKind::METHOD,
|
||||||
|
$this->getDefinitionLocation('TestClass::staticTestMethod()'),
|
||||||
|
'TestClass'
|
||||||
|
),
|
||||||
|
new SymbolInformation(
|
||||||
|
'testMethod',
|
||||||
|
SymbolKind::METHOD,
|
||||||
|
$this->getDefinitionLocation('TestClass::testMethod()'),
|
||||||
|
'TestClass'
|
||||||
|
)
|
||||||
|
],
|
||||||
|
$result
|
||||||
|
);
|
||||||
// @codingStandardsIgnoreEnd
|
// @codingStandardsIgnoreEnd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,10 @@ class ValidationTest extends TestCase
|
||||||
$disabled = json_decode(file_get_contents(__DIR__ . '/disabled.json'));
|
$disabled = json_decode(file_get_contents(__DIR__ . '/disabled.json'));
|
||||||
|
|
||||||
foreach (new RecursiveIteratorIterator($iterator) as $file) {
|
foreach (new RecursiveIteratorIterator($iterator) as $file) {
|
||||||
if (strpos(\strrev((string)$file), \strrev(".php")) === 0 && !\in_array(basename((string)$file), $disabled)) {
|
if (
|
||||||
|
strpos(\strrev((string) $file), \strrev(".php")) === 0 &&
|
||||||
|
!\in_array(basename((string) $file), $disabled)
|
||||||
|
) {
|
||||||
if ($file->getSize() < 100000) {
|
if ($file->getSize() < 100000) {
|
||||||
$testProviderArray[] = [$file->getPathname()];
|
$testProviderArray[] = [$file->getPathname()];
|
||||||
}
|
}
|
||||||
|
@ -64,7 +67,11 @@ class ValidationTest extends TestCase
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->assertEquals($expectedValues['definitions'], $actualValues['definitions']);
|
$this->assertEquals($expectedValues['definitions'], $actualValues['definitions']);
|
||||||
$this->assertEquals((array)$expectedValues['references'], (array)$actualValues['references'], sprintf('references match in "%s"', $outputFile));
|
$this->assertEquals(
|
||||||
|
(array) $expectedValues['references'],
|
||||||
|
(array) $actualValues['references'],
|
||||||
|
sprintf('references match in "%s"', $outputFile)
|
||||||
|
);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$outputFile = getExpectedValuesFile($testCaseFile);
|
$outputFile = getExpectedValuesFile($testCaseFile);
|
||||||
file_put_contents($outputFile, json_encode($actualValues, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
file_put_contents($outputFile, json_encode($actualValues, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||||
|
@ -106,10 +113,22 @@ class ValidationTest extends TestCase
|
||||||
|
|
||||||
// Turn def locations into relative paths
|
// Turn def locations into relative paths
|
||||||
foreach ($refsAndDefs['definitions'] as $key => $def) {
|
foreach ($refsAndDefs['definitions'] as $key => $def) {
|
||||||
if ($def !== null && $def->symbolInformation !== null &&
|
if (
|
||||||
$def->symbolInformation->location !== null && $def->symbolInformation->location->uri !== null) {
|
$def !== null &&
|
||||||
$def->symbolInformation->location->uri = str_replace($testCasesDir, '.', $def->symbolInformation->location->uri);
|
$def->symbolInformation !== null &&
|
||||||
$def->symbolInformation->location->uri = str_replace(DIRECTORY_SEPARATOR, '/', $def->symbolInformation->location->uri);
|
$def->symbolInformation->location !== null &&
|
||||||
|
$def->symbolInformation->location->uri !== null
|
||||||
|
) {
|
||||||
|
$def->symbolInformation->location->uri = str_replace(
|
||||||
|
$testCasesDir,
|
||||||
|
'.',
|
||||||
|
$def->symbolInformation->location->uri
|
||||||
|
);
|
||||||
|
$def->symbolInformation->location->uri = str_replace(
|
||||||
|
DIRECTORY_SEPARATOR,
|
||||||
|
'/',
|
||||||
|
$def->symbolInformation->location->uri
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1 @@
|
||||||
[
|
["forLoopReference1.php", "namespaces3.php", "parameterTypeResolution1.php", "parent2.php", "newStatic.php"]
|
||||||
"forLoopReference1.php",
|
|
||||||
"namespaces3.php",
|
|
||||||
"parameterTypeResolution1.php",
|
|
||||||
"parent2.php",
|
|
||||||
"newStatic.php"
|
|
||||||
]
|
|
||||||
|
|
Loading…
Reference in New Issue