summaryrefslogtreecommitdiff
path: root/clang-tools-extra/clangd/xpc/test-client/ClangdXPCTestClient.cpp
diff options
context:
space:
mode:
authorJan Korous <jkorous@apple.com>2019-01-16 00:24:22 +0000
committerJan Korous <jkorous@apple.com>2019-01-16 00:24:22 +0000
commitde3bade227c6caf680cebb3fa995d017ad99a771 (patch)
treefeb25812c37ed5e408643d851fe177f5710160fc /clang-tools-extra/clangd/xpc/test-client/ClangdXPCTestClient.cpp
parentd6ecaee1815084cc81ec145677f085d1fa591afc (diff)
[clangd] XPC transport layer
- New transport layer for macOS. - XPC Framework - Test client Framework and client were written by Alex Lorenz. Differential Revision: https://reviews.llvm.org/D54428
Diffstat (limited to 'clang-tools-extra/clangd/xpc/test-client/ClangdXPCTestClient.cpp')
-rw-r--r--clang-tools-extra/clangd/xpc/test-client/ClangdXPCTestClient.cpp96
1 files changed, 96 insertions, 0 deletions
diff --git a/clang-tools-extra/clangd/xpc/test-client/ClangdXPCTestClient.cpp b/clang-tools-extra/clangd/xpc/test-client/ClangdXPCTestClient.cpp
new file mode 100644
index 00000000000..da204a6925a
--- /dev/null
+++ b/clang-tools-extra/clangd/xpc/test-client/ClangdXPCTestClient.cpp
@@ -0,0 +1,96 @@
+#include "xpc/Conversion.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/LineIterator.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string>
+#include <xpc/xpc.h>
+
+typedef const char *(*clangd_xpc_get_bundle_identifier_t)(void);
+
+using namespace llvm;
+using namespace clang;
+
+std::string getLibraryPath() {
+ Dl_info info;
+ if (dladdr((void *)(uintptr_t)getLibraryPath, &info) == 0)
+ llvm_unreachable("Call to dladdr() failed");
+ llvm::SmallString<128> LibClangPath;
+ LibClangPath = llvm::sys::path::parent_path(
+ llvm::sys::path::parent_path(info.dli_fname));
+ llvm::sys::path::append(LibClangPath, "lib", "ClangdXPC.framework",
+ "ClangdXPC");
+ return LibClangPath.str();
+}
+
+static void dumpXPCObject(xpc_object_t Object, llvm::raw_ostream &OS) {
+ xpc_type_t Type = xpc_get_type(Object);
+ if (Type == XPC_TYPE_DICTIONARY) {
+ json::Value Json = clang::clangd::xpcToJson(Object);
+ OS << Json;
+ } else {
+ OS << "<UNKNOWN>";
+ }
+}
+
+int main(int argc, char *argv[]) {
+ // Open the ClangdXPC dylib in the framework.
+ std::string LibPath = getLibraryPath();
+ void *dlHandle = dlopen(LibPath.c_str(), RTLD_LOCAL | RTLD_FIRST);
+ if (!dlHandle)
+ return 1;
+
+ // Lookup the XPC service bundle name, and launch it.
+ clangd_xpc_get_bundle_identifier_t clangd_xpc_get_bundle_identifier =
+ (clangd_xpc_get_bundle_identifier_t)dlsym(
+ dlHandle, "clangd_xpc_get_bundle_identifier");
+ xpc_connection_t conn = xpc_connection_create(
+ clangd_xpc_get_bundle_identifier(), dispatch_get_main_queue());
+
+ // Dump the XPC events.
+ xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
+ if (event == XPC_ERROR_CONNECTION_INVALID) {
+ llvm::errs() << "Received XPC_ERROR_CONNECTION_INVALID.";
+ exit(EXIT_SUCCESS);
+ }
+ if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
+ llvm::errs() << "Received XPC_ERROR_CONNECTION_INTERRUPTED.";
+ exit(EXIT_SUCCESS);
+ }
+
+ dumpXPCObject(event, llvm::outs());
+ llvm::outs() << "\n";
+ });
+
+ xpc_connection_resume(conn);
+
+ // Read the input to determine the things to send to clangd.
+ llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> Stdin =
+ llvm::MemoryBuffer::getSTDIN();
+ if (!Stdin) {
+ llvm::errs() << "Failed to get STDIN!\n";
+ return 1;
+ }
+ for (llvm::line_iterator It(**Stdin, /*SkipBlanks=*/true,
+ /*CommentMarker=*/'#');
+ !It.is_at_eof(); ++It) {
+ StringRef Line = *It;
+ if (auto Request = json::parse(Line)) {
+ xpc_object_t Object = clangd::jsonToXpc(*Request);
+ xpc_connection_send_message(conn, Object);
+ } else {
+ llvm::errs() << llvm::Twine("JSON parse error: ")
+ << llvm::toString(Request.takeError());
+ return 1;
+ }
+ }
+
+ dispatch_main();
+
+ // dispatch_main() doesn't return
+ return EXIT_FAILURE;
+}