Skip to content

Commit c3aaa48

Browse files
committed
Implement cancellation for pending parser requests in the LSP server
Signed-off-by: Roberto Raggi <[email protected]>
1 parent 0625562 commit c3aaa48

File tree

4 files changed

+86
-13
lines changed

4 files changed

+86
-13
lines changed

src/lsp/cxx/lsp/cxx_document.cc

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
#include <cxx/wasm32_wasi_toolchain.h>
3535
#include <cxx/windows_toolchain.h>
3636

37+
#ifndef CXX_NO_THREADS
38+
#include <atomic>
39+
#endif
40+
3741
namespace cxx::lsp {
3842

3943
namespace {
@@ -65,12 +69,20 @@ struct Diagnostics final : cxx::DiagnosticsClient {
6569

6670
struct CxxDocument::Private {
6771
const CLI& cli;
72+
std::string fileName;
6873
long version;
6974
Diagnostics diagnosticsClient;
7075
TranslationUnit unit{&diagnosticsClient};
7176
std::shared_ptr<Toolchain> toolchain;
7277

73-
Private(const CLI& cli, long version) : cli(cli), version(version) {}
78+
#ifndef CXX_NO_THREADS
79+
std::atomic<bool> cancelled{false};
80+
#else
81+
bool cancelled{false};
82+
#endif
83+
84+
Private(const CLI& cli, std::string fileName, long version)
85+
: cli(cli), fileName(std::move(fileName)), version(version) {}
7486

7587
void configure();
7688
};
@@ -169,27 +181,53 @@ void CxxDocument::Private::configure() {
169181
}
170182
}
171183

172-
CxxDocument::CxxDocument(const CLI& cli, long version)
173-
: d(std::make_unique<Private>(cli, version)) {}
184+
CxxDocument::CxxDocument(const CLI& cli, std::string fileName, long version)
185+
: d(std::make_unique<Private>(cli, std::move(fileName), version)) {}
174186

175-
void CxxDocument::parse(std::string source, std::string fileName,
176-
std::function<bool()> stopParsingPredicate) {
187+
auto CxxDocument::isCancelled() const -> bool {
188+
#ifndef CXX_NO_THREADS
189+
return d->cancelled.load();
190+
#else
191+
return d->cancelled;
192+
#endif
193+
}
194+
195+
void CxxDocument::cancel() {
196+
#ifndef CXX_NO_THREADS
197+
d->cancelled.store(true);
198+
#else
199+
d->cancelled = true;
200+
#endif
201+
}
202+
203+
auto CxxDocument::fileName() const -> const std::string& { return d->fileName; }
204+
205+
void CxxDocument::parse(std::string source) {
177206
d->configure();
178207

179208
auto& unit = d->unit;
180209
auto& cli = d->cli;
181210

182-
unit.setSource(std::move(source), fileName);
183-
184211
auto preprocessor = unit.preprocessor();
185212

213+
DefaultPreprocessorState state{*preprocessor};
214+
215+
unit.beginPreprocessing(std::move(source), d->fileName);
216+
217+
while (state) {
218+
if (isCancelled()) break;
219+
std::visit(state, unit.continuePreprocessing());
220+
}
221+
222+
unit.endPreprocessing();
223+
186224
unit.parse(ParserConfiguration{
187225
.checkTypes = cli.opt_fcheck,
188226
.fuzzyTemplateResolution = true,
189227
.staticAssert = cli.opt_fstatic_assert || cli.opt_fcheck,
190228
.reflect = !cli.opt_fno_reflect,
191229
.templates = cli.opt_ftemplates,
192-
.stopParsingPredicate = std::move(stopParsingPredicate),
230+
.stopParsingPredicate = [this] { return isCancelled(); },
193231
});
194232
}
195233

src/lsp/cxx/lsp/cxx_document.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,15 @@ namespace cxx::lsp {
3131

3232
class CxxDocument {
3333
public:
34-
explicit CxxDocument(const CLI& cli, long version);
34+
explicit CxxDocument(const CLI& cli, std::string fileName, long version);
3535
~CxxDocument();
3636

37-
void parse(std::string source, std::string fileName,
38-
std::function<bool()> stopParsingPredicate = {});
37+
[[nodiscard]] auto isCancelled() const -> bool;
38+
void cancel();
39+
40+
[[nodiscard]] auto fileName() const -> const std::string&;
41+
42+
void parse(std::string source);
3943

4044
[[nodiscard]] auto version() const -> long;
4145
[[nodiscard]] auto diagnostics() const -> Vector<Diagnostic>;

src/lsp/cxx/lsp/lsp_server.cc

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,21 +286,49 @@ void Server::run(std::function<void()> task) {
286286
task();
287287
}
288288

289+
void Server::cancelPendingParserRequests(const std::string& fileName) {
290+
#ifndef CXX_NO_THREADS
291+
auto lock = std::unique_lock(documentsMutex_);
292+
#endif
293+
294+
std::vector<std::shared_ptr<CxxDocument>> pendingParserRequests;
295+
std::swap(pendingParserRequests_, pendingParserRequests);
296+
297+
for (const auto& doc : pendingParserRequests) {
298+
if (doc->fileName() == fileName) {
299+
doc->cancel();
300+
} else {
301+
pendingParserRequests_.push_back(doc);
302+
}
303+
}
304+
}
305+
289306
void Server::parse(const std::string& uri) {
290307
const auto& doc = documentContents_.at(uri);
291308

292309
auto text = doc.value;
293310
auto version = doc.version;
294311

295312
run([text = std::move(text), uri = std::move(uri), version, this] {
296-
auto doc = std::make_shared<CxxDocument>(cli, version);
297-
doc->parse(std::move(text), pathFromUri(uri));
313+
auto fileName = pathFromUri(uri);
314+
315+
cancelPendingParserRequests(fileName);
316+
317+
auto doc = std::make_shared<CxxDocument>(cli, std::move(fileName), version);
318+
pendingParserRequests_.push_back(doc);
319+
320+
doc->parse(std::move(text));
298321

299322
{
300323
#ifndef CXX_NO_THREADS
301324
auto locker = std::unique_lock(outputMutex_);
302325
#endif
303326

327+
if (auto it = std::ranges::find(pendingParserRequests_, doc);
328+
it != pendingParserRequests_.end()) {
329+
pendingParserRequests_.erase(it);
330+
}
331+
304332
if (documents_.contains(uri) && documents_.at(uri)->version() > version) {
305333
return;
306334
}

src/lsp/cxx/lsp/lsp_server.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ class Server {
6868
void startWorkersIfNeeded();
6969
void stopWorkersIfNeeded();
7070

71+
void cancelPendingParserRequests(const std::string& fileName);
72+
7173
void run(std::function<void()> task);
7274

7375
void parse(const std::string& uri);
@@ -105,6 +107,7 @@ class Server {
105107
std::ostream& log;
106108
std::unordered_map<std::string, std::shared_ptr<CxxDocument>> documents_;
107109
std::unordered_map<std::string, Text> documentContents_;
110+
std::vector<std::shared_ptr<CxxDocument>> pendingParserRequests_;
108111
#ifndef CXX_NO_THREADS
109112
SyncQueue syncQueue_;
110113
std::vector<std::thread> workers_;

0 commit comments

Comments
 (0)