| //===--- sourcekitdInProc.cpp ---------------------------------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "sourcekitd/Internal.h" |
| |
| #include "SourceKit/Support/Concurrency.h" |
| #include "SourceKit/Support/UIdent.h" |
| |
| #include "llvm/Support/Mutex.h" |
| #include "llvm/Support/Path.h" |
| |
| // FIXME: Portability ? |
| #include <Block.h> |
| #include <dispatch/dispatch.h> |
| |
| #ifdef LLVM_ON_WIN32 |
| #include <windows.h> |
| #else |
| #include <dlfcn.h> |
| #endif |
| |
| using namespace SourceKit; |
| |
| static llvm::sys::Mutex GlobalHandlersMtx; |
| static sourcekitd_uid_handler_t UidMappingHandler; |
| static sourcekitd_str_from_uid_handler_t StrFromUidMappingHandler; |
| |
| void |
| sourcekitd_set_uid_handler(sourcekitd_uid_handler_t handler) { |
| llvm::sys::ScopedLock L(GlobalHandlersMtx); |
| sourcekitd_uid_handler_t newHandler = Block_copy(handler); |
| Block_release(UidMappingHandler); |
| UidMappingHandler = newHandler; |
| } |
| |
| void |
| sourcekitd_set_uid_handlers(sourcekitd_uid_from_str_handler_t uid_from_str, |
| sourcekitd_str_from_uid_handler_t str_from_uid) { |
| llvm::sys::ScopedLock L(GlobalHandlersMtx); |
| |
| sourcekitd_uid_handler_t newUIDFromStrHandler = Block_copy(uid_from_str); |
| Block_release(UidMappingHandler); |
| UidMappingHandler = newUIDFromStrHandler; |
| |
| sourcekitd_str_from_uid_handler_t newStrFromUIDHandler = Block_copy(str_from_uid); |
| Block_release(StrFromUidMappingHandler); |
| StrFromUidMappingHandler = newStrFromUIDHandler; |
| } |
| |
| sourcekitd_uid_t sourcekitd::SKDUIDFromUIdent(UIdent UID) { |
| if (void *Tag = UID.getTag()) |
| return reinterpret_cast<sourcekitd_uid_t>(Tag); |
| |
| if (UidMappingHandler) { |
| sourcekitd_uid_t skduid = UidMappingHandler(UID.c_str()); |
| if (skduid) { |
| UID.setTag(skduid); |
| return skduid; |
| } |
| } |
| |
| return reinterpret_cast<sourcekitd_uid_t>(UID.getAsOpaqueValue()); |
| } |
| |
| UIdent sourcekitd::UIdentFromSKDUID(sourcekitd_uid_t uid) { |
| if (StrFromUidMappingHandler) |
| return UIdent(StrFromUidMappingHandler(uid)); |
| |
| return UIdent::getFromOpaqueValue(uid); |
| } |
| |
| std::string sourcekitd::getRuntimeLibPath() { |
| // FIXME: Move to an LLVM API. Note that libclang does the same thing. |
| #ifdef LLVM_ON_WIN32 |
| #error Not implemented |
| #else |
| // This silly cast below avoids a C++ warning. |
| Dl_info info; |
| if (dladdr((void *)(uintptr_t)sourcekitd_initialize, &info) == 0) |
| llvm_unreachable("Call to dladdr() failed"); |
| |
| // We now have the path to the shared lib, move to the parent 'lib' path. |
| return llvm::sys::path::parent_path(info.dli_fname); |
| #endif |
| } |
| |
| void sourcekitd::set_interrupted_connection_handler( |
| sourcekitd_interrupted_connection_handler_t handler) { |
| } |
| |
| //----------------------------------------------------------------------------// |
| // sourcekitd_request_sync |
| //----------------------------------------------------------------------------// |
| |
| sourcekitd_response_t sourcekitd_send_request_sync(sourcekitd_object_t req) { |
| dispatch_semaphore_t sema = dispatch_semaphore_create(0); |
| |
| sourcekitd_response_t ReturnedResp; |
| sourcekitd::handleRequest(req, [&](sourcekitd_response_t resp) { |
| ReturnedResp = resp; |
| dispatch_semaphore_signal(sema); |
| }); |
| |
| dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); |
| dispatch_release(sema); |
| return ReturnedResp; |
| } |
| |
| void sourcekitd_send_request(sourcekitd_object_t req, |
| sourcekitd_request_handle_t *out_handle, |
| sourcekitd_response_receiver_t receiver) { |
| // FIXME: Implement request handle. |
| |
| sourcekitd_request_retain(req); |
| receiver = Block_copy(receiver); |
| WorkQueue::dispatchConcurrent([=]{ |
| sourcekitd::handleRequest(req, [&](sourcekitd_response_t resp) { |
| // The receiver accepts ownership of the response. |
| receiver(resp); |
| Block_release(receiver); |
| }); |
| sourcekitd_request_release(req); |
| }); |
| } |
| |
| void sourcekitd_cancel_request(sourcekitd_request_handle_t handle) { |
| // FIXME: Implement cancelling. |
| } |
| |
| void |
| sourcekitd_set_interrupted_connection_handler( |
| sourcekitd_interrupted_connection_handler_t handler) { |
| // This is only meaningful in an IPC implementation. |
| } |
| |
| static sourcekitd_response_receiver_t NotificationReceiver; |
| |
| void |
| sourcekitd_set_notification_handler(sourcekitd_response_receiver_t receiver) { |
| sourcekitd_response_receiver_t newReceiver = Block_copy(receiver); |
| WorkQueue::dispatchOnMain([=]{ |
| Block_release(NotificationReceiver); |
| NotificationReceiver = newReceiver; |
| }); |
| } |
| |
| void sourcekitd::postNotification(sourcekitd_response_t Notification) { |
| sourcekitd_response_receiver_t receiver = Block_copy(NotificationReceiver); |
| if (!receiver) { |
| sourcekitd_response_dispose(Notification); |
| return; |
| } |
| |
| WorkQueue::dispatchOnMain([=]{ |
| // The receiver accepts ownership of the notification object. |
| receiver(Notification); |
| Block_release(receiver); |
| }); |
| } |