1 //===-- ClangdXPCTestClient.cpp ----------------------------------*- C++-*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "xpc/Conversion.h"
10 #include "clang/Basic/LLVM.h"
11 #include "llvm/ADT/SmallString.h"
12 #include "llvm/Support/LineIterator.h"
13 #include "llvm/Support/MemoryBuffer.h"
14 #include "llvm/Support/Path.h"
15 #include "llvm/Support/raw_ostream.h"
21 typedef const char *(*clangd_xpc_get_bundle_identifier_t
)(void);
24 using namespace clang
;
26 static std::string
getLibraryPath() {
28 if (dladdr((void *)(uintptr_t)getLibraryPath
, &info
) == 0)
29 llvm_unreachable("Call to dladdr() failed");
30 llvm::SmallString
<128> LibClangPath
;
31 LibClangPath
= llvm::sys::path::parent_path(
32 llvm::sys::path::parent_path(info
.dli_fname
));
33 llvm::sys::path::append(LibClangPath
, "lib", "ClangdXPC.framework",
35 return std::string(LibClangPath
.str());
38 static void dumpXPCObject(xpc_object_t Object
, llvm::raw_ostream
&OS
) {
39 xpc_type_t Type
= xpc_get_type(Object
);
40 if (Type
== XPC_TYPE_DICTIONARY
) {
41 json::Value Json
= clang::clangd::xpcToJson(Object
);
48 int main(int argc
, char *argv
[]) {
49 // Open the ClangdXPC dylib in the framework.
50 std::string LibPath
= getLibraryPath();
51 void *dlHandle
= dlopen(LibPath
.c_str(), RTLD_LOCAL
| RTLD_FIRST
);
53 llvm::errs() << "Failed to load framework from \'" << LibPath
<< "\'\n";
57 // Lookup the XPC service bundle name, and launch it.
58 clangd_xpc_get_bundle_identifier_t clangd_xpc_get_bundle_identifier
=
59 (clangd_xpc_get_bundle_identifier_t
)dlsym(
60 dlHandle
, "clangd_xpc_get_bundle_identifier");
61 xpc_connection_t conn
= xpc_connection_create(
62 clangd_xpc_get_bundle_identifier(), dispatch_get_main_queue());
64 // Dump the XPC events.
65 xpc_connection_set_event_handler(conn
, ^(xpc_object_t event
) {
66 if (event
== XPC_ERROR_CONNECTION_INVALID
) {
67 llvm::errs() << "Received XPC_ERROR_CONNECTION_INVALID.";
70 if (event
== XPC_ERROR_CONNECTION_INTERRUPTED
) {
71 llvm::errs() << "Received XPC_ERROR_CONNECTION_INTERRUPTED.";
75 dumpXPCObject(event
, llvm::outs());
79 xpc_connection_resume(conn
);
81 // Read the input to determine the things to send to clangd.
82 llvm::ErrorOr
<std::unique_ptr
<MemoryBuffer
>> Stdin
=
83 llvm::MemoryBuffer::getSTDIN();
85 llvm::errs() << "Failed to get STDIN!\n";
88 for (llvm::line_iterator
It(**Stdin
, /*SkipBlanks=*/true,
89 /*CommentMarker=*/'#');
90 !It
.is_at_eof(); ++It
) {
92 if (auto Request
= json::parse(Line
)) {
93 xpc_object_t Object
= clangd::jsonToXpc(*Request
);
94 xpc_connection_send_message(conn
, Object
);
96 llvm::errs() << llvm::Twine("JSON parse error: ")
97 << llvm::toString(Request
.takeError());
104 // dispatch_main() doesn't return