179 lines · cpp
1//===--- SyncAPI.cpp - Sync version of ClangdServer's API --------*- C++-*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "SyncAPI.h"10#include "Protocol.h"11#include "index/Index.h"12#include <optional>13 14namespace clang {15namespace clangd {16 17void runAddDocument(ClangdServer &Server, PathRef File,18 llvm::StringRef Contents, llvm::StringRef Version,19 WantDiagnostics WantDiags, bool ForceRebuild) {20 Server.addDocument(File, Contents, Version, WantDiags, ForceRebuild);21 if (!Server.blockUntilIdleForTest())22 llvm_unreachable("not idle after addDocument");23}24 25namespace {26/// A helper that waits for async callbacks to fire and exposes their result in27/// the output variable. Intended to be used in the following way:28/// T Result;29/// someAsyncFunc(Param1, Param2, /*Callback=*/capture(Result));30template <typename T> struct CaptureProxy {31 CaptureProxy(std::optional<T> &Target) : Target(&Target) { assert(!Target); }32 33 CaptureProxy(const CaptureProxy &) = delete;34 CaptureProxy &operator=(const CaptureProxy &) = delete;35 // We need move ctor to return a value from the 'capture' helper.36 CaptureProxy(CaptureProxy &&Other) : Target(Other.Target) {37 Other.Target = nullptr;38 }39 CaptureProxy &operator=(CaptureProxy &&) = delete;40 41 operator llvm::unique_function<void(T)>() && {42 assert(!Future.valid() && "conversion to callback called multiple times");43 Future = Promise.get_future();44 return [Promise = std::move(Promise)](T Value) mutable {45 Promise.set_value(std::make_shared<T>(std::move(Value)));46 };47 }48 49 ~CaptureProxy() {50 if (!Target)51 return;52 assert(Future.valid() && "conversion to callback was not called");53 assert(!Target->has_value());54 Target->emplace(std::move(*Future.get()));55 }56 57private:58 std::optional<T> *Target;59 // Using shared_ptr to workaround compilation errors with MSVC.60 // MSVC only allows default-constructible and copyable objects as future<>61 // arguments.62 std::promise<std::shared_ptr<T>> Promise;63 std::future<std::shared_ptr<T>> Future;64};65 66template <typename T> CaptureProxy<T> capture(std::optional<T> &Target) {67 return CaptureProxy<T>(Target);68}69} // namespace70 71llvm::Expected<CodeCompleteResult>72runCodeComplete(ClangdServer &Server, PathRef File, Position Pos,73 clangd::CodeCompleteOptions Opts) {74 std::optional<llvm::Expected<CodeCompleteResult>> Result;75 Server.codeComplete(File, Pos, Opts, capture(Result));76 return std::move(*Result);77}78 79llvm::Expected<SignatureHelp> runSignatureHelp(ClangdServer &Server,80 PathRef File, Position Pos,81 MarkupKind DocumentationFormat) {82 std::optional<llvm::Expected<SignatureHelp>> Result;83 Server.signatureHelp(File, Pos, DocumentationFormat, capture(Result));84 return std::move(*Result);85}86 87llvm::Expected<std::vector<LocatedSymbol>>88runLocateSymbolAt(ClangdServer &Server, PathRef File, Position Pos) {89 std::optional<llvm::Expected<std::vector<LocatedSymbol>>> Result;90 Server.locateSymbolAt(File, Pos, capture(Result));91 return std::move(*Result);92}93 94llvm::Expected<std::vector<DocumentHighlight>>95runFindDocumentHighlights(ClangdServer &Server, PathRef File, Position Pos) {96 std::optional<llvm::Expected<std::vector<DocumentHighlight>>> Result;97 Server.findDocumentHighlights(File, Pos, capture(Result));98 return std::move(*Result);99}100 101llvm::Expected<RenameResult> runRename(ClangdServer &Server, PathRef File,102 Position Pos, llvm::StringRef NewName,103 const RenameOptions &RenameOpts) {104 std::optional<llvm::Expected<RenameResult>> Result;105 Server.rename(File, Pos, NewName, RenameOpts, capture(Result));106 return std::move(*Result);107}108 109llvm::Expected<RenameResult>110runPrepareRename(ClangdServer &Server, PathRef File, Position Pos,111 std::optional<std::string> NewName,112 const RenameOptions &RenameOpts) {113 std::optional<llvm::Expected<RenameResult>> Result;114 Server.prepareRename(File, Pos, NewName, RenameOpts, capture(Result));115 return std::move(*Result);116}117 118llvm::Expected<tooling::Replacements>119runFormatFile(ClangdServer &Server, PathRef File,120 const std::vector<Range> &Rngs) {121 std::optional<llvm::Expected<tooling::Replacements>> Result;122 Server.formatFile(File, Rngs, capture(Result));123 return std::move(*Result);124}125 126SymbolSlab runFuzzyFind(const SymbolIndex &Index, llvm::StringRef Query) {127 FuzzyFindRequest Req;128 Req.Query = std::string(Query);129 Req.AnyScope = true;130 return runFuzzyFind(Index, Req);131}132 133SymbolSlab runFuzzyFind(const SymbolIndex &Index, const FuzzyFindRequest &Req) {134 SymbolSlab::Builder Builder;135 Index.fuzzyFind(Req, [&](const Symbol &Sym) { Builder.insert(Sym); });136 return std::move(Builder).build();137}138 139RefSlab getRefs(const SymbolIndex &Index, SymbolID ID) {140 RefsRequest Req;141 Req.IDs = {ID};142 RefSlab::Builder Slab;143 Index.refs(Req, [&](const Ref &S) { Slab.insert(ID, S); });144 return std::move(Slab).build();145}146 147llvm::Expected<std::vector<SelectionRange>>148runSemanticRanges(ClangdServer &Server, PathRef File,149 const std::vector<Position> &Pos) {150 std::optional<llvm::Expected<std::vector<SelectionRange>>> Result;151 Server.semanticRanges(File, Pos, capture(Result));152 return std::move(*Result);153}154 155llvm::Expected<std::optional<clangd::Path>>156runSwitchHeaderSource(ClangdServer &Server, PathRef File) {157 std::optional<llvm::Expected<std::optional<clangd::Path>>> Result;158 Server.switchSourceHeader(File, capture(Result));159 return std::move(*Result);160}161 162llvm::Error runCustomAction(ClangdServer &Server, PathRef File,163 llvm::function_ref<void(InputsAndAST)> Action) {164 llvm::Error Result = llvm::Error::success();165 Notification Done;166 Server.customAction(File, "Custom", [&](llvm::Expected<InputsAndAST> AST) {167 if (!AST)168 Result = AST.takeError();169 else170 Action(*AST);171 Done.notify();172 });173 Done.wait();174 return Result;175}176 177} // namespace clangd178} // namespace clang179