├── .github └── workflows │ ├── build.yml │ └── semantic.yml ├── LICENSE.txt ├── README.md ├── benchmarks ├── completion.php └── parsing.php ├── bin └── php-language-server.php ├── composer.json ├── extra_stubs └── enum.php ├── package-lock.json ├── src ├── Cache │ ├── Cache.php │ ├── ClientCache.php │ └── FileSystemCache.php ├── Client │ ├── TextDocument.php │ ├── Window.php │ ├── WorkDoneProgress.php │ ├── Workspace.php │ └── XCache.php ├── ClientHandler.php ├── CompletionProvider.php ├── ComposerScripts.php ├── ContentRetriever │ ├── ClientContentRetriever.php │ ├── ContentRetriever.php │ └── FileSystemContentRetriever.php ├── ContentTooLargeException.php ├── Definition.php ├── DefinitionResolver.php ├── Factory │ ├── CompletionItemFactory.php │ ├── LocationFactory.php │ ├── RangeFactory.php │ └── SymbolInformationFactory.php ├── FilesFinder │ ├── ClientFilesFinder.php │ ├── FileSystemFilesFinder.php │ └── FilesFinder.php ├── FqnUtilities.php ├── IdGenerator.php ├── Index │ ├── AbstractAggregateIndex.php │ ├── DependenciesIndex.php │ ├── GlobalIndex.php │ ├── Index.php │ ├── ProjectIndex.php │ ├── ReadableIndex.php │ └── StubsIndex.php ├── Indexer.php ├── LanguageClient.php ├── LanguageServer.php ├── Message.php ├── ParserHelpers.php ├── PhpDocument.php ├── PhpDocumentLoader.php ├── ProtocolReader.php ├── ProtocolStreamReader.php ├── ProtocolStreamWriter.php ├── ProtocolWriter.php ├── Server │ ├── TextDocument.php │ └── Workspace.php ├── SignatureHelpProvider.php ├── SignatureInformationFactory.php ├── StderrLogger.php ├── TreeAnalyzer.php └── utils.php └── tests ├── ClientHandlerTest.php ├── DefinitionResolverTest.php ├── Diagnostics └── InvalidThisUsageTest.php ├── Index └── IndexTest.php ├── LanguageServerTest.php ├── MockPhpDocument.php ├── MockProtocolStream.php ├── NodeVisitor └── DefinitionCollectorTest.php ├── PhpDocumentLoaderTest.php ├── PhpDocumentTest.php ├── ProtocolStreamReaderTest.php ├── ProtocolStreamWriterTest.php ├── Server ├── ServerTestCase.php ├── TextDocument │ ├── CompletionTest.php │ ├── Definition │ │ ├── GlobalFallbackTest.php │ │ ├── GlobalTest.php │ │ └── NamespacedTest.php │ ├── DidChangeTest.php │ ├── DidCloseTest.php │ ├── DocumentSymbolTest.php │ ├── HoverTest.php │ ├── ParseErrorsTest.php │ ├── References │ │ ├── GlobalFallbackTest.php │ │ ├── GlobalTest.php │ │ └── NamespacedTest.php │ └── SignatureHelpTest.php └── Workspace │ ├── DidChangeWatchedFilesTest.php │ └── SymbolTest.php ├── Utils ├── FileUriTest.php └── StripStringOverlapTest.php └── Validation ├── ValidationTest.php ├── cases ├── WithReturnTypehints.php ├── WithReturnTypehints.php.expected.json ├── anonymousClassMembersShouldNotBeSymbols.php ├── anonymousClassMembersShouldNotBeSymbols.php.expected.json ├── arrayValueShouldBeBoolean.php ├── arrayValueShouldBeBoolean.php.expected.json ├── caseStatement1.php ├── caseStatement1.php.expected.json ├── circularVar.php ├── circularVar.php.expected.json ├── classDefinition1.php ├── classDefinition1.php.expected.json ├── classProperty1.php ├── classProperty1.php.expected.json ├── constants.php ├── constants.php.expected.json ├── constants2.php ├── constants2.php.expected.json ├── constants3.php ├── constants3.php.expected.json ├── constants4.php ├── constants4.php.expected.json ├── constants5.php ├── constants5.php.expected.json ├── constantsInFunctionParamDefault.php ├── constantsInFunctionParamDefault.php.expected.json ├── docBlocksOnNamespaceDefinition.php ├── docBlocksOnNamespaceDefinition.php.expected.json ├── exceptions1.php ├── exceptions1.php.expected.json ├── forLoopReference1.php ├── forLoopReference1.php.expected.json ├── functionParamInters.php ├── functionParamInters.php.expected.json ├── functionParamUnion.php ├── functionParamUnion.php.expected.json ├── functionReturnInters.php ├── functionReturnInters.php.expected.json ├── functionReturnUnion.php ├── functionReturnUnion.php.expected.json ├── functionUse.php ├── functionUse.php.expected.json ├── functionUse2.php ├── functionUse2.php.expected.json ├── ifStatement1.php ├── ifStatement1.php.expected.json ├── interfaceProperty.php ├── interfaceProperty.php.expected.json ├── magicConstantsShouldBeGlobal.php ├── magicConstantsShouldBeGlobal.php.expected.json ├── magicConsts.php ├── magicConsts.php.expected.json ├── memberAccess1.php ├── memberAccess1.php.expected.json ├── memberAccess2.php ├── memberAccess2.php.expected.json ├── memberAccess3.php ├── memberAccess3.php.expected.json ├── memberAccess4.php ├── memberAccess4.php.expected.json ├── memberAccess5.php ├── memberAccess5.php.expected.json ├── memberCall1.php ├── memberCall1.php.expected.json ├── methodReturnType.php ├── methodReturnType.php.expected.json ├── multipleNamespaces.php ├── multipleNamespaces.php.expected.json ├── multiplePreceedingComments.php ├── multiplePreceedingComments.php.expected.json ├── nameToken.php ├── nameToken.php.expected.json ├── namespaces2.php ├── namespaces2.php.expected.json ├── namespaces3.php ├── namespaces3.php.expected.json ├── namespaces4.php ├── namespaces4.php.expected.json ├── namespaces5.php ├── namespaces5.php.expected.json ├── namespaces6.php ├── namespaces6.php.expected.json ├── namespaces7.php ├── namespaces7.php.expected.json ├── namespaces8.php ├── namespaces8.php.expected.json ├── namespaces9.php ├── namespaces9.php.expected.json ├── newStatic.php ├── newStatic.php.expected.json ├── objectCreation.php ├── objectCreation.php.expected.json ├── objectCreation2.php ├── objectCreation2.php.expected.json ├── objectCreation3.php ├── objectCreation3.php.expected.json ├── param1.php ├── param1.php.expected.json ├── parameterTypeResolution1.php ├── parameterTypeResolution1.php.expected.json ├── parent1.php ├── parent1.php.expected.json ├── parent2.php ├── parent2.php.expected.json ├── parent3.php ├── parent3.php.expected.json ├── promotedConstructor.php ├── promotedConstructor.php.expected.json ├── propertyName1.php ├── propertyName1.php.expected.json ├── propertyName2.php ├── propertyName2.php.expected.json ├── returnType.php ├── returnType.php.expected.json ├── scopedPropertyAccess.php ├── scopedPropertyAccess.php.expected.json ├── scopedPropertyAccess2.php ├── scopedPropertyAccess2.php.expected.json ├── scopedPropertyAccess3.php ├── scopedPropertyAccess3.php.expected.json ├── scopedPropertyAccess4.php ├── scopedPropertyAccess4.php.expected.json ├── scopedPropertyAccess5.php ├── scopedPropertyAccess5.php.expected.json ├── self1.php ├── self1.php.expected.json ├── self2.php ├── self2.php.expected.json ├── self3.php ├── self3.php.expected.json ├── self4.php ├── self4.php.expected.json ├── self5.php ├── self5.php.expected.json ├── static1.php ├── static1.php.expected.json ├── static2.php ├── static2.php.expected.json ├── static3.php ├── static3.php.expected.json ├── static4.php ├── static4.php.expected.json ├── staticInArray.php ├── staticInArray.php.expected.json ├── staticMethodReturnType.php ├── staticMethodReturnType.php.expected.json ├── stringVariable.php ├── stringVariable.php.expected.json ├── testQualifiedNameOutsideOfNamespace.php ├── testQualifiedNameOutsideOfNamespace.php.expected.json ├── trait1.php ├── trait1.php.expected.json ├── trait2.php ├── trait2.php.expected.json ├── trait3.php ├── trait3.php.expected.json ├── trait4.php ├── trait4.php.expected.json ├── verifyFqsenOnClassProperty.php └── verifyFqsenOnClassProperty.php.expected.json ├── cases81 ├── enum1.php ├── enum1.php.expected.json ├── enum2.php ├── enum2.php.expected.json ├── enum3.php └── enum3.php.expected.json ├── cases82 ├── dnfTypes1.php └── dnfTypes1.php.expected.json └── disabled.json /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | FORCE_COLOR: 3 7 | 8 | jobs: 9 | test: 10 | if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main' 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | matrix: 14 | include: 15 | - xdebug: xdebug-3.1.1 # renovate:keep-up-to-date 16 | php: '7.4' 17 | os: ubuntu-22.04 18 | - xdebug: xdebug-3.1.1 # renovate:keep-up-to-date 19 | php: '8.1' 20 | os: ubuntu-22.04 21 | steps: 22 | - uses: actions/checkout@v2 23 | - name: Setup Node.js 24 | uses: actions/setup-node@v2 25 | with: 26 | node-version: '14.15.3' # renovate:keep-up-to-date 27 | - name: Install npm dependencies 28 | run: npm ci 29 | - name: Setup PHP 30 | uses: shivammathur/setup-php@v2 31 | with: 32 | php-version: ${{ matrix.php }} 33 | extensions: ${{ matrix.xdebug }}, ast 34 | tools: composer 35 | - name: Composer Install 36 | run: composer install --ignore-platform-reqs 37 | - name: phpcs 38 | run: ./vendor/bin/phpcs -n 39 | # - name: phan 40 | # run: ./vendor/bin/phan 41 | - name: phpunit 42 | run: vendor/bin/phpunit --coverage-clover=coverage.xml --colors=always 43 | - name: Upload coverage to Codecov 44 | uses: codecov/codecov-action@v2 45 | # release: 46 | # runs-on: ubuntu-18.04 47 | # needs: test 48 | # if: github.repository_owner == 'xdebug' && github.event_name == 'push' && github.ref == 'refs/heads/main' 49 | # steps: 50 | # - uses: actions/checkout@v2 51 | # - name: Setup Node.js 52 | # uses: actions/setup-node@v2 53 | # with: 54 | # node-version: '14.15.3' # renovate:keep-up-to-date 55 | # - name: Install npm dependencies 56 | # run: npm ci 57 | # - name: Build VS Code extension 58 | # run: npm run build 59 | # - name: Release 60 | # env: 61 | # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 62 | # VSCE_TOKEN: ${{ secrets.VSCE_TOKEN }} 63 | # run: npm run semantic-release 64 | -------------------------------------------------------------------------------- /.github/workflows/semantic.yml: -------------------------------------------------------------------------------- 1 | name: 'Semantic Pull Request' 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | # pull_request: 10 | # types: 11 | # - opened 12 | # - edited 13 | # - synchronize 14 | 15 | jobs: 16 | main: 17 | name: Validate PR Title 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: semantic-pull-request 21 | uses: amannn/action-semantic-pull-request@v4 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | with: 25 | validateSingleCommit: false 26 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2016, Felix Frederick Becker 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /benchmarks/parsing.php: -------------------------------------------------------------------------------- 1 | setLogger($logger); 20 | $xdebugHandler->check(); 21 | unset($xdebugHandler); 22 | 23 | $totalSize = 0; 24 | 25 | $frameworks = ["drupal", "wordpress", "php-language-server", "tolerant-php-parser", "math-php", "symfony", "codeigniter", "cakephp"]; 26 | 27 | foreach($frameworks as $framework) { 28 | $iterator = new RecursiveDirectoryIterator(__DIR__ . "/../validation/frameworks/$framework"); 29 | $testProviderArray = array(); 30 | 31 | foreach (new RecursiveIteratorIterator($iterator) as $file) { 32 | if (strpos((string)$file, ".php") !== false) { 33 | $totalSize += $file->getSize(); 34 | $testProviderArray[] = $file->getPathname(); 35 | } 36 | } 37 | 38 | if (count($testProviderArray) === 0) { 39 | throw new Exception("ERROR: Validation testsuite frameworks not found - run `git submodule update --init --recursive` to download."); 40 | } 41 | 42 | $start = microtime(true); 43 | 44 | foreach ($testProviderArray as $idx => $testCaseFile) { 45 | if (filesize($testCaseFile) > 10000) { 46 | continue; 47 | } 48 | if ($idx % 500 === 0) { 49 | echo $idx . '/' . count($testProviderArray) . PHP_EOL; 50 | } 51 | 52 | $fileContents = file_get_contents($testCaseFile); 53 | 54 | $docBlockFactory = DocBlockFactory::createInstance(); 55 | $index = new Index; 56 | $maxRecursion = []; 57 | $definitions = []; 58 | 59 | $definitionResolver = new DefinitionResolver($index); 60 | $parser = new PhpParser\Parser(); 61 | 62 | $document = new PhpDocument($testCaseFile, $fileContents, $index, $parser, $docBlockFactory, $definitionResolver); 63 | } 64 | 65 | echo "------------------------------\n"; 66 | 67 | echo "Time [$framework]: " . (microtime(true) - $start) . PHP_EOL; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "felixfbecker/language-server", 3 | "description": "PHP Implementation of the Visual Studio Code Language Server Protocol", 4 | "license": "ISC", 5 | "keywords": [ 6 | "php", 7 | "language", 8 | "server", 9 | "microsoft", 10 | "visual", 11 | "studio", 12 | "code", 13 | "intellisense", 14 | "autocompletion", 15 | "refactor" 16 | ], 17 | "authors": [ 18 | { 19 | "name": "Felix Becker", 20 | "email": "felix.b@outlook.com" 21 | } 22 | ], 23 | "repositories": [ 24 | { 25 | "type": "git", 26 | "url": "https://github.com/zobo/php-language-server-protocol" 27 | }, 28 | { 29 | "type": "git", 30 | "url": "https://github.com/microsoft/tolerant-php-parser.git" 31 | } 32 | ], 33 | "require": { 34 | "php": ">=7.4", 35 | "composer/xdebug-handler": "^1.0", 36 | "felixfbecker/advanced-json-rpc": "^3.0.0", 37 | "felixfbecker/language-server-protocol": "dev-main", 38 | "jetbrains/phpstorm-stubs": "dev-master", 39 | "microsoft/tolerant-php-parser": "dev-main as 0.1.2", 40 | "netresearch/jsonmapper": "^1.0", 41 | "phpdocumentor/reflection-docblock": "^5.2.2", 42 | "psr/log": "^1.0", 43 | "sabre/event": "^5.0", 44 | "sabre/uri": "^2.0", 45 | "webmozart/glob": "^4.6", 46 | "webmozart/path-util": "^2.3" 47 | }, 48 | "require-dev": { 49 | "phan/phan": "^5.2", 50 | "phpstan/phpstan": "^1.9", 51 | "phpunit/phpunit": "^9.0", 52 | "squizlabs/php_codesniffer": "^3.6" 53 | }, 54 | "autoload": { 55 | "psr-4": { 56 | "LanguageServer\\": "src/" 57 | }, 58 | "files" : [ 59 | "src/utils.php", 60 | "src/FqnUtilities.php", 61 | "src/ParserHelpers.php" 62 | ] 63 | }, 64 | "autoload-dev": { 65 | "psr-4": { 66 | "LanguageServer\\Tests\\": "tests/" 67 | } 68 | }, 69 | "bin": [ 70 | "bin/php-language-server.php" 71 | ], 72 | "scripts": { 73 | "parse-stubs": "LanguageServer\\ComposerScripts::parseStubs", 74 | "post-install-cmd": "@parse-stubs", 75 | "post-update-cmd": "@parse-stubs", 76 | "test": "vendor/bin/phpunit", 77 | "lint": "vendor/bin/phpcs" 78 | }, 79 | "config": { 80 | "sort-packages": true 81 | }, 82 | "minimum-stability": "dev", 83 | "prefer-stable": true 84 | } 85 | -------------------------------------------------------------------------------- /extra_stubs/enum.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | public function get(string $key): Promise; 20 | 21 | /** 22 | * Sets a value in the cache 23 | * 24 | * @param string $key 25 | * @param mixed $value 26 | * @return Promise 27 | */ 28 | public function set(string $key, $value): Promise; 29 | } 30 | -------------------------------------------------------------------------------- /src/Cache/ClientCache.php: -------------------------------------------------------------------------------- 1 | client = $client; 25 | } 26 | 27 | /** 28 | * Gets a value from the cache 29 | * 30 | * @param string $key 31 | * @return Promise 32 | */ 33 | public function get(string $key): Promise 34 | { 35 | return $this->client->xcache->get($key)->then('unserialize')->otherwise(function () { 36 | // Ignore 37 | }); 38 | } 39 | 40 | /** 41 | * Sets a value in the cache 42 | * 43 | * @param string $key 44 | * @param mixed $value 45 | * @return Promise 46 | */ 47 | public function set(string $key, $value): Promise 48 | { 49 | return $this->client->xcache->set($key, serialize($value))->otherwise(function () { 50 | // Ignore 51 | }); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Cache/FileSystemCache.php: -------------------------------------------------------------------------------- 1 | cacheDir = getenv('LOCALAPPDATA') . '\\PHP Language Server\\'; 22 | } else if (getenv('XDG_CACHE_HOME')) { 23 | $this->cacheDir = getenv('XDG_CACHE_HOME') . '/phpls/'; 24 | } else { 25 | $this->cacheDir = getenv('HOME') . '/.phpls/'; 26 | } 27 | } 28 | 29 | /** 30 | * Gets a value from the cache 31 | * 32 | * @param string $key 33 | * @return Promise 34 | */ 35 | public function get(string $key): Promise 36 | { 37 | try { 38 | $file = $this->cacheDir . urlencode($key); 39 | if (!file_exists($file)) { 40 | return Promise\resolve(null); 41 | } 42 | return Promise\resolve(unserialize(file_get_contents($file))); 43 | } catch (\Exception $e) { 44 | return Promise\resolve(null); 45 | } 46 | } 47 | 48 | /** 49 | * Sets a value in the cache 50 | * 51 | * @param string $key 52 | * @param mixed $value 53 | * @return Promise 54 | */ 55 | public function set(string $key, $value): Promise 56 | { 57 | try { 58 | $file = $this->cacheDir . urlencode($key); 59 | if (!file_exists($this->cacheDir)) { 60 | mkdir($this->cacheDir); 61 | } 62 | file_put_contents($file, serialize($value)); 63 | } finally { 64 | return Promise\resolve(null); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Client/TextDocument.php: -------------------------------------------------------------------------------- 1 | handler = $handler; 29 | $this->mapper = $mapper; 30 | } 31 | 32 | /** 33 | * Diagnostics notification are sent from the server to the client to signal results of validation runs. 34 | * 35 | * @param string $uri 36 | * @param Diagnostic[] $diagnostics 37 | * @return Promise 38 | */ 39 | public function publishDiagnostics(string $uri, array $diagnostics): Promise 40 | { 41 | return $this->handler->notify('textDocument/publishDiagnostics', [ 42 | 'uri' => $uri, 43 | 'diagnostics' => $diagnostics 44 | ]); 45 | } 46 | 47 | /** 48 | * The content request is sent from a server to a client 49 | * to request the current content of a text document identified by the URI 50 | * 51 | * @param TextDocumentIdentifier $textDocument The document to get the content for 52 | * @return Promise The document's current content 53 | */ 54 | public function xcontent(TextDocumentIdentifier $textDocument): Promise 55 | { 56 | return $this->handler->request( 57 | 'textDocument/xcontent', 58 | ['textDocument' => $textDocument] 59 | )->then(function ($result) { 60 | return $this->mapper->map($result, new TextDocumentItem); 61 | }); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Client/Window.php: -------------------------------------------------------------------------------- 1 | handler = $handler; 22 | } 23 | 24 | /** 25 | * The show message notification is sent from a server to a client 26 | * to ask the client to display a particular message in the user interface. 27 | * 28 | * @param int $type 29 | * @param string $message 30 | * @return Promise 31 | */ 32 | public function showMessage(int $type, string $message): Promise 33 | { 34 | return $this->handler->notify('window/showMessage', ['type' => $type, 'message' => $message]); 35 | } 36 | 37 | /** 38 | * The log message notification is sent from the server to the client to ask the client to log a particular message. 39 | * 40 | * @param int $type 41 | * @param string $message 42 | * @return Promise 43 | */ 44 | public function logMessage(int $type, string $message): Promise 45 | { 46 | return $this->handler->notify('window/logMessage', ['type' => $type, 'message' => $message]); 47 | } 48 | 49 | /** 50 | * https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#window_workDoneProgress_create 51 | * 52 | * @return Promise 53 | */ 54 | public function createWorkDoneProgress(): Promise 55 | { 56 | $token = uniqid("pls-"); 57 | 58 | return $this->handler->request( 59 | 'window/workDoneProgress/create', 60 | ['token' => $token] 61 | )->then(function ($result) use ($token) { 62 | // check result?? 63 | return new WorkDoneProgress($this->handler, $token); 64 | })->otherwise(function () { 65 | return null; 66 | }); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Client/WorkDoneProgress.php: -------------------------------------------------------------------------------- 1 | handler = $handler; 26 | $this->token = $token; 27 | } 28 | 29 | public function beginProgress(string $title, string $message = null, int $percentage = null): Promise 30 | { 31 | return $this->handler->notify( 32 | '$/progress', 33 | [ 34 | 'token' => $this->token, 35 | 'value' => [ 36 | 'kind' => 'begin', 37 | 'title' => $title, 38 | // 'cancellable' 39 | 'message' => $message, 40 | 'percentage' => $percentage, 41 | ] 42 | ] 43 | ); 44 | } 45 | 46 | public function reportProgress(string $message = null, int $percentage = null): Promise 47 | { 48 | return $this->handler->notify( 49 | '$/progress', 50 | [ 51 | 'token' => $this->token, 52 | 'value' => [ 53 | 'kind' => 'report', 54 | // 'cancellable' 55 | 'message' => $message, 56 | 'percentage' => $percentage, 57 | ] 58 | ] 59 | ); 60 | } 61 | 62 | public function endProgress(string $message = null): Promise 63 | { 64 | return $this->handler->notify( 65 | '$/progress', 66 | [ 67 | 'token' => $this->token, 68 | 'value' => [ 69 | 'kind' => 'end', 70 | 'message' => $message, 71 | ] 72 | ] 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Client/Workspace.php: -------------------------------------------------------------------------------- 1 | handler = $handler; 29 | $this->mapper = $mapper; 30 | } 31 | 32 | /** 33 | * Returns a list of all files in a directory 34 | * 35 | * @param string $base The base directory (defaults to the workspace) 36 | * @return Promise Array of documents 37 | */ 38 | public function xfiles(string $base = null): Promise 39 | { 40 | return $this->handler->request( 41 | 'workspace/xfiles', 42 | ['base' => $base] 43 | )->then(function (array $textDocuments) { 44 | return $this->mapper->mapArray($textDocuments, [], TextDocumentIdentifier::class); 45 | }); 46 | } 47 | 48 | /** 49 | * The workspace/configuration request is sent from the server to the client 50 | * to fetch configuration settings from the client. The request can fetch 51 | * several configuration settings in one roundtrip. The order of the 52 | * returned configuration settings correspond to the order of the passed 53 | * ConfigurationItems (e.g. the first item in the response is the result 54 | * for the first configuration item in the params). 55 | * 56 | * @param array{'section': string}[] $items Array of configuration items 57 | * @return Promise <\stdClass[]> Array of configuration objects 58 | */ 59 | public function configuration(array $items): Promise 60 | { 61 | return $this->handler->request( 62 | 'workspace/configuration', 63 | ['items' => $items] 64 | )->then(function (array $items) { 65 | return $items; 66 | //return $this->mapper->mapArray($items, [], ConfigurationItem::class); 67 | }); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Client/XCache.php: -------------------------------------------------------------------------------- 1 | handler = $handler; 22 | } 23 | 24 | /** 25 | * @param string $key 26 | * @return Promise 27 | */ 28 | public function get(string $key): Promise 29 | { 30 | return $this->handler->request('xcache/get', ['key' => $key]); 31 | } 32 | 33 | /** 34 | * @param string $key 35 | * @param mixed $value 36 | * @return Promise 37 | */ 38 | public function set(string $key, $value): Promise 39 | { 40 | return $this->handler->notify('xcache/set', ['key' => $key, 'value' => $value]); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/ClientHandler.php: -------------------------------------------------------------------------------- 1 | protocolReader = $protocolReader; 29 | $this->protocolWriter = $protocolWriter; 30 | $this->idGenerator = new IdGenerator; 31 | } 32 | 33 | /** 34 | * Sends a request to the client and returns a promise that is resolved with the result or rejected with the error 35 | * 36 | * @param string $method The method to call 37 | * @param array|object $params The method parameters 38 | * @return Promise Resolved with the result of the request or rejected with an error 39 | */ 40 | public function request(string $method, $params): Promise 41 | { 42 | $id = $this->idGenerator->generate(); 43 | return $this->protocolWriter->write( 44 | new Message( 45 | new AdvancedJsonRpc\Request($id, $method, (object)$params) 46 | ) 47 | )->then(function () use ($id) { 48 | $promise = new Promise; 49 | $listener = function (Message $msg) use ($id, $promise, &$listener) { 50 | if (AdvancedJsonRpc\Response::isResponse($msg->body) && $msg->body->id === $id) { 51 | // Received a response 52 | $this->protocolReader->removeListener('message', $listener); 53 | if (AdvancedJsonRpc\SuccessResponse::isSuccessResponse($msg->body)) { 54 | $promise->fulfill($msg->body->result); 55 | } else { 56 | $promise->reject($msg->body->error); 57 | } 58 | } 59 | }; 60 | $this->protocolReader->on('message', $listener); 61 | return $promise; 62 | }); 63 | } 64 | 65 | /** 66 | * Sends a notification to the client 67 | * 68 | * @param string $method The method to call 69 | * @param array|object $params The method parameters 70 | * @return Promise Will be resolved as soon as the notification has been sent 71 | */ 72 | public function notify(string $method, $params): Promise 73 | { 74 | return $this->protocolWriter->write( 75 | new Message( 76 | new AdvancedJsonRpc\Notification($method, (object)$params) 77 | ) 78 | ); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/ComposerScripts.php: -------------------------------------------------------------------------------- 1 | find("$stubsLocation/**/*.php"); 48 | 49 | $uris = array_merge($uris, yield $finder->find(__DIR__ . '/../extra_stubs/*.php')); 50 | 51 | foreach ($uris as $uri) { 52 | echo "Parsing $uri\n"; 53 | $content = yield $contentRetriever->retrieve($uri); 54 | 55 | // Change URI to phpstubs:// 56 | $parts = Uri\parse($uri); 57 | $parts['path'] = Path::makeRelative(uriToPath($uri), $stubsLocation); 58 | $parts['scheme'] = 'phpstubs'; 59 | $uri = Uri\build($parts); 60 | 61 | // Create a new document and add it to $index 62 | new PhpDocument($uri, $content, $index, $parser, $docBlockFactory, $definitionResolver); 63 | } 64 | 65 | $index->setComplete(); 66 | 67 | echo "Saving Index\n"; 68 | 69 | $index->save(); 70 | 71 | echo "Finished\n"; 72 | })->wait(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/ContentRetriever/ClientContentRetriever.php: -------------------------------------------------------------------------------- 1 | client = $client; 23 | } 24 | 25 | /** 26 | * Retrieves the content of a text document identified by the URI through a textDocument/xcontent request 27 | * 28 | * @param string $uri The URI of the document 29 | * @return Promise Resolved with the content as a string 30 | */ 31 | public function retrieve(string $uri): Promise 32 | { 33 | return $this->client->textDocument->xcontent(new TextDocumentIdentifier($uri)) 34 | ->then(function (TextDocumentItem $textDocument) { 35 | return $textDocument->text; 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/ContentRetriever/ContentRetriever.php: -------------------------------------------------------------------------------- 1 | Resolved with the content as a string 18 | */ 19 | public function retrieve(string $uri): Promise; 20 | } 21 | -------------------------------------------------------------------------------- /src/ContentRetriever/FileSystemContentRetriever.php: -------------------------------------------------------------------------------- 1 | Resolved with the content as a string 19 | */ 20 | public function retrieve(string $uri): Promise 21 | { 22 | return Promise\resolve(file_get_contents(uriToPath($uri))); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ContentTooLargeException.php: -------------------------------------------------------------------------------- 1 | uri = $uri; 41 | $this->size = $size; 42 | $this->limit = $limit; 43 | parent::__construct("$uri exceeds size limit of $limit bytes ($size)", 0, $previous); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Factory/CompletionItemFactory.php: -------------------------------------------------------------------------------- 1 | label = $def->symbolInformation->name; 22 | $item->kind = CompletionItemKind::fromSymbolKind($def->symbolInformation->kind); 23 | if ($def->type) { 24 | $item->detail = (string)$def->type; 25 | } else if ($def->symbolInformation->containerName) { 26 | $item->detail = $def->symbolInformation->containerName; 27 | } 28 | if ($def->documentation) { 29 | $item->documentation = $def->documentation; 30 | } 31 | if ($def->isStatic && $def->symbolInformation->kind === SymbolKind::PROPERTY) { 32 | $item->insertText = '$' . $def->symbolInformation->name; 33 | } 34 | return $item; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Factory/LocationFactory.php: -------------------------------------------------------------------------------- 1 | getStartPosition(), 23 | $node->getWidth(), 24 | $node->getFileContents() 25 | ); 26 | 27 | return new Location($node->getUri(), new Range( 28 | new Position($range->start->line, $range->start->character), 29 | new Position($range->end->line, $range->end->character) 30 | )); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Factory/RangeFactory.php: -------------------------------------------------------------------------------- 1 | getStartPosition(), 22 | $node->getWidth(), 23 | $node->getFileContents() 24 | ); 25 | 26 | return new Range( 27 | new Position($range->start->line, $range->start->character), 28 | new Position($range->end->line, $range->end->character) 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/FilesFinder/ClientFilesFinder.php: -------------------------------------------------------------------------------- 1 | client = $client; 28 | } 29 | 30 | /** 31 | * Returns all files in the workspace that match a glob. 32 | * If the client does not support workspace/files, it falls back to searching the file system directly. 33 | * 34 | * @param string $glob 35 | * @return Promise The URIs 36 | */ 37 | public function find(string $glob): Promise 38 | { 39 | return $this->client->workspace->xfiles()->then(function (array $textDocuments) use ($glob) { 40 | $uris = []; 41 | foreach ($textDocuments as $textDocument) { 42 | $path = Path::normalize(uriToPath($textDocument->uri)); 43 | if (Glob::match($path, $glob)) { 44 | $uris[] = $textDocument->uri; 45 | } 46 | } 47 | return $uris; 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/FilesFinder/FileSystemFilesFinder.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | public function find(string $glob): Promise 21 | { 22 | return coroutine(function () use ($glob) { 23 | $uris = []; 24 | foreach (new GlobIterator($glob, 0, true) as $path) { 25 | // Exclude any directories that also match the glob pattern 26 | if (!is_dir($path)) { 27 | $uris[] = pathToUri($path); 28 | } 29 | 30 | yield timeout(); 31 | } 32 | return $uris; 33 | }); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/FilesFinder/FilesFinder.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | public function find(string $glob): Promise; 21 | } 22 | -------------------------------------------------------------------------------- /src/IdGenerator.php: -------------------------------------------------------------------------------- 1 | counter++; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Index/DependenciesIndex.php: -------------------------------------------------------------------------------- 1 | indexes; 21 | } 22 | 23 | /** 24 | * @param string $packageName 25 | * @return Index 26 | */ 27 | public function getDependencyIndex(string $packageName): Index 28 | { 29 | if (!isset($this->indexes[$packageName])) { 30 | $index = new Index; 31 | $this->indexes[$packageName] = $index; 32 | $this->registerIndex($index); 33 | } 34 | return $this->indexes[$packageName]; 35 | } 36 | 37 | /** 38 | * @param string $packageName 39 | * @param Index $index 40 | * @return void 41 | */ 42 | public function setDependencyIndex(string $packageName, Index $index) 43 | { 44 | $this->indexes[$packageName] = $index; 45 | $this->registerIndex($index); 46 | } 47 | 48 | /** 49 | * @param string $packageName 50 | * @return void 51 | */ 52 | public function removeDependencyIndex(string $packageName) 53 | { 54 | unset($this->indexes[$packageName]); 55 | } 56 | 57 | /** 58 | * @param string $packageName 59 | * @return bool 60 | */ 61 | public function hasDependencyIndex(string $packageName): bool 62 | { 63 | return isset($this->indexes[$packageName]); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Index/GlobalIndex.php: -------------------------------------------------------------------------------- 1 | stubsIndex = $stubsIndex; 28 | $this->projectIndex = $projectIndex; 29 | parent::__construct(); 30 | } 31 | 32 | /** 33 | * @return ReadableIndex[] 34 | */ 35 | protected function getIndexes(): array 36 | { 37 | return [$this->stubsIndex, $this->projectIndex]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Index/ProjectIndex.php: -------------------------------------------------------------------------------- 1 | sourceIndex = $sourceIndex; 32 | $this->dependenciesIndex = $dependenciesIndex; 33 | $this->composerJson = $composerJson; 34 | parent::__construct(); 35 | } 36 | 37 | /** 38 | * @return ReadableIndex[] 39 | */ 40 | protected function getIndexes(): array 41 | { 42 | return [$this->sourceIndex, $this->dependenciesIndex]; 43 | } 44 | 45 | /** 46 | * @param string $uri 47 | * @return Index 48 | */ 49 | public function getIndexForUri(string $uri): Index 50 | { 51 | $packageName = getPackageName($uri, $this->composerJson); 52 | if ($packageName) { 53 | return $this->dependenciesIndex->getDependencyIndex($packageName); 54 | } 55 | return $this->sourceIndex; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Index/ReadableIndex.php: -------------------------------------------------------------------------------- 1 | Definition] 34 | * that maps fully qualified symbol names to Definitions (global or not) 35 | * 36 | * @return \Generator yields Definition 37 | */ 38 | public function getDefinitions(): \Generator; 39 | 40 | /** 41 | * Returns a Generator that yields all the direct child Definitions of a given FQN 42 | * 43 | * @param string $fqn 44 | * @return \Generator yields Definition 45 | */ 46 | public function getChildDefinitionsForFqn(string $fqn): \Generator; 47 | 48 | /** 49 | * Returns the Definition object by a specific FQN 50 | * 51 | * @param string $fqn 52 | * @param bool $globalFallback Whether to fallback to global if the namespaced FQN was not found 53 | * @return Definition|null 54 | */ 55 | public function getDefinition(string $fqn, bool $globalFallback = false); 56 | 57 | /** 58 | * Returns a Generator that yields all URIs in this index that reference a symbol 59 | * 60 | * @param string $fqn The fully qualified name of the symbol 61 | * @return \Generator yields string 62 | */ 63 | public function getReferenceUris(string $fqn): \Generator; 64 | } 65 | -------------------------------------------------------------------------------- /src/Index/StubsIndex.php: -------------------------------------------------------------------------------- 1 | textDocument = new Client\TextDocument($handler, $mapper); 44 | $this->window = new Client\Window($handler); 45 | $this->workspace = new Client\Workspace($handler, $mapper); 46 | $this->xcache = new Client\XCache($handler); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Message.php: -------------------------------------------------------------------------------- 1 | body = MessageBody::parse(array_pop($parts)); 32 | foreach ($parts as $line) { 33 | if ($line) { 34 | $pair = explode(': ', $line); 35 | $obj->headers[$pair[0]] = $pair[1]; 36 | } 37 | } 38 | return $obj; 39 | } 40 | 41 | /** 42 | * @param \AdvancedJsonRpc\Message $body 43 | * @param string[] $headers 44 | */ 45 | public function __construct(MessageBody $body = null, array $headers = []) 46 | { 47 | $this->body = $body; 48 | if (!isset($headers['Content-Type'])) { 49 | $headers['Content-Type'] = 'application/vscode-jsonrpc; charset=utf8'; 50 | } 51 | $this->headers = $headers; 52 | } 53 | 54 | public function __toString(): string 55 | { 56 | $body = (string)$this->body; 57 | $contentLength = strlen($body); 58 | $this->headers['Content-Length'] = $contentLength; 59 | $headers = ''; 60 | foreach ($this->headers as $name => $value) { 61 | $headers .= "$name: $value\r\n"; 62 | } 63 | return $headers . "\r\n" . $body; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/ProtocolReader.php: -------------------------------------------------------------------------------- 1 | input = $input; 27 | 28 | $this->on('close', function () { 29 | Loop\removeReadStream($this->input); 30 | }); 31 | 32 | Loop\addReadStream($this->input, function () { 33 | if (feof($this->input)) { 34 | // If stream_select reported a status change for this stream, 35 | // but the stream is EOF, it means it was closed. 36 | $this->emit('close'); 37 | return; 38 | } 39 | while (($c = fgetc($this->input)) !== false && $c !== '') { 40 | $this->buffer .= $c; 41 | switch ($this->parsingMode) { 42 | case self::PARSE_HEADERS: 43 | if ($this->buffer === "\r\n") { 44 | $this->parsingMode = self::PARSE_BODY; 45 | $this->contentLength = (int)$this->headers['Content-Length']; 46 | $this->buffer = ''; 47 | } else if (substr($this->buffer, -2) === "\r\n") { 48 | $parts = explode(':', $this->buffer); 49 | $this->headers[$parts[0]] = trim($parts[1]); 50 | $this->buffer = ''; 51 | } 52 | break; 53 | case self::PARSE_BODY: 54 | if (strlen($this->buffer) === $this->contentLength) { 55 | $msg = new Message(MessageBody::parse($this->buffer), $this->headers); 56 | $this->emit('message', [$msg]); 57 | $this->parsingMode = self::PARSE_HEADERS; 58 | $this->headers = []; 59 | $this->buffer = ''; 60 | } 61 | break; 62 | } 63 | } 64 | }); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/ProtocolStreamWriter.php: -------------------------------------------------------------------------------- 1 | output = $output; 30 | } 31 | 32 | /** 33 | * {@inheritdoc} 34 | */ 35 | public function write(Message $msg): Promise 36 | { 37 | // if the message queue is currently empty, register a write handler. 38 | if (empty($this->messages)) { 39 | Loop\addWriteStream($this->output, function () { 40 | $this->flush(); 41 | }); 42 | } 43 | 44 | $promise = new Promise(); 45 | $this->messages[] = [ 46 | 'message' => (string)$msg, 47 | 'promise' => $promise 48 | ]; 49 | return $promise; 50 | } 51 | 52 | /** 53 | * Writes pending messages to the output stream. 54 | * 55 | * @return void 56 | */ 57 | private function flush() 58 | { 59 | $keepWriting = true; 60 | while ($keepWriting) { 61 | $message = $this->messages[0]['message']; 62 | $promise = $this->messages[0]['promise']; 63 | 64 | $bytesWritten = @fwrite($this->output, $message); 65 | 66 | if ($bytesWritten > 0) { 67 | $message = substr($message, $bytesWritten); 68 | } 69 | 70 | // Determine if this message was completely sent 71 | if (strlen($message) === 0) { 72 | array_shift($this->messages); 73 | 74 | // This was the last message in the queue, remove the write handler. 75 | if (count($this->messages) === 0) { 76 | Loop\removeWriteStream($this->output); 77 | $keepWriting = false; 78 | } 79 | 80 | $promise->fulfill(); 81 | } else { 82 | $this->messages[0]['message'] = $message; 83 | $keepWriting = false; 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/ProtocolWriter.php: -------------------------------------------------------------------------------- 1 | once('message', function (Message $msg) use ($reader) { 20 | // Respond to request 21 | Loop\setTimeout(function () use ($reader, $msg) { 22 | $reader->write(new Message(new AdvancedJsonRpc\SuccessResponse($msg->body->id, 'pong'))); 23 | }, 0); 24 | }); 25 | $handler->request('testMethod', ['ping'])->then(function ($result) { 26 | $this->assertEquals('pong', $result); 27 | })->wait(); 28 | // No event listeners 29 | $this->assertEquals([], $reader->listeners('message')); 30 | $this->assertEquals([], $writer->listeners('message')); 31 | } 32 | 33 | public function testNotify() 34 | { 35 | $reader = new MockProtocolStream; 36 | $writer = new MockProtocolStream; 37 | $handler = new ClientHandler($reader, $writer); 38 | $handler->notify('testMethod', ['ping'])->wait(); 39 | // No event listeners 40 | $this->assertEquals([], $reader->listeners('message')); 41 | $this->assertEquals([], $writer->listeners('message')); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/DefinitionResolverTest.php: -------------------------------------------------------------------------------- 1 | parseSourceFile("getUri()); 18 | 19 | $index = new Index; 20 | $definitionResolver = new DefinitionResolver($index); 21 | $def = $definitionResolver->createDefinitionFromNode($sourceFileNode->statementList[1]->expression, '\TEST_DEFINE'); 22 | 23 | $this->assertInstanceOf(\phpDocumentor\Reflection\Types\Boolean::class, $def->type); 24 | } 25 | 26 | public function testGetTypeFromNode() 27 | { 28 | $parser = new PhpParser\Parser; 29 | $doc = new MockPhpDocument; 30 | $sourceFileNode = $parser->parseSourceFile("getUri()); 31 | 32 | $index = new Index; 33 | $definitionResolver = new DefinitionResolver($index); 34 | $type = $definitionResolver->getTypeFromNode($sourceFileNode->statementList[1]->expression); 35 | 36 | $this->assertInstanceOf(\phpDocumentor\Reflection\Types\Boolean::class, $type); 37 | } 38 | 39 | public function testGetDefinedFqnForIncompleteDefine() 40 | { 41 | // define('XXX') (only one argument) must not introduce a new symbol 42 | $parser = new PhpParser\Parser; 43 | $doc = new MockPhpDocument; 44 | $sourceFileNode = $parser->parseSourceFile("getUri()); 45 | 46 | $index = new Index; 47 | $definitionResolver = new DefinitionResolver($index); 48 | $fqn = $definitionResolver->getDefinedFqn($sourceFileNode->statementList[1]->expression); 49 | 50 | $this->assertNull($fqn); 51 | } 52 | 53 | public function testGetDefinedFqnForDefine() 54 | { 55 | $parser = new PhpParser\Parser; 56 | $doc = new MockPhpDocument; 57 | $sourceFileNode = $parser->parseSourceFile("getUri()); 58 | 59 | $index = new Index; 60 | $definitionResolver = new DefinitionResolver($index); 61 | $fqn = $definitionResolver->getDefinedFqn($sourceFileNode->statementList[1]->expression); 62 | 63 | $this->assertEquals('TEST_DEFINE', $fqn); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/Diagnostics/InvalidThisUsageTest.php: -------------------------------------------------------------------------------- 1 | getDiagnostics(); 38 | } 39 | 40 | /** 41 | * Assertions about a diagnostic. 42 | * 43 | * @param Diagnostic|null $diagnostic 44 | * @param int $message 45 | * @param string $severity 46 | * @param Range $range 47 | */ 48 | private function assertDiagnostic($diagnostic, $message, $severity, $range) 49 | { 50 | $this->assertInstanceOf(Diagnostic::class, $diagnostic); 51 | $this->assertEquals($message, $diagnostic->message); 52 | $this->assertEquals($severity, $diagnostic->severity); 53 | $this->assertEquals($range, $diagnostic->range); 54 | } 55 | 56 | public function testThisInStaticMethodProducesError() 57 | { 58 | $diagnostics = $this->collectDiagnostics( 59 | __DIR__ . '/../../fixtures/diagnostics/errors/this_in_static_method.php' 60 | ); 61 | 62 | $this->assertCount(1, $diagnostics); 63 | $this->assertDiagnostic( 64 | $diagnostics[0], 65 | '$this can not be used in static methods.', 66 | DiagnosticSeverity::ERROR, 67 | new Range( 68 | new Position(6, 15), 69 | new Position(6, 20) 70 | ) 71 | ); 72 | } 73 | 74 | public function testThisInMethodProducesNoError() 75 | { 76 | $diagnostics = $this->collectDiagnostics( 77 | __DIR__ . '/../../fixtures/diagnostics/baselines/this_in_method.php' 78 | ); 79 | 80 | $this->assertCount(0, $diagnostics); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /tests/Index/IndexTest.php: -------------------------------------------------------------------------------- 1 | setDefinition('SomeNamespace\SomeClass', new Definition); 15 | $methodDefinition = new Definition; 16 | $methodFqn = 'SomeNamespace\SomeClass->someMethod()'; 17 | $index->setDefinition($methodFqn, $methodDefinition); 18 | $index->setDefinition('SomeNamespace\SomeClass->someProperty', new Definition); 19 | $this->assertSame($methodDefinition, $index->getDefinition($methodFqn)); 20 | } 21 | 22 | public function testGetSetClassDefinition() 23 | { 24 | $index = new Index; 25 | $definition = new Definition; 26 | $fqn = 'SomeNamespace\SomeClass'; 27 | $index->setDefinition($fqn, $definition); 28 | $this->assertSame($definition, $index->getDefinition($fqn)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/MockPhpDocument.php: -------------------------------------------------------------------------------- 1 | emit('message', [Message::parse((string)$msg)]); 25 | }); 26 | return Promise\resolve(null); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/PhpDocumentLoaderTest.php: -------------------------------------------------------------------------------- 1 | loader = new PhpDocumentLoader( 27 | new FileSystemContentRetriever, 28 | $projectIndex, 29 | new DefinitionResolver($projectIndex) 30 | ); 31 | } 32 | 33 | public function testGetOrLoadLoadsDocument() 34 | { 35 | $document = $this->loader->getOrLoad(pathToUri(__FILE__))->wait(); 36 | 37 | $this->assertNotNull($document); 38 | $this->assertInstanceOf(PhpDocument::class, $document); 39 | } 40 | 41 | public function testGetReturnsOpenedInstance() 42 | { 43 | $document1 = $this->loader->open(pathToUri(__FILE__), file_get_contents(__FILE__)); 44 | $document2 = $this->loader->get(pathToUri(__FILE__)); 45 | 46 | $this->assertSame($document1, $document2); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/PhpDocumentTest.php: -------------------------------------------------------------------------------- 1 | createDocument('whatever', "assertEquals([], $document->getDefinitions()); 37 | } 38 | 39 | public function testGetNodeAtPosition() 40 | { 41 | $document = $this->createDocument('whatever', "getNodeAtPosition(new Position(1, 13)); 43 | $this->assertQualifiedName($node); 44 | $this->assertEquals('SomeClass', (string)$node); 45 | } 46 | 47 | private function assertQualifiedName($node) 48 | { 49 | $this->assertInstanceOf(Node\QualifiedName::class, $node); 50 | } 51 | 52 | public function testIsVendored() 53 | { 54 | $document = $this->createDocument('file:///dir/vendor/x.php', "assertEquals(true, isVendored($document)); 56 | 57 | $document = $this->createDocument('file:///c:/dir/vendor/x.php', "assertEquals(true, isVendored($document)); 59 | 60 | $document = $this->createDocument('file:///vendor/x.php', "assertEquals(true, isVendored($document)); 62 | 63 | $document = $this->createDocument('file:///dir/vendor.php', "assertEquals(false, isVendored($document)); 65 | 66 | $document = $this->createDocument('file:///dir/x.php', "assertEquals(false, isVendored($document)); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/ProtocolStreamReaderTest.php: -------------------------------------------------------------------------------- 1 | on('message', function (Message $message) use (&$msg) { 21 | $msg = $message; 22 | }); 23 | $ret = fwrite($writeHandle, (string)new Message(new RequestBody(1, 'aMethod', ['arg' => 'Hello World']))); 24 | Loop\tick(); 25 | $this->assertNotNull($msg); 26 | $this->assertInstanceOf(Message::class, $msg); 27 | $this->assertInstanceOf(RequestBody::class, $msg->body); 28 | $this->assertEquals(1, $msg->body->id); 29 | $this->assertEquals('aMethod', $msg->body->method); 30 | $this->assertEquals((object)['arg' => 'Hello World'], $msg->body->params); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/ProtocolStreamWriterTest.php: -------------------------------------------------------------------------------- 1 | str_repeat('X', 100000)])); 23 | $msgString = (string)$msg; 24 | 25 | $promise = $writer->write($msg); 26 | 27 | Loop\tick(); 28 | 29 | $promise->wait(); 30 | 31 | fclose($writeHandle); 32 | 33 | $this->assertEquals(strlen($msgString), filesize($tmpfile)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/Server/TextDocument/Definition/GlobalFallbackTest.php: -------------------------------------------------------------------------------- 1 | setComplete(); 21 | $client = new LanguageClient(new MockProtocolStream, new MockProtocolStream); 22 | $definitionResolver = new DefinitionResolver($projectIndex); 23 | $contentRetriever = new FileSystemContentRetriever; 24 | $loader = new PhpDocumentLoader($contentRetriever, $projectIndex, $definitionResolver); 25 | $this->textDocument = new Server\TextDocument($loader, $definitionResolver, $client, $projectIndex); 26 | $loader->open('global_fallback', file_get_contents(__DIR__ . '/../../../../fixtures/global_fallback.php')); 27 | $loader->open('global_symbols', file_get_contents(__DIR__ . '/../../../../fixtures/global_symbols.php')); 28 | } 29 | 30 | public function testClassDoesNotFallback() 31 | { 32 | // $obj = new TestClass(); 33 | // Get definition for TestClass should not fall back to global 34 | $result = $this->textDocument->definition( 35 | new TextDocumentIdentifier('global_fallback'), 36 | new Position(9, 16) 37 | )->wait(); 38 | $this->assertEquals([], $result); 39 | } 40 | 41 | public function testFallsBackForConstants() 42 | { 43 | // echo TEST_CONST; 44 | // Get definition for TEST_CONST 45 | $result = $this->textDocument->definition( 46 | new TextDocumentIdentifier('global_fallback'), 47 | new Position(6, 10) 48 | )->wait(); 49 | $this->assertEquals(new Location('global_symbols', new Range(new Position(9, 6), new Position(9, 22))), $result); 50 | } 51 | 52 | public function testFallsBackForFunctions() 53 | { 54 | // test_function(); 55 | // Get definition for test_function 56 | $result = $this->textDocument->definition( 57 | new TextDocumentIdentifier('global_fallback'), 58 | new Position(5, 6) 59 | )->wait(); 60 | $this->assertEquals(new Location('global_symbols', new Range(new Position(78, 0), new Position(81, 1))), $result); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tests/Server/TextDocument/Definition/NamespacedTest.php: -------------------------------------------------------------------------------- 1 | getReferenceLocations('TEST_CONST')[0]; 26 | $result = $this->textDocument->definition( 27 | new TextDocumentIdentifier($reference->uri), 28 | $reference->range->start 29 | )->wait(); 30 | $this->assertEquals($this->getDefinitionLocation('TEST_CONST'), $result); 31 | } 32 | 33 | public function testDefinitionForClassLikeUseStatement() 34 | { 35 | // use TestNamespace\TestClass; 36 | // Get definition for TestClass 37 | $reference = $this->getReferenceLocations('TestClass')[7]; 38 | $result = $this->textDocument->definition( 39 | new TextDocumentIdentifier($reference->uri), 40 | $reference->range->start 41 | )->wait(); 42 | $this->assertEquals($this->getDefinitionLocation('TestClass'), $result); 43 | } 44 | 45 | public function testDefinitionForClassLikeGroupUseStatement() 46 | { 47 | // use TestNamespace\{TestTrait, TestInterface}; 48 | // Get definition for TestInterface 49 | $reference = $this->getReferenceLocations('TestClass')[1]; 50 | $result = $this->textDocument->definition( 51 | new TextDocumentIdentifier($reference->uri), 52 | $reference->range->start 53 | )->wait(); 54 | $this->assertEquals($this->getDefinitionLocation('TestClass'), $result); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/Server/TextDocument/DidChangeTest.php: -------------------------------------------------------------------------------- 1 | open('whatever', "range = new Range(new Position(0, 0), new Position(9999, 9999)); 34 | $changeEvent->rangeLength = 9999; 35 | $changeEvent->text = "didChange($identifier, [$changeEvent]); 38 | 39 | $this->assertEquals("getContent()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Server/TextDocument/DidCloseTest.php: -------------------------------------------------------------------------------- 1 | open('whatever', "uri = 'whatever'; 28 | $textDocumentItem->languageId = 'php'; 29 | $textDocumentItem->version = 1; 30 | $textDocumentItem->text = 'hello world'; 31 | $textDocument->didOpen($textDocumentItem); 32 | 33 | $textDocument->didClose(new TextDocumentIdentifier($textDocumentItem->uri)); 34 | 35 | $this->assertFalse($loader->isOpen($textDocumentItem->uri)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/Server/TextDocument/References/NamespacedTest.php: -------------------------------------------------------------------------------- 1 | textDocument->references( 27 | new ReferenceContext, 28 | new TextDocumentIdentifier($definition->uri), 29 | $definition->range->end 30 | )->wait(); 31 | $this->assertEquals(parent::getReferenceLocations('TestNamespace'), $result); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/Server/Workspace/DidChangeWatchedFilesTest.php: -------------------------------------------------------------------------------- 1 | on('message', function (Message $message) use ($fileEvent, &$isDiagnosticsCleared) { 30 | if ($message->body->method === "textDocument/publishDiagnostics") { 31 | $this->assertEquals($message->body->params->uri, $fileEvent->uri); 32 | $this->assertEquals($message->body->params->diagnostics, []); 33 | $isDiagnosticsCleared = true; 34 | } 35 | }); 36 | 37 | $workspace->didChangeWatchedFiles([$fileEvent]); 38 | Loop\tick(true); 39 | 40 | $this->assertTrue($isDiagnosticsCleared, "Deleting file should clear all diagnostics."); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/Utils/FileUriTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('file:///var/log', $uri); 16 | 17 | $uri = pathToUri('/usr/local/bin'); 18 | $this->assertEquals('file:///usr/local/bin', $uri); 19 | 20 | $uri = pathToUri('a/b/c/test.txt'); 21 | $this->assertEquals('file:///a/b/c/test.txt', $uri); 22 | 23 | $uri = pathToUri('/d/e/f'); 24 | $this->assertEquals('file:///d/e/f', $uri); 25 | 26 | // special chars are escaped 27 | $uri = pathToUri('c:/path/to/file/dürüm döner.php'); 28 | $this->assertEquals('file:///c:/path/to/file/d%C3%BCr%C3%BCm%20d%C3%B6ner.php', $uri); 29 | 30 | //backslashes are transformed 31 | $uri = pathToUri('c:\\foo\\bar.baz'); 32 | $this->assertEquals('file:///c:/foo/bar.baz', $uri); 33 | } 34 | 35 | public function testUriToPath() 36 | { 37 | $uri = 'file:///var/log'; 38 | $this->assertEquals('/var/log', uriToPath($uri)); 39 | 40 | $uri = 'file:///usr/local/bin'; 41 | $this->assertEquals('/usr/local/bin', uriToPath($uri)); 42 | 43 | $uri = 'file:///a/b/c/test.txt'; 44 | $this->assertEquals('/a/b/c/test.txt', uriToPath($uri)); 45 | 46 | $uri = 'file:///d/e/f'; 47 | $this->assertEquals('/d/e/f', uriToPath($uri)); 48 | 49 | $uri = 'file:///c:/path/to/file/d%C3%BCr%C3%BCm+d%C3%B6ner.php'; 50 | $this->assertEquals('c:\\path\\to\\file\\dürüm döner.php', uriToPath($uri)); 51 | 52 | $uri = 'file:///c:/foo/bar.baz'; 53 | $this->assertEquals('c:\\foo\\bar.baz', uriToPath($uri)); 54 | 55 | $uri = 'file:///c%3A/path/to/file/d%C3%BCr%C3%BCm+d%C3%B6ner.php'; 56 | $this->assertEquals('c:\\path\\to\\file\\dürüm döner.php', uriToPath($uri)); 57 | 58 | $uri = 'file:///c%3A/foo/bar.baz'; 59 | $this->assertEquals('c:\\foo\\bar.baz', uriToPath($uri)); 60 | } 61 | 62 | public function testUriToPathForUnknownProtocol() 63 | { 64 | $this->expectException(InvalidArgumentException::class); 65 | $uri = 'vfs:///whatever'; 66 | uriToPath($uri); 67 | } 68 | 69 | public function testUriToPathForInvalidProtocol() 70 | { 71 | $this->expectException(InvalidArgumentException::class); 72 | $uri = 'http://www.google.com'; 73 | uriToPath($uri); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tests/Utils/StripStringOverlapTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('assertEquals('?php', stripStringOverlap('bla<', 'assertEquals('php', stripStringOverlap('blaassertEquals('', stripStringOverlap('blaassertEquals('assertEquals('', stripStringOverlap('bla', '')); 39 | } 40 | 41 | public function testBothEmpty() 42 | { 43 | $this->assertEquals('', stripStringOverlap('', '')); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/Validation/cases/WithReturnTypehints.php: -------------------------------------------------------------------------------- 1 | TRUE]; 4 | } -------------------------------------------------------------------------------- /tests/Validation/cases/arrayValueShouldBeBoolean.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": [], 3 | "definitions": { 4 | "A": { 5 | "fqn": "A", 6 | "extends": [], 7 | "isMember": false, 8 | "roamed": false, 9 | "isStatic": false, 10 | "canBeInstantiated": true, 11 | "symbolInformation": { 12 | "name": "A", 13 | "kind": 5, 14 | "location": { 15 | "uri": "./arrayValueShouldBeBoolean.php" 16 | }, 17 | "containerName": "" 18 | }, 19 | "type": null, 20 | "declarationLine": "class A {", 21 | "documentation": null, 22 | "signatureInformation": null 23 | }, 24 | "A->foo": { 25 | "fqn": "A->foo", 26 | "extends": [], 27 | "isMember": true, 28 | "roamed": false, 29 | "isStatic": false, 30 | "canBeInstantiated": false, 31 | "symbolInformation": { 32 | "name": "foo", 33 | "kind": 7, 34 | "location": { 35 | "uri": "./arrayValueShouldBeBoolean.php" 36 | }, 37 | "containerName": "A" 38 | }, 39 | "type__tostring": "array", 40 | "type": {}, 41 | "declarationLine": "protected $foo;", 42 | "documentation": null, 43 | "signatureInformation": null 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /tests/Validation/cases/caseStatement1.php: -------------------------------------------------------------------------------- 1 | a; 8 | 9 | class A { 10 | public $a = 3; 11 | } -------------------------------------------------------------------------------- /tests/Validation/cases/classDefinition1.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "TestNamespace\\A": [ 4 | "./classDefinition1.php" 5 | ], 6 | "TestNamespace\\A->a": [ 7 | "./classDefinition1.php" 8 | ] 9 | }, 10 | "definitions": { 11 | "TestNamespace": { 12 | "fqn": "TestNamespace", 13 | "extends": [], 14 | "isMember": false, 15 | "roamed": false, 16 | "isStatic": false, 17 | "canBeInstantiated": false, 18 | "symbolInformation": { 19 | "name": "TestNamespace", 20 | "kind": 3, 21 | "location": { 22 | "uri": "./classDefinition1.php" 23 | }, 24 | "containerName": "" 25 | }, 26 | "type": null, 27 | "declarationLine": "namespace TestNamespace;", 28 | "documentation": null, 29 | "signatureInformation": null 30 | }, 31 | "TestNamespace\\A": { 32 | "fqn": "TestNamespace\\A", 33 | "extends": [], 34 | "isMember": false, 35 | "roamed": false, 36 | "isStatic": false, 37 | "canBeInstantiated": true, 38 | "symbolInformation": { 39 | "name": "A", 40 | "kind": 5, 41 | "location": { 42 | "uri": "./classDefinition1.php" 43 | }, 44 | "containerName": "TestNamespace" 45 | }, 46 | "type": null, 47 | "declarationLine": "class A {", 48 | "documentation": null, 49 | "signatureInformation": null 50 | }, 51 | "TestNamespace\\A->a": { 52 | "fqn": "TestNamespace\\A->a", 53 | "extends": [], 54 | "isMember": true, 55 | "roamed": false, 56 | "isStatic": false, 57 | "canBeInstantiated": false, 58 | "symbolInformation": { 59 | "name": "a", 60 | "kind": 7, 61 | "location": { 62 | "uri": "./classDefinition1.php" 63 | }, 64 | "containerName": "TestNamespace\\A" 65 | }, 66 | "type__tostring": "int", 67 | "type": {}, 68 | "declarationLine": "public $a;", 69 | "documentation": null, 70 | "signatureInformation": null 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /tests/Validation/cases/classProperty1.php: -------------------------------------------------------------------------------- 1 | BYE 11 | ]; 12 | } 13 | } -------------------------------------------------------------------------------- /tests/Validation/cases/constants.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "MyNamespace\\BYE": [ 4 | "./constants.php" 5 | ], 6 | "BYE": [ 7 | "./constants.php" 8 | ] 9 | }, 10 | "definitions": { 11 | "MyNamespace": { 12 | "fqn": "MyNamespace", 13 | "extends": [], 14 | "isMember": false, 15 | "roamed": false, 16 | "isStatic": false, 17 | "canBeInstantiated": false, 18 | "symbolInformation": { 19 | "name": "MyNamespace", 20 | "kind": 3, 21 | "location": { 22 | "uri": "./constants.php" 23 | }, 24 | "containerName": "" 25 | }, 26 | "type": null, 27 | "declarationLine": "namespace MyNamespace;", 28 | "documentation": null, 29 | "signatureInformation": null 30 | }, 31 | "MyNamespace\\A": { 32 | "fqn": "MyNamespace\\A", 33 | "extends": [], 34 | "isMember": false, 35 | "roamed": false, 36 | "isStatic": false, 37 | "canBeInstantiated": true, 38 | "symbolInformation": { 39 | "name": "A", 40 | "kind": 5, 41 | "location": { 42 | "uri": "./constants.php" 43 | }, 44 | "containerName": "MyNamespace" 45 | }, 46 | "type": null, 47 | "declarationLine": "class A", 48 | "documentation": null, 49 | "signatureInformation": null 50 | }, 51 | "MyNamespace\\A::suite()": { 52 | "fqn": "MyNamespace\\A::suite()", 53 | "extends": [], 54 | "isMember": true, 55 | "roamed": false, 56 | "isStatic": true, 57 | "canBeInstantiated": false, 58 | "symbolInformation": { 59 | "name": "suite", 60 | "kind": 6, 61 | "location": { 62 | "uri": "./constants.php" 63 | }, 64 | "containerName": "MyNamespace\\A" 65 | }, 66 | "type__tostring": "mixed", 67 | "type": {}, 68 | "declarationLine": "public static function suite()", 69 | "documentation": null, 70 | "signatureInformation": { 71 | "label": "()", 72 | "parameters": [] 73 | } 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /tests/Validation/cases/constants2.php: -------------------------------------------------------------------------------- 1 | "hi" 11 | ]; 12 | } 13 | } -------------------------------------------------------------------------------- /tests/Validation/cases/constants2.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "MyNamespace\\BYE": [ 4 | "./constants2.php" 5 | ], 6 | "BYE": [ 7 | "./constants2.php" 8 | ] 9 | }, 10 | "definitions": { 11 | "MyNamespace": { 12 | "fqn": "MyNamespace", 13 | "extends": [], 14 | "isMember": false, 15 | "roamed": false, 16 | "isStatic": false, 17 | "canBeInstantiated": false, 18 | "symbolInformation": { 19 | "name": "MyNamespace", 20 | "kind": 3, 21 | "location": { 22 | "uri": "./constants2.php" 23 | }, 24 | "containerName": "" 25 | }, 26 | "type": null, 27 | "declarationLine": "namespace MyNamespace;", 28 | "documentation": null, 29 | "signatureInformation": null 30 | }, 31 | "MyNamespace\\A": { 32 | "fqn": "MyNamespace\\A", 33 | "extends": [], 34 | "isMember": false, 35 | "roamed": false, 36 | "isStatic": false, 37 | "canBeInstantiated": true, 38 | "symbolInformation": { 39 | "name": "A", 40 | "kind": 5, 41 | "location": { 42 | "uri": "./constants2.php" 43 | }, 44 | "containerName": "MyNamespace" 45 | }, 46 | "type": null, 47 | "declarationLine": "class A", 48 | "documentation": null, 49 | "signatureInformation": null 50 | }, 51 | "MyNamespace\\A::suite()": { 52 | "fqn": "MyNamespace\\A::suite()", 53 | "extends": [], 54 | "isMember": true, 55 | "roamed": false, 56 | "isStatic": true, 57 | "canBeInstantiated": false, 58 | "symbolInformation": { 59 | "name": "suite", 60 | "kind": 6, 61 | "location": { 62 | "uri": "./constants2.php" 63 | }, 64 | "containerName": "MyNamespace\\A" 65 | }, 66 | "type__tostring": "mixed", 67 | "type": {}, 68 | "declarationLine": "public static function suite()", 69 | "documentation": null, 70 | "signatureInformation": { 71 | "label": "()", 72 | "parameters": [] 73 | } 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /tests/Validation/cases/constants3.php: -------------------------------------------------------------------------------- 1 | suite()": { 52 | "fqn": "MyNamespace\\A->suite()", 53 | "extends": [], 54 | "isMember": true, 55 | "roamed": false, 56 | "isStatic": false, 57 | "canBeInstantiated": false, 58 | "symbolInformation": { 59 | "name": "suite", 60 | "kind": 6, 61 | "location": { 62 | "uri": "./constants4.php" 63 | }, 64 | "containerName": "MyNamespace\\A" 65 | }, 66 | "type__tostring": "mixed", 67 | "type": {}, 68 | "declarationLine": "public function suite()", 69 | "documentation": null, 70 | "signatureInformation": { 71 | "label": "()", 72 | "parameters": [] 73 | } 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /tests/Validation/cases/constants5.php: -------------------------------------------------------------------------------- 1 | b()": { 29 | "fqn": "A->b()", 30 | "extends": [], 31 | "isMember": true, 32 | "roamed": false, 33 | "isStatic": false, 34 | "canBeInstantiated": false, 35 | "symbolInformation": { 36 | "name": "b", 37 | "kind": 6, 38 | "location": { 39 | "uri": "./constantsInFunctionParamDefault.php" 40 | }, 41 | "containerName": "A" 42 | }, 43 | "type__tostring": "mixed", 44 | "type": {}, 45 | "declarationLine": "function b ($a = MY_CONSTANT);", 46 | "documentation": null, 47 | "signatureInformation": { 48 | "label": "(\\MY_CONSTANT $a = MY_CONSTANT)", 49 | "parameters": [ 50 | { 51 | "label": "\\MY_CONSTANT $a = MY_CONSTANT" 52 | } 53 | ] 54 | } 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /tests/Validation/cases/docBlocksOnNamespaceDefinition.php: -------------------------------------------------------------------------------- 1 | foo()) { 6 | } 7 | } 8 | 9 | public function foo() { 10 | return $this; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/Validation/cases/forLoopReference1.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "ForLoopReference1->foo()": [ 4 | "./_cases/forLoopReference1.php" 5 | ] 6 | }, 7 | "definitions": { 8 | "ForLoopReference1": { 9 | "extends": [], 10 | "isGlobal": true, 11 | "isStatic": false, 12 | "canBeInstantiated": true, 13 | "symbolInformation": { 14 | "name": "ForLoopReference1", 15 | "kind": 5, 16 | "location": { 17 | "uri": "./_cases/forLoopReference1.php" 18 | }, 19 | "containerName": "" 20 | }, 21 | "type__class": "LanguageServer\\Tests\\ValidationTest", 22 | "type": null, 23 | "documentation": null 24 | }, 25 | "ForLoopReference1->getThat()": { 26 | "extends": [], 27 | "isGlobal": false, 28 | "isStatic": false, 29 | "canBeInstantiated": false, 30 | "symbolInformation": { 31 | "name": "getThat", 32 | "kind": 6, 33 | "location": { 34 | "uri": "./_cases/forLoopReference1.php" 35 | }, 36 | "containerName": "ForLoopReference1" 37 | }, 38 | "type__class": "phpDocumentor\\Reflection\\Types\\Mixed", 39 | "type": {}, 40 | "documentation": null 41 | }, 42 | "ForLoopReference1->foo()": { 43 | "extends": [], 44 | "isGlobal": false, 45 | "isStatic": false, 46 | "canBeInstantiated": false, 47 | "symbolInformation": { 48 | "name": "foo", 49 | "kind": 6, 50 | "location": { 51 | "uri": "./_cases/forLoopReference1.php" 52 | }, 53 | "containerName": "ForLoopReference1" 54 | }, 55 | "type__class": "phpDocumentor\\Reflection\\Types\\Mixed", 56 | "type": {}, 57 | "documentation": null 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /tests/Validation/cases/functionParamInters.php: -------------------------------------------------------------------------------- 1 | b(); 7 | }; -------------------------------------------------------------------------------- /tests/Validation/cases/functionUse.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "A": [ 4 | "./functionUse.php" 5 | ], 6 | "A->b()": [ 7 | "./functionUse.php" 8 | ] 9 | }, 10 | "definitions": [] 11 | } -------------------------------------------------------------------------------- /tests/Validation/cases/functionUse2.php: -------------------------------------------------------------------------------- 1 | true 6 | ); 7 | } -------------------------------------------------------------------------------- /tests/Validation/cases/magicConsts.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "__CLASS__": [ 4 | "./magicConsts.php" 5 | ] 6 | }, 7 | "definitions": { 8 | "A": { 9 | "fqn": "A", 10 | "extends": [], 11 | "isMember": false, 12 | "roamed": false, 13 | "isStatic": false, 14 | "canBeInstantiated": true, 15 | "symbolInformation": { 16 | "name": "A", 17 | "kind": 5, 18 | "location": { 19 | "uri": "./magicConsts.php" 20 | }, 21 | "containerName": "" 22 | }, 23 | "type": null, 24 | "declarationLine": "class A {", 25 | "documentation": null, 26 | "signatureInformation": null 27 | }, 28 | "A::$deprecationsTriggered": { 29 | "fqn": "A::$deprecationsTriggered", 30 | "extends": [], 31 | "isMember": true, 32 | "roamed": false, 33 | "isStatic": true, 34 | "canBeInstantiated": false, 35 | "symbolInformation": { 36 | "name": "deprecationsTriggered", 37 | "kind": 7, 38 | "location": { 39 | "uri": "./magicConsts.php" 40 | }, 41 | "containerName": "A" 42 | }, 43 | "type__tostring": "array<\\__CLASS__,bool>", 44 | "type": {}, 45 | "declarationLine": "private static $deprecationsTriggered;", 46 | "documentation": null, 47 | "signatureInformation": null 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /tests/Validation/cases/memberAccess1.php: -------------------------------------------------------------------------------- 1 | a(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Validation/cases/memberAccess1.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "MyNamespace\\a": [ 4 | "./memberAccess1.php" 5 | ], 6 | "MyNamespace\\a->a()": [ 7 | "./memberAccess1.php" 8 | ] 9 | }, 10 | "definitions": { 11 | "MyNamespace": { 12 | "fqn": "MyNamespace", 13 | "extends": [], 14 | "isMember": false, 15 | "roamed": false, 16 | "isStatic": false, 17 | "canBeInstantiated": false, 18 | "symbolInformation": { 19 | "name": "MyNamespace", 20 | "kind": 3, 21 | "location": { 22 | "uri": "./memberAccess1.php" 23 | }, 24 | "containerName": "" 25 | }, 26 | "type": null, 27 | "declarationLine": "namespace MyNamespace;", 28 | "documentation": null, 29 | "signatureInformation": null 30 | }, 31 | "MyNamespace\\A": { 32 | "fqn": "MyNamespace\\A", 33 | "extends": [], 34 | "isMember": false, 35 | "roamed": false, 36 | "isStatic": false, 37 | "canBeInstantiated": true, 38 | "symbolInformation": { 39 | "name": "A", 40 | "kind": 5, 41 | "location": { 42 | "uri": "./memberAccess1.php" 43 | }, 44 | "containerName": "MyNamespace" 45 | }, 46 | "type": null, 47 | "declarationLine": "class A {", 48 | "documentation": null, 49 | "signatureInformation": null 50 | }, 51 | "MyNamespace\\A::a()": { 52 | "fqn": "MyNamespace\\A::a()", 53 | "extends": [], 54 | "isMember": true, 55 | "roamed": false, 56 | "isStatic": true, 57 | "canBeInstantiated": false, 58 | "symbolInformation": { 59 | "name": "a", 60 | "kind": 6, 61 | "location": { 62 | "uri": "./memberAccess1.php" 63 | }, 64 | "containerName": "MyNamespace\\A" 65 | }, 66 | "type__tostring": "mixed", 67 | "type": {}, 68 | "declarationLine": "static function a()", 69 | "documentation": null, 70 | "signatureInformation": { 71 | "label": "()", 72 | "parameters": [] 73 | } 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /tests/Validation/cases/memberAccess2.php: -------------------------------------------------------------------------------- 1 | a(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Validation/cases/memberAccess2.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "MyNamespace\\a": [ 4 | "./memberAccess2.php" 5 | ], 6 | "MyNamespace\\a->a()": [ 7 | "./memberAccess2.php" 8 | ] 9 | }, 10 | "definitions": { 11 | "MyNamespace": { 12 | "fqn": "MyNamespace", 13 | "extends": [], 14 | "isMember": false, 15 | "roamed": false, 16 | "isStatic": false, 17 | "canBeInstantiated": false, 18 | "symbolInformation": { 19 | "name": "MyNamespace", 20 | "kind": 3, 21 | "location": { 22 | "uri": "./memberAccess2.php" 23 | }, 24 | "containerName": "" 25 | }, 26 | "type": null, 27 | "declarationLine": "namespace MyNamespace;", 28 | "documentation": null, 29 | "signatureInformation": null 30 | }, 31 | "MyNamespace\\A": { 32 | "fqn": "MyNamespace\\A", 33 | "extends": [], 34 | "isMember": false, 35 | "roamed": false, 36 | "isStatic": false, 37 | "canBeInstantiated": true, 38 | "symbolInformation": { 39 | "name": "A", 40 | "kind": 5, 41 | "location": { 42 | "uri": "./memberAccess2.php" 43 | }, 44 | "containerName": "MyNamespace" 45 | }, 46 | "type": null, 47 | "declarationLine": "class A {", 48 | "documentation": null, 49 | "signatureInformation": null 50 | }, 51 | "MyNamespace\\A::a()": { 52 | "fqn": "MyNamespace\\A::a()", 53 | "extends": [], 54 | "isMember": true, 55 | "roamed": false, 56 | "isStatic": true, 57 | "canBeInstantiated": false, 58 | "symbolInformation": { 59 | "name": "a", 60 | "kind": 6, 61 | "location": { 62 | "uri": "./memberAccess2.php" 63 | }, 64 | "containerName": "MyNamespace\\A" 65 | }, 66 | "type__tostring": "mixed", 67 | "type": {}, 68 | "declarationLine": "static function a()", 69 | "documentation": null, 70 | "signatureInformation": { 71 | "label": "()", 72 | "parameters": [] 73 | } 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /tests/Validation/cases/memberAccess3.php: -------------------------------------------------------------------------------- 1 | prefixesPsr0 = ComposerStaticInitIncludePath::$prefixesPsr0; 10 | 11 | }, null, ClassLoader::class); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/Validation/cases/memberAccess4.php: -------------------------------------------------------------------------------- 1 | toString()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Validation/cases/memberAccess4.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "MyNamespace\\Request::create()": [ 4 | "./memberAccess4.php" 5 | ], 6 | "MyNamespace\\Request": [ 7 | "./memberAccess4.php" 8 | ], 9 | "MyNamespace\\Url->toString()": [ 10 | "./memberAccess4.php" 11 | ], 12 | "MyNamespace\\Url": [ 13 | "./memberAccess4.php" 14 | ] 15 | }, 16 | "definitions": { 17 | "MyNamespace": { 18 | "fqn": "MyNamespace", 19 | "extends": [], 20 | "isMember": false, 21 | "roamed": false, 22 | "isStatic": false, 23 | "canBeInstantiated": false, 24 | "symbolInformation": { 25 | "name": "MyNamespace", 26 | "kind": 3, 27 | "location": { 28 | "uri": "./memberAccess4.php" 29 | }, 30 | "containerName": "" 31 | }, 32 | "type": null, 33 | "declarationLine": "namespace MyNamespace;", 34 | "documentation": null, 35 | "signatureInformation": null 36 | }, 37 | "MyNamespace\\A": { 38 | "fqn": "MyNamespace\\A", 39 | "extends": [], 40 | "isMember": false, 41 | "roamed": false, 42 | "isStatic": false, 43 | "canBeInstantiated": true, 44 | "symbolInformation": { 45 | "name": "A", 46 | "kind": 5, 47 | "location": { 48 | "uri": "./memberAccess4.php" 49 | }, 50 | "containerName": "MyNamespace" 51 | }, 52 | "type": null, 53 | "declarationLine": "class A {", 54 | "documentation": null, 55 | "signatureInformation": null 56 | }, 57 | "MyNamespace\\A->testRequest()": { 58 | "fqn": "MyNamespace\\A->testRequest()", 59 | "extends": [], 60 | "isMember": true, 61 | "roamed": false, 62 | "isStatic": false, 63 | "canBeInstantiated": false, 64 | "symbolInformation": { 65 | "name": "testRequest", 66 | "kind": 6, 67 | "location": { 68 | "uri": "./memberAccess4.php" 69 | }, 70 | "containerName": "MyNamespace\\A" 71 | }, 72 | "type__tostring": "mixed", 73 | "type": {}, 74 | "declarationLine": "public function testRequest()", 75 | "documentation": null, 76 | "signatureInformation": { 77 | "label": "()", 78 | "parameters": [] 79 | } 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /tests/Validation/cases/memberAccess5.php: -------------------------------------------------------------------------------- 1 | args) { }; 10 | } 11 | } -------------------------------------------------------------------------------- /tests/Validation/cases/memberAccess5.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "MyNamespace\\ParseErrorsTest->args": [ 4 | "./memberAccess5.php" 5 | ] 6 | }, 7 | "definitions": { 8 | "MyNamespace": { 9 | "fqn": "MyNamespace", 10 | "extends": [], 11 | "isMember": false, 12 | "roamed": false, 13 | "isStatic": false, 14 | "canBeInstantiated": false, 15 | "symbolInformation": { 16 | "name": "MyNamespace", 17 | "kind": 3, 18 | "location": { 19 | "uri": "./memberAccess5.php" 20 | }, 21 | "containerName": "" 22 | }, 23 | "type": null, 24 | "declarationLine": "namespace MyNamespace;", 25 | "documentation": null, 26 | "signatureInformation": null 27 | }, 28 | "MyNamespace\\ParseErrorsTest": { 29 | "fqn": "MyNamespace\\ParseErrorsTest", 30 | "extends": [], 31 | "isMember": false, 32 | "roamed": false, 33 | "isStatic": false, 34 | "canBeInstantiated": true, 35 | "symbolInformation": { 36 | "name": "ParseErrorsTest", 37 | "kind": 5, 38 | "location": { 39 | "uri": "./memberAccess5.php" 40 | }, 41 | "containerName": "MyNamespace" 42 | }, 43 | "type": null, 44 | "declarationLine": "class ParseErrorsTest {", 45 | "documentation": null, 46 | "signatureInformation": null 47 | }, 48 | "MyNamespace\\ParseErrorsTest->setUp()": { 49 | "fqn": "MyNamespace\\ParseErrorsTest->setUp()", 50 | "extends": [], 51 | "isMember": true, 52 | "roamed": false, 53 | "isStatic": false, 54 | "canBeInstantiated": false, 55 | "symbolInformation": { 56 | "name": "setUp", 57 | "kind": 6, 58 | "location": { 59 | "uri": "./memberAccess5.php" 60 | }, 61 | "containerName": "MyNamespace\\ParseErrorsTest" 62 | }, 63 | "type__tostring": "mixed", 64 | "type": {}, 65 | "declarationLine": "public function setUp()", 66 | "documentation": null, 67 | "signatureInformation": { 68 | "label": "()", 69 | "parameters": [] 70 | } 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /tests/Validation/cases/memberCall1.php: -------------------------------------------------------------------------------- 1 | getAccount(); 13 | } 14 | 15 | } 16 | } -------------------------------------------------------------------------------- /tests/Validation/cases/methodReturnType.php: -------------------------------------------------------------------------------- 1 | b(); 16 | } 17 | } -------------------------------------------------------------------------------- /tests/Validation/cases/multiplePreceedingComments.php: -------------------------------------------------------------------------------- 1 | fn()": { 25 | "fqn": "Foo->fn()", 26 | "extends": [], 27 | "isMember": true, 28 | "roamed": false, 29 | "isStatic": false, 30 | "canBeInstantiated": false, 31 | "symbolInformation": { 32 | "name": "fn", 33 | "kind": 6, 34 | "location": { 35 | "uri": "./multiplePreceedingComments.php" 36 | }, 37 | "containerName": "Foo" 38 | }, 39 | "type__tostring": "\\Iterator", 40 | "type": {}, 41 | "declarationLine": "public function fn()", 42 | "documentation": "Foo", 43 | "signatureInformation": { 44 | "label": "()", 45 | "documentation": "Foo", 46 | "parameters": [] 47 | } 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /tests/Validation/cases/nameToken.php: -------------------------------------------------------------------------------- 1 | b()": { 29 | "fqn": "A->b()", 30 | "extends": [], 31 | "isMember": true, 32 | "roamed": false, 33 | "isStatic": false, 34 | "canBeInstantiated": false, 35 | "symbolInformation": { 36 | "name": "b", 37 | "kind": 6, 38 | "location": { 39 | "uri": "./nameToken.php" 40 | }, 41 | "containerName": "A" 42 | }, 43 | "type__tostring": "mixed", 44 | "type": {}, 45 | "declarationLine": "function b()", 46 | "documentation": null, 47 | "signatureInformation": { 48 | "label": "()", 49 | "parameters": [] 50 | } 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /tests/Validation/cases/namespaces2.php: -------------------------------------------------------------------------------- 1 | foo(); 8 | } 9 | 10 | private function foo() { 11 | } 12 | } -------------------------------------------------------------------------------- /tests/Validation/cases/newStatic.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "static": [ 4 | "\/Users\/roblou\/code\/php-language-server\/tests\/Validation\/..\/..\/validation\/frameworks\/_cases\/newStatic.php" 5 | ], 6 | "NewStatic->foo()": [ 7 | "\/Users\/roblou\/code\/php-language-server\/tests\/Validation\/..\/..\/validation\/frameworks\/_cases\/newStatic.php" 8 | ] 9 | }, 10 | "definitions": { 11 | "NewStatic": { 12 | "extends": [], 13 | "isGlobal": true, 14 | "isStatic": false, 15 | "canBeInstantiated": true, 16 | "symbolInformation": { 17 | "name": "NewStatic", 18 | "kind": 5, 19 | "location": { 20 | "uri": "\/Users\/roblou\/code\/php-language-server\/tests\/Validation\/..\/..\/validation\/frameworks\/_cases\/newStatic.php" 21 | }, 22 | "containerName": "" 23 | }, 24 | "type__class": "LanguageServer\\Tests\\ValidationTest", 25 | "type": null, 26 | "documentation": null 27 | }, 28 | "NewStatic::main()": { 29 | "extends": [], 30 | "isGlobal": false, 31 | "isStatic": true, 32 | "canBeInstantiated": false, 33 | "symbolInformation": { 34 | "name": "main", 35 | "kind": 6, 36 | "location": { 37 | "uri": "\/Users\/roblou\/code\/php-language-server\/tests\/Validation\/..\/..\/validation\/frameworks\/_cases\/newStatic.php" 38 | }, 39 | "containerName": "NewStatic" 40 | }, 41 | "type__class": "phpDocumentor\\Reflection\\Types\\Mixed", 42 | "type": {}, 43 | "documentation": null 44 | }, 45 | "NewStatic->foo()": { 46 | "extends": [], 47 | "isGlobal": false, 48 | "isStatic": false, 49 | "canBeInstantiated": false, 50 | "symbolInformation": { 51 | "name": "foo", 52 | "kind": 6, 53 | "location": { 54 | "uri": "\/Users\/roblou\/code\/php-language-server\/tests\/Validation\/..\/..\/validation\/frameworks\/_cases\/newStatic.php" 55 | }, 56 | "containerName": "NewStatic" 57 | }, 58 | "type__class": "phpDocumentor\\Reflection\\Types\\Mixed", 59 | "type": {}, 60 | "documentation": null 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /tests/Validation/cases/objectCreation.php: -------------------------------------------------------------------------------- 1 | inline_diff_renderer; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/Validation/cases/objectCreation.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "MyNamespace\\A->inline_diff_renderer": [ 4 | "./objectCreation.php" 5 | ] 6 | }, 7 | "definitions": { 8 | "MyNamespace": { 9 | "fqn": "MyNamespace", 10 | "extends": [], 11 | "isMember": false, 12 | "roamed": false, 13 | "isStatic": false, 14 | "canBeInstantiated": false, 15 | "symbolInformation": { 16 | "name": "MyNamespace", 17 | "kind": 3, 18 | "location": { 19 | "uri": "./objectCreation.php" 20 | }, 21 | "containerName": "" 22 | }, 23 | "type": null, 24 | "declarationLine": "namespace MyNamespace;", 25 | "documentation": null, 26 | "signatureInformation": null 27 | }, 28 | "MyNamespace\\A": { 29 | "fqn": "MyNamespace\\A", 30 | "extends": [], 31 | "isMember": false, 32 | "roamed": false, 33 | "isStatic": false, 34 | "canBeInstantiated": true, 35 | "symbolInformation": { 36 | "name": "A", 37 | "kind": 5, 38 | "location": { 39 | "uri": "./objectCreation.php" 40 | }, 41 | "containerName": "MyNamespace" 42 | }, 43 | "type": null, 44 | "declarationLine": "class A {", 45 | "documentation": null, 46 | "signatureInformation": null 47 | }, 48 | "MyNamespace\\A->a()": { 49 | "fqn": "MyNamespace\\A->a()", 50 | "extends": [], 51 | "isMember": true, 52 | "roamed": false, 53 | "isStatic": false, 54 | "canBeInstantiated": false, 55 | "symbolInformation": { 56 | "name": "a", 57 | "kind": 6, 58 | "location": { 59 | "uri": "./objectCreation.php" 60 | }, 61 | "containerName": "MyNamespace\\A" 62 | }, 63 | "type__tostring": "mixed", 64 | "type": {}, 65 | "declarationLine": "function a ()", 66 | "documentation": null, 67 | "signatureInformation": { 68 | "label": "()", 69 | "parameters": [] 70 | } 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /tests/Validation/cases/objectCreation2.php: -------------------------------------------------------------------------------- 1 | hi(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/Validation/cases/objectCreation3.php: -------------------------------------------------------------------------------- 1 | textDocument = new class($this->args) 6 | { 7 | }; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/Validation/cases/objectCreation3.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "A->args": [ 4 | "./objectCreation3.php" 5 | ] 6 | }, 7 | "definitions": { 8 | "A": { 9 | "fqn": "A", 10 | "extends": [], 11 | "isMember": false, 12 | "roamed": false, 13 | "isStatic": false, 14 | "canBeInstantiated": true, 15 | "symbolInformation": { 16 | "name": "A", 17 | "kind": 5, 18 | "location": { 19 | "uri": "./objectCreation3.php" 20 | }, 21 | "containerName": "" 22 | }, 23 | "type": null, 24 | "declarationLine": "class A {", 25 | "documentation": null, 26 | "signatureInformation": null 27 | }, 28 | "A->a()": { 29 | "fqn": "A->a()", 30 | "extends": [], 31 | "isMember": true, 32 | "roamed": false, 33 | "isStatic": false, 34 | "canBeInstantiated": false, 35 | "symbolInformation": { 36 | "name": "a", 37 | "kind": 6, 38 | "location": { 39 | "uri": "./objectCreation3.php" 40 | }, 41 | "containerName": "A" 42 | }, 43 | "type__tostring": "mixed", 44 | "type": {}, 45 | "declarationLine": "function a ()", 46 | "documentation": null, 47 | "signatureInformation": { 48 | "label": "()", 49 | "parameters": [] 50 | } 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /tests/Validation/cases/param1.php: -------------------------------------------------------------------------------- 1 | getAccount(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/Validation/cases/parameterTypeResolution1.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "ParamType": [ 4 | "./_cases/parameterTypeResolution1.php" 5 | ], 6 | "static": [ 7 | "./_cases/parameterTypeResolution1.php" 8 | ], 9 | "ParamType->getAccount()": [ 10 | "./_cases/parameterTypeResolution1.php" 11 | ] 12 | }, 13 | "definitions": { 14 | "ParamType": { 15 | "extends": [], 16 | "isGlobal": true, 17 | "isStatic": false, 18 | "canBeInstantiated": true, 19 | "symbolInformation": { 20 | "name": "ParamType", 21 | "kind": 5, 22 | "location": { 23 | "uri": "./_cases/parameterTypeResolution1.php" 24 | }, 25 | "containerName": "" 26 | }, 27 | "type__class": "LanguageServer\\Tests\\ValidationTest", 28 | "type": null, 29 | "documentation": null 30 | }, 31 | "ParamType->setAccount()": { 32 | "extends": [], 33 | "isGlobal": false, 34 | "isStatic": false, 35 | "canBeInstantiated": false, 36 | "symbolInformation": { 37 | "name": "setAccount", 38 | "kind": 6, 39 | "location": { 40 | "uri": "./_cases/parameterTypeResolution1.php" 41 | }, 42 | "containerName": "ParamType" 43 | }, 44 | "type__class": "phpDocumentor\\Reflection\\Types\\Mixed", 45 | "type": {}, 46 | "documentation": null 47 | }, 48 | "ParamType->getAccount()": { 49 | "extends": [], 50 | "isGlobal": false, 51 | "isStatic": false, 52 | "canBeInstantiated": false, 53 | "symbolInformation": { 54 | "name": "getAccount", 55 | "kind": 6, 56 | "location": { 57 | "uri": "./_cases/parameterTypeResolution1.php" 58 | }, 59 | "containerName": "ParamType" 60 | }, 61 | "type__class": "phpDocumentor\\Reflection\\Types\\Mixed", 62 | "type": {}, 63 | "documentation": null 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /tests/Validation/cases/parent1.php: -------------------------------------------------------------------------------- 1 | b(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/Validation/cases/promotedConstructor.php: -------------------------------------------------------------------------------- 1 | mainPropertyName": { 25 | "fqn": "MyClass->mainPropertyName", 26 | "extends": [], 27 | "isMember": true, 28 | "roamed": false, 29 | "isStatic": false, 30 | "canBeInstantiated": false, 31 | "symbolInformation": { 32 | "name": "mainPropertyName", 33 | "kind": 7, 34 | "location": { 35 | "uri": "./propertyName1.php" 36 | }, 37 | "containerName": "MyClass" 38 | }, 39 | "type__tostring": "string", 40 | "type": {}, 41 | "declarationLine": "protected $mainPropertyName;", 42 | "documentation": "The name of the main property, or NULL if there is none.", 43 | "signatureInformation": null 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /tests/Validation/cases/propertyName2.php: -------------------------------------------------------------------------------- 1 | mainPropertyName": { 25 | "fqn": "MyClass->mainPropertyName", 26 | "extends": [], 27 | "isMember": true, 28 | "roamed": false, 29 | "isStatic": false, 30 | "canBeInstantiated": false, 31 | "symbolInformation": { 32 | "name": "mainPropertyName", 33 | "kind": 7, 34 | "location": { 35 | "uri": "./propertyName2.php" 36 | }, 37 | "containerName": "MyClass" 38 | }, 39 | "type__tostring": "string", 40 | "type": {}, 41 | "declarationLine": "protected $mainPropertyName;", 42 | "documentation": "The name of the main property, or NULL if there is none.", 43 | "signatureInformation": null 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /tests/Validation/cases/returnType.php: -------------------------------------------------------------------------------- 1 | testProperty; -------------------------------------------------------------------------------- /tests/Validation/cases/scopedPropertyAccess5.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "TestInterface": [ 4 | "./scopedPropertyAccess5.php" 5 | ], 6 | "TestClass": [ 7 | "./scopedPropertyAccess5.php" 8 | ], 9 | "TestClass::$testProperty": [ 10 | "./scopedPropertyAccess5.php" 11 | ], 12 | "TestClass::$staticTestProperty": [ 13 | "./scopedPropertyAccess5.php" 14 | ] 15 | }, 16 | "definitions": { 17 | "TestClass": { 18 | "fqn": "TestClass", 19 | "extends": [], 20 | "isMember": false, 21 | "roamed": false, 22 | "isStatic": false, 23 | "canBeInstantiated": true, 24 | "symbolInformation": { 25 | "name": "TestClass", 26 | "kind": 5, 27 | "location": { 28 | "uri": "./scopedPropertyAccess5.php" 29 | }, 30 | "containerName": "" 31 | }, 32 | "type": null, 33 | "declarationLine": "class TestClass implements TestInterface {", 34 | "documentation": null, 35 | "signatureInformation": null 36 | }, 37 | "TestClass::$testProperty": { 38 | "fqn": "TestClass::$testProperty", 39 | "extends": [], 40 | "isMember": true, 41 | "roamed": false, 42 | "isStatic": true, 43 | "canBeInstantiated": false, 44 | "symbolInformation": { 45 | "name": "testProperty", 46 | "kind": 7, 47 | "location": { 48 | "uri": "./scopedPropertyAccess5.php" 49 | }, 50 | "containerName": "TestClass" 51 | }, 52 | "type__tostring": "\\TestClass[]", 53 | "type": {}, 54 | "declarationLine": "public static $testProperty;", 55 | "documentation": "Lorem excepteur officia sit anim velit veniam enim.", 56 | "signatureInformation": null 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /tests/Validation/cases/self1.php: -------------------------------------------------------------------------------- 1 | b(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/Validation/cases/self4.php: -------------------------------------------------------------------------------- 1 | addTestFile(__DIR__ . DS . 'Database' . DS . 'ConnectionTest.php'); 11 | 12 | } 13 | } -------------------------------------------------------------------------------- /tests/Validation/cases/self5.php: -------------------------------------------------------------------------------- 1 | assertTrue("HI"); 11 | } 12 | } -------------------------------------------------------------------------------- /tests/Validation/cases/self5.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "MyNamespace\\A->assertTrue()": [ 4 | "./self5.php" 5 | ] 6 | }, 7 | "definitions": { 8 | "MyNamespace": { 9 | "fqn": "MyNamespace", 10 | "extends": [], 11 | "isMember": false, 12 | "roamed": false, 13 | "isStatic": false, 14 | "canBeInstantiated": false, 15 | "symbolInformation": { 16 | "name": "MyNamespace", 17 | "kind": 3, 18 | "location": { 19 | "uri": "./self5.php" 20 | }, 21 | "containerName": "" 22 | }, 23 | "type": null, 24 | "declarationLine": "namespace MyNamespace;", 25 | "documentation": null, 26 | "signatureInformation": null 27 | }, 28 | "MyNamespace\\A": { 29 | "fqn": "MyNamespace\\A", 30 | "extends": [], 31 | "isMember": false, 32 | "roamed": false, 33 | "isStatic": false, 34 | "canBeInstantiated": true, 35 | "symbolInformation": { 36 | "name": "A", 37 | "kind": 5, 38 | "location": { 39 | "uri": "./self5.php" 40 | }, 41 | "containerName": "MyNamespace" 42 | }, 43 | "type": null, 44 | "declarationLine": "class A", 45 | "documentation": null, 46 | "signatureInformation": null 47 | }, 48 | "MyNamespace\\A->typesProvider()": { 49 | "fqn": "MyNamespace\\A->typesProvider()", 50 | "extends": [], 51 | "isMember": true, 52 | "roamed": false, 53 | "isStatic": false, 54 | "canBeInstantiated": false, 55 | "symbolInformation": { 56 | "name": "typesProvider", 57 | "kind": 6, 58 | "location": { 59 | "uri": "./self5.php" 60 | }, 61 | "containerName": "MyNamespace\\A" 62 | }, 63 | "type__tostring": "mixed", 64 | "type": {}, 65 | "declarationLine": "public function typesProvider()", 66 | "documentation": null, 67 | "signatureInformation": { 68 | "label": "()", 69 | "parameters": [] 70 | } 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /tests/Validation/cases/static1.php: -------------------------------------------------------------------------------- 1 | b(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/Validation/cases/static4.php: -------------------------------------------------------------------------------- 1 | a()": { 54 | "fqn": "MyNamespace\\A->a()", 55 | "extends": [], 56 | "isMember": true, 57 | "roamed": false, 58 | "isStatic": false, 59 | "canBeInstantiated": false, 60 | "symbolInformation": { 61 | "name": "a", 62 | "kind": 6, 63 | "location": { 64 | "uri": "./static4.php" 65 | }, 66 | "containerName": "MyNamespace\\A" 67 | }, 68 | "type__tostring": "mixed", 69 | "type": {}, 70 | "declarationLine": "function a ()", 71 | "documentation": null, 72 | "signatureInformation": { 73 | "label": "()", 74 | "parameters": [] 75 | } 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /tests/Validation/cases/staticInArray.php: -------------------------------------------------------------------------------- 1 | hi"; 8 | } 9 | } -------------------------------------------------------------------------------- /tests/Validation/cases/stringVariable.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "B->hi": [ 4 | "./stringVariable.php" 5 | ] 6 | }, 7 | "definitions": { 8 | "B": { 9 | "fqn": "B", 10 | "extends": [], 11 | "isMember": false, 12 | "roamed": false, 13 | "isStatic": false, 14 | "canBeInstantiated": true, 15 | "symbolInformation": { 16 | "name": "B", 17 | "kind": 5, 18 | "location": { 19 | "uri": "./stringVariable.php" 20 | }, 21 | "containerName": "" 22 | }, 23 | "type": null, 24 | "declarationLine": "class B", 25 | "documentation": null, 26 | "signatureInformation": null 27 | }, 28 | "B->hi": { 29 | "fqn": "B->hi", 30 | "extends": [], 31 | "isMember": true, 32 | "roamed": false, 33 | "isStatic": false, 34 | "canBeInstantiated": false, 35 | "symbolInformation": { 36 | "name": "hi", 37 | "kind": 7, 38 | "location": { 39 | "uri": "./stringVariable.php" 40 | }, 41 | "containerName": "B" 42 | }, 43 | "type__tostring": "int", 44 | "type": {}, 45 | "declarationLine": "public $hi;", 46 | "documentation": null, 47 | "signatureInformation": null 48 | }, 49 | "B->a()": { 50 | "fqn": "B->a()", 51 | "extends": [], 52 | "isMember": true, 53 | "roamed": false, 54 | "isStatic": false, 55 | "canBeInstantiated": false, 56 | "symbolInformation": { 57 | "name": "a", 58 | "kind": 6, 59 | "location": { 60 | "uri": "./stringVariable.php" 61 | }, 62 | "containerName": "B" 63 | }, 64 | "type__tostring": "mixed", 65 | "type": {}, 66 | "declarationLine": "function a ()", 67 | "documentation": null, 68 | "signatureInformation": { 69 | "label": "()", 70 | "parameters": [] 71 | } 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /tests/Validation/cases/testQualifiedNameOutsideOfNamespace.php: -------------------------------------------------------------------------------- 1 | bar = 'hello'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/Validation/cases/verifyFqsenOnClassProperty.php.expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": { 3 | "CURLAUTH_BASIC": [ 4 | "./verifyFqsenOnClassProperty.php" 5 | ], 6 | "Foo->bar": [ 7 | "./verifyFqsenOnClassProperty.php" 8 | ] 9 | }, 10 | "definitions": { 11 | "Foo": { 12 | "fqn": "Foo", 13 | "extends": [], 14 | "isMember": false, 15 | "roamed": false, 16 | "isStatic": false, 17 | "canBeInstantiated": true, 18 | "symbolInformation": { 19 | "name": "Foo", 20 | "kind": 5, 21 | "location": { 22 | "uri": "./verifyFqsenOnClassProperty.php" 23 | }, 24 | "containerName": "" 25 | }, 26 | "type": null, 27 | "declarationLine": "class Foo {", 28 | "documentation": null, 29 | "signatureInformation": null 30 | }, 31 | "Foo->bar": { 32 | "fqn": "Foo->bar", 33 | "extends": [], 34 | "isMember": true, 35 | "roamed": false, 36 | "isStatic": false, 37 | "canBeInstantiated": false, 38 | "symbolInformation": { 39 | "name": "bar", 40 | "kind": 7, 41 | "location": { 42 | "uri": "./verifyFqsenOnClassProperty.php" 43 | }, 44 | "containerName": "Foo" 45 | }, 46 | "type__tostring": "\\", 47 | "type": {}, 48 | "declarationLine": "protected $bar;", 49 | "documentation": null, 50 | "signatureInformation": null 51 | }, 52 | "Foo->foo()": { 53 | "fqn": "Foo->foo()", 54 | "extends": [], 55 | "isMember": true, 56 | "roamed": false, 57 | "isStatic": false, 58 | "canBeInstantiated": false, 59 | "symbolInformation": { 60 | "name": "foo", 61 | "kind": 6, 62 | "location": { 63 | "uri": "./verifyFqsenOnClassProperty.php" 64 | }, 65 | "containerName": "Foo" 66 | }, 67 | "type__tostring": "mixed", 68 | "type": {}, 69 | "declarationLine": "public function foo ()", 70 | "documentation": null, 71 | "signatureInformation": { 72 | "label": "()", 73 | "parameters": [] 74 | } 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /tests/Validation/cases81/enum1.php: -------------------------------------------------------------------------------- 1 |