| //===--- sourcekitdAPI-XPC.cpp --------------------------------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "DictionaryKeys.h" |
| #include "sourcekitd/CodeCompletionResultsArray.h" |
| #include "sourcekitd/DocStructureArray.h" |
| #include "sourcekitd/DocSupportAnnotationArray.h" |
| #include "sourcekitd/TokenAnnotationsArray.h" |
| #include "sourcekitd/RequestResponsePrinterBase.h" |
| #include "SourceKit/Support/UIdent.h" |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| #include <vector> |
| #include <xpc/xpc.h> |
| |
| using namespace SourceKit; |
| using namespace sourcekitd; |
| using llvm::ArrayRef; |
| using llvm::StringRef; |
| using llvm::raw_ostream; |
| |
| namespace { |
| |
| class CustomXPCData { |
| public: |
| enum class Kind : char { |
| ErrorRequestInvalid, |
| ErrorRequestFailed, |
| ErrorRequestInterrupted, |
| ErrorRequestCancelled |
| }; |
| |
| explicit CustomXPCData(xpc_object_t xobj) : XObj(xobj) { |
| assert(xpc_get_type(XObj) == XPC_TYPE_DATA); |
| assert(getLength() > 0); |
| } |
| |
| xpc_object_t getXObj() const { return XObj; } |
| |
| Kind getKind() const { return Kind(getPtr()[0]); } |
| |
| const char *getPtr() const { |
| return (const char *)xpc_data_get_bytes_ptr(XObj); |
| } |
| size_t getLength() const { |
| return xpc_data_get_length(XObj); |
| } |
| |
| bool isError() const { |
| return true; // No other kind for now. |
| } |
| |
| const char *getErrorDescription() const { |
| assert(isError()); |
| assert(getLength() > 1); |
| return getPtr()+1; |
| } |
| |
| static CustomXPCData createErrorRequestInvalid(const char *Description) { |
| return createKindAndString(Kind::ErrorRequestInvalid, Description); |
| } |
| static CustomXPCData createErrorRequestFailed(const char *Description) { |
| return createKindAndString(Kind::ErrorRequestFailed, Description); |
| } |
| static CustomXPCData createErrorRequestInterrupted(const char *Description) { |
| return createKindAndString(Kind::ErrorRequestInterrupted, Description); |
| } |
| static CustomXPCData createErrorRequestCancelled(const char *Description) { |
| return createKindAndString(Kind::ErrorRequestCancelled, Description); |
| } |
| |
| private: |
| static CustomXPCData createKindAndString(Kind K, const char *Str) { |
| llvm::SmallVector<char, 128> Buf; |
| Buf.push_back((char)K); |
| Buf.append(Str, Str+strlen(Str)+1); |
| return CustomXPCData(xpc_data_create(Buf.begin(), Buf.size())); |
| } |
| |
| xpc_object_t XObj; |
| }; |
| |
| template <typename ImplClass, typename RetTy = void> |
| class SKDObjectVisitor { |
| public: |
| typedef std::vector<std::pair<UIdent, sourcekitd_object_t>> DictMap; |
| |
| static bool compKeys(const std::pair<UIdent, sourcekitd_object_t> &LHS, |
| const std::pair<UIdent, sourcekitd_object_t> &RHS) { |
| return sourcekitd::compareDictKeys(LHS.first, RHS.first); |
| } |
| |
| RetTy visit(sourcekitd_object_t Obj) { |
| xpc_type_t XType = xpc_get_type(Obj); |
| if (XType == XPC_TYPE_DICTIONARY) { |
| DictMap Dict; |
| DictMap &DictRef = Dict; |
| xpc_dictionary_apply(Obj, ^(const char *Key, xpc_object_t Value) { |
| UIdent UID = UIdent(Key); |
| DictRef.push_back({ UID, Value }); |
| return true; |
| }); |
| std::sort(Dict.begin(), Dict.end(), compKeys); |
| return static_cast<ImplClass*>(this)->visitDictionary(Dict); |
| } |
| if (XType == XPC_TYPE_ARRAY) { |
| std::vector<sourcekitd_object_t> Vec; |
| for (size_t i = 0, e = xpc_array_get_count(Obj); i != e; ++i) |
| Vec.push_back(xpc_array_get_value(Obj, i)); |
| return static_cast<ImplClass*>(this)->visitArray(Vec); |
| } |
| if (XType == XPC_TYPE_INT64) |
| return static_cast<ImplClass*>(this)->visitInt64(xpc_int64_get_value(Obj)); |
| if (XType == XPC_TYPE_STRING) { |
| size_t Len = xpc_string_get_length(Obj); |
| const char *Ptr = xpc_string_get_string_ptr(Obj); |
| return static_cast<ImplClass*>(this)->visitString(StringRef(Ptr, Len)); |
| } |
| if (XType == XPC_TYPE_UINT64) { |
| sourcekitd_uid_t SKDUID = sourcekitd_uid_t(xpc_uint64_get_value(Obj)); |
| UIdent UID = UIdentFromSKDUID(SKDUID); |
| return static_cast<ImplClass*>(this)->visitUID(UID.getName()); |
| } |
| |
| llvm_unreachable("unknown sourcekitd_object_t"); |
| } |
| }; |
| |
| class SKDObjectPrinter : public SKDObjectVisitor<SKDObjectPrinter>, |
| public RequestResponsePrinterBase<SKDObjectPrinter, |
| sourcekitd_object_t> { |
| public: |
| SKDObjectPrinter(raw_ostream &OS, unsigned Indent = 0) |
| : RequestResponsePrinterBase(OS, Indent) { } |
| }; |
| |
| } // anonymous namespace |
| |
| void sourcekitd::printRequestObject(sourcekitd_object_t Obj, raw_ostream &OS) { |
| if (!Obj) { |
| OS << "<<NULL>>"; |
| return; |
| } |
| |
| SKDObjectPrinter(OS).visit(Obj); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Internal API |
| //===----------------------------------------------------------------------===// |
| |
| ResponseBuilder::ResponseBuilder() { |
| Impl = xpc_dictionary_create(nullptr, nullptr, 0); |
| } |
| |
| ResponseBuilder::~ResponseBuilder() { |
| xpc_release(Impl); |
| } |
| |
| ResponseBuilder::ResponseBuilder(const ResponseBuilder &Other) { |
| Impl = xpc_retain(Other.Impl); |
| } |
| |
| ResponseBuilder &ResponseBuilder::operator =(const ResponseBuilder &Other) { |
| xpc_object_t Tmp = xpc_retain(Other.Impl); |
| xpc_release(Impl); |
| Impl = Tmp; |
| return *this; |
| } |
| |
| ResponseBuilder::Dictionary ResponseBuilder::getDictionary() { |
| return Dictionary(Impl); |
| } |
| |
| sourcekitd_response_t ResponseBuilder::createResponse() { |
| return xpc_retain(Impl); |
| } |
| |
| void ResponseBuilder::Dictionary::set(UIdent Key, SourceKit::UIdent UID) { |
| set(Key, SKDUIDFromUIdent(UID)); |
| } |
| |
| void ResponseBuilder::Dictionary::set(UIdent Key, sourcekitd_uid_t UID) { |
| xpc_dictionary_set_uint64(Impl, Key.c_str(), uintptr_t(UID)); |
| } |
| |
| void ResponseBuilder::Dictionary::set(UIdent Key, const char *Str) { |
| xpc_dictionary_set_string(Impl, Key.c_str(), Str); |
| } |
| |
| void ResponseBuilder::Dictionary::set(UIdent Key, llvm::StringRef Str) { |
| llvm::SmallString<512> Buf(Str); |
| xpc_dictionary_set_string(Impl, Key.c_str(), Buf.c_str()); |
| } |
| |
| void ResponseBuilder::Dictionary::set(UIdent Key, int64_t val) { |
| xpc_dictionary_set_int64(Impl, Key.c_str(), val); |
| } |
| |
| void ResponseBuilder::Dictionary::set(SourceKit::UIdent Key, |
| ArrayRef<StringRef> Strs) { |
| llvm::SmallString<128> Buf; |
| xpc_object_t arr = xpc_array_create(nullptr, 0); |
| for (auto Str : Strs) { |
| Buf = Str; |
| xpc_array_set_string(arr, XPC_ARRAY_APPEND, Buf.c_str()); |
| } |
| xpc_dictionary_set_value(Impl, Key.c_str(), arr); |
| xpc_release(arr); |
| } |
| |
| void ResponseBuilder::Dictionary::setBool(UIdent Key, bool val) { |
| xpc_dictionary_set_bool(Impl, Key.c_str(), val); |
| } |
| |
| ResponseBuilder::Array |
| ResponseBuilder::Dictionary::setArray(UIdent Key) { |
| xpc_object_t arr = xpc_array_create(nullptr, 0); |
| xpc_dictionary_set_value(Impl, Key.c_str(), arr); |
| xpc_release(arr); |
| return Array(arr); |
| } |
| |
| ResponseBuilder::Dictionary |
| ResponseBuilder::Dictionary::setDictionary(UIdent Key) { |
| xpc_object_t dict = xpc_dictionary_create(nullptr, nullptr, 0); |
| xpc_dictionary_set_value(Impl, Key.c_str(), dict); |
| xpc_release(dict); |
| return Dictionary(dict); |
| } |
| |
| void ResponseBuilder::Dictionary::setCustomBuffer( |
| SourceKit::UIdent Key, |
| CustomBufferKind Kind, std::unique_ptr<llvm::MemoryBuffer> MemBuf) { |
| |
| std::unique_ptr<llvm::MemoryBuffer> CustomBuf; |
| CustomBuf = llvm::MemoryBuffer::getNewUninitMemBuffer( |
| sizeof(uint64_t) + MemBuf->getBufferSize()); |
| char *BufPtr = (char*)CustomBuf->getBufferStart(); |
| *reinterpret_cast<uint64_t*>(BufPtr) = (uint64_t)Kind; |
| BufPtr += sizeof(uint64_t); |
| memcpy(BufPtr, MemBuf->getBufferStart(), MemBuf->getBufferSize()); |
| |
| xpc_object_t xdata = xpc_data_create(CustomBuf->getBufferStart(), |
| CustomBuf->getBufferSize()); |
| xpc_dictionary_set_value(Impl, Key.c_str(), xdata); |
| xpc_release(xdata); |
| } |
| |
| ResponseBuilder::Dictionary ResponseBuilder::Array::appendDictionary() { |
| xpc_object_t dict = xpc_dictionary_create(nullptr, nullptr, 0); |
| xpc_array_append_value(Impl, dict); |
| xpc_release(dict); |
| return Dictionary(dict); |
| } |
| |
| sourcekitd_uid_t RequestDict::getUID(UIdent Key) { |
| return sourcekitd_uid_t(xpc_dictionary_get_uint64(Dict, Key.c_str())); |
| } |
| |
| Optional<StringRef> RequestDict::getString(UIdent Key) { |
| xpc_object_t xobj = xpc_dictionary_get_value(Dict, Key.c_str()); |
| if (!xobj) |
| return None; |
| if (xpc_get_type(xobj) != XPC_TYPE_STRING) |
| return None; |
| return StringRef(xpc_string_get_string_ptr(xobj), |
| xpc_string_get_length(xobj)); |
| } |
| |
| Optional<RequestDict> RequestDict::getDictionary(SourceKit::UIdent Key) { |
| xpc_object_t xobj = xpc_dictionary_get_value(Dict, Key.c_str()); |
| if (!xobj) |
| return None; |
| if (xpc_get_type(xobj) != XPC_TYPE_DICTIONARY) |
| return None; |
| return RequestDict(xobj); |
| } |
| |
| bool RequestDict::getStringArray(SourceKit::UIdent Key, |
| llvm::SmallVectorImpl<const char *> &Arr, |
| bool isOptional) { |
| xpc_object_t xarr = xpc_dictionary_get_value(Dict, Key.c_str()); |
| if (!xarr) |
| return !isOptional; |
| if (xpc_get_type(xarr) != XPC_TYPE_ARRAY) |
| return true; |
| size_t count = xpc_array_get_count(xarr); |
| Arr.reserve(count); |
| for (size_t i = 0; i != count; ++i) { |
| const char *Str = xpc_array_get_string(xarr, i); |
| if (!Str) |
| return true; |
| Arr.push_back(Str); |
| } |
| return false; |
| } |
| |
| bool RequestDict::getUIDArray(SourceKit::UIdent Key, |
| llvm::SmallVectorImpl<sourcekitd_uid_t> &Arr, |
| bool isOptional) { |
| xpc_object_t xarr = xpc_dictionary_get_value(Dict, Key.c_str()); |
| if (!xarr) |
| return !isOptional; |
| if (xpc_get_type(xarr) != XPC_TYPE_ARRAY) |
| return true; |
| size_t count = xpc_array_get_count(xarr); |
| Arr.reserve(count); |
| for (size_t i = 0; i != count; ++i) { |
| auto UID = sourcekitd_uid_t(xpc_array_get_uint64(xarr, i)); |
| if (!UID) |
| return true; |
| Arr.push_back(UID); |
| } |
| return false; |
| } |
| |
| bool RequestDict::dictionaryArrayApply( |
| SourceKit::UIdent key, llvm::function_ref<bool(RequestDict)> applier) { |
| xpc_object_t xarr = xpc_dictionary_get_value(Dict, key.c_str()); |
| if (!xarr || xpc_get_type(xarr) != XPC_TYPE_ARRAY) |
| return true; |
| size_t count = xpc_array_get_count(xarr); |
| for (size_t i = 0; i != count; ++i) { |
| auto xdict = xpc_array_get_value(xarr, i); |
| if (!xdict || xpc_get_type(xdict) != XPC_TYPE_DICTIONARY) |
| return true; |
| if (applier(RequestDict(xdict))) |
| return true; |
| } |
| return false; |
| } |
| |
| bool RequestDict::getInt64(SourceKit::UIdent Key, int64_t &Val, |
| bool isOptional) { |
| xpc_object_t xobj = xpc_dictionary_get_value(Dict, Key.c_str()); |
| if (!xobj) |
| return !isOptional; |
| Val = xpc_int64_get_value(xobj); |
| return false; |
| } |
| |
| Optional<int64_t> RequestDict::getOptionalInt64(SourceKit::UIdent Key) { |
| xpc_object_t xobj = xpc_dictionary_get_value(Dict, Key.c_str()); |
| if (!xobj) |
| return None; |
| return xpc_int64_get_value(xobj); |
| } |
| |
| sourcekitd_response_t |
| sourcekitd::createErrorRequestInvalid(const char *Description) { |
| return CustomXPCData::createErrorRequestInvalid(Description).getXObj(); |
| } |
| sourcekitd_response_t |
| sourcekitd::createErrorRequestFailed(const char *Description) { |
| return CustomXPCData::createErrorRequestFailed(Description).getXObj(); |
| } |
| sourcekitd_response_t |
| sourcekitd::createErrorRequestInterrupted(const char *Description) { |
| return CustomXPCData::createErrorRequestInterrupted(Description).getXObj(); |
| } |
| sourcekitd_response_t |
| sourcekitd::createErrorRequestCancelled() { |
| return CustomXPCData::createErrorRequestCancelled("").getXObj(); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Public Request API |
| //===----------------------------------------------------------------------===// |
| |
| static inline const char *strFromUID(sourcekitd_uid_t uid) { |
| return UIdentFromSKDUID(uid).c_str(); |
| } |
| |
| sourcekitd_object_t |
| sourcekitd_request_retain(sourcekitd_object_t object) { |
| return xpc_retain(object); |
| } |
| |
| void sourcekitd_request_release(sourcekitd_object_t object) { |
| xpc_release(object); |
| } |
| |
| sourcekitd_object_t |
| sourcekitd_request_dictionary_create(const sourcekitd_uid_t *keys, |
| const sourcekitd_object_t *values, |
| size_t count) { |
| llvm::SmallVector<const char *, 8> Keys; |
| Keys.reserve(count); |
| for (size_t i = 0; i < count; ++i) |
| Keys.push_back(strFromUID(keys[i])); |
| return xpc_dictionary_create(Keys.data(), values, count); |
| } |
| |
| void |
| sourcekitd_request_dictionary_set_value(sourcekitd_object_t dict, |
| sourcekitd_uid_t key, |
| sourcekitd_object_t value) { |
| xpc_dictionary_set_value(dict, strFromUID(key), value); |
| } |
| |
| void sourcekitd_request_dictionary_set_string(sourcekitd_object_t dict, |
| sourcekitd_uid_t key, |
| const char *string) { |
| xpc_dictionary_set_string(dict, strFromUID(key), string); |
| } |
| |
| void |
| sourcekitd_request_dictionary_set_stringbuf(sourcekitd_object_t dict, |
| sourcekitd_uid_t key, |
| const char *buf, size_t length) { |
| llvm::SmallString<512> SS; |
| SS += StringRef(buf, length); |
| sourcekitd_request_dictionary_set_string(dict, key, SS.c_str()); |
| } |
| |
| void sourcekitd_request_dictionary_set_int64(sourcekitd_object_t dict, |
| sourcekitd_uid_t key, |
| int64_t val) { |
| xpc_dictionary_set_int64(dict, strFromUID(key), val); |
| } |
| |
| void |
| sourcekitd_request_dictionary_set_uid(sourcekitd_object_t dict, |
| sourcekitd_uid_t key, |
| sourcekitd_uid_t uid) { |
| xpc_dictionary_set_uint64(dict, strFromUID(key), uintptr_t(uid)); |
| } |
| |
| sourcekitd_object_t |
| sourcekitd_request_array_create(const sourcekitd_object_t *objects, |
| size_t count) { |
| return xpc_array_create(objects, count); |
| } |
| |
| void |
| sourcekitd_request_array_set_value(sourcekitd_object_t array, size_t index, |
| sourcekitd_object_t value) { |
| xpc_array_set_value(array, index, value); |
| } |
| |
| void |
| sourcekitd_request_array_set_string(sourcekitd_object_t array, size_t index, |
| const char *string) { |
| xpc_array_set_string(array, index, string); |
| } |
| |
| void |
| sourcekitd_request_array_set_stringbuf(sourcekitd_object_t array, size_t index, |
| const char *buf, size_t length) { |
| llvm::SmallString<512> SS; |
| SS += StringRef(buf, length); |
| sourcekitd_request_array_set_string(array, index, SS.c_str()); |
| } |
| |
| void |
| sourcekitd_request_array_set_int64(sourcekitd_object_t array, size_t index, |
| int64_t val) { |
| xpc_array_set_int64(array, index, val); |
| } |
| |
| void |
| sourcekitd_request_array_set_uid(sourcekitd_object_t array, size_t index, |
| sourcekitd_uid_t uid) { |
| xpc_array_set_uint64(array, index, uintptr_t(uid)); |
| } |
| |
| sourcekitd_object_t |
| sourcekitd_request_int64_create(int64_t val) { |
| return xpc_int64_create(val); |
| } |
| |
| sourcekitd_object_t |
| sourcekitd_request_string_create(const char *string) { |
| return xpc_string_create(string); |
| } |
| |
| sourcekitd_object_t |
| sourcekitd_request_uid_create(sourcekitd_uid_t uid) { |
| return xpc_uint64_create(uintptr_t(uid)); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Public Response API |
| //===----------------------------------------------------------------------===// |
| |
| void |
| sourcekitd_response_dispose(sourcekitd_response_t obj) { |
| xpc_release(obj); |
| } |
| |
| bool |
| sourcekitd_response_is_error(sourcekitd_response_t obj) { |
| xpc_type_t type = xpc_get_type(obj); |
| if (type == XPC_TYPE_ERROR) |
| return true; |
| if (type == XPC_TYPE_DATA) { |
| CustomXPCData Dat(obj); |
| return Dat.isError(); |
| } |
| return false; |
| } |
| |
| sourcekitd_error_t |
| sourcekitd_response_error_get_kind(sourcekitd_response_t obj) { |
| xpc_type_t type = xpc_get_type(obj); |
| if (type == XPC_TYPE_ERROR) { |
| if (obj == XPC_ERROR_CONNECTION_INTERRUPTED) |
| return SOURCEKITD_ERROR_CONNECTION_INTERRUPTED; |
| // This can originate if the client initiated shutdown. |
| if (obj == XPC_ERROR_CONNECTION_INVALID) |
| return SOURCEKITD_ERROR_REQUEST_CANCELLED; |
| } |
| if (type == XPC_TYPE_DATA) { |
| CustomXPCData Dat(obj); |
| switch (Dat.getKind()) { |
| case CustomXPCData::Kind::ErrorRequestInvalid: |
| return SOURCEKITD_ERROR_REQUEST_INVALID; |
| case CustomXPCData::Kind::ErrorRequestFailed: |
| return SOURCEKITD_ERROR_REQUEST_FAILED; |
| case CustomXPCData::Kind::ErrorRequestInterrupted: |
| return SOURCEKITD_ERROR_CONNECTION_INTERRUPTED; |
| case CustomXPCData::Kind::ErrorRequestCancelled: |
| return SOURCEKITD_ERROR_REQUEST_CANCELLED; |
| } |
| } |
| |
| llvm::report_fatal_error("sourcekitd error did not resolve to a known kind"); |
| } |
| |
| const char * |
| sourcekitd_response_error_get_description(sourcekitd_response_t obj) { |
| xpc_type_t type = xpc_get_type(obj); |
| if (type == XPC_TYPE_ERROR) |
| return xpc_dictionary_get_string(obj, XPC_ERROR_KEY_DESCRIPTION); |
| if (type == XPC_TYPE_DATA) { |
| CustomXPCData Dat(obj); |
| if (Dat.isError()) |
| return Dat.getErrorDescription(); |
| } |
| |
| llvm::report_fatal_error("invalid sourcekitd error object"); |
| } |
| |
| static sourcekitd_variant_t variantFromXPCObject(xpc_object_t obj); |
| |
| sourcekitd_variant_t |
| sourcekitd_response_get_value(sourcekitd_response_t resp) { |
| if (sourcekitd_response_is_error(resp)) |
| return makeNullVariant(); |
| return variantFromXPCObject(resp); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Variant functions |
| //===----------------------------------------------------------------------===// |
| |
| #define XPC_OBJ(var) ((xpc_object_t)(var).data[1]) |
| |
| #define CUSTOM_BUF_KIND(xobj) \ |
| ((CustomBufferKind)*(uint64_t*)xpc_data_get_bytes_ptr(xobj)) |
| #define CUSTOM_BUF_START(xobj) \ |
| ((void*)(((uint64_t*)xpc_data_get_bytes_ptr(xobj))+1)) |
| |
| static sourcekitd_variant_type_t XPCVar_get_type(sourcekitd_variant_t var) { |
| xpc_object_t obj = XPC_OBJ(var); |
| |
| xpc_type_t type = xpc_get_type(obj); |
| if (type == XPC_TYPE_DICTIONARY) |
| return SOURCEKITD_VARIANT_TYPE_DICTIONARY; |
| if (type == XPC_TYPE_ARRAY) |
| return SOURCEKITD_VARIANT_TYPE_ARRAY; |
| if (type == XPC_TYPE_INT64) |
| return SOURCEKITD_VARIANT_TYPE_INT64; |
| if (type == XPC_TYPE_BOOL) |
| return SOURCEKITD_VARIANT_TYPE_BOOL; |
| if (type == XPC_TYPE_STRING) |
| return SOURCEKITD_VARIANT_TYPE_STRING; |
| // Take over XPC's UINT64 to mean SourceKitD's UID. |
| // This means that UINT64 will not be available to be constructed in a |
| // sourcekitd message. |
| if (type == XPC_TYPE_UINT64) |
| return SOURCEKITD_VARIANT_TYPE_UID; |
| |
| if (type == XPC_TYPE_DATA) { |
| switch(CUSTOM_BUF_KIND(obj)) { |
| case CustomBufferKind::TokenAnnotationsArray: |
| return SOURCEKITD_VARIANT_TYPE_ARRAY; |
| case CustomBufferKind::DocSupportAnnotationArray: |
| return SOURCEKITD_VARIANT_TYPE_ARRAY; |
| case CustomBufferKind::CodeCompletionResultsArray: |
| return SOURCEKITD_VARIANT_TYPE_ARRAY; |
| case CustomBufferKind::DocStructureArray: |
| case CustomBufferKind::InheritedTypesArray: |
| case CustomBufferKind::DocStructureElementArray: |
| case CustomBufferKind::AttributesArray: |
| return SOURCEKITD_VARIANT_TYPE_ARRAY; |
| } |
| } |
| |
| llvm::report_fatal_error("sourcekitd object did not resolve to a known type"); |
| } |
| |
| static bool XPCVar_array_apply( |
| sourcekitd_variant_t array, |
| llvm::function_ref<bool(size_t, sourcekitd_variant_t)> applier) { |
| return xpc_array_apply(XPC_OBJ(array), |
| ^(size_t index, xpc_object_t obj) { |
| return applier(index, variantFromXPCObject(obj)); |
| }); |
| } |
| |
| static bool XPCVar_array_get_bool(sourcekitd_variant_t array, size_t index) { |
| return xpc_array_get_bool(XPC_OBJ(array), index); |
| } |
| |
| static size_t XPCVar_array_get_count(sourcekitd_variant_t array) { |
| return xpc_array_get_count(XPC_OBJ(array)); |
| } |
| |
| static int64_t XPCVar_array_get_int64(sourcekitd_variant_t array, size_t index) { |
| return xpc_array_get_int64(XPC_OBJ(array), index); |
| } |
| |
| static const char * |
| XPCVar_array_get_string(sourcekitd_variant_t array, size_t index) { |
| return xpc_array_get_string(XPC_OBJ(array), index); |
| } |
| |
| static sourcekitd_uid_t XPCVar_array_get_uid(sourcekitd_variant_t array, size_t index) { |
| return sourcekitd_uid_t(xpc_array_get_uint64(XPC_OBJ(array), index)); |
| } |
| |
| static sourcekitd_variant_t |
| XPCVar_array_get_value(sourcekitd_variant_t array, size_t index) { |
| return variantFromXPCObject(xpc_array_get_value(XPC_OBJ(array), index)); |
| } |
| |
| static bool XPCVar_bool_get_value(sourcekitd_variant_t obj) { |
| return xpc_bool_get_value(XPC_OBJ(obj)); |
| } |
| |
| static bool XPCVar_dictionary_apply( |
| sourcekitd_variant_t dict, |
| llvm::function_ref<bool(sourcekitd_uid_t, sourcekitd_variant_t)> applier) { |
| return xpc_dictionary_apply(XPC_OBJ(dict), |
| ^(const char *key, xpc_object_t obj) { |
| return applier(sourcekitd_uid_get_from_cstr(key),variantFromXPCObject(obj)); |
| }); |
| } |
| |
| static bool |
| XPCVar_dictionary_get_bool(sourcekitd_variant_t dict, sourcekitd_uid_t key) { |
| return xpc_dictionary_get_bool(XPC_OBJ(dict), strFromUID(key)); |
| } |
| |
| static int64_t |
| XPCVar_dictionary_get_int64(sourcekitd_variant_t dict, sourcekitd_uid_t key) { |
| return xpc_dictionary_get_int64(XPC_OBJ(dict), strFromUID(key)); |
| } |
| |
| static const char * |
| XPCVar_dictionary_get_string(sourcekitd_variant_t dict, sourcekitd_uid_t key) { |
| return xpc_dictionary_get_string(XPC_OBJ(dict), strFromUID(key)); |
| } |
| |
| static sourcekitd_variant_t |
| XPCVar_dictionary_get_value(sourcekitd_variant_t dict, sourcekitd_uid_t key) { |
| return variantFromXPCObject( |
| xpc_dictionary_get_value(XPC_OBJ(dict), strFromUID(key))); |
| } |
| |
| static sourcekitd_uid_t |
| XPCVar_dictionary_get_uid(sourcekitd_variant_t dict, sourcekitd_uid_t key) { |
| return sourcekitd_uid_t( |
| xpc_dictionary_get_uint64(XPC_OBJ(dict), strFromUID(key))); |
| } |
| |
| static size_t XPCVar_string_get_length(sourcekitd_variant_t obj) { |
| return xpc_string_get_length(XPC_OBJ(obj)); |
| } |
| |
| static const char *XPCVar_string_get_ptr(sourcekitd_variant_t obj) { |
| return xpc_string_get_string_ptr(XPC_OBJ(obj)); |
| } |
| |
| static int64_t XPCVar_int64_get_value(sourcekitd_variant_t obj) { |
| return xpc_int64_get_value(XPC_OBJ(obj)); |
| } |
| |
| static sourcekitd_uid_t XPCVar_uid_get_value(sourcekitd_variant_t obj) { |
| return sourcekitd_uid_t(xpc_uint64_get_value(XPC_OBJ(obj))); |
| } |
| |
| |
| static VariantFunctions XPCVariantFuncs = { |
| XPCVar_get_type, |
| XPCVar_array_apply, |
| XPCVar_array_get_bool, |
| XPCVar_array_get_count, |
| XPCVar_array_get_int64, |
| XPCVar_array_get_string, |
| XPCVar_array_get_uid, |
| XPCVar_array_get_value, |
| XPCVar_bool_get_value, |
| XPCVar_dictionary_apply, |
| XPCVar_dictionary_get_bool, |
| XPCVar_dictionary_get_int64, |
| XPCVar_dictionary_get_string, |
| XPCVar_dictionary_get_value, |
| XPCVar_dictionary_get_uid, |
| XPCVar_string_get_length, |
| XPCVar_string_get_ptr, |
| XPCVar_int64_get_value, |
| XPCVar_uid_get_value |
| }; |
| |
| static sourcekitd_variant_t variantFromXPCObject(xpc_object_t obj) { |
| if (!obj) |
| return makeNullVariant(); |
| |
| if (xpc_get_type(obj) == XPC_TYPE_DATA) { |
| switch(CUSTOM_BUF_KIND(obj)) { |
| case CustomBufferKind::TokenAnnotationsArray: |
| return {{ (uintptr_t)getVariantFunctionsForTokenAnnotationsArray(), |
| (uintptr_t)CUSTOM_BUF_START(obj), 0 }}; |
| case CustomBufferKind::DocSupportAnnotationArray: |
| return {{ (uintptr_t)getVariantFunctionsForDocSupportAnnotationArray(), |
| (uintptr_t)CUSTOM_BUF_START(obj), 0 }}; |
| case CustomBufferKind::CodeCompletionResultsArray: |
| return {{ (uintptr_t)getVariantFunctionsForCodeCompletionResultsArray(), |
| (uintptr_t)CUSTOM_BUF_START(obj), 0 }}; |
| case CustomBufferKind::DocStructureArray: |
| return {{ (uintptr_t)getVariantFunctionsForDocStructureArray(), |
| (uintptr_t)CUSTOM_BUF_START(obj), ~size_t(0) }}; |
| case CustomBufferKind::InheritedTypesArray: |
| return {{ (uintptr_t)getVariantFunctionsForInheritedTypesArray(), |
| (uintptr_t)CUSTOM_BUF_START(obj), 0 }}; |
| case CustomBufferKind::DocStructureElementArray: |
| return {{ (uintptr_t)getVariantFunctionsForDocStructureElementArray(), |
| (uintptr_t)CUSTOM_BUF_START(obj), 0 }}; |
| case CustomBufferKind::AttributesArray: |
| return {{ (uintptr_t)getVariantFunctionsForAttributesArray(), |
| (uintptr_t)CUSTOM_BUF_START(obj), 0 }}; |
| } |
| } |
| |
| return {{ (uintptr_t)&XPCVariantFuncs, (uintptr_t)obj, 0 }}; |
| } |