1
0
Fork 0

Merge remote-tracking branch 'felixfbecker/master' into signatureHelp

pull/547/head
Philip Nelson 2017-12-04 17:52:30 +11:00
commit 962785493e
108 changed files with 964 additions and 686 deletions

View File

@ -7,3 +7,4 @@ fixtures/
coverage/ coverage/
coverage.xml coverage.xml
images/ images/
node_modules/

View File

@ -7,7 +7,7 @@ trim_trailing_whitespace = true
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
[*.json,*.yml] [*.{json,yml}]
indent_size = 2 indent_size = 2
[composer.json] [composer.json]

23
.gitattributes vendored Normal file
View File

@ -0,0 +1,23 @@
* text=auto
/.vscode export-ignore
/fixtures export-ignore
/images export-ignore
/tests export-ignore
/validation export-ignore
/.dockerignore export-ignore
/.editorconfig export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/.gitmodules export-ignore
/.npmrc export-ignore
/.travis.yml export-ignore
/codecov.yml export-ignore
/dependencies.yml export-ignore
/Dockerfile export-ignore
/package.json export-ignore
/Performance.php export-ignore
/php.ini export-ignore
/phpcs.xml.dist export-ignore
/phpunit.xml.dist export-ignore
/release-docker.php export-ignore

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ vendor/
composer.lock composer.lock
stubs stubs
*.ast *.ast
node_modules/

1
.npmrc Normal file
View File

@ -0,0 +1 @@
package-lock=false

View File

@ -1,28 +1,60 @@
language: php language: php
php: php:
- '7.0' - '7.0'
- '7.2.0RC5'
services: git:
- docker depth: 10
submodules: false
cache: cache:
directories: directories:
- $HOME/Library/Caches/Homebrew
- $HOME/.composer/cache - $HOME/.composer/cache
- $HOME/.npm
install: install:
- composer install - composer install --prefer-dist --no-interaction
- composer run-script parse-stubs
script: script:
- vendor/bin/phpcs -n - vendor/bin/phpcs -n
- vendor/bin/phpunit --coverage-clover=coverage.xml - vendor/bin/phpunit --coverage-clover=coverage.xml --colors=always
after_success:
- bash <(curl -s https://codecov.io/bash) - bash <(curl -s https://codecov.io/bash)
- |
if [[ $TRAVIS_TAG == v* ]]; then jobs:
docker build -t felixfbecker/php-language-server:${TRAVIS_TAG:1} . include:
docker login -e="$DOCKER_EMAIL" -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD" - stage: test
docker push felixfbecker/php-language-server:${TRAVIS_TAG:1} os: osx
fi osx_image: xcode9.1
language: generic
before_install:
# Fix ruby error https://github.com/Homebrew/brew/issues/3299
- brew update
- brew tap homebrew/homebrew-php
- brew install php71
- brew install homebrew/php/php71-xdebug
- php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
- php composer-setup.php
- ln -s "`pwd`/composer.phar" /usr/local/bin/composer
- stage: release
php: '7.0'
services:
- docker
install:
- composer install --prefer-dist --no-interaction
- nvm install 8
- nvm use 8
- npm install
script:
- docker build -t felixfbecker/php-language-server .
- npm run semantic-release
stages:
- test
- name: release
if: branch = master AND type = push AND fork = false
branches:
except:
- /^v\d+\.\d+\.\d+$/

18
.vscode/launch.json vendored
View File

@ -1,6 +1,14 @@
{ {
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{
"name": "PHPUnit",
"type": "php",
"request": "launch",
"program": "${workspaceRoot}/vendor/phpunit/phpunit/phpunit",
// "args": ["--filter", "testDefinitionForSelfKeyword"],
"cwd": "${workspaceRoot}"
},
{ {
"name": "Listen for XDebug", "name": "Listen for XDebug",
"type": "php", "type": "php",
@ -14,16 +22,6 @@
"program": "${file}", "program": "${file}",
"cwd": "${fileDirname}", "cwd": "${fileDirname}",
"port": 9000 "port": 9000
},
{
"name": "PHPUnit",
"type": "php",
"request": "launch",
"program": "${workspaceRoot}/vendor/phpunit/phpunit/phpunit",
"cwd": "${workspaceRoot}",
"args": [
// "--filter", "CompletionTest"
]
} }
] ]
} }

View File

@ -7,11 +7,6 @@
FROM php:7-cli FROM php:7-cli
MAINTAINER Felix Becker <felix.b@outlook.com> MAINTAINER Felix Becker <felix.b@outlook.com>
RUN apt-get update \
# Needed for CodeSniffer
&& apt-get install -y libxml2 libxml2-dev \
&& rm -rf /var/lib/apt/lists/*
RUN docker-php-ext-configure pcntl --enable-pcntl RUN docker-php-ext-configure pcntl --enable-pcntl
RUN docker-php-ext-install pcntl RUN docker-php-ext-install pcntl
COPY ./php.ini /usr/local/etc/php/conf.d/ COPY ./php.ini /usr/local/etc/php/conf.d/

View File

@ -1,9 +1,11 @@
# PHP Language Server # PHP Language Server
[![Version](https://img.shields.io/packagist/v/felixfbecker/language-server.svg)](https://packagist.org/packages/felixfbecker/language-server) [![Version](https://img.shields.io/packagist/v/felixfbecker/language-server.svg)](https://packagist.org/packages/felixfbecker/language-server)
[![Build Status](https://travis-ci.org/felixfbecker/php-language-server.svg?branch=master)](https://travis-ci.org/felixfbecker/php-language-server) [![Linux Build Status](https://travis-ci.org/felixfbecker/php-language-server.svg?branch=master)](https://travis-ci.org/felixfbecker/php-language-server)
[![Windows Build status](https://ci.appveyor.com/api/projects/status/2sp5ll052wdjqmdm/branch/master?svg=true)](https://ci.appveyor.com/project/felixfbecker/php-language-server/branch/master)
[![Coverage](https://codecov.io/gh/felixfbecker/php-language-server/branch/master/graph/badge.svg)](https://codecov.io/gh/felixfbecker/php-language-server) [![Coverage](https://codecov.io/gh/felixfbecker/php-language-server/branch/master/graph/badge.svg)](https://codecov.io/gh/felixfbecker/php-language-server)
[![Dependency Status](https://gemnasium.com/badges/github.com/felixfbecker/php-language-server.svg)](https://gemnasium.com/github.com/felixfbecker/php-language-server) [![Dependency Status](https://gemnasium.com/badges/github.com/felixfbecker/php-language-server.svg)](https://gemnasium.com/github.com/felixfbecker/php-language-server)
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
[![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%207.0-8892BF.svg)](https://php.net/) [![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%207.0-8892BF.svg)](https://php.net/)
[![License](https://img.shields.io/packagist/l/felixfbecker/language-server.svg)](https://github.com/felixfbecker/php-language-server/blob/master/LICENSE.txt) [![License](https://img.shields.io/packagist/l/felixfbecker/language-server.svg)](https://github.com/felixfbecker/php-language-server/blob/master/LICENSE.txt)
[![Gitter](https://badges.gitter.im/felixfbecker/php-language-server.svg)](https://gitter.im/felixfbecker/php-language-server?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Gitter](https://badges.gitter.im/felixfbecker/php-language-server.svg)](https://gitter.im/felixfbecker/php-language-server?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
@ -40,9 +42,6 @@ For Parameters, it will return the `@param` tag.
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.
### [Document Formatting](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#document-formatting-request)
![Document Formatting demo](images/formatDocument.gif)
### 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)
![Error reporting demo](images/publishDiagnostics.png) ![Error reporting demo](images/publishDiagnostics.png)
@ -190,14 +189,21 @@ Clone the repository and run
composer install composer install
to install dependencies. to install dependencies.
Then parse the stubs with
composer run-script parse-stubs
Run the tests with Run the tests with
vendor/bin/phpunit composer test
Lint with Lint with
vendor/bin/phpcs composer lint
The project parses PHPStorm's PHP stubs to get support for PHP builtins. It re-parses them as needed after Composer processes, but after some code changes (such as ones involving the index or parsing) you may have to explicitly re-parse them:
composer run-script parse-stubs
To debug with xDebug ensure that you have this set as an environment variable
COMPOSER_ALLOW_XDEBUG=1
This tells the Language Server to not restart without XDebug if it detects that XDebug is enabled (XDebug has a high performance impact).

54
appveyor.yml Normal file
View File

@ -0,0 +1,54 @@
version: '{build}'
image: Visual Studio 2017
platform:
- x64
skip_tags: true
skip_branch_with_pr: true
clone_depth: 1
max_jobs: 3
cache:
- '%LOCALAPPDATA%\Composer'
- '%LOCALAPPDATA%\Temp\Chocolatey'
environment:
ANSICON: 121x90 (121x90)
matrix:
- { PHP_VERSION: '7.1.11', VC_VERSION: '14', XDEBUG_VERSION: '2.5.5' }
install:
# Enable Windows Update service, needed to install vcredist2015 (dependency of php)
- ps: Set-Service wuauserv -StartupType Manual
- choco config set cacheLocation %LOCALAPPDATA%\Temp\Chocolatey
- choco install -y php --version %PHP_VERSION%
- choco install -y composer
- refreshenv
- composer install --no-interaction --no-progress --prefer-dist
# Install XDebug for code coverage
- ps: |
$client = New-Object System.Net.WebClient
$phpMinorVersion = $env:PHP_VERSION -replace '\.\d+$'
$xdebugUrl = "https://xdebug.org/files/php_xdebug-$env:XDEBUG_VERSION-$phpMinorVersion-vc14-nts-x86_64.dll"
$phpDir = (Get-Item (Get-Command php).Source).Directory.FullName
$xdebugPath = Join-Path $phpDir ext\xdebug.dll
$client.DownloadFile($xdebugUrl, $xdebugPath)
$phpIniPath = Join-Path $phpDir php.ini
Add-Content $phpIniPath @"
zend_extension=$xdebugPath
"@
build: off
test_script:
- vendor\bin\phpunit --coverage-clover=coverage/coverage.xml
after_test:
- ps: |
# Delete vendor because it causes problems with codecovs report search
# https://github.com/codecov/codecov-bash/issues/96
Remove-Item -Recurse -Force vendor
$env:PATH = 'C:\msys64\usr\bin;' + $env:PATH
Invoke-WebRequest -Uri 'https://codecov.io/bash' -OutFile codecov.sh
bash codecov.sh -f 'coverage/coverage.xml'

View File

@ -1,14 +1,7 @@
{ {
"name": "felixfbecker/language-server", "name": "felixfbecker/language-server",
"description": "PHP Implementation of the Visual Studio Code Language Server Protocol", "description": "PHP Implementation of the Visual Studio Code Language Server Protocol",
"authors": [
{
"name": "Felix Becker",
"email": "felix.b@outlook.com"
}
],
"license": "ISC", "license": "ISC",
"type": "library",
"keywords": [ "keywords": [
"php", "php",
"language", "language",
@ -21,27 +14,29 @@
"autocompletion", "autocompletion",
"refactor" "refactor"
], ],
"bin": ["bin/php-language-server.php"], "authors": [
"scripts": { {
"parse-stubs": "LanguageServer\\ComposerScripts::parseStubs", "name": "Felix Becker",
"post-install-cmd": "@parse-stubs" "email": "felix.b@outlook.com"
}, }
],
"require": { "require": {
"php": ">=7.0", "php": "^7.0",
"phpdocumentor/reflection-docblock": "~3.1.1",
"sabre/event": "^5.0",
"felixfbecker/advanced-json-rpc": "^2.0",
"squizlabs/php_codesniffer" : "3.0.0RC3",
"netresearch/jsonmapper": "^1.0",
"webmozart/path-util": "^2.3",
"webmozart/glob": "^4.1",
"sabre/uri": "^2.0",
"jetbrains/phpstorm-stubs": "dev-master",
"composer/composer": "^1.3", "composer/composer": "^1.3",
"Microsoft/tolerant-php-parser": "^0.0.4" "felixfbecker/advanced-json-rpc": "^3.0.0",
"jetbrains/phpstorm-stubs": "dev-master",
"microsoft/tolerant-php-parser": "0.0.*",
"netresearch/jsonmapper": "^1.0",
"phpdocumentor/reflection-docblock": "^4.0.0",
"sabre/event": "^5.0",
"sabre/uri": "^2.0",
"webmozart/glob": "^4.1",
"webmozart/path-util": "^2.3"
},
"require-dev": {
"phpunit/phpunit": "^6.3",
"squizlabs/php_codesniffer": "^3.1"
}, },
"minimum-stability": "dev",
"prefer-stable": true,
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"LanguageServer\\": "src/" "LanguageServer\\": "src/"
@ -57,8 +52,19 @@
"LanguageServer\\Tests\\": "tests/" "LanguageServer\\Tests\\": "tests/"
} }
}, },
"require-dev": { "bin": [
"phpunit/phpunit": "^5.5", "bin/php-language-server.php"
"phpunit/php-code-coverage": "^4.0" ],
} "scripts": {
"parse-stubs": "LanguageServer\\ComposerScripts::parseStubs",
"post-install-cmd": "@parse-stubs",
"post-update-cmd": "@parse-stubs",
"test": "vendor/bin/phpunit",
"lint": "vendor/bin/phpcs"
},
"config": {
"sort-packages": true
},
"minimum-stability": "dev",
"prefer-stable": true
} }

20
dependencies.yml Normal file
View File

@ -0,0 +1,20 @@
collectors:
# pull requests for new major versions
- type: php-composer
path: /
actors:
- type: php-composer
versions: "Y.0.0"
settings:
commit_message_prefix: "chore: "
- type: js-npm
path: /
settings:
dist_tags:
semantic-release: next
actors:
- type: js-npm
versions: "Y.0.0"
settings:
commit_message_prefix: "chore: "

View File

@ -0,0 +1 @@
<

View File

@ -0,0 +1,9 @@
<?php
class Foo
{
public function bar()
{
return $this;
}
}

View File

@ -0,0 +1,9 @@
<?php
class Foo
{
public static function bar()
{
return $this;
}
}

View File

@ -1,20 +0,0 @@
<?php
namespace TestNamespace;
use SomeNamespace\Goo;
class TestClass
{
public $testProperty;
public function testMethod($testParameter)
{
$testVariable = 123;
if (empty($testParameter)){
echo 'Empty';
}
}
}

View File

@ -1,19 +0,0 @@
<?php
namespace TestNamespace;
use SomeNamespace\Goo;
class TestClass
{
public $testProperty;
public function testMethod($testParameter)
{
$testVariable = 123;
if (empty($testParameter)) {
echo 'Empty';
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

41
package.json Normal file
View File

@ -0,0 +1,41 @@
{
"name": "php-language-server",
"version": "0.0.0-development",
"private": true,
"scripts": {
"commitmsg": "validate-commit-msg",
"semantic-release": "semantic-release"
},
"devDependencies": {
"@semantic-release/github": "^2.0.0",
"@semantic-release/last-release-git-tag": "^2.0.0",
"cz-conventional-changelog": "^2.0.0",
"husky": "^0.14.3",
"semantic-release": "^11.0.0",
"semantic-release-docker": "^2.0.0",
"validate-commit-msg": "^2.14.0"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
},
"release": {
"verifyConditions": [
"@semantic-release/github",
"semantic-release-docker"
],
"getLastRelease": "@semantic-release/last-release-git-tag",
"publish": [
"@semantic-release/github",
{
"path": "semantic-release-docker",
"name": "felixfbecker/php-language-server"
}
]
},
"repository": {
"type": "git",
"url": "https://github.com/felixfbecker/php-language-server.git"
}
}

View File

@ -1,14 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php"> <phpunit backupGlobals="false"
backupStaticAttributes="false"
beStrictAboutTestsThatDoNotTestAnything="true"
beStrictAboutOutputDuringTests="true"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
failOnWarning="true"
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
verbose="true"
>
<testsuites> <testsuites>
<testsuite name="PHP Language Server Test Suite"> <testsuite name="PHP Language Server Test Suite">
<directory>./tests</directory> <directory suffix="Test.php">./tests</directory>
</testsuite> </testsuite>
</testsuites> </testsuites>
<filter> <filter>
<whitelist> <whitelist processUncoveredFilesFromWhitelist="true">
<directory>./src</directory> <directory suffix=".php">./src</directory>
</whitelist> </whitelist>
</filter> </filter>
<php> <php>

View File

@ -71,7 +71,6 @@ class ClientHandler
*/ */
public function notify(string $method, $params): Promise public function notify(string $method, $params): Promise
{ {
$id = $this->idGenerator->generate();
return $this->protocolWriter->write( return $this->protocolWriter->write(
new Protocol\Message( new Protocol\Message(
new AdvancedJsonRpc\Notification($method, (object)$params) new AdvancedJsonRpc\Notification($method, (object)$params)

View File

@ -10,7 +10,9 @@ use LanguageServer\Protocol\{
Position, Position,
CompletionList, CompletionList,
CompletionItem, CompletionItem,
CompletionItemKind CompletionItemKind,
CompletionContext,
CompletionTriggerKind
}; };
use Microsoft\PhpParser; use Microsoft\PhpParser;
use Microsoft\PhpParser\Node; use Microsoft\PhpParser\Node;
@ -122,9 +124,10 @@ class CompletionProvider
* *
* @param PhpDocument $doc The opened document * @param PhpDocument $doc The opened document
* @param Position $pos The cursor position * @param Position $pos The cursor position
* @param CompletionContext $context The completion context
* @return CompletionList * @return CompletionList
*/ */
public function provideCompletion(PhpDocument $doc, Position $pos): CompletionList public function provideCompletion(PhpDocument $doc, Position $pos, CompletionContext $context = null): CompletionList
{ {
// This can be made much more performant if the tree follows specific invariants. // This can be made much more performant if the tree follows specific invariants.
$node = $doc->getNodeAtPosition($pos); $node = $doc->getNodeAtPosition($pos);
@ -152,7 +155,21 @@ class CompletionProvider
// Inspect the type of expression under the cursor // Inspect the type of expression under the cursor
if ($node === null || $node instanceof Node\Statement\InlineHtml || $pos == new Position(0, 0)) { $content = $doc->getContent();
$offset = $pos->toOffset($content);
if (
$node === null
|| (
$node instanceof Node\Statement\InlineHtml
&& (
$context === null
// Make sure to not suggest on the > trigger character in HTML
|| $context->triggerKind === CompletionTriggerKind::INVOKED
|| $context->triggerCharacter === '<'
)
)
|| $pos == new Position(0, 0)
) {
// HTML, beginning of file // HTML, beginning of file
// Inside HTML and at the beginning of the file, propose <?php // Inside HTML and at the beginning of the file, propose <?php
@ -210,7 +227,7 @@ class CompletionProvider
// Collect all definitions that match any of the prefixes // Collect all definitions that match any of the prefixes
foreach ($this->index->getDefinitions() as $fqn => $def) { foreach ($this->index->getDefinitions() as $fqn => $def) {
foreach ($prefixes as $prefix) { foreach ($prefixes as $prefix) {
if (substr($fqn, 0, strlen($prefix)) === $prefix && !$def->isGlobal) { if (substr($fqn, 0, strlen($prefix)) === $prefix && $def->isMember) {
$list->items[] = CompletionItem::fromDefinition($def); $list->items[] = CompletionItem::fromDefinition($def);
} }
} }
@ -243,7 +260,7 @@ class CompletionProvider
// Collect all definitions that match any of the prefixes // Collect all definitions that match any of the prefixes
foreach ($this->index->getDefinitions() as $fqn => $def) { foreach ($this->index->getDefinitions() as $fqn => $def) {
foreach ($prefixes as $prefix) { foreach ($prefixes as $prefix) {
if (substr(strtolower($fqn), 0, strlen($prefix)) === strtolower($prefix) && !$def->isGlobal) { if (substr(strtolower($fqn), 0, strlen($prefix)) === strtolower($prefix) && $def->isMember) {
$list->items[] = CompletionItem::fromDefinition($def); $list->items[] = CompletionItem::fromDefinition($def);
} }
} }
@ -316,7 +333,7 @@ class CompletionProvider
if ( if (
// Exclude methods, properties etc. // Exclude methods, properties etc.
$def->isGlobal !$def->isMember
&& ( && (
!$prefix !$prefix
|| ( || (
@ -415,7 +432,7 @@ class CompletionProvider
// Walk the AST upwards until a scope boundary is met // Walk the AST upwards until a scope boundary is met
$level = $node; $level = $node;
while ($level && !ParserHelpers\isFunctionLike($level)) { 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()) {
@ -429,7 +446,7 @@ class CompletionProvider
// If the traversal ended because a function was met, // If the traversal ended because a function was met,
// also add its parameters and closure uses to the result list // also add its parameters and closure uses to the result list
if ($level && ParserHelpers\isFunctionLike($level) && $level->parameters !== null) { if ($level && $level instanceof PhpParser\FunctionLike && $level->parameters !== null) {
foreach ($level->parameters->getValues() as $param) { foreach ($level->parameters->getValues() as $param) {
$paramName = $param->getName(); $paramName = $param->getName();
if (empty($namePrefix) || strpos($paramName, $namePrefix) !== false) { if (empty($namePrefix) || strpos($paramName, $namePrefix) !== false) {

View File

@ -56,7 +56,8 @@ class ComposerScripts
$parts['scheme'] = 'phpstubs'; $parts['scheme'] = 'phpstubs';
$uri = Uri\build($parts); $uri = Uri\build($parts);
$document = new PhpDocument($uri, $content, $index, $parser, $docBlockFactory, $definitionResolver); // Create a new document and add it to $index
new PhpDocument($uri, $content, $index, $parser, $docBlockFactory, $definitionResolver);
} }
$index->setComplete(); $index->setComplete();

View File

@ -39,12 +39,13 @@ class Definition
public $extends; public $extends;
/** /**
* Only true for classes, interfaces, traits, functions and non-class constants * False for classes, interfaces, traits, functions and non-class constants
* True for methods, properties and class constants
* This is so methods and properties are not suggested in the global scope * This is so methods and properties are not suggested in the global scope
* *
* @var bool * @var bool
*/ */
public $isGlobal; public $isMember;
/** /**
* True if this definition is affected by global namespace fallback (global function or global constant) * True if this definition is affected by global namespace fallback (global function or global constant)
@ -78,7 +79,7 @@ class Definition
* For functions and methods, this is the return type. * For functions and methods, this is the return type.
* For any other declaration it will be null. * For any other declaration it will be null.
* Can also be a compound type. * Can also be a compound type.
* If it is unknown, will be Types\Mixed. * If it is unknown, will be Types\Mixed_.
* *
* @var \phpDocumentor\Type|null * @var \phpDocumentor\Type|null
*/ */

View File

@ -181,10 +181,8 @@ class DefinitionResolver
); );
// Interfaces, classes, traits, namespaces, functions, and global const elements // Interfaces, classes, traits, namespaces, functions, and global const elements
$def->isGlobal = ( $def->isMember = !(
$node instanceof Node\Statement\InterfaceDeclaration || $node instanceof PhpParser\ClassLike ||
$node instanceof Node\Statement\ClassDeclaration ||
$node instanceof Node\Statement\TraitDeclaration ||
($node instanceof Node\Statement\NamespaceDefinition && $node->name !== null) || ($node instanceof Node\Statement\NamespaceDefinition && $node->name !== null) ||
@ -266,13 +264,38 @@ class DefinitionResolver
// Other references are references to a global symbol that have an FQN // Other references are references to a global symbol that have an FQN
// Find out the FQN // Find out the FQN
$fqn = $this->resolveReferenceNodeToFqn($node); $fqn = $this->resolveReferenceNodeToFqn($node);
if ($fqn === null) { if (!$fqn) {
return null; return null;
} }
if ($fqn === 'self' || $fqn === 'static') {
// Resolve self and static keywords to the containing class
// (This is not 100% correct for static but better than nothing)
$classNode = $node->getFirstAncestor(Node\Statement\ClassDeclaration::class);
if (!$classNode) {
return;
}
$fqn = (string)$classNode->getNamespacedName();
if (!$fqn) {
return;
}
} else if ($fqn === 'parent') {
// Resolve parent keyword to the base class FQN
$classNode = $node->getFirstAncestor(Node\Statement\ClassDeclaration::class);
if (!$classNode || !$classNode->classBaseClause || !$classNode->classBaseClause->baseClass) {
return;
}
$fqn = (string)$classNode->classBaseClause->baseClass->getResolvedName();
if (!$fqn) {
return;
}
}
// If the node is a function or constant, it could be namespaced, but PHP falls back to global // If the node is a function or constant, it could be namespaced, but PHP falls back to global
// http://php.net/manual/en/language.namespaces.fallback.php // http://php.net/manual/en/language.namespaces.fallback.php
// TODO - verify that this is not a method // TODO - verify that this is not a method
$globalFallback = ParserHelpers\isConstantFetch($node) || $parent instanceof Node\Expression\CallExpression; $globalFallback = ParserHelpers\isConstantFetch($node) || $parent instanceof Node\Expression\CallExpression;
// Return the Definition object from the index index // Return the Definition object from the index index
return $this->index->getDefinition($fqn, $globalFallback); return $this->index->getDefinition($fqn, $globalFallback);
} }
@ -280,6 +303,7 @@ class DefinitionResolver
/** /**
* Given any node, returns the FQN of the symbol that is referenced * Given any node, returns the FQN of the symbol that is referenced
* Returns null if the FQN could not be resolved or the reference node references a variable * Returns null if the FQN could not be resolved or the reference node references a variable
* May also return "static", "self" or "parent"
* *
* @param Node $node * @param Node $node
* @return string|null * @return string|null
@ -511,7 +535,7 @@ class DefinitionResolver
// Traverse the AST up // Traverse the AST up
do { do {
// If a function is met, check the parameters and use statements // If a function is met, check the parameters and use statements
if (ParserHelpers\isFunctionLike($n)) { if ($n instanceof PhpParser\FunctionLike) {
if ($n->parameters !== null) { if ($n->parameters !== null) {
foreach ($n->parameters->getElements() as $param) { foreach ($n->parameters->getElements() as $param) {
if ($param->getName() === $name) { if ($param->getName() === $name) {
@ -551,7 +575,7 @@ class DefinitionResolver
/** /**
* Given an expression node, resolves that expression recursively to a type. * Given an expression node, resolves that expression recursively to a type.
* If the type could not be resolved, returns Types\Mixed. * If the type could not be resolved, returns Types\Mixed_.
* *
* @param Node\Expression $expr * @param Node\Expression $expr
* @return \phpDocumentor\Reflection\Type|null * @return \phpDocumentor\Reflection\Type|null
@ -567,7 +591,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
@ -597,7 +621,7 @@ class DefinitionResolver
// 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) {
@ -646,7 +670,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;
@ -659,10 +683,10 @@ class DefinitionResolver
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_;
} }
} else if (!($t instanceof Types\Object_) || $t->getFqsen() === null) { } else if (!($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);
} }
@ -689,7 +713,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) . '::';
@ -701,7 +725,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;
} }
@ -888,7 +912,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();
} }
@ -897,14 +921,14 @@ 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_;
} }
@ -918,7 +942,7 @@ 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
@ -958,7 +982,7 @@ class DefinitionResolver
* For classes and interfaces, this is the class type (object). * For classes and interfaces, this is the class type (object).
* For variables / assignments, this is the documented type or type the assignment resolves to. * For variables / assignments, this is the documented type or type the assignment resolves to.
* Can also be a compound type. * Can also be a compound type.
* If it is unknown, will be Types\Mixed. * If it is unknown, will be Types\Mixed_.
* Returns null if the node does not have a type. * Returns null if the node does not have a type.
* *
* @param Node $node * @param Node $node
@ -1012,7 +1036,7 @@ class DefinitionResolver
} }
$type = $defaultType; $type = $defaultType;
} }
return $type ?? new Types\Mixed; return $type ?? new Types\Mixed_;
} }
// FUNCTIONS AND METHODS // FUNCTIONS AND METHODS
@ -1020,7 +1044,7 @@ class DefinitionResolver
// 1. doc block // 1. doc block
// 2. return type hint // 2. return type hint
// 3. TODO: infer from return statements // 3. TODO: infer from return statements
if (ParserHelpers\isFunctionLike($node)) { if ($node instanceof PhpParser\FunctionLike) {
// Functions/methods // Functions/methods
$docBlock = $this->getDocBlock($node); $docBlock = $this->getDocBlock($node);
if ( if (
@ -1040,7 +1064,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_;
} }
// PROPERTIES, CONSTS, CLASS CONSTS, ASSIGNMENT EXPRESSIONS // PROPERTIES, CONSTS, CLASS CONSTS, ASSIGNMENT EXPRESSIONS
@ -1077,7 +1101,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
@ -1101,9 +1125,7 @@ class DefinitionResolver
// interface C { } A\B\C // interface C { } A\B\C
// trait C { } A\B\C // trait C { } A\B\C
if ( if (
$node instanceof Node\Statement\ClassDeclaration || $node instanceof PhpParser\ClassLike
$node instanceof Node\Statement\InterfaceDeclaration ||
$node instanceof Node\Statement\TraitDeclaration
) { ) {
return (string) $node->getNamespacedName(); return (string) $node->getNamespacedName();
} }
@ -1134,9 +1156,7 @@ class DefinitionResolver
// Class method: use ClassName->methodName() as name // Class method: use ClassName->methodName() as name
$class = $node->getFirstAncestor( $class = $node->getFirstAncestor(
Node\Expression\ObjectCreationExpression::class, Node\Expression\ObjectCreationExpression::class,
Node\Statement\ClassDeclaration::class, PhpParser\ClassLike::class
Node\Statement\InterfaceDeclaration::class,
Node\Statement\TraitDeclaration::class
); );
if (!isset($class->name)) { if (!isset($class->name)) {
// Ignore anonymous classes // Ignore anonymous classes
@ -1160,9 +1180,7 @@ class DefinitionResolver
($classDeclaration = ($classDeclaration =
$node->getFirstAncestor( $node->getFirstAncestor(
Node\Expression\ObjectCreationExpression::class, Node\Expression\ObjectCreationExpression::class,
Node\Statement\ClassDeclaration::class, PhpParser\ClassLike::class
Node\Statement\InterfaceDeclaration::class,
Node\Statement\TraitDeclaration::class
) )
) !== null && isset($classDeclaration->name)) { ) !== null && isset($classDeclaration->name)) {
$name = $node->getName(); $name = $node->getName();
@ -1190,9 +1208,7 @@ class DefinitionResolver
// Class constant: use ClassName::CONSTANT_NAME as name // Class constant: use ClassName::CONSTANT_NAME as name
$classDeclaration = $constDeclaration->getFirstAncestor( $classDeclaration = $constDeclaration->getFirstAncestor(
Node\Expression\ObjectCreationExpression::class, Node\Expression\ObjectCreationExpression::class,
Node\Statement\ClassDeclaration::class, PhpParser\ClassLike::class
Node\Statement\InterfaceDeclaration::class,
Node\Statement\TraitDeclaration::class
); );
if (!isset($classDeclaration->name)) { if (!isset($classDeclaration->name)) {

View File

@ -1,107 +0,0 @@
<?php
declare(strict_types = 1);
namespace LanguageServer;
use LanguageServer\Protocol\{
TextEdit,
Range,
Position
};
use Exception;
use PHP_CodeSniffer\{
Config,
Ruleset
};
use PHP_CodeSniffer\Files\DummyFile;
use PHP_CodeSniffer\Util\Tokens;
abstract class Formatter
{
/**
* Generate array of TextEdit changes for content formatting.
*
* @param string $content source code to format
* @param string $uri URI of document
*
* @return \LanguageServer\Protocol\TextEdit[]
* @throws \Exception
*/
public static function format(string $content, string $uri)
{
if (!defined('PHP_CODESNIFFER_CBF')) {
define('PHP_CODESNIFFER_CBF', true);
}
if (!defined('PHP_CODESNIFFER_VERBOSITY')) {
define('PHP_CODESNIFFER_VERBOSITY', false);
}
$path = uriToPath($uri);
$config = new Config(['dummy'], false);
$config->standards = self::findConfiguration($path);
// Autoload class to set up a bunch of PHP_CodeSniffer-specific token type constants
spl_autoload_call(Tokens::class);
$file = new DummyFile($content, new Ruleset($config), $config);
$file->process();
$fixed = $file->fixer->fixFile();
if (!$fixed && $file->getErrorCount() > 0) {
throw new Exception('Unable to format file');
}
$new = $file->fixer->getContents();
if ($content === $new) {
return [];
}
return [new TextEdit(new Range(new Position(0, 0), self::calculateEndPosition($content)), $new)];
}
/**
* Calculate position of last character.
*
* @param string $content document as string
*
* @return \LanguageServer\Protocol\Position
*/
private static function calculateEndPosition(string $content): Position
{
$lines = explode("\n", $content);
return new Position(count($lines) - 1, strlen(end($lines)));
}
/**
* Search for PHP_CodeSniffer configuration file at given directory or its parents.
* If no configuration found then PSR2 standard is loaded by default.
*
* @param string $path path to file or directory
* @return string[]
*/
private static function findConfiguration(string $path)
{
if (is_dir($path)) {
$currentDir = $path;
} else {
$currentDir = dirname($path);
}
do {
$default = $currentDir . DIRECTORY_SEPARATOR . 'phpcs.xml';
if (is_file($default)) {
return [$default];
}
$default = $currentDir . DIRECTORY_SEPARATOR . 'phpcs.xml.dist';
if (is_file($default)) {
return [$default];
}
$lastDir = $currentDir;
$currentDir = dirname($currentDir);
} while ($currentDir !== '.' && $currentDir !== $lastDir);
$standard = Config::getConfigData('default_standard') ?? 'PSR2';
return explode(',', $standard);
}
}

View File

@ -22,7 +22,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($type) as $fqn) { foreach (getFqnsFromType($t) as $fqn) {
$fqns[] = $fqn; $fqns[] = $fqn;
} }
} }

View File

@ -16,9 +16,9 @@ use function Sabre\Event\coroutine;
class Indexer class Indexer
{ {
/** /**
* @var The prefix for every cache item * @var int The prefix for every cache item
*/ */
const CACHE_VERSION = 1; const CACHE_VERSION = 2;
/** /**
* @var FilesFinder * @var FilesFinder

View File

@ -266,8 +266,6 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher
$serverCapabilities->documentSymbolProvider = true; $serverCapabilities->documentSymbolProvider = true;
// Support "Find all symbols in workspace" // Support "Find all symbols in workspace"
$serverCapabilities->workspaceSymbolProvider = true; $serverCapabilities->workspaceSymbolProvider = true;
// Support "Format Code"
$serverCapabilities->documentFormattingProvider = true;
// Support "Go to definition" // Support "Go to definition"
$serverCapabilities->definitionProvider = true; $serverCapabilities->definitionProvider = true;
// Support "Find all references" // Support "Find all references"

View File

@ -25,7 +25,7 @@ function isConstantFetch(Node $node) : bool
$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 ||
isFunctionLike($parent) || $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
@ -38,14 +38,6 @@ function getFunctionLikeDeclarationFromParameter(Node\Parameter $node)
return $node->parent->parent; return $node->parent->parent;
} }
function isFunctionLike(Node $node)
{
return
$node instanceof Node\Statement\FunctionDeclaration ||
$node instanceof Node\MethodDeclaration ||
$node instanceof Node\Expression\AnonymousFunctionCreationExpression;
}
function isBooleanExpression($expression) : bool function isBooleanExpression($expression) : bool
{ {
if (!($expression instanceof Node\Expression\BinaryExpression)) { if (!($expression instanceof Node\Expression\BinaryExpression)) {

View File

@ -166,19 +166,6 @@ class PhpDocument
$this->sourceFileNode = $treeAnalyzer->getSourceFileNode(); $this->sourceFileNode = $treeAnalyzer->getSourceFileNode();
} }
/**
* Returns array of TextEdit changes to format this document.
*
* @return \LanguageServer\Protocol\TextEdit[]
*/
public function getFormattedText()
{
if (empty($this->getContent())) {
return [];
}
return Formatter::format($this->getContent(), $this->uri);
}
/** /**
* Returns this document's text content. * Returns this document's text content.
* *

View File

@ -0,0 +1,30 @@
<?php
namespace LanguageServer\Protocol;
/**
* Contains additional information about the context in which a completion request is triggered.
*/
class CompletionContext
{
/**
* How the completion was triggered.
*
* @var int
*/
public $triggerKind;
/**
* The trigger character (a single character) that has trigger code complete.
* Is null if `triggerKind !== CompletionTriggerKind::TRIGGER_CHARACTER`
*
* @var string|null
*/
public $triggerCharacter;
public function __construct(int $triggerKind, string $triggerCharacter = null)
{
$this->triggerKind = $triggerKind;
$this->triggerCharacter = $triggerCharacter;
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace LanguageServer\Protocol;
class CompletionTriggerKind
{
/**
* Completion was triggered by invoking it manuall or using API.
*/
const INVOKED = 1;
/**
* Completion was triggered by a trigger character.
*/
const TRIGGER_CHARACTER = 2;
}

View File

@ -7,7 +7,7 @@ namespace LanguageServer\Protocol;
* special attention. Usually a document highlight is visualized by changing * special attention. Usually a document highlight is visualized by changing
* the background color of its range. * the background color of its range.
*/ */
class DocumentHighlightKind class DocumentHighlight
{ {
/** /**
* The range this highlight applies to. * The range this highlight applies to.

View File

@ -20,7 +20,8 @@ use LanguageServer\Protocol\{
SymbolLocationInformation, SymbolLocationInformation,
TextDocumentIdentifier, TextDocumentIdentifier,
TextDocumentItem, TextDocumentItem,
VersionedTextDocumentIdentifier VersionedTextDocumentIdentifier,
CompletionContext
}; };
use Microsoft\PhpParser; use Microsoft\PhpParser;
use Microsoft\PhpParser\Node; use Microsoft\PhpParser\Node;
@ -157,7 +158,7 @@ class TextDocument
* The document's truth now exists where the document's uri points to (e.g. if the document's uri is a file uri the * The document's truth now exists where the document's uri points to (e.g. if the document's uri is a file uri the
* truth now exists on disk). * truth now exists on disk).
* *
* @param \LanguageServer\Protocol\TextDocumentItem $textDocument The document that was closed * @param \LanguageServer\Protocol\TextDocumentIdentifier $textDocument The document that was closed
* @return void * @return void
*/ */
public function didClose(TextDocumentIdentifier $textDocument) public function didClose(TextDocumentIdentifier $textDocument)
@ -165,20 +166,6 @@ class TextDocument
$this->documentLoader->close($textDocument->uri); $this->documentLoader->close($textDocument->uri);
} }
/**
* The document formatting request is sent from the server to the client to format a whole document.
*
* @param TextDocumentIdentifier $textDocument The document to format
* @param FormattingOptions $options The format options
* @return Promise <TextEdit[]>
*/
public function formatting(TextDocumentIdentifier $textDocument, FormattingOptions $options)
{
return $this->documentLoader->getOrLoad($textDocument->uri)->then(function (PhpDocument $document) {
return $document->getFormattedText();
});
}
/** /**
* The references request is sent from the client to the server to resolve project-wide references for the symbol * The references request is sent from the client to the server to resolve project-wide references for the symbol
* denoted by the given text document position. * denoted by the given text document position.
@ -372,13 +359,14 @@ class TextDocument
* *
* @param TextDocumentIdentifier The text document * @param TextDocumentIdentifier The text document
* @param Position $position The position * @param Position $position The position
* @param CompletionContext|null $context The completion context
* @return Promise <CompletionItem[]|CompletionList> * @return Promise <CompletionItem[]|CompletionList>
*/ */
public function completion(TextDocumentIdentifier $textDocument, Position $position): Promise public function completion(TextDocumentIdentifier $textDocument, Position $position, CompletionContext $context = null): Promise
{ {
return coroutine(function () use ($textDocument, $position) { 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); return $this->completionProvider->provideCompletion($document, $position, $context);
}); });
} }

View File

@ -123,6 +123,7 @@ class Workspace
*/ */
public function xreferences($query, array $files = null): Promise public function xreferences($query, array $files = null): Promise
{ {
// TODO: $files is unused in the coroutine
return coroutine(function () use ($query, $files) { return coroutine(function () use ($query, $files) {
if ($this->composerLock === null) { if ($this->composerLock === null) {
return []; return [];

View File

@ -9,12 +9,19 @@ use phpDocumentor\Reflection\DocBlockFactory;
use Sabre\Uri; use Sabre\Uri;
use Microsoft\PhpParser; use Microsoft\PhpParser;
use Microsoft\PhpParser\Node; use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
class TreeAnalyzer class TreeAnalyzer
{ {
/** @var PhpParser\Parser */ /** @var PhpParser\Parser */
private $parser; private $parser;
/** @var DocBlockFactory */
private $docBlockFactory;
/** @var DefinitionResolver */
private $definitionResolver;
/** @var Node\SourceFileNode */ /** @var Node\SourceFileNode */
private $sourceFileNode; private $sourceFileNode;
@ -49,34 +56,32 @@ class TreeAnalyzer
// TODO - docblock errors // TODO - docblock errors
$this->collectDefinitionsAndReferences($this->sourceFileNode); $this->traverse($this->sourceFileNode);
} }
private function collectDefinitionsAndReferences(Node $sourceFileNode) /**
* Collects Parser diagnostic messages for the Node/Token
* and transforms them into LSP Format
*
* @param Node|Token $node
* @return void
*/
private function collectDiagnostics($node)
{ {
foreach ($sourceFileNode::CHILD_NAMES as $name) { // Get errors from the parser.
$node = $sourceFileNode->$name;
if ($node === null) {
continue;
}
if (\is_array($node)) {
foreach ($node as $child) {
if ($child instanceof Node) {
$this->update($child);
}
}
continue;
}
if ($node instanceof Node) {
$this->update($node);
}
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) {
case PhpParser\DiagnosticKind::Error:
$severity = DiagnosticSeverity::ERROR;
break;
case PhpParser\DiagnosticKind::Warning:
default:
$severity = DiagnosticSeverity::WARNING;
break;
}
$this->diagnostics[] = new Diagnostic( $this->diagnostics[] = new Diagnostic(
$error->message, $error->message,
new Range( new Range(
@ -84,6 +89,21 @@ class TreeAnalyzer
new Position($range->end->line, $range->start->character) new Position($range->end->line, $range->start->character)
), ),
null, null,
$severity,
'php'
);
}
// Check for invalid usage of $this.
if ($node instanceof Node\Expression\Variable && $node->getName() === 'this') {
// Find the first ancestor that's a class method. Return an error
// if there is none, or if the method is static.
$method = $node->getFirstAncestor(Node\MethodDeclaration::class);
if ($method && $method->isStatic()) {
$this->diagnostics[] = new Diagnostic(
"\$this can not be used in static methods.",
Range::fromNode($node),
null,
DiagnosticSeverity::ERROR, DiagnosticSeverity::ERROR,
'php' 'php'
); );
@ -91,12 +111,45 @@ class TreeAnalyzer
} }
} }
/**
* Recursive AST traversal to collect definitions/references and diagnostics
*
* @param Node|Token $currentNode The node/token to process
*/
private function traverse($currentNode)
{
$this->collectDiagnostics($currentNode);
// Only update/descend into Nodes, Tokens are leaves
if ($currentNode instanceof Node) {
$this->collectDefinitionsAndReferences($currentNode);
foreach ($currentNode::CHILD_NAMES as $name) {
$child = $currentNode->$name;
if ($child === null) {
continue;
}
if (\is_array($child)) {
foreach ($child as $actualChild) {
if ($actualChild !== null) {
$this->traverse($actualChild);
}
}
} else {
$this->traverse($child);
}
}
}
}
/** /**
* Collect definitions and references for the given node * Collect definitions and references for the given node
* *
* @param Node $node * @param Node $node
*/ */
private function update(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)
@ -104,8 +157,9 @@ class TreeAnalyzer
$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 ||
@ -114,10 +168,39 @@ class TreeAnalyzer
$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;
}
$fqn = $this->definitionResolver->resolveReferenceNodeToFqn($node); $fqn = $this->definitionResolver->resolveReferenceNodeToFqn($node);
if ($fqn !== null) { if (!$fqn) {
return;
}
if ($fqn === 'self' || $fqn === 'static') {
// Resolve self and static keywords to the containing class
// (This is not 100% correct for static but better than nothing)
$classNode = $node->getFirstAncestor(Node\Statement\ClassDeclaration::class);
if (!$classNode) {
return;
}
$fqn = (string)$classNode->getNamespacedName();
if (!$fqn) {
return;
}
} else if ($fqn === 'parent') {
// Resolve parent keyword to the base class FQN
$classNode = $node->getFirstAncestor(Node\Statement\ClassDeclaration::class);
if (!$classNode || !$classNode->classBaseClause || !$classNode->classBaseClause->baseClass) {
return;
}
$fqn = (string)$classNode->classBaseClause->baseClass->getResolvedName();
if (!$fqn) {
return;
}
}
$this->addReference($fqn, $node); $this->addReference($fqn, $node);
if ( if (
@ -151,9 +234,6 @@ class TreeAnalyzer
} }
} }
} }
}
$this->collectDefinitionsAndReferences($node);
}
/** /**
* @return Diagnostic[] * @return Diagnostic[]
@ -175,7 +255,7 @@ class TreeAnalyzer
} }
/** /**
* @return Definition * @return Definition[]
*/ */
public function getDefinitions() public function getDefinitions()
{ {

View File

@ -148,9 +148,8 @@ function isVendored(PhpDocument $document, \stdClass $composerJson = null): bool
* Check a given URI against the composer.json to see if it * Check a given URI against the composer.json to see if it
* is a vendored URI * is a vendored URI
* *
* @param \stdClass|null $composerJson
* @param string $uri * @param string $uri
* @param array $matches * @param \stdClass|null $composerJson
* @return string|null * @return string|null
*/ */
function getPackageName(string $uri, \stdClass $composerJson = null) function getPackageName(string $uri, \stdClass $composerJson = null)

View File

@ -0,0 +1,82 @@
<?php
declare(strict_types = 1);
namespace LanguageServer\Tests\Diagnostics;
use PHPUnit\Framework\TestCase;
use phpDocumentor\Reflection\DocBlockFactory;
use LanguageServer\{
DefinitionResolver, TreeAnalyzer
};
use LanguageServer\Index\{Index};
use LanguageServer\Protocol\{
Diagnostic, DiagnosticSeverity, Position, Range
};
use function LanguageServer\pathToUri;
use Microsoft\PhpParser\Parser;
class InvalidThisUsageTest extends TestCase
{
/**
* Parse the given file and return diagnostics.
*
* @param string $path
* @return Diagnostic[]
*/
private function collectDiagnostics(string $path): array
{
$uri = pathToUri($path);
$parser = new Parser();
$docBlockFactory = DocBlockFactory::createInstance();
$index = new Index;
$definitionResolver = new DefinitionResolver($index);
$content = file_get_contents($path);
$treeAnalyzer = new TreeAnalyzer($parser, $content, $docBlockFactory, $definitionResolver, $uri);
return $treeAnalyzer->getDiagnostics();
}
/**
* Assertions about a diagnostic.
*
* @param Diagnostic|null $diagnostic
* @param int $message
* @param string $severity
* @param Range $range
*/
private function assertDiagnostic($diagnostic, $message, $severity, $range)
{
$this->assertInstanceOf(Diagnostic::class, $diagnostic);
$this->assertEquals($message, $diagnostic->message);
$this->assertEquals($severity, $diagnostic->severity);
$this->assertEquals($range, $diagnostic->range);
}
public function testThisInStaticMethodProducesError()
{
$diagnostics = $this->collectDiagnostics(
__DIR__ . '/../../fixtures/diagnostics/errors/this_in_static_method.php'
);
$this->assertCount(1, $diagnostics);
$this->assertDiagnostic(
$diagnostics[0],
'$this can not be used in static methods.',
DiagnosticSeverity::ERROR,
new Range(
new Position(6, 15),
new Position(6, 20)
)
);
}
public function testThisInMethodProducesNoError()
{
$diagnostics = $this->collectDiagnostics(
__DIR__ . '/../../fixtures/diagnostics/baselines/this_in_method.php'
);
$this->assertCount(0, $diagnostics);
}
}

View File

@ -1,28 +0,0 @@
<?php
declare(strict_types = 1);
namespace LanguageServer\Tests;
use PHPUnit\Framework\TestCase;
use LanguageServer\Formatter;
class FormatterTest extends TestCase
{
public function testFormat()
{
$input = file_get_contents(__DIR__ . '/../fixtures/format.php');
$output = file_get_contents(__DIR__ . '/../fixtures/format_expected.php');
$edits = Formatter::format($input, 'file:///whatever');
$this->assertSame($output, $edits[0]->newText);
}
public function testFormatNoChange()
{
$expected = file_get_contents(__DIR__ . '/../fixtures/format_expected.php');
$edits = Formatter::format($expected, 'file:///whatever');
$this->assertSame([], $edits);
}
}

30
tests/Index/IndexTest.php Normal file
View File

@ -0,0 +1,30 @@
<?php
namespace LanguageServer\Tests;
use PHPUnit\Framework\TestCase;
use LanguageServer\Index\Index;
use LanguageServer\Definition;
class IndexTest extends TestCase
{
public function testGetSetMethodDefinition()
{
$index = new Index;
$index->setDefinition('SomeNamespace\SomeClass', new Definition);
$methodDefinition = new Definition;
$methodFqn = 'SomeNamespace\SomeClass->someMethod()';
$index->setDefinition($methodFqn, $methodDefinition);
$index->setDefinition('SomeNamespace\SomeClass->someProperty', new Definition);
$this->assertSame($methodDefinition, $index->getDefinition($methodFqn));
}
public function testGetSetClassDefinition()
{
$index = new Index;
$definition = new Definition;
$fqn = 'SomeNamespace\SomeClass';
$index->setDefinition($fqn, $definition);
$this->assertSame($definition, $index->getDefinition($fqn));
}
}

View File

@ -34,7 +34,6 @@ class LanguageServerTest extends TestCase
$serverCapabilities->textDocumentSync = TextDocumentSyncKind::FULL; $serverCapabilities->textDocumentSync = TextDocumentSyncKind::FULL;
$serverCapabilities->documentSymbolProvider = true; $serverCapabilities->documentSymbolProvider = true;
$serverCapabilities->workspaceSymbolProvider = true; $serverCapabilities->workspaceSymbolProvider = true;
$serverCapabilities->documentFormattingProvider = true;
$serverCapabilities->definitionProvider = true; $serverCapabilities->definitionProvider = true;
$serverCapabilities->referencesProvider = true; $serverCapabilities->referencesProvider = true;
$serverCapabilities->hoverProvider = true; $serverCapabilities->hoverProvider = true;

View File

@ -122,15 +122,16 @@ abstract class ServerTestCase extends TestCase
0 => new Location($referencesUri, new Range(new Position(29, 5), new Position(29, 15))) 0 => new Location($referencesUri, new Range(new Position(29, 5), new Position(29, 15)))
], ],
'TestNamespace\\TestClass' => [ 'TestNamespace\\TestClass' => [
0 => new Location($symbolsUri , new Range(new Position(99, 25), new Position(99, 34))), // class ChildClass extends TestClass {} 0 => new Location($symbolsUri, new Range(new Position(48, 13), new Position(48, 17))), // echo self::TEST_CLASS_CONST;
1 => new Location($referencesUri, new Range(new Position( 4, 11), new Position( 4, 20))), // $obj = new TestClass(); 1 => new Location($symbolsUri , new Range(new Position(99, 25), new Position(99, 34))), // class ChildClass extends TestClass {}
2 => new Location($referencesUri, new Range(new Position( 7, 0), new Position( 7, 9))), // TestClass::staticTestMethod(); 2 => new Location($referencesUri, new Range(new Position( 4, 11), new Position( 4, 20))), // $obj = new TestClass();
3 => new Location($referencesUri, new Range(new Position( 8, 5), new Position( 8, 14))), // echo TestClass::$staticTestProperty; 3 => new Location($referencesUri, new Range(new Position( 7, 0), new Position( 7, 9))), // TestClass::staticTestMethod();
4 => new Location($referencesUri, new Range(new Position( 9, 5), new Position( 9, 14))), // TestClass::TEST_CLASS_CONST; 4 => new Location($referencesUri, new Range(new Position( 8, 5), new Position( 8, 14))), // echo TestClass::$staticTestProperty;
5 => new Location($referencesUri, new Range(new Position(21, 18), new Position(21, 27))), // function whatever(TestClass $param) 5 => new Location($referencesUri, new Range(new Position( 9, 5), new Position( 9, 14))), // TestClass::TEST_CLASS_CONST;
6 => new Location($referencesUri, new Range(new Position(21, 37), new Position(21, 46))), // function whatever(TestClass $param): TestClass 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(39, 0), new Position(39, 9))), // TestClass::$staticTestProperty[123]->testProperty; 7 => new Location($referencesUri, new Range(new Position(21, 37), new Position(21, 46))), // function whatever(TestClass $param): TestClass
8 => new Location($useUri, new Range(new Position( 4, 4), new Position( 4, 27))), // use TestNamespace\TestClass; 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;
], ],
'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;
@ -176,14 +177,15 @@ abstract class ServerTestCase extends TestCase
1 => new Location($globalReferencesUri, new Range(new Position(29, 5), new Position(29, 15))) 1 => new Location($globalReferencesUri, new Range(new Position(29, 5), new Position(29, 15)))
], ],
'TestClass' => [ 'TestClass' => [
0 => new Location($globalSymbolsUri, new Range(new Position(99, 25), new Position(99, 34))), // class ChildClass extends TestClass {} 0 => new Location($globalSymbolsUri, new Range(new Position(48, 13), new Position(48, 17))), // echo self::TEST_CLASS_CONST;
1 => new Location($globalReferencesUri, new Range(new Position( 4, 11), new Position( 4, 20))), // $obj = new TestClass(); 1 => new Location($globalSymbolsUri, new Range(new Position(99, 25), new Position(99, 34))), // class ChildClass extends TestClass {}
2 => new Location($globalReferencesUri, new Range(new Position( 7, 0), new Position( 7, 9))), // TestClass::staticTestMethod(); 2 => new Location($globalReferencesUri, new Range(new Position( 4, 11), new Position( 4, 20))), // $obj = new TestClass();
3 => new Location($globalReferencesUri, new Range(new Position( 8, 5), new Position( 8, 14))), // echo TestClass::$staticTestProperty; 3 => new Location($globalReferencesUri, new Range(new Position( 7, 0), new Position( 7, 9))), // TestClass::staticTestMethod();
4 => new Location($globalReferencesUri, new Range(new Position( 9, 5), new Position( 9, 14))), // TestClass::TEST_CLASS_CONST; 4 => new Location($globalReferencesUri, new Range(new Position( 8, 5), new Position( 8, 14))), // echo TestClass::$staticTestProperty;
5 => new Location($globalReferencesUri, new Range(new Position(21, 18), new Position(21, 27))), // function whatever(TestClass $param) 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, 37), new Position(21, 46))), // function whatever(TestClass $param): TestClass 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(39, 0), new Position(39, 9))), // TestClass::$staticTestProperty[123]->testProperty; 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;
], ],
'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;

View File

@ -17,7 +17,9 @@ use LanguageServer\Protocol\{
Position, Position,
CompletionList, CompletionList,
CompletionItem, CompletionItem,
CompletionItemKind CompletionItemKind,
CompletionContext,
CompletionTriggerKind
}; };
use function LanguageServer\pathToUri; use function LanguageServer\pathToUri;
@ -464,6 +466,41 @@ class CompletionTest extends TestCase
], true), $items); ], true), $items);
} }
public function testHtmlPrefixShouldNotTriggerCompletion()
{
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/html_no_completion.php');
$this->loader->open($completionUri, file_get_contents($completionUri));
$items = $this->textDocument->completion(
new TextDocumentIdentifier($completionUri),
new Position(0, 1),
new CompletionContext(CompletionTriggerKind::TRIGGER_CHARACTER, '>')
)->wait();
$this->assertEquals(new CompletionList([], true), $items);
}
public function testHtmlPrefixShouldTriggerCompletionIfManuallyInvoked()
{
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/html_no_completion.php');
$this->loader->open($completionUri, file_get_contents($completionUri));
$items = $this->textDocument->completion(
new TextDocumentIdentifier($completionUri),
new Position(0, 1),
new CompletionContext(CompletionTriggerKind::INVOKED)
)->wait();
$this->assertEquals(new CompletionList([
new CompletionItem(
'<?php',
CompletionItemKind::KEYWORD,
null,
null,
null,
null,
null,
new TextEdit(new Range(new Position(0, 1), new Position(0, 1)), '?php')
)
], true), $items);
}
public function testNamespace() public function testNamespace()
{ {
$completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/namespace.php'); $completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/namespace.php');

View File

@ -29,11 +29,23 @@ class GlobalTest extends ServerTestCase
$this->assertEquals([], $result); $this->assertEquals([], $result);
} }
public function testDefinitionForSelfKeyword()
{
// echo self::TEST_CLASS_CONST;
// Get definition for self
$reference = $this->getReferenceLocations('TestClass')[0];
$result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri),
$reference->range->start
)->wait();
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
}
public function testDefinitionForClassLike() public function testDefinitionForClassLike()
{ {
// $obj = new TestClass(); // $obj = new TestClass();
// Get definition for TestClass // Get definition for TestClass
$reference = $this->getReferenceLocations('TestClass')[0]; $reference = $this->getReferenceLocations('TestClass')[1];
$result = $this->textDocument->definition( $result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start
@ -45,7 +57,7 @@ class GlobalTest extends ServerTestCase
{ {
// TestClass::staticTestMethod(); // TestClass::staticTestMethod();
// Get definition for TestClass // Get definition for TestClass
$reference = $this->getReferenceLocations('TestClass')[1]; $reference = $this->getReferenceLocations('TestClass')[2];
$result = $this->textDocument->definition( $result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start
@ -57,7 +69,7 @@ class GlobalTest extends ServerTestCase
{ {
// echo TestClass::$staticTestProperty; // echo TestClass::$staticTestProperty;
// Get definition for TestClass // Get definition for TestClass
$reference = $this->getReferenceLocations('TestClass')[2]; $reference = $this->getReferenceLocations('TestClass')[3];
$result = $this->textDocument->definition( $result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start
@ -69,7 +81,7 @@ class GlobalTest extends ServerTestCase
{ {
// TestClass::TEST_CLASS_CONST; // TestClass::TEST_CLASS_CONST;
// Get definition for TestClass // Get definition for TestClass
$reference = $this->getReferenceLocations('TestClass')[3]; $reference = $this->getReferenceLocations('TestClass')[4];
$result = $this->textDocument->definition( $result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start
@ -213,7 +225,7 @@ class GlobalTest extends ServerTestCase
{ {
// function whatever(TestClass $param) { // function whatever(TestClass $param) {
// Get definition for TestClass // Get definition for TestClass
$reference = $this->getReferenceLocations('TestClass')[4]; $reference = $this->getReferenceLocations('TestClass')[5];
$result = $this->textDocument->definition( $result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start
@ -225,7 +237,7 @@ 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')[5]; $reference = $this->getReferenceLocations('TestClass')[6];
$result = $this->textDocument->definition( $result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start

View File

@ -34,7 +34,7 @@ class NamespacedTest extends GlobalTest
{ {
// use TestNamespace\TestClass; // use TestNamespace\TestClass;
// Get definition for TestClass // Get definition for TestClass
$reference = $this->getReferenceLocations('TestClass')[6]; $reference = $this->getReferenceLocations('TestClass')[7];
$result = $this->textDocument->definition( $result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start
@ -46,7 +46,7 @@ class NamespacedTest extends GlobalTest
{ {
// use TestNamespace\{TestTrait, TestInterface}; // use TestNamespace\{TestTrait, TestInterface};
// Get definition for TestInterface // Get definition for TestInterface
$reference = $this->getReferenceLocations('TestClass')[0]; $reference = $this->getReferenceLocations('TestClass')[1];
$result = $this->textDocument->definition( $result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start

View File

@ -1,50 +0,0 @@
<?php
declare(strict_types = 1);
namespace LanguageServer\Tests\Server\TextDocument;
use PHPUnit\Framework\TestCase;
use LanguageServer\Tests\MockProtocolStream;
use LanguageServer\{
Server, LanguageClient, PhpDocumentLoader, DefinitionResolver
};
use LanguageServer\Index\{Index, ProjectIndex, DependenciesIndex};
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
use LanguageServer\Protocol\{
TextDocumentIdentifier,
TextDocumentItem,
FormattingOptions,
TextEdit,
Range,
Position
};
use function LanguageServer\{pathToUri, uriToPath};
class FormattingTest extends TestCase
{
public function testFormatting()
{
$projectIndex = new ProjectIndex(new Index, new DependenciesIndex);
$client = new LanguageClient(new MockProtocolStream, new MockProtocolStream);
$definitionResolver = new DefinitionResolver($projectIndex);
$loader = new PhpDocumentLoader(new FileSystemContentRetriever, $projectIndex, $definitionResolver);
$textDocument = new Server\TextDocument($loader, $definitionResolver, $client, $projectIndex);
$path = realpath(__DIR__ . '/../../../fixtures/format.php');
$uri = pathToUri($path);
// Trigger parsing of source
$textDocumentItem = new TextDocumentItem();
$textDocumentItem->uri = $uri;
$textDocumentItem->languageId = 'php';
$textDocumentItem->version = 1;
$textDocumentItem->text = file_get_contents($path);
$textDocument->didOpen($textDocumentItem);
// how code should look after formatting
$expected = file_get_contents(__DIR__ . '/../../../fixtures/format_expected.php');
// Request formatting
$result = $textDocument->formatting(new TextDocumentIdentifier($uri), new FormattingOptions())->wait();
$this->assertEquals([new TextEdit(new Range(new Position(0, 0), new Position(20, 0)), $expected)], $result);
}
}

View File

@ -15,7 +15,7 @@ class HoverTest extends ServerTestCase
{ {
// $obj = new TestClass(); // $obj = new TestClass();
// Get hover for TestClass // Get hover for TestClass
$reference = $this->getReferenceLocations('TestClass')[0]; $reference = $this->getReferenceLocations('TestClass')[1];
$result = $this->textDocument->hover( $result = $this->textDocument->hover(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start

View File

@ -151,7 +151,7 @@ class GlobalTest extends ServerTestCase
{ {
// $obj = new TestClass(); // $obj = new TestClass();
// Get references for TestClass // Get references for TestClass
$reference = $this->getReferenceLocations('TestClass')[0]; $reference = $this->getReferenceLocations('TestClass')[1];
$result = $this->textDocument->references( $result = $this->textDocument->references(
new ReferenceContext, new ReferenceContext,
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),

View File

@ -96,7 +96,9 @@ class ValidationTest extends TestCase
$testCasesDir = realpath(__DIR__ . '/cases'); $testCasesDir = realpath(__DIR__ . '/cases');
foreach ($refsAndDefs['references'] as $key => $list) { foreach ($refsAndDefs['references'] as $key => $list) {
$fixedPathRefs = array_map(function ($ref) use ($testCasesDir) { $fixedPathRefs = array_map(function ($ref) use ($testCasesDir) {
return str_replace($testCasesDir, '.', $ref); $ref = str_replace($testCasesDir, '.', $ref);
$ref = str_replace(DIRECTORY_SEPARATOR, '/', $ref);
return $ref;
}, $list); }, $list);
$refsAndDefs['references']->$key = $fixedPathRefs; $refsAndDefs['references']->$key = $fixedPathRefs;
@ -107,6 +109,7 @@ class ValidationTest extends TestCase
if ($def !== null && $def->symbolInformation !== null && if ($def !== null && $def->symbolInformation !== null &&
$def->symbolInformation->location !== null && $def->symbolInformation->location->uri !== null) { $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($testCasesDir, '.', $def->symbolInformation->location->uri);
$def->symbolInformation->location->uri = str_replace(DIRECTORY_SEPARATOR, '/', $def->symbolInformation->location->uri);
} }
} }

View File

@ -3,7 +3,7 @@
"Fixtures\\Prophecy\\EmptyClass": [ "Fixtures\\Prophecy\\EmptyClass": [
"./WithReturnTypehints.php" "./WithReturnTypehints.php"
], ],
"self": [ "Fixtures\\Prophecy\\WithReturnTypehints": [
"./WithReturnTypehints.php" "./WithReturnTypehints.php"
], ],
"Fixtures\\Prophecy\\__CLASS__": [ "Fixtures\\Prophecy\\__CLASS__": [
@ -11,16 +11,13 @@
], ],
"__CLASS__": [ "__CLASS__": [
"./WithReturnTypehints.php" "./WithReturnTypehints.php"
],
"parent": [
"./WithReturnTypehints.php"
] ]
}, },
"definitions": { "definitions": {
"Fixtures\\Prophecy": { "Fixtures\\Prophecy": {
"fqn": "Fixtures\\Prophecy", "fqn": "Fixtures\\Prophecy",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -41,7 +38,7 @@
"extends": [ "extends": [
"Fixtures\\Prophecy\\EmptyClass" "Fixtures\\Prophecy\\EmptyClass"
], ],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -60,7 +57,7 @@
"Fixtures\\Prophecy\\WithReturnTypehints->getSelf()": { "Fixtures\\Prophecy\\WithReturnTypehints->getSelf()": {
"fqn": "Fixtures\\Prophecy\\WithReturnTypehints->getSelf()", "fqn": "Fixtures\\Prophecy\\WithReturnTypehints->getSelf()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -80,7 +77,7 @@
"Fixtures\\Prophecy\\WithReturnTypehints->getName()": { "Fixtures\\Prophecy\\WithReturnTypehints->getName()": {
"fqn": "Fixtures\\Prophecy\\WithReturnTypehints->getName()", "fqn": "Fixtures\\Prophecy\\WithReturnTypehints->getName()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -100,7 +97,7 @@
"Fixtures\\Prophecy\\WithReturnTypehints->getParent()": { "Fixtures\\Prophecy\\WithReturnTypehints->getParent()": {
"fqn": "Fixtures\\Prophecy\\WithReturnTypehints->getParent()", "fqn": "Fixtures\\Prophecy\\WithReturnTypehints->getParent()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -4,7 +4,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -4,7 +4,7 @@
"A": { "A": {
"fqn": "A", "fqn": "A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -23,7 +23,7 @@
"A->foo": { "A->foo": {
"fqn": "A->foo", "fqn": "A->foo",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -11,7 +11,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -11,7 +11,7 @@
"TestNamespace": { "TestNamespace": {
"fqn": "TestNamespace", "fqn": "TestNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -30,7 +30,7 @@
"TestNamespace\\A": { "TestNamespace\\A": {
"fqn": "TestNamespace\\A", "fqn": "TestNamespace\\A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -49,7 +49,7 @@
"TestNamespace\\A->a": { "TestNamespace\\A->a": {
"fqn": "TestNamespace\\A->a", "fqn": "TestNamespace\\A->a",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -11,7 +11,7 @@
"TestNamespace": { "TestNamespace": {
"fqn": "TestNamespace", "fqn": "TestNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -30,7 +30,7 @@
"TestNamespace\\TestClass": { "TestNamespace\\TestClass": {
"fqn": "TestNamespace\\TestClass", "fqn": "TestNamespace\\TestClass",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -49,7 +49,7 @@
"TestNamespace\\TestClass->testProperty": { "TestNamespace\\TestClass->testProperty": {
"fqn": "TestNamespace\\TestClass->testProperty", "fqn": "TestNamespace\\TestClass->testProperty",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -69,7 +69,7 @@
"TestNamespace\\TestClass->testMethod()": { "TestNamespace\\TestClass->testMethod()": {
"fqn": "TestNamespace\\TestClass->testMethod()", "fqn": "TestNamespace\\TestClass->testMethod()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -11,7 +11,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -30,7 +30,7 @@
"MyNamespace\\A": { "MyNamespace\\A": {
"fqn": "MyNamespace\\A", "fqn": "MyNamespace\\A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -49,7 +49,7 @@
"MyNamespace\\A::suite()": { "MyNamespace\\A::suite()": {
"fqn": "MyNamespace\\A::suite()", "fqn": "MyNamespace\\A::suite()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": true, "isStatic": true,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -11,7 +11,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -30,7 +30,7 @@
"MyNamespace\\A": { "MyNamespace\\A": {
"fqn": "MyNamespace\\A", "fqn": "MyNamespace\\A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -49,7 +49,7 @@
"MyNamespace\\A::suite()": { "MyNamespace\\A::suite()": {
"fqn": "MyNamespace\\A::suite()", "fqn": "MyNamespace\\A::suite()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": true, "isStatic": true,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -11,7 +11,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -30,7 +30,7 @@
"MyNamespace\\A": { "MyNamespace\\A": {
"fqn": "MyNamespace\\A", "fqn": "MyNamespace\\A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -49,7 +49,7 @@
"MyNamespace\\A::suite()": { "MyNamespace\\A::suite()": {
"fqn": "MyNamespace\\A::suite()", "fqn": "MyNamespace\\A::suite()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": true, "isStatic": true,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -11,7 +11,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -30,7 +30,7 @@
"MyNamespace\\A": { "MyNamespace\\A": {
"fqn": "MyNamespace\\A", "fqn": "MyNamespace\\A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -49,7 +49,7 @@
"MyNamespace\\A->suite()": { "MyNamespace\\A->suite()": {
"fqn": "MyNamespace\\A->suite()", "fqn": "MyNamespace\\A->suite()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -8,7 +8,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -27,7 +27,7 @@
"MyNamespace\\Mbstring": { "MyNamespace\\Mbstring": {
"fqn": "MyNamespace\\Mbstring", "fqn": "MyNamespace\\Mbstring",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -46,7 +46,7 @@
"MyNamespace\\Mbstring::MB_CASE_FOLD": { "MyNamespace\\Mbstring::MB_CASE_FOLD": {
"fqn": "MyNamespace\\Mbstring::MB_CASE_FOLD", "fqn": "MyNamespace\\Mbstring::MB_CASE_FOLD",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -8,7 +8,7 @@
"A": { "A": {
"fqn": "A", "fqn": "A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -27,7 +27,7 @@
"A->b()": { "A->b()": {
"fqn": "A->b()", "fqn": "A->b()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -4,7 +4,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -8,7 +8,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -11,7 +11,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -4,7 +4,7 @@
"A": { "A": {
"fqn": "A", "fqn": "A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -11,7 +11,7 @@
"B": { "B": {
"fqn": "B", "fqn": "B",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -8,7 +8,7 @@
"A": { "A": {
"fqn": "A", "fqn": "A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -27,7 +27,7 @@
"A::$deprecationsTriggered": { "A::$deprecationsTriggered": {
"fqn": "A::$deprecationsTriggered", "fqn": "A::$deprecationsTriggered",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": true, "isStatic": true,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -11,7 +11,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -30,7 +30,7 @@
"MyNamespace\\A": { "MyNamespace\\A": {
"fqn": "MyNamespace\\A", "fqn": "MyNamespace\\A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -49,7 +49,7 @@
"MyNamespace\\A::a()": { "MyNamespace\\A::a()": {
"fqn": "MyNamespace\\A::a()", "fqn": "MyNamespace\\A::a()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": true, "isStatic": true,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -11,7 +11,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -30,7 +30,7 @@
"MyNamespace\\A": { "MyNamespace\\A": {
"fqn": "MyNamespace\\A", "fqn": "MyNamespace\\A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -49,7 +49,7 @@
"MyNamespace\\A::a()": { "MyNamespace\\A::a()": {
"fqn": "MyNamespace\\A::a()", "fqn": "MyNamespace\\A::a()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": true, "isStatic": true,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -26,7 +26,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -45,7 +45,7 @@
"MyNamespace\\A": { "MyNamespace\\A": {
"fqn": "MyNamespace\\A", "fqn": "MyNamespace\\A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -64,7 +64,7 @@
"MyNamespace\\A::getInitializer()": { "MyNamespace\\A::getInitializer()": {
"fqn": "MyNamespace\\A::getInitializer()", "fqn": "MyNamespace\\A::getInitializer()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": true, "isStatic": true,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -17,7 +17,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -36,7 +36,7 @@
"MyNamespace\\A": { "MyNamespace\\A": {
"fqn": "MyNamespace\\A", "fqn": "MyNamespace\\A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -55,7 +55,7 @@
"MyNamespace\\A->testRequest()": { "MyNamespace\\A->testRequest()": {
"fqn": "MyNamespace\\A->testRequest()", "fqn": "MyNamespace\\A->testRequest()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -8,7 +8,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -27,7 +27,7 @@
"MyNamespace\\ParseErrorsTest": { "MyNamespace\\ParseErrorsTest": {
"fqn": "MyNamespace\\ParseErrorsTest", "fqn": "MyNamespace\\ParseErrorsTest",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -46,7 +46,7 @@
"MyNamespace\\ParseErrorsTest->setUp()": { "MyNamespace\\ParseErrorsTest->setUp()": {
"fqn": "MyNamespace\\ParseErrorsTest->setUp()", "fqn": "MyNamespace\\ParseErrorsTest->setUp()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -14,7 +14,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -33,7 +33,7 @@
"MyNamespace\\ParseErrorsTest": { "MyNamespace\\ParseErrorsTest": {
"fqn": "MyNamespace\\ParseErrorsTest", "fqn": "MyNamespace\\ParseErrorsTest",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -52,7 +52,7 @@
"MyNamespace\\ParseErrorsTest->setAccount()": { "MyNamespace\\ParseErrorsTest->setAccount()": {
"fqn": "MyNamespace\\ParseErrorsTest->setAccount()", "fqn": "MyNamespace\\ParseErrorsTest->setAccount()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -8,7 +8,7 @@
"FooClass": { "FooClass": {
"fqn": "FooClass", "fqn": "FooClass",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -27,7 +27,7 @@
"FooClass->foo()": { "FooClass->foo()": {
"fqn": "FooClass->foo()", "fqn": "FooClass->foo()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -17,7 +17,7 @@
"MyNamespace1": { "MyNamespace1": {
"fqn": "MyNamespace1", "fqn": "MyNamespace1",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -36,7 +36,7 @@
"MyNamespace1\\B": { "MyNamespace1\\B": {
"fqn": "MyNamespace1\\B", "fqn": "MyNamespace1\\B",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -55,7 +55,7 @@
"MyNamespace1\\B->b()": { "MyNamespace1\\B->b()": {
"fqn": "MyNamespace1\\B->b()", "fqn": "MyNamespace1\\B->b()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -75,7 +75,7 @@
"MyNamespace2": { "MyNamespace2": {
"fqn": "MyNamespace2", "fqn": "MyNamespace2",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -96,7 +96,7 @@
"extends": [ "extends": [
"MyNamespace2\\MyNamespace1\\B" "MyNamespace2\\MyNamespace1\\B"
], ],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -115,7 +115,7 @@
"MyNamespace2\\A->a()": { "MyNamespace2\\A->a()": {
"fqn": "MyNamespace2\\A->a()", "fqn": "MyNamespace2\\A->a()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -4,7 +4,7 @@
"Foo": { "Foo": {
"fqn": "Foo", "fqn": "Foo",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -23,7 +23,7 @@
"Foo->fn()": { "Foo->fn()": {
"fqn": "Foo->fn()", "fqn": "Foo->fn()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -1,10 +1,14 @@
{ {
"references": [], "references": {
"A": [
"./nameToken.php"
]
},
"definitions": { "definitions": {
"A": { "A": {
"fqn": "A", "fqn": "A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -23,7 +27,7 @@
"A->b()": { "A->b()": {
"fqn": "A->b()", "fqn": "A->b()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -17,7 +17,7 @@
"MyNamespace1": { "MyNamespace1": {
"fqn": "MyNamespace1", "fqn": "MyNamespace1",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -26,7 +26,7 @@
"B": { "B": {
"fqn": "B", "fqn": "B",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -4,7 +4,7 @@
"A\\B": { "A\\B": {
"fqn": "A\\B", "fqn": "A\\B",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -14,7 +14,7 @@
"LanguageServer\\Tests\\Utils": { "LanguageServer\\Tests\\Utils": {
"fqn": "LanguageServer\\Tests\\Utils", "fqn": "LanguageServer\\Tests\\Utils",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -8,7 +8,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -27,7 +27,7 @@
"MyNamespace\\A": { "MyNamespace\\A": {
"fqn": "MyNamespace\\A", "fqn": "MyNamespace\\A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -46,7 +46,7 @@
"MyNamespace\\A->a()": { "MyNamespace\\A->a()": {
"fqn": "MyNamespace\\A->a()", "fqn": "MyNamespace\\A->a()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -11,7 +11,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -30,7 +30,7 @@
"MyNamespace\\B": { "MyNamespace\\B": {
"fqn": "MyNamespace\\B", "fqn": "MyNamespace\\B",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -49,7 +49,7 @@
"MyNamespace\\A": { "MyNamespace\\A": {
"fqn": "MyNamespace\\A", "fqn": "MyNamespace\\A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -68,7 +68,7 @@
"MyNamespace\\A->a()": { "MyNamespace\\A->a()": {
"fqn": "MyNamespace\\A->a()", "fqn": "MyNamespace\\A->a()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -8,7 +8,7 @@
"A": { "A": {
"fqn": "A", "fqn": "A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -27,7 +27,7 @@
"A->a()": { "A->a()": {
"fqn": "A->a()", "fqn": "A->a()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -8,7 +8,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -27,7 +27,7 @@
"MyNamespace\\init()": { "MyNamespace\\init()": {
"fqn": "MyNamespace\\init()", "fqn": "MyNamespace\\init()",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -2,16 +2,13 @@
"references": { "references": {
"MyNamespace\\B": [ "MyNamespace\\B": [
"./parent1.php" "./parent1.php"
],
"parent": [
"./parent1.php"
] ]
}, },
"definitions": { "definitions": {
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -30,7 +27,7 @@
"MyNamespace\\B": { "MyNamespace\\B": {
"fqn": "MyNamespace\\B", "fqn": "MyNamespace\\B",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -49,7 +46,7 @@
"MyNamespace\\B->b()": { "MyNamespace\\B->b()": {
"fqn": "MyNamespace\\B->b()", "fqn": "MyNamespace\\B->b()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -71,7 +68,7 @@
"extends": [ "extends": [
"MyNamespace\\B" "MyNamespace\\B"
], ],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -90,7 +87,7 @@
"MyNamespace\\A->a()": { "MyNamespace\\A->a()": {
"fqn": "MyNamespace\\A->a()", "fqn": "MyNamespace\\A->a()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -5,16 +5,13 @@
], ],
"MyNamespace\\B->b()": [ "MyNamespace\\B->b()": [
"./parent3.php" "./parent3.php"
],
"parent": [
"./parent3.php"
] ]
}, },
"definitions": { "definitions": {
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -33,7 +30,7 @@
"MyNamespace\\B": { "MyNamespace\\B": {
"fqn": "MyNamespace\\B", "fqn": "MyNamespace\\B",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -52,7 +49,7 @@
"MyNamespace\\B->b()": { "MyNamespace\\B->b()": {
"fqn": "MyNamespace\\B->b()", "fqn": "MyNamespace\\B->b()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -74,7 +71,7 @@
"extends": [ "extends": [
"MyNamespace\\B" "MyNamespace\\B"
], ],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -93,7 +90,7 @@
"MyNamespace\\A->a()": { "MyNamespace\\A->a()": {
"fqn": "MyNamespace\\A->a()", "fqn": "MyNamespace\\A->a()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -4,7 +4,7 @@
"MyClass": { "MyClass": {
"fqn": "MyClass", "fqn": "MyClass",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -23,7 +23,7 @@
"MyClass->mainPropertyName": { "MyClass->mainPropertyName": {
"fqn": "MyClass->mainPropertyName", "fqn": "MyClass->mainPropertyName",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -4,7 +4,7 @@
"MyClass": { "MyClass": {
"fqn": "MyClass", "fqn": "MyClass",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -23,7 +23,7 @@
"MyClass->mainPropertyName": { "MyClass->mainPropertyName": {
"fqn": "MyClass->mainPropertyName", "fqn": "MyClass->mainPropertyName",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -11,7 +11,7 @@
"TestNamespace": { "TestNamespace": {
"fqn": "TestNamespace", "fqn": "TestNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -30,7 +30,7 @@
"TestNamespace\\whatever()": { "TestNamespace\\whatever()": {
"fqn": "TestNamespace\\whatever()", "fqn": "TestNamespace\\whatever()",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -11,7 +11,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -30,7 +30,7 @@
"MyNamespace\\A": { "MyNamespace\\A": {
"fqn": "MyNamespace\\A", "fqn": "MyNamespace\\A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -49,7 +49,7 @@
"MyNamespace\\A::a()": { "MyNamespace\\A::a()": {
"fqn": "MyNamespace\\A::a()", "fqn": "MyNamespace\\A::a()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": true, "isStatic": true,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -8,7 +8,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -11,7 +11,7 @@
"A": { "A": {
"fqn": "A", "fqn": "A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -30,7 +30,7 @@
"A::$a": { "A::$a": {
"fqn": "A::$a", "fqn": "A::$a",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": true, "isStatic": true,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -17,7 +17,7 @@
"TestClass": { "TestClass": {
"fqn": "TestClass", "fqn": "TestClass",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -36,7 +36,7 @@
"TestClass::$testProperty": { "TestClass::$testProperty": {
"fqn": "TestClass::$testProperty", "fqn": "TestClass::$testProperty",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": true, "isStatic": true,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -6,7 +6,7 @@
"MyNamespace\\A::b()": [ "MyNamespace\\A::b()": [
"./self1.php" "./self1.php"
], ],
"self": [ "MyNamespace\\A": [
"./self1.php" "./self1.php"
] ]
}, },
@ -14,7 +14,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -33,7 +33,7 @@
"MyNamespace\\B": { "MyNamespace\\B": {
"fqn": "MyNamespace\\B", "fqn": "MyNamespace\\B",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -52,7 +52,7 @@
"MyNamespace\\B->b()": { "MyNamespace\\B->b()": {
"fqn": "MyNamespace\\B->b()", "fqn": "MyNamespace\\B->b()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -74,7 +74,7 @@
"extends": [ "extends": [
"MyNamespace\\B" "MyNamespace\\B"
], ],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -93,7 +93,7 @@
"MyNamespace\\A->a()": { "MyNamespace\\A->a()": {
"fqn": "MyNamespace\\A->a()", "fqn": "MyNamespace\\A->a()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -6,7 +6,7 @@
"MyNamespace\\A::b()": [ "MyNamespace\\A::b()": [
"./self2.php" "./self2.php"
], ],
"self": [ "MyNamespace\\A": [
"./self2.php" "./self2.php"
] ]
}, },
@ -14,7 +14,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -33,7 +33,7 @@
"MyNamespace\\B": { "MyNamespace\\B": {
"fqn": "MyNamespace\\B", "fqn": "MyNamespace\\B",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -52,7 +52,7 @@
"MyNamespace\\B->b()": { "MyNamespace\\B->b()": {
"fqn": "MyNamespace\\B->b()", "fqn": "MyNamespace\\B->b()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -74,7 +74,7 @@
"extends": [ "extends": [
"MyNamespace\\B" "MyNamespace\\B"
], ],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -93,7 +93,7 @@
"MyNamespace\\A->a()": { "MyNamespace\\A->a()": {
"fqn": "MyNamespace\\A->a()", "fqn": "MyNamespace\\A->a()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -6,7 +6,7 @@
"MyNamespace\\A->b()": [ "MyNamespace\\A->b()": [
"./self3.php" "./self3.php"
], ],
"self": [ "MyNamespace\\A": [
"./self3.php" "./self3.php"
] ]
}, },
@ -14,7 +14,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -33,7 +33,7 @@
"MyNamespace\\B": { "MyNamespace\\B": {
"fqn": "MyNamespace\\B", "fqn": "MyNamespace\\B",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -52,7 +52,7 @@
"MyNamespace\\B->b()": { "MyNamespace\\B->b()": {
"fqn": "MyNamespace\\B->b()", "fqn": "MyNamespace\\B->b()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -74,7 +74,7 @@
"extends": [ "extends": [
"MyNamespace\\B" "MyNamespace\\B"
], ],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -93,7 +93,7 @@
"MyNamespace\\A->a()": { "MyNamespace\\A->a()": {
"fqn": "MyNamespace\\A->a()", "fqn": "MyNamespace\\A->a()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -1,6 +1,6 @@
{ {
"references": { "references": {
"self": [ "MyNamespace\\A": [
"./self4.php" "./self4.php"
], ],
"MyNamespace\\A->addTestFile()": [ "MyNamespace\\A->addTestFile()": [
@ -23,7 +23,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -42,7 +42,7 @@
"MyNamespace\\A": { "MyNamespace\\A": {
"fqn": "MyNamespace\\A", "fqn": "MyNamespace\\A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -61,7 +61,7 @@
"MyNamespace\\A::suite()": { "MyNamespace\\A::suite()": {
"fqn": "MyNamespace\\A::suite()", "fqn": "MyNamespace\\A::suite()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": true, "isStatic": true,
"canBeInstantiated": false, "canBeInstantiated": false,

View File

@ -8,7 +8,7 @@
"MyNamespace": { "MyNamespace": {
"fqn": "MyNamespace", "fqn": "MyNamespace",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,
@ -27,7 +27,7 @@
"MyNamespace\\A": { "MyNamespace\\A": {
"fqn": "MyNamespace\\A", "fqn": "MyNamespace\\A",
"extends": [], "extends": [],
"isGlobal": true, "isMember": false,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": true, "canBeInstantiated": true,
@ -46,7 +46,7 @@
"MyNamespace\\A->typesProvider()": { "MyNamespace\\A->typesProvider()": {
"fqn": "MyNamespace\\A->typesProvider()", "fqn": "MyNamespace\\A->typesProvider()",
"extends": [], "extends": [],
"isGlobal": false, "isMember": true,
"roamed": false, "roamed": false,
"isStatic": false, "isStatic": false,
"canBeInstantiated": false, "canBeInstantiated": false,

Some files were not shown because too many files have changed in this diff Show More