diff --git a/composer.json b/composer.json index 8fae461bf..925a0037c 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,7 @@ "composer/xdebug-handler": "^1.1 || ^2.0 || ^3.0", "dnoegel/php-xdg-base-dir": "^0.1.1", "felixfbecker/advanced-json-rpc": "^3.0.3", - "felixfbecker/language-server-protocol": "@dev", + "felixfbecker/language-server-protocol": "dev-feature/spec-3.16", "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", "nikic/php-parser": "^4.13", "openlss/lib-array2xml": "^1.0", @@ -97,8 +97,8 @@ "url": "examples/plugins/composer-based/echo-checker" }, { - "type": "path", - "url": "/usr/src/php-language-server-protocol" + "type": "vcs", + "url": "https://github.com/tm1000/php-language-server-protocol" } ], "minimum-stability": "dev", diff --git a/src/Psalm/Codebase.php b/src/Psalm/Codebase.php index cb72efa8b..a9fbb4279 100644 --- a/src/Psalm/Codebase.php +++ b/src/Psalm/Codebase.php @@ -409,15 +409,19 @@ class Codebase * @param array $candidate_files * */ - public function reloadFiles(ProjectAnalyzer $project_analyzer, array $candidate_files): void + public function reloadFiles(ProjectAnalyzer $project_analyzer, array $candidate_files, bool $force = false): void { $this->loadAnalyzer(); - $this->file_reference_provider->loadReferenceCache(false); + if($force) { + FileReferenceProvider::clearCache(); + } + + $this->file_reference_provider->loadReferenceCache($force); FunctionLikeAnalyzer::clearCache(); - if (!$this->statements_provider->parser_cache_provider) { + if ($force || !$this->statements_provider->parser_cache_provider) { $diff_files = $candidate_files; } else { $diff_files = []; diff --git a/src/Psalm/Internal/LanguageServer/LanguageServer.php b/src/Psalm/Internal/LanguageServer/LanguageServer.php index 95856f0e9..27e267e43 100644 --- a/src/Psalm/Internal/LanguageServer/LanguageServer.php +++ b/src/Psalm/Internal/LanguageServer/LanguageServer.php @@ -190,6 +190,7 @@ class LanguageServer extends Dispatcher */ if (Request::isRequest($msg->body)) { if ($error !== null) { + $this->logError($error->message); $responseBody = new ErrorResponse($msg->body->id, $error); } else { $responseBody = new SuccessResponse($msg->body->id, $result); @@ -212,7 +213,7 @@ class LanguageServer extends Dispatcher $this->project_analyzer->progress = new Progress($this); - $this->logInfo("Language server has started."); + $this->logInfo("Psalm Language Server ".PSALM_VERSION." has started."); } /** @@ -361,14 +362,11 @@ class LanguageServer extends Dispatcher */ public function initialized(): void { - $this->logInfo("Initialized."); try { $this->client->refreshConfiguration(); } catch(Throwable $e) { error_log($e->getMessage()); } - $this->logInfo("Initialized. After"); - $this->clientStatus('running'); } @@ -555,19 +553,19 @@ class LanguageServer extends Dispatcher */ public function log(int $type, string $message, array $context = []): void { - $full = $type === MessageType::LOG ? $message : \sprintf('[Psalm ' .PSALM_VERSION. ' - PHP Language Server] %s', $message); if(!empty($context)) { - $full .= "\n" . \json_encode($context, JSON_PRETTY_PRINT); + $message .= "\n" . \json_encode($context, JSON_PRETTY_PRINT); } try { $this->client->logMessage( new LogMessage( $type, - $full, + $message, ) ); } catch (Throwable $err) { - // do nothing + // do nothing as we could potentially go into a loop here is not careful + //TODO: Investigate if we can use error_log instead } } diff --git a/src/Psalm/Internal/LanguageServer/Server/TextDocument.php b/src/Psalm/Internal/LanguageServer/Server/TextDocument.php index ea4412b96..a755918f4 100644 --- a/src/Psalm/Internal/LanguageServer/Server/TextDocument.php +++ b/src/Psalm/Internal/LanguageServer/Server/TextDocument.php @@ -439,6 +439,7 @@ class TextDocument ]) ); + /* $fixers["fixAll.{$diagnostic->data->type}"] = new CodeAction( "FixAll {$diagnostic->data->type} for this file", CodeActionKind::QUICK_FIX, @@ -455,6 +456,7 @@ class TextDocument ] ) ); + */ } if (empty($fixers)) { diff --git a/src/Psalm/Internal/LanguageServer/Server/Workspace.php b/src/Psalm/Internal/LanguageServer/Server/Workspace.php index 84d75a805..bf16a2ab5 100644 --- a/src/Psalm/Internal/LanguageServer/Server/Workspace.php +++ b/src/Psalm/Internal/LanguageServer/Server/Workspace.php @@ -9,7 +9,9 @@ use LanguageServerProtocol\FileChangeType; use LanguageServerProtocol\FileEvent; use Psalm\Codebase; use Psalm\Internal\Analyzer\ProjectAnalyzer; +use Psalm\Internal\Composer; use Psalm\Internal\LanguageServer\LanguageServer; +use Psalm\Internal\Provider\FileReferenceProvider; /** * Provides method handlers for all workspace/* methods @@ -57,9 +59,28 @@ class Workspace $this->server->logDebug( 'workspace/didChangeWatchedFiles' ); + + $realFiles = array_map(function(FileEvent $change) { + return LanguageServer::uriToPath($change->uri); + }, $changes); + + $composerLockFile = realpath(Composer::getLockFilePath($this->codebase->config->base_dir)); + if(in_array($composerLockFile, $realFiles)) { + $this->server->logInfo('Composer.lock file changed. Reloading codebase'); + FileReferenceProvider::clearCache(); + foreach($this->codebase->file_provider->getOpenFiles() as $file) { + $this->server->queueFileAnalysis($file, $this->server->pathToUri($file)); + } + return; + } + foreach ($changes as $change) { $file_path = LanguageServer::uriToPath($change->uri); + if($composerLockFile === $file_path) { + continue; + } + if ($change->type === FileChangeType::DELETED) { $this->codebase->invalidateInformationForFile($file_path); continue; @@ -73,7 +94,7 @@ class Workspace continue; } - //If the file is currently open then dont analyse it because its tracked by the client + //If the file is currently open then dont analize it because its tracked in didChange if (!$this->codebase->file_provider->isOpen($file_path)) { $this->server->queueFileAnalysis($file_path, $change->uri); } @@ -117,7 +138,8 @@ class Workspace $codebase = $this->project_analyzer->getCodebase(); $codebase->reloadFiles( $this->project_analyzer, - [$file] + [$file], + true ); $codebase->analyzer->addFilesToAnalyze( @@ -125,7 +147,7 @@ class Workspace ); $codebase->analyzer->analyzeFiles($this->project_analyzer, 1, false); - $this->server->emitVersionedIssues([$file]); + $this->server->emitVersionedIssues([$file => $arguments->uri]); break; } diff --git a/src/Psalm/Internal/Provider/FileProvider.php b/src/Psalm/Internal/Provider/FileProvider.php index de6d58733..02674c519 100644 --- a/src/Psalm/Internal/Provider/FileProvider.php +++ b/src/Psalm/Internal/Provider/FileProvider.php @@ -94,6 +94,11 @@ class FileProvider unset($this->temp_files[strtolower($file_path)]); } + public function getOpenFiles(): array + { + return array_keys($this->open_files); + } + public function openFile(string $file_path): void { $this->open_files[strtolower($file_path)] = $this->getContents($file_path, true);