blob: 5bda2f17af273a41185177b52cf34bafadd88284 [file] [log] [blame]
//===--- sourcekitdAPI-Common.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/Internal.h"
#include "sourcekitd/Logging.h"
#include "sourcekitd/RequestResponsePrinterBase.h"
#include "SourceKit/Support/Logging.h"
#include "SourceKit/Support/UIdent.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/YAMLParser.h"
#include <mutex>
using namespace SourceKit;
using namespace sourcekitd;
using llvm::ArrayRef;
using llvm::StringRef;
using llvm::raw_ostream;
#define KEY(NAME, CONTENT) UIdent sourcekitd::Key##NAME(CONTENT);
#include "SourceKit/Core/ProtocolUIDs.def"
/// Order for the keys to use when emitting the debug description of
/// dictionaries.
static UIdent *OrderedKeys[] = {
#define KEY(NAME, CONTENT) &Key##NAME,
#include "SourceKit/Core/ProtocolUIDs.def"
};
static unsigned findPrintOrderForDictKey(UIdent Key) {
unsigned Order = 1;
for (auto UIDPtr : OrderedKeys) {
if (*UIDPtr == Key)
return Order;
++Order;
}
return 10000;
}
bool sourcekitd::compareDictKeys(UIdent LHS, UIdent RHS) {
if (LHS == RHS)
return false;
unsigned LHSOrder = findPrintOrderForDictKey(LHS);
unsigned RHSOrder = findPrintOrderForDictKey(RHS);
if (LHSOrder == RHSOrder)
return LHS.getName() < RHS.getName();
return LHSOrder < RHSOrder;
}
namespace {
template <typename ImplClass,
typename RetTy = void>
class VariantVisitor {
public:
typedef std::vector<std::pair<UIdent, sourcekitd_variant_t>> DictMap;
static bool compKeys(const std::pair<UIdent, sourcekitd_variant_t> &LHS,
const std::pair<UIdent, sourcekitd_variant_t> &RHS) {
return sourcekitd::compareDictKeys(LHS.first, RHS.first);
}
RetTy visit(sourcekitd_variant_t Obj) {
switch (sourcekitd_variant_get_type(Obj)) {
case SOURCEKITD_VARIANT_TYPE_NULL:
return static_cast<ImplClass*>(this)->visitNull();
case SOURCEKITD_VARIANT_TYPE_DICTIONARY: {
DictMap Dict;
DictMap &DictRef = Dict;
sourcekitd_variant_dictionary_apply_impl(
Obj,
[&](sourcekitd_uid_t key, sourcekitd_variant_t value) {
DictRef.push_back({UIdentFromSKDUID(key), value});
return true;
});
std::sort(Dict.begin(), Dict.end(), compKeys);
return static_cast<ImplClass*>(this)->visitDictionary(Dict);
}
case SOURCEKITD_VARIANT_TYPE_ARRAY: {
std::vector<sourcekitd_variant_t> Vec;
for (size_t i = 0, e = sourcekitd_variant_array_get_count(Obj);
i != e; ++i)
Vec.push_back(sourcekitd_variant_array_get_value(Obj, i));
return static_cast<ImplClass*>(this)->visitArray(Vec);
}
case SOURCEKITD_VARIANT_TYPE_INT64:
return static_cast<ImplClass*>(this)->visitInt64(
sourcekitd_variant_int64_get_value(Obj));
case SOURCEKITD_VARIANT_TYPE_BOOL:
return static_cast<ImplClass*>(this)->visitBool(
sourcekitd_variant_bool_get_value(Obj));
case SOURCEKITD_VARIANT_TYPE_STRING: {
size_t Len = sourcekitd_variant_string_get_length(Obj);
const char *Ptr = sourcekitd_variant_string_get_ptr(Obj);
return static_cast<ImplClass*>(this)->visitString(StringRef(Ptr, Len));
}
case SOURCEKITD_VARIANT_TYPE_UID: {
sourcekitd_uid_t UID = sourcekitd_variant_uid_get_value(Obj);
size_t Len = sourcekitd_uid_get_length(UID);
const char *Ptr = sourcekitd_uid_get_string_ptr(UID);
return static_cast<ImplClass*>(this)->visitUID(StringRef(Ptr, Len));
}
case SOURCEKITD_VARIANT_TYPE_DATA: {
const void *Data = sourcekitd_variant_data_get_ptr(Obj);
size_t Size = sourcekitd_variant_data_get_size(Obj);
return static_cast<ImplClass*>(this)->visitData(Data, Size);
}
}
}
};
class VariantPrinter : public VariantVisitor<VariantPrinter>,
public RequestResponsePrinterBase<VariantPrinter,
sourcekitd_variant_t> {
public:
VariantPrinter(raw_ostream &OS, unsigned Indent = 0, bool PrintAsJSON = false)
: RequestResponsePrinterBase(OS, Indent, PrintAsJSON) { }
};
} // end anonymous namespace
void sourcekitd::writeEscaped(llvm::StringRef Str, llvm::raw_ostream &OS) {
for (unsigned i = 0, e = Str.size(); i != e; ++i) {
unsigned char c = Str[i];
switch (c) {
case '\\':
OS << '\\' << '\\';
break;
case '\t':
OS << '\\' << 't';
break;
case '\n':
OS << '\\' << 'n';
break;
case '"':
OS << '\\' << '"';
break;
default:
OS << c;
break;
}
}
}
static void printError(sourcekitd_response_t Err, raw_ostream &OS) {
OS << "error response (";
switch (sourcekitd_response_error_get_kind(Err)) {
case SOURCEKITD_ERROR_CONNECTION_INTERRUPTED:
OS << "Connection Interrupted"; break;
case SOURCEKITD_ERROR_REQUEST_INVALID:
OS << "Request Invalid"; break;
case SOURCEKITD_ERROR_REQUEST_FAILED:
OS << "Request Failed"; break;
case SOURCEKITD_ERROR_REQUEST_CANCELLED:
OS << "Request Cancelled"; break;
}
OS << "): ";
OS << sourcekitd_response_error_get_description(Err);
}
static void printVariant(sourcekitd_variant_t obj, raw_ostream &OS) {
VariantPrinter(OS).visit(obj);
}
void sourcekitd::printResponse(sourcekitd_response_t Resp, raw_ostream &OS) {
if (!Resp) {
OS << "<<NULL>>";
return;
}
if (sourcekitd_response_is_error(Resp))
printError(Resp, OS);
else
printVariant(sourcekitd_response_get_value(Resp), OS);
}
static void fatal_error_handler(void *user_data, const std::string& reason,
bool gen_crash_diag) {
// Write the result out to stderr avoiding errs() because raw_ostreams can
// call report_fatal_error.
// FIXME: Put the error message in the crash report.
fprintf(stderr, "SOURCEKITD FATAL ERROR: %s\n", reason.c_str());
::abort();
}
void sourcekitd::enableLogging(StringRef LoggerName) {
Logger::Level LogLevel = Logger::Level::Warning;
const char *EnvOpt = ::getenv("SOURCEKIT_LOGGING");
if (EnvOpt) {
int Val;
bool Err = StringRef(EnvOpt).getAsInteger(10, Val);
if (!Err) {
if (Val > 2)
LogLevel = Logger::Level::InfoLowPrio;
else if (Val == 2)
LogLevel = Logger::Level::InfoMediumPrio;
else if (Val == 1)
LogLevel = Logger::Level::InfoHighPrio;
}
}
Logger::enableLogging(LoggerName, LogLevel);
}
//===----------------------------------------------------------------------===//
// Public API
//===----------------------------------------------------------------------===//
static llvm::sys::Mutex GlobalInitMtx;
static unsigned gInitRefCount = 0;
bool sourcekitd::initializeClient() {
llvm::sys::ScopedLock L(GlobalInitMtx);
++gInitRefCount;
if (gInitRefCount > 1)
return false;
static std::once_flag flag;
std::call_once(flag, []() {
llvm::install_fatal_error_handler(fatal_error_handler, 0);
sourcekitd::enableLogging("sourcekit");
});
return true;
}
bool sourcekitd::shutdownClient() {
llvm::sys::ScopedLock L(GlobalInitMtx);
--gInitRefCount;
if (gInitRefCount > 0)
return false;
return true;
}
void
sourcekitd_response_description_dump(sourcekitd_response_t resp) {
// Avoid colors here, we don't properly detect that the debug window inside
// Xcode doesn't support colors.
llvm::SmallString<128> Desc;
llvm::raw_svector_ostream OS(Desc);
printResponse(resp, OS);
llvm::errs() << OS.str() << '\n';
}
void
sourcekitd_response_description_dump_filedesc(sourcekitd_response_t resp,
int fd) {
llvm::raw_fd_ostream OS(fd, /*shouldClose=*/false);
printResponse(resp, OS);
OS << '\n';
}
char *
sourcekitd_response_description_copy(sourcekitd_response_t resp) {
llvm::SmallString<128> Desc;
llvm::raw_svector_ostream OS(Desc);
printResponse(resp, OS);
return strdup(Desc.c_str());
}
sourcekitd_uid_t
sourcekitd_uid_get_from_cstr(const char *string) {
return SKDUIDFromUIdent(UIdent(string));
}
sourcekitd_uid_t
sourcekitd_uid_get_from_buf(const char *buf, size_t length) {
return SKDUIDFromUIdent(UIdent(llvm::StringRef(buf, length)));
}
size_t
sourcekitd_uid_get_length(sourcekitd_uid_t uid) {
UIdent UID = UIdentFromSKDUID(uid);
return UID.getName().size();
}
const char *
sourcekitd_uid_get_string_ptr(sourcekitd_uid_t uid) {
UIdent UID = UIdentFromSKDUID(uid);
return UID.getName().begin();
}
void
sourcekitd_request_description_dump(sourcekitd_object_t obj) {
// Avoid colors here, we don't properly detect that the debug window inside
// Xcode doesn't support colors.
llvm::SmallString<128> Desc;
llvm::raw_svector_ostream OS(Desc);
printRequestObject(obj, OS);
llvm::errs() << OS.str() << '\n';
}
char *
sourcekitd_request_description_copy(sourcekitd_object_t obj) {
llvm::SmallString<128> Desc;
llvm::raw_svector_ostream OS(Desc);
printRequestObject(obj, OS);
return strdup(Desc.c_str());
}
//===----------------------------------------------------------------------===//
// Variant API
//===----------------------------------------------------------------------===//
#define VAR_FN(var, name) ((var).data[0] ? \
((VariantFunctions*)(var).data[0])->name : nullptr)
sourcekitd_variant_type_t
sourcekitd_variant_get_type(sourcekitd_variant_t var) {
if (auto fn = VAR_FN(var, get_type))
return fn(var);
// Default implementation:
// Assume the variant encapsulates a basic type.
static_assert(SOURCEKITD_VARIANT_TYPE_NULL == 0,
"NULL type does not match null variant");
return (sourcekitd_variant_type_t)var.data[2];
}
sourcekitd_variant_t
sourcekitd_variant_dictionary_get_value(sourcekitd_variant_t dict,
sourcekitd_uid_t key) {
if (auto fn = VAR_FN(dict, dictionary_get_value))
return fn(dict, key);
// Default implementation:
// Linear search for the key/value pair via sourcekitd_variant_dictionary_apply.
sourcekitd_variant_t result = makeNullVariant();
sourcekitd_variant_dictionary_apply_impl(
dict, [&](sourcekitd_uid_t curr_key, sourcekitd_variant_t curr_value) {
if (curr_key == key) {
result = curr_value;
return false;
}
return true;
});
return result;
}
const char *
sourcekitd_variant_dictionary_get_string(sourcekitd_variant_t dict,
sourcekitd_uid_t key) {
if (auto fn = VAR_FN(dict, dictionary_get_string))
return fn(dict, key);
// Default implementation:
// Get the value via sourcekitd_variant_dictionary_get_value.
return sourcekitd_variant_string_get_ptr(
sourcekitd_variant_dictionary_get_value(dict, key));
}
int64_t
sourcekitd_variant_dictionary_get_int64(sourcekitd_variant_t dict,
sourcekitd_uid_t key) {
if (auto fn = VAR_FN(dict, dictionary_get_int64))
return fn(dict, key);
// Default implementation:
// Get the value via sourcekitd_variant_dictionary_get_value.
return sourcekitd_variant_int64_get_value(
sourcekitd_variant_dictionary_get_value(dict, key));
}
bool
sourcekitd_variant_dictionary_get_bool(sourcekitd_variant_t dict,
sourcekitd_uid_t key) {
if (auto fn = VAR_FN(dict, dictionary_get_bool))
return fn(dict, key);
// Default implementation:
// Get the value via sourcekitd_variant_dictionary_get_value.
return sourcekitd_variant_bool_get_value(
sourcekitd_variant_dictionary_get_value(dict, key));
}
sourcekitd_uid_t
sourcekitd_variant_dictionary_get_uid(sourcekitd_variant_t dict,
sourcekitd_uid_t key) {
if (auto fn = VAR_FN(dict, dictionary_get_uid))
return fn(dict, key);
// Default implementation:
// Get the value via sourcekitd_variant_dictionary_get_value.
return sourcekitd_variant_uid_get_value(
sourcekitd_variant_dictionary_get_value(dict, key));
}
#if SOURCEKITD_HAS_BLOCKS
bool
sourcekitd_variant_dictionary_apply(sourcekitd_variant_t dict,
sourcekitd_variant_dictionary_applier_t applier) {
return sourcekitd_variant_dictionary_apply_impl(dict, applier);
}
#endif
bool
sourcekitd_variant_dictionary_apply_impl(
sourcekitd_variant_t dict,
llvm::function_ref<bool(sourcekitd_uid_t, sourcekitd_variant_t)> applier) {
if (auto fn = VAR_FN(dict, dictionary_apply))
return fn(dict, applier);
// Default implementation:
// Treat as empty container.
return true;
}
bool
sourcekitd_variant_dictionary_apply_f(sourcekitd_variant_t dict,
sourcekitd_variant_dictionary_applier_f_t applier,
void *context) {
return sourcekitd_variant_dictionary_apply_impl(
dict,
[&](sourcekitd_uid_t key, sourcekitd_variant_t value) {
return applier(key, value, context);
});
}
size_t
sourcekitd_variant_array_get_count(sourcekitd_variant_t array) {
if (auto fn = VAR_FN(array, array_get_count))
return fn(array);
// Default implementation:
// Treat as empty container.
return 0;
}
sourcekitd_variant_t
sourcekitd_variant_array_get_value(sourcekitd_variant_t array, size_t index) {
if (auto fn = VAR_FN(array, array_get_value))
return fn(array, index);
llvm::report_fatal_error("Trying to index an empty array.");
}
const char *
sourcekitd_variant_array_get_string(sourcekitd_variant_t array, size_t index) {
if (auto fn = VAR_FN(array, array_get_string))
return fn(array, index);
// Default implementation:
// Get the value via sourcekitd_variant_array_get_value.
return sourcekitd_variant_string_get_ptr(
sourcekitd_variant_array_get_value(array, index));
}
int64_t
sourcekitd_variant_array_get_int64(sourcekitd_variant_t array, size_t index) {
if (auto fn = VAR_FN(array, array_get_int64))
return fn(array, index);
// Default implementation:
// Get the value via sourcekitd_variant_array_get_value.
return sourcekitd_variant_int64_get_value(
sourcekitd_variant_array_get_value(array, index));
}
bool
sourcekitd_variant_array_get_bool(sourcekitd_variant_t array, size_t index) {
if (auto fn = VAR_FN(array, array_get_bool))
return fn(array, index);
// Default implementation:
// Get the value via sourcekitd_variant_array_get_value.
return sourcekitd_variant_bool_get_value(
sourcekitd_variant_array_get_value(array, index));
}
sourcekitd_uid_t
sourcekitd_variant_array_get_uid(sourcekitd_variant_t array, size_t index) {
if (auto fn = VAR_FN(array, array_get_uid))
return fn(array, index);
// Default implementation:
// Get the value via sourcekitd_variant_array_get_value.
return sourcekitd_variant_uid_get_value(
sourcekitd_variant_array_get_value(array, index));
}
#if SOURCEKITD_HAS_BLOCKS
bool
sourcekitd_variant_array_apply(sourcekitd_variant_t array,
sourcekitd_variant_array_applier_t applier) {
return sourcekitd_variant_array_apply_impl(array, applier);
}
#endif
bool sourcekitd_variant_array_apply_impl(
sourcekitd_variant_t array,
llvm::function_ref<bool(size_t, sourcekitd_variant_t)> applier) {
if (auto fn = VAR_FN(array, array_apply))
return fn(array, applier);
// Default implementation:
// Iterate over elements via a for-loop.
for (size_t i = 0, e = sourcekitd_variant_array_get_count(array); i != e; ++i) {
bool Continue = applier(i, sourcekitd_variant_array_get_value(array, i));
if (!Continue)
return false;
}
return true;
}
bool sourcekitd_variant_array_apply_f(
sourcekitd_variant_t array, sourcekitd_variant_array_applier_f_t applier,
void *context) {
return sourcekitd_variant_array_apply_impl(
array, [&](size_t index, sourcekitd_variant_t value) {
return applier(index, value, context);
});
}
int64_t
sourcekitd_variant_int64_get_value(sourcekitd_variant_t obj) {
if (auto fn = VAR_FN(obj, int64_get_value))
return fn(obj);
// Default implementation:
// Assume this is a variant encapsulating the basic type.
return obj.data[1];
}
bool
sourcekitd_variant_bool_get_value(sourcekitd_variant_t obj) {
if (auto fn = VAR_FN(obj, bool_get_value))
return fn(obj);
// Default implementation:
// Assume this is a variant encapsulating the basic type.
return obj.data[1];
}
size_t
sourcekitd_variant_string_get_length(sourcekitd_variant_t obj) {
if (auto fn = VAR_FN(obj, string_get_length))
return fn(obj);
// Default implementation:
// Use strlen.
return strlen(sourcekitd_variant_string_get_ptr(obj));
}
const char *
sourcekitd_variant_string_get_ptr(sourcekitd_variant_t obj) {
if (auto fn = VAR_FN(obj, string_get_ptr))
return fn(obj);
// Default implementation:
// Assume this is a variant encapsulating the basic type.
return (const char *)obj.data[1];
}
size_t
sourcekitd_variant_data_get_size(sourcekitd_variant_t obj) {
if (auto fn = VAR_FN(obj, data_get_size))
return fn(obj);
// Default implementation:
// We store the byte's length in data[2] and its data in data[1]
return obj.data[2];
}
const void *
sourcekitd_variant_data_get_ptr(sourcekitd_variant_t obj) {
if (auto fn = VAR_FN(obj, data_get_ptr))
return fn(obj);
// Default implementation:
// We store the byte's length in data[2] and its data in data[1]
return reinterpret_cast<void *>(obj.data[1]);
}
sourcekitd_uid_t
sourcekitd_variant_uid_get_value(sourcekitd_variant_t obj) {
if (auto fn = VAR_FN(obj, uid_get_value))
return fn(obj);
// Default implementation:
// Assume this is a variant encapsulating the basic type.
return (sourcekitd_uid_t)obj.data[1];
}
void
sourcekitd_variant_description_dump(sourcekitd_variant_t obj) {
// Avoid colors here, we don't properly detect that the debug window inside
// Xcode doesn't support colors.
llvm::SmallString<128> Desc;
llvm::raw_svector_ostream OS(Desc);
printVariant(obj, OS);
llvm::errs() << OS.str() << '\n';
}
void
sourcekitd_variant_description_dump_filedesc(sourcekitd_variant_t obj, int fd) {
llvm::raw_fd_ostream OS(fd, /*shouldClose=*/false);
printVariant(obj, OS);
OS << '\n';
}
char *
sourcekitd_variant_description_copy(sourcekitd_variant_t obj) {
llvm::SmallString<128> Desc;
llvm::raw_svector_ostream OS(Desc);
printVariant(obj, OS);
return strdup(Desc.c_str());
}
char *
sourcekitd_variant_json_description_copy(sourcekitd_variant_t obj) {
llvm::SmallString<128> Desc;
{
llvm::raw_svector_ostream OS(Desc);
VariantPrinter(OS, /*Indent=*/0, /*PrintAsJSON=*/true).visit(obj);
}
return strdup(Desc.c_str());
}
namespace {
class YAMLRequestParser {
public:
sourcekitd_object_t parse(StringRef YAMLStr, std::string &Error);
private:
sourcekitd_object_t createObjFromNode(llvm::yaml::Node *Value,
std::string &Error);
bool parseDict(sourcekitd_object_t Dict, llvm::yaml::MappingNode *Node,
std::string &Error);
bool parseArray(sourcekitd_object_t Array, llvm::yaml::SequenceNode *Node,
std::string &Error);
void initError(StringRef Desc, llvm::yaml::Node *Node, std::string &Error);
sourcekitd_object_t withError(StringRef Desc, llvm::yaml::Node *Node,
std::string &Error) {
initError(Desc, Node, Error);
return nullptr;
}
bool withBoolError(StringRef Desc, llvm::yaml::Node *Node,
std::string &Error) {
initError(Desc, Node, Error);
return true;
}
};
} // anonymous namespace
sourcekitd_object_t
sourcekitd_request_create_from_yaml(const char *yaml, char **error) {
std::string Error;
sourcekitd_object_t Result = YAMLRequestParser().parse(yaml, Error);
if (Result)
return Result;
if (error)
*error = strdup(Error.c_str());
return nullptr;
}
sourcekitd_object_t YAMLRequestParser::parse(StringRef YAMLStr,
std::string &Error) {
llvm::SourceMgr SM;
llvm::yaml::Stream YAMLStream(YAMLStr, SM);
llvm::yaml::document_iterator I = YAMLStream.begin();
if (I == YAMLStream.end()) {
Error = "Error while parsing";
return nullptr;
}
llvm::yaml::Node *Root = I->getRoot();
if (Root == nullptr) {
Error = "Error while parsing";
return nullptr;
}
return createObjFromNode(Root, Error);
}
sourcekitd_object_t YAMLRequestParser::createObjFromNode(
llvm::yaml::Node *Value, std::string &Error) {
if (auto Array = dyn_cast<llvm::yaml::SequenceNode>(Value)) {
sourcekitd_object_t Val = sourcekitd_request_array_create(nullptr, 0);
if (parseArray(Val, Array, Error)) {
sourcekitd_request_release(Val);
return nullptr;
}
return Val;
}
if (auto Map = dyn_cast<llvm::yaml::MappingNode>(Value)) {
sourcekitd_object_t Val =
sourcekitd_request_dictionary_create(nullptr, nullptr, 0);
if (parseDict(Val, Map, Error)) {
sourcekitd_request_release(Val);
return nullptr;
}
return Val;
}
if (auto ValueString = dyn_cast<llvm::yaml::ScalarNode>(Value)) {
StringRef Raw = ValueString->getRawValue().trim();
SmallString<32> ValueStorage;
if (Raw[0] == '\"') {
SmallString<32> Str(ValueString->getValue(ValueStorage));
return sourcekitd_request_string_create(Str.c_str());
}
long long val;
if (!Raw.getAsInteger(10, val))
return sourcekitd_request_int64_create(val);
if (Raw.find(' ') != StringRef::npos)
return withError("Found space in non-string value", Value, Error);
return sourcekitd_request_uid_create(
sourcekitd_uid_get_from_buf(Raw.data(), Raw.size()));
}
return withError("Expected value as array, dictionary, or scalar", Value,
Error);
}
bool YAMLRequestParser::parseDict(sourcekitd_object_t Dict,
llvm::yaml::MappingNode *Node,
std::string &Error) {
for (llvm::yaml::MappingNode::iterator KVI = Node->begin(),
KVE = Node->end();
KVI != KVE; ++KVI) {
llvm::yaml::Node *Value = (*KVI).getValue();
if (Value == nullptr || isa<llvm::yaml::NullNode>(Value))
return withBoolError("Expected value", (*KVI).getKey(), Error);
sourcekitd_object_t Val = createObjFromNode(Value, Error);
if (!Val)
return true;
auto KeyString = dyn_cast<llvm::yaml::ScalarNode>((*KVI).getKey());
if (KeyString == nullptr) {
sourcekitd_request_release(Val);
return withBoolError("Expected string as key", (*KVI).getKey(), Error);
}
SmallString<32> KeyStorage;
StringRef Key = KeyString->getValue(KeyStorage);
sourcekitd_uid_t uid_key =
sourcekitd_uid_get_from_buf(Key.data(), Key.size());
sourcekitd_request_dictionary_set_value(Dict, uid_key, Val);
}
return false;
}
bool YAMLRequestParser::parseArray(sourcekitd_object_t Array,
llvm::yaml::SequenceNode *Node,
std::string &Error) {
for (llvm::yaml::SequenceNode::iterator AI = Node->begin(),
AE = Node->end();
AI != AE; ++AI) {
sourcekitd_object_t Val = createObjFromNode(&*AI, Error);
if (!Val)
return true;
sourcekitd_request_array_set_value(Array, SOURCEKITD_ARRAY_APPEND, Val);
}
return false;
}
void YAMLRequestParser::initError(StringRef Desc, llvm::yaml::Node *Node,
std::string &Error) {
Error = Desc.str();
Error += " at: ";
llvm::SMRange Range = Node->getSourceRange();
StringRef Text(Range.Start.getPointer(),
Range.End.getPointer() - Range.Start.getPointer());
Error.append(Text.begin(), Text.end());
}