1//===-- ClangdXPCTestClient.cpp ----------------------------------*- 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 "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"
16#include <dlfcn.h>
17#include <stdio.h>
18#include <string>
19#include <xpc/xpc.h>
20
21typedef const char *(*clangd_xpc_get_bundle_identifier_t)(void);
22
23using namespace llvm;
24using namespace clang;
25
26static std::string getLibraryPath() {
27 Dl_info info;
28 if (dladdr(address: (void *)(uintptr_t)getLibraryPath, info: &info) == 0)
29 llvm_unreachable("Call to dladdr() failed");
30 llvm::SmallString<128> LibClangPath;
31 LibClangPath = llvm::sys::path::parent_path(
32 path: llvm::sys::path::parent_path(path: info.dli_fname));
33 llvm::sys::path::append(LibClangPath, "lib", "ClangdXPC.framework",
34 "ClangdXPC");
35 return std::string(LibClangPath.str());
36}
37
38static 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);
42 OS << Json;
43 } else {
44 OS << "<UNKNOWN>";
45 }
46}
47
48int 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);
52 if (!dlHandle) {
53 llvm::errs() << "Failed to load framework from \'" << LibPath << "\'\n";
54 return 1;
55 }
56
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 handle: dlHandle, name: "clangd_xpc_get_bundle_identifier");
61 xpc_connection_t conn = xpc_connection_create(
62 clangd_xpc_get_bundle_identifier(), dispatch_get_main_queue());
63
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.";
68 exit(EXIT_SUCCESS);
69 }
70 if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
71 llvm::errs() << "Received XPC_ERROR_CONNECTION_INTERRUPTED.";
72 exit(EXIT_SUCCESS);
73 }
74
75 dumpXPCObject(event, llvm::outs());
76 llvm::outs() << "\n";
77 });
78
79 xpc_connection_resume(conn);
80
81 // Read the input to determine the things to send to clangd.
82 llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> Stdin =
83 llvm::MemoryBuffer::getSTDIN();
84 if (!Stdin) {
85 llvm::errs() << "Failed to get STDIN!\n";
86 return 1;
87 }
88 for (llvm::line_iterator It(**Stdin, /*SkipBlanks=*/true,
89 /*CommentMarker=*/'#');
90 !It.is_at_eof(); ++It) {
91 StringRef Line = *It;
92 if (auto Request = json::parse(JSON: Line)) {
93 xpc_object_t Object = clangd::jsonToXpc(*Request);
94 xpc_connection_send_message(conn, Object);
95 } else {
96 llvm::errs() << llvm::Twine("JSON parse error: ")
97 << llvm::toString(E: Request.takeError());
98 return 1;
99 }
100 }
101
102 dispatch_main();
103
104 // dispatch_main() doesn't return
105 return EXIT_FAILURE;
106}
107

source code of clang-tools-extra/clangd/xpc/test-client/ClangdXPCTestClient.cpp