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<FileEdits> runRename(ClangdServer &Server, PathRef File, 101 Position Pos, llvm::StringRef NewName, 102 const RenameOptions &RenameOpts) { 103 llvm::Optional<llvm::Expected<FileEdits>> Result; 104 Server.rename(File, Pos, NewName, RenameOpts, capture(Result)); 105 return std::move(*Result); 106 } 107 108 std::string runDumpAST(ClangdServer &Server, PathRef File) { 109 llvm::Optional<std::string> Result; 110 Server.dumpAST(File, capture(Result)); 111 return std::move(*Result); 112 } 113 114 llvm::Expected<std::vector<SymbolInformation>> 115 runWorkspaceSymbols(ClangdServer &Server, llvm::StringRef Query, int Limit) { 116 llvm::Optional<llvm::Expected<std::vector<SymbolInformation>>> Result; 117 Server.workspaceSymbols(Query, Limit, capture(Result)); 118 return std::move(*Result); 119 } 120 121 llvm::Expected<std::vector<DocumentSymbol>> 122 runDocumentSymbols(ClangdServer &Server, PathRef File) { 123 llvm::Optional<llvm::Expected<std::vector<DocumentSymbol>>> Result; 124 Server.documentSymbols(File, capture(Result)); 125 return std::move(*Result); 126 } 127 128 SymbolSlab runFuzzyFind(const SymbolIndex &Index, llvm::StringRef Query) { 129 FuzzyFindRequest Req; 130 Req.Query = std::string(Query); 131 Req.AnyScope = true; 132 return runFuzzyFind(Index, Req); 133 } 134 135 SymbolSlab runFuzzyFind(const SymbolIndex &Index, const FuzzyFindRequest &Req) { 136 SymbolSlab::Builder Builder; 137 Index.fuzzyFind(Req, [&](const Symbol &Sym) { Builder.insert(Sym); }); 138 return std::move(Builder).build(); 139 } 140 141 RefSlab getRefs(const SymbolIndex &Index, SymbolID ID) { 142 RefsRequest Req; 143 Req.IDs = {ID}; 144 RefSlab::Builder Slab; 145 Index.refs(Req, [&](const Ref &S) { Slab.insert(ID, S); }); 146 return std::move(Slab).build(); 147 } 148 149 llvm::Expected<std::vector<SelectionRange>> 150 runSemanticRanges(ClangdServer &Server, PathRef File, 151 const std::vector<Position> &Pos) { 152 llvm::Optional<llvm::Expected<std::vector<SelectionRange>>> Result; 153 Server.semanticRanges(File, Pos, capture(Result)); 154 return std::move(*Result); 155 } 156 157 llvm::Expected<llvm::Optional<clangd::Path>> 158 runSwitchHeaderSource(ClangdServer &Server, PathRef File) { 159 llvm::Optional<llvm::Expected<llvm::Optional<clangd::Path>>> Result; 160 Server.switchSourceHeader(File, capture(Result)); 161 return std::move(*Result); 162 } 163 164 } // namespace clangd 165 } // namespace clang 166