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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "SyncAPI.h" 10 #include "index/Index.h" 11 12 namespace clang { 13 namespace clangd { 14 15 void runAddDocument(ClangdServer &Server, PathRef File, 16 llvm::StringRef Contents, llvm::StringRef Version, 17 WantDiagnostics WantDiags, bool ForceRebuild) { 18 Server.addDocument(File, Contents, Version, WantDiags, ForceRebuild); 19 if (!Server.blockUntilIdleForTest()) 20 llvm_unreachable("not idle after addDocument"); 21 } 22 23 namespace { 24 /// A helper that waits for async callbacks to fire and exposes their result in 25 /// the output variable. Intended to be used in the following way: 26 /// T Result; 27 /// someAsyncFunc(Param1, Param2, /*Callback=*/capture(Result)); 28 template <typename T> struct CaptureProxy { 29 CaptureProxy(llvm::Optional<T> &Target) : Target(&Target) { 30 assert(!Target.hasValue()); 31 } 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->hasValue()); 54 Target->emplace(std::move(*Future.get())); 55 } 56 57 private: 58 llvm::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 66 template <typename T> CaptureProxy<T> capture(llvm::Optional<T> &Target) { 67 return CaptureProxy<T>(Target); 68 } 69 } // namespace 70 71 llvm::Expected<CodeCompleteResult> 72 runCodeComplete(ClangdServer &Server, PathRef File, Position Pos, 73 clangd::CodeCompleteOptions Opts) { 74 llvm::Optional<llvm::Expected<CodeCompleteResult>> Result; 75 Server.codeComplete(File, Pos, Opts, capture(Result)); 76 return std::move(*Result); 77 } 78 79 llvm::Expected<SignatureHelp> runSignatureHelp(ClangdServer &Server, 80 PathRef File, Position Pos) { 81 llvm::Optional<llvm::Expected<SignatureHelp>> Result; 82 Server.signatureHelp(File, Pos, capture(Result)); 83 return std::move(*Result); 84 } 85 86 llvm::Expected<std::vector<LocatedSymbol>> 87 runLocateSymbolAt(ClangdServer &Server, PathRef File, Position Pos) { 88 llvm::Optional<llvm::Expected<std::vector<LocatedSymbol>>> Result; 89 Server.locateSymbolAt(File, Pos, capture(Result)); 90 return std::move(*Result); 91 } 92 93 llvm::Expected<std::vector<DocumentHighlight>> 94 runFindDocumentHighlights(ClangdServer &Server, PathRef File, Position Pos) { 95 llvm::Optional<llvm::Expected<std::vector<DocumentHighlight>>> Result; 96 Server.findDocumentHighlights(File, Pos, capture(Result)); 97 return std::move(*Result); 98 } 99 100 llvm::Expected<RenameResult> runRename(ClangdServer &Server, PathRef File, 101 Position Pos, llvm::StringRef NewName, 102 const RenameOptions &RenameOpts) { 103 llvm::Optional<llvm::Expected<RenameResult>> Result; 104 Server.rename(File, Pos, NewName, RenameOpts, capture(Result)); 105 return std::move(*Result); 106 } 107 108 llvm::Expected<RenameResult> 109 runPrepareRename(ClangdServer &Server, PathRef File, Position Pos, 110 llvm::Optional<std::string> NewName, 111 const RenameOptions &RenameOpts) { 112 llvm::Optional<llvm::Expected<RenameResult>> Result; 113 Server.prepareRename(File, Pos, NewName, RenameOpts, capture(Result)); 114 return std::move(*Result); 115 } 116 117 llvm::Expected<tooling::Replacements> 118 runFormatFile(ClangdServer &Server, PathRef File, llvm::Optional<Range> Rng) { 119 llvm::Optional<llvm::Expected<tooling::Replacements>> Result; 120 Server.formatFile(File, Rng, capture(Result)); 121 return std::move(*Result); 122 } 123 124 SymbolSlab runFuzzyFind(const SymbolIndex &Index, llvm::StringRef Query) { 125 FuzzyFindRequest Req; 126 Req.Query = std::string(Query); 127 Req.AnyScope = true; 128 return runFuzzyFind(Index, Req); 129 } 130 131 SymbolSlab runFuzzyFind(const SymbolIndex &Index, const FuzzyFindRequest &Req) { 132 SymbolSlab::Builder Builder; 133 Index.fuzzyFind(Req, [&](const Symbol &Sym) { Builder.insert(Sym); }); 134 return std::move(Builder).build(); 135 } 136 137 RefSlab getRefs(const SymbolIndex &Index, SymbolID ID) { 138 RefsRequest Req; 139 Req.IDs = {ID}; 140 RefSlab::Builder Slab; 141 Index.refs(Req, [&](const Ref &S) { Slab.insert(ID, S); }); 142 return std::move(Slab).build(); 143 } 144 145 llvm::Expected<std::vector<SelectionRange>> 146 runSemanticRanges(ClangdServer &Server, PathRef File, 147 const std::vector<Position> &Pos) { 148 llvm::Optional<llvm::Expected<std::vector<SelectionRange>>> Result; 149 Server.semanticRanges(File, Pos, capture(Result)); 150 return std::move(*Result); 151 } 152 153 llvm::Expected<llvm::Optional<clangd::Path>> 154 runSwitchHeaderSource(ClangdServer &Server, PathRef File) { 155 llvm::Optional<llvm::Expected<llvm::Optional<clangd::Path>>> Result; 156 Server.switchSourceHeader(File, capture(Result)); 157 return std::move(*Result); 158 } 159 160 llvm::Error runCustomAction(ClangdServer &Server, PathRef File, 161 llvm::function_ref<void(InputsAndAST)> Action) { 162 llvm::Error Result = llvm::Error::success(); 163 Notification Done; 164 Server.customAction(File, "Custom", [&](llvm::Expected<InputsAndAST> AST) { 165 if (!AST) 166 Result = AST.takeError(); 167 else 168 Action(*AST); 169 Done.notify(); 170 }); 171 Done.wait(); 172 return Result; 173 } 174 175 } // namespace clangd 176 } // namespace clang 177