//===--- SyncAPI.cpp - Sync version of ClangdServer's API --------*- C++-*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "SyncAPI.h" #include "index/Index.h" namespace clang { namespace clangd { void runAddDocument(ClangdServer &Server, PathRef File, llvm::StringRef Contents, WantDiagnostics WantDiags) { Server.addDocument(File, Contents, WantDiags); if (!Server.blockUntilIdleForTest()) llvm_unreachable("not idle after addDocument"); } namespace { /// A helper that waits for async callbacks to fire and exposes their result in /// the output variable. Intended to be used in the following way: /// T Result; /// someAsyncFunc(Param1, Param2, /*Callback=*/capture(Result)); template struct CaptureProxy { CaptureProxy(llvm::Optional &Target) : Target(&Target) { assert(!Target.hasValue()); } CaptureProxy(const CaptureProxy &) = delete; CaptureProxy &operator=(const CaptureProxy &) = delete; // We need move ctor to return a value from the 'capture' helper. CaptureProxy(CaptureProxy &&Other) : Target(Other.Target) { Other.Target = nullptr; } CaptureProxy &operator=(CaptureProxy &&) = delete; operator llvm::unique_function() && { assert(!Future.valid() && "conversion to callback called multiple times"); Future = Promise.get_future(); return Bind( [](std::promise> Promise, T Value) { Promise.set_value(std::make_shared(std::move(Value))); }, std::move(Promise)); } ~CaptureProxy() { if (!Target) return; assert(Future.valid() && "conversion to callback was not called"); assert(!Target->hasValue()); Target->emplace(std::move(*Future.get())); } private: llvm::Optional *Target; // Using shared_ptr to workaround compilation errors with MSVC. // MSVC only allows default-construcitble and copyable objects as future<> // arguments. std::promise> Promise; std::future> Future; }; template CaptureProxy capture(llvm::Optional &Target) { return CaptureProxy(Target); } } // namespace llvm::Expected runCodeComplete(ClangdServer &Server, PathRef File, Position Pos, clangd::CodeCompleteOptions Opts) { llvm::Optional> Result; Server.codeComplete(File, Pos, Opts, capture(Result)); return std::move(*Result); } llvm::Expected runSignatureHelp(ClangdServer &Server, PathRef File, Position Pos) { llvm::Optional> Result; Server.signatureHelp(File, Pos, capture(Result)); return std::move(*Result); } llvm::Expected> runFindDefinitions(ClangdServer &Server, PathRef File, Position Pos) { llvm::Optional>> Result; Server.findDefinitions(File, Pos, capture(Result)); return std::move(*Result); } llvm::Expected> runFindDocumentHighlights(ClangdServer &Server, PathRef File, Position Pos) { llvm::Optional>> Result; Server.findDocumentHighlights(File, Pos, capture(Result)); return std::move(*Result); } llvm::Expected> runRename(ClangdServer &Server, PathRef File, Position Pos, llvm::StringRef NewName) { llvm::Optional>> Result; Server.rename(File, Pos, NewName, capture(Result)); return std::move(*Result); } std::string runDumpAST(ClangdServer &Server, PathRef File) { llvm::Optional Result; Server.dumpAST(File, capture(Result)); return std::move(*Result); } llvm::Expected> runWorkspaceSymbols(ClangdServer &Server, llvm::StringRef Query, int Limit) { llvm::Optional>> Result; Server.workspaceSymbols(Query, Limit, capture(Result)); return std::move(*Result); } llvm::Expected> runDocumentSymbols(ClangdServer &Server, PathRef File) { llvm::Optional>> Result; Server.documentSymbols(File, capture(Result)); return std::move(*Result); } SymbolSlab runFuzzyFind(const SymbolIndex &Index, llvm::StringRef Query) { FuzzyFindRequest Req; Req.Query = Query; Req.AnyScope = true; return runFuzzyFind(Index, Req); } SymbolSlab runFuzzyFind(const SymbolIndex &Index, const FuzzyFindRequest &Req) { SymbolSlab::Builder Builder; Index.fuzzyFind(Req, [&](const Symbol &Sym) { Builder.insert(Sym); }); return std::move(Builder).build(); } RefSlab getRefs(const SymbolIndex &Index, SymbolID ID) { RefsRequest Req; Req.IDs = {ID}; RefSlab::Builder Slab; Index.refs(Req, [&](const Ref &S) { Slab.insert(ID, S); }); return std::move(Slab).build(); } } // namespace clangd } // namespace clang