blob: c03f0d829d4478d007ac66ae3776fe151002f04a [file] [log] [blame]
//===--- DocStructureArray.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 "sourcekitd/DocStructureArray.h"
#include "DictionaryKeys.h"
#include "SourceKit/Core/LLVM.h"
#include "SourceKit/Support/UIdent.h"
#include "sourcekitd/CompactArray.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
using namespace SourceKit;
using namespace sourcekitd;
namespace {
struct Node {
// Scalars
unsigned Offset;
unsigned Length;
UIdent Kind;
UIdent AccessLevel;
UIdent SetterAccessLevel;
unsigned NameOffset;
unsigned NameLength;
unsigned BodyOffset;
unsigned BodyLength;
unsigned DocOffset;
unsigned DocLength;
std::string DisplayName;
std::string TypeName;
std::string RuntimeName;
std::string SelectorName;
// Arrays
unsigned InheritedTypesOffset;
unsigned AttrsOffset;
// Children
struct Element {
UIdent Kind;
unsigned Offset;
unsigned Length;
};
SmallVector<Element, 4> elements;
SmallVector<unsigned, 4> childIndices;
};
} // end anonymous namespace
struct DocStructureArrayBuilder::Implementation {
typedef CompactArrayBuilder<StringRef> InheritedTypesBuilder;
SmallVector<char, 256> inheritedTypesBuffer;
typedef CompactArrayBuilder<UIdent, unsigned, unsigned> AttrsBuilder;
SmallVector<char, 256> attrsBuffer;
typedef CompactArrayBuilder<UIdent, unsigned, unsigned> ElementsBuilder;
SmallVector<char, 256> elementsBuffer;
typedef CompactArrayBuilder<unsigned> StructureArrayBuilder;
SmallVector<char, 256> structureArrayBuffer;
CompactArrayBuilder<unsigned, // Offset
unsigned, // Length
UIdent, // Kind
UIdent, // AccessLevel
UIdent, // SetterAccessLevel
unsigned, // NameOffset
unsigned, // NameLength
unsigned, // BodyOffset
unsigned, // BodyLength
unsigned, // DocOffset
unsigned, // DocLength
Optional<StringRef>, // DisplayName
Optional<StringRef>, // TypeName
Optional<StringRef>, // RuntimeName
Optional<StringRef>, // SelectorName
unsigned, // InheritedTypesOffset
unsigned, // AttrsOffset
unsigned, // ElementsOffset
unsigned // ChildrenOffset
>
structureBuilder;
SmallVector<Node, 8> structure;
SmallVector<unsigned, 16> topIndices;
unsigned addInheritedTypes(ArrayRef<StringRef> inheritedTypes);
unsigned addAttrs(ArrayRef<std::tuple<UIdent, unsigned, unsigned>> attrs);
unsigned addElements(ArrayRef<Node::Element> elements);
unsigned addChildren(ArrayRef<unsigned> offsets);
Implementation();
};
DocStructureArrayBuilder::Implementation::Implementation() {
// For each kind of compact array, fill in the first entry in the buffer as
// empty so we don't duplicate empty arrays anywhere.
InheritedTypesBuilder().appendTo(inheritedTypesBuffer);
AttrsBuilder().appendTo(attrsBuffer);
ElementsBuilder().appendTo(elementsBuffer);
StructureArrayBuilder().appendTo(structureArrayBuffer);
}
unsigned DocStructureArrayBuilder::Implementation::addInheritedTypes(
ArrayRef<StringRef> inheritedTypes) {
if (inheritedTypes.empty())
return 0;
InheritedTypesBuilder builder;
for (StringRef type : inheritedTypes)
builder.addEntry(type);
unsigned offset = inheritedTypesBuffer.size();
builder.appendTo(inheritedTypesBuffer);
return offset;
}
unsigned
DocStructureArrayBuilder::Implementation::addAttrs(ArrayRef<std::tuple<UIdent, unsigned, unsigned>> attrs) {
if (attrs.empty())
return 0;
AttrsBuilder builder;
for (auto attr : attrs) {
UIdent uid;
unsigned offset, length;
std::tie(uid, offset, length) = attr;
builder.addEntry(uid, offset, length);
}
unsigned offset = attrsBuffer.size();
builder.appendTo(attrsBuffer);
return offset;
}
unsigned DocStructureArrayBuilder::Implementation::addElements(
ArrayRef<Node::Element> elements) {
if (elements.empty())
return 0;
ElementsBuilder builder;
for (auto &element : elements)
builder.addEntry(element.Kind, element.Offset, element.Length);
unsigned offset = elementsBuffer.size();
builder.appendTo(elementsBuffer);
return offset;
}
unsigned DocStructureArrayBuilder::Implementation::addChildren(
ArrayRef<unsigned> offsets) {
if (offsets.empty())
return 0;
StructureArrayBuilder builder;
for (unsigned value : offsets)
builder.addEntry(value);
unsigned offset = structureArrayBuffer.size();
builder.appendTo(structureArrayBuffer);
return offset;
}
DocStructureArrayBuilder::DocStructureArrayBuilder()
: impl(*new Implementation()) {}
DocStructureArrayBuilder::~DocStructureArrayBuilder() { delete &impl; }
void DocStructureArrayBuilder::beginSubStructure(
unsigned Offset, unsigned Length, SourceKit::UIdent Kind,
SourceKit::UIdent AccessLevel, SourceKit::UIdent SetterAccessLevel,
unsigned NameOffset, unsigned NameLength, unsigned BodyOffset,
unsigned BodyLength, unsigned DocOffset, unsigned DocLength,
StringRef DisplayName, StringRef TypeName,
StringRef RuntimeName, StringRef SelectorName,
ArrayRef<StringRef> InheritedTypes,
ArrayRef<std::tuple<UIdent, unsigned, unsigned>> Attrs) {
Node node = {
Offset,
Length,
Kind,
AccessLevel,
SetterAccessLevel,
NameOffset,
NameLength,
BodyOffset,
BodyLength,
DocOffset,
DocLength,
DisplayName,
TypeName,
RuntimeName,
SelectorName,
impl.addInheritedTypes(InheritedTypes),
impl.addAttrs(Attrs),
{}, // elements
{}, // children
};
impl.structure.push_back(std::move(node));
}
void DocStructureArrayBuilder::addElement(SourceKit::UIdent Kind,
unsigned Offset, unsigned Length) {
impl.structure.back().elements.push_back({Kind, Offset, Length});
}
void DocStructureArrayBuilder::endSubStructure() {
Node node = impl.structure.pop_back_val();
unsigned index = impl.structureBuilder.size();
if (!impl.structure.empty()) {
impl.structure.back().childIndices.push_back(index);
} else {
impl.topIndices.push_back(index);
}
// Canonicalize empty strings to None for the CompactArray.
auto str = [](StringRef str) -> Optional<StringRef> {
return str.empty() ? None : Optional<StringRef>(str);
};
impl.structureBuilder.addEntry(
node.Offset, node.Length, node.Kind, node.AccessLevel,
node.SetterAccessLevel, node.NameOffset, node.NameLength, node.BodyOffset,
node.BodyLength, node.DocOffset, node.DocLength, str(node.DisplayName),
str(node.TypeName), str(node.RuntimeName), str(node.SelectorName),
node.InheritedTypesOffset, node.AttrsOffset,
impl.addElements(node.elements), impl.addChildren(node.childIndices));
}
std::unique_ptr<llvm::MemoryBuffer> DocStructureArrayBuilder::createBuffer() {
assert(impl.structure.empty());
uint64_t topOffset = impl.addChildren(impl.topIndices);
size_t inheritedTypesBufferSize = impl.inheritedTypesBuffer.size();
size_t attrsBufferSize = impl.attrsBuffer.size();
size_t elementsBufferSize = impl.elementsBuffer.size();
size_t structureArrayBufferSize = impl.structureArrayBuffer.size();
size_t structureBufferSize = impl.structureBuilder.sizeInBytes();
// Header:
// * offset of each section start (5)
// * offset of top structure array (relative to structure array section) (1)
size_t headerSize = sizeof(uint64_t) * 6;
auto result = llvm::MemoryBuffer::getNewUninitMemBuffer(
inheritedTypesBufferSize + attrsBufferSize + elementsBufferSize +
structureArrayBufferSize + structureBufferSize + headerSize);
char *start = const_cast<char *>(result->getBufferStart());
char *headerPtr = start;
char *ptr = start + headerSize;
auto addBuffer = [&](ArrayRef<char> buffer) {
uint64_t offset = ptr - start;
memcpy(headerPtr, &offset, sizeof(offset));
headerPtr += sizeof(offset);
auto bytes = sizeof(buffer[0]) * buffer.size();
memcpy(ptr, buffer.data(), bytes);
ptr += bytes;
};
addBuffer(impl.structureArrayBuffer);
SmallVector<char, 256> structureBuffer;
impl.structureBuilder.appendTo(structureBuffer);
addBuffer(structureBuffer);
addBuffer(impl.elementsBuffer);
addBuffer(impl.attrsBuffer);
addBuffer(impl.inheritedTypesBuffer);
assert(ptr == result->getBufferEnd());
assert(headerPtr == start + (headerSize - sizeof(topOffset)));
memcpy(headerPtr, &topOffset, sizeof(topOffset));
return result;
}
namespace {
struct OutNode {
// Scalars
unsigned Offset;
unsigned Length;
sourcekitd_uid_t Kind;
sourcekitd_uid_t AccessLevel;
sourcekitd_uid_t SetterAccessLevel;
unsigned NameOffset;
unsigned NameLength;
unsigned BodyOffset;
unsigned BodyLength;
unsigned DocOffset;
unsigned DocLength;
const char *DisplayName;
const char *TypeName;
const char *RuntimeName;
const char *SelectorName;
// Arrays
unsigned InheritedTypesOffset;
unsigned AttrsOffset;
unsigned ElementsOffset;
unsigned ChildIndicesOffset;
};
class DocStructureArrayReader {
public:
DocStructureArrayReader(void *buffer);
OutNode readStructure(size_t index);
CompactArrayReader<unsigned> readStructureArray(size_t offset);
void *getElementsBuffer(size_t offset) const {
return (char *)getElementsBufferStart() + offset;
}
void *getInheritedTypesBuffer(size_t offset) const {
return (char *)getInheritedTypesBufferStart() + offset;
}
void *getAttrsBuffer(size_t offset) const {
return (char *)getAttrsBufferStart() + offset;
}
private:
void *getStructureArrayBufferStart() const { return getBufferStart(0); }
void *getStructureBufferStart() const { return getBufferStart(1); }
void *getElementsBufferStart() const { return getBufferStart(2); }
void *getAttrsBufferStart() const { return getBufferStart(3); }
void *getInheritedTypesBufferStart() const { return getBufferStart(4); }
size_t getTopStructureArrayOffset() const { return getHeaderValue(5); }
uint64_t getHeaderValue(unsigned index) const;
void *getBufferStart(unsigned index) const;
private:
void *buffer;
typedef CompactArrayReader<unsigned, // Offset
unsigned, // Length
sourcekitd_uid_t, // Kind
sourcekitd_uid_t, // AccessLevel
sourcekitd_uid_t, // SetterAccessLevel
unsigned, // NameOffset
unsigned, // NameLength
unsigned, // BodyOffset
unsigned, // BodyLength
unsigned, // DocOffset
unsigned, // DocLength
const char *, // DisplayName
const char *, // TypeName
const char *, // RuntimeName
const char *, // SelectorName
unsigned, // InheritedTypesOffset
unsigned, // AttrsOffset
unsigned, // ElementsOffset
unsigned // ChildrenOffset
>
StructureReader;
};
} // end anonymous namespace
DocStructureArrayReader::DocStructureArrayReader(void *buffer)
: buffer(buffer) {}
OutNode DocStructureArrayReader::readStructure(size_t index) {
OutNode result;
StructureReader reader(getStructureBufferStart());
reader.readEntries(
index, result.Offset, result.Length, result.Kind, result.AccessLevel,
result.SetterAccessLevel, result.NameOffset, result.NameLength,
result.BodyOffset, result.BodyLength, result.DocOffset, result.DocLength,
result.DisplayName, result.TypeName, result.RuntimeName,
result.SelectorName, result.InheritedTypesOffset,
result.AttrsOffset, result.ElementsOffset, result.ChildIndicesOffset);
return result;
}
CompactArrayReader<unsigned>
DocStructureArrayReader::readStructureArray(size_t offset) {
if (offset == ~size_t(0))
offset = getTopStructureArrayOffset();
void *arrayBuffer = (char *)getStructureArrayBufferStart() + offset;
return CompactArrayReader<unsigned>(arrayBuffer);
}
void *DocStructureArrayReader::getBufferStart(unsigned index) const {
return (char *)buffer + getHeaderValue(index);
}
uint64_t DocStructureArrayReader::getHeaderValue(unsigned index) const {
uint64_t headerField;
memcpy(&headerField, (uint64_t*)buffer + index, sizeof(headerField));
return headerField;
}
#define APPLY(K, Ty, Field) \
do { \
sourcekitd_uid_t key = SKDUIDFromUIdent(K); \
sourcekitd_variant_t var = make##Ty##Variant(Field); \
if (!applier(key, var)) \
return false; \
} while (0)
namespace {
struct ElementReader {
typedef CompactArrayReader<sourcekitd_uid_t, unsigned, unsigned>
CompactArrayReaderTy;
static bool
dictionary_apply(void *buffer, size_t index,
llvm::function_ref<bool(sourcekitd_uid_t,
sourcekitd_variant_t)> applier) {
CompactArrayReaderTy reader(buffer);
sourcekitd_uid_t kind;
unsigned offset;
unsigned length;
reader.readEntries(index, kind, offset, length);
APPLY(KeyKind, UID, kind);
APPLY(KeyOffset, Int, offset);
APPLY(KeyLength, Int, length);
return true;
}
};
struct InheritedTypeReader {
typedef CompactArrayReader<const char *> CompactArrayReaderTy;
static bool
dictionary_apply(void *buffer, size_t index,
llvm::function_ref<bool(sourcekitd_uid_t,
sourcekitd_variant_t)> applier) {
CompactArrayReaderTy reader(buffer);
const char *value = nullptr;
reader.readEntries(index, value);
if (value)
APPLY(KeyName, String, value);
return true;
}
};
struct AttributesReader {
typedef CompactArrayReader<sourcekitd_uid_t, unsigned, unsigned> CompactArrayReaderTy;
static bool
dictionary_apply(void *buffer, size_t index,
llvm::function_ref<bool(sourcekitd_uid_t,
sourcekitd_variant_t)> applier) {
CompactArrayReaderTy reader(buffer);
sourcekitd_uid_t value;
unsigned offset;
unsigned length;
reader.readEntries(index, value, offset, length);
APPLY(KeyAttribute, UID, value);
APPLY(KeyOffset, Int, offset);
APPLY(KeyLength, Int, length);
return true;
}
};
struct DocStructureReader {
static bool
dictionary_apply(void *buffer, size_t index,
llvm::function_ref<bool(sourcekitd_uid_t,
sourcekitd_variant_t)> applier) {
auto reader = DocStructureArrayReader(buffer);
auto node = reader.readStructure(index);
APPLY(KeyOffset, Int, node.Offset);
APPLY(KeyLength, Int, node.Length);
APPLY(KeyKind, UID, node.Kind);
if (node.AccessLevel)
APPLY(KeyAccessLevel, UID, node.AccessLevel);
if (node.SetterAccessLevel)
APPLY(KeySetterAccessLevel, UID, node.SetterAccessLevel);
APPLY(KeyNameOffset, Int, node.NameOffset);
APPLY(KeyNameLength, Int, node.NameLength);
if (node.BodyOffset || node.BodyLength) {
APPLY(KeyBodyOffset, Int, node.BodyOffset);
APPLY(KeyBodyLength, Int, node.BodyLength);
}
if (node.DocOffset || node.DocLength) {
APPLY(KeyDocOffset, Int, node.DocOffset);
APPLY(KeyDocLength, Int, node.DocLength);
}
if (node.DisplayName)
APPLY(KeyName, String, node.DisplayName);
if (node.TypeName)
APPLY(KeyTypeName, String, node.TypeName);
if (node.RuntimeName)
APPLY(KeyRuntimeName, String, node.RuntimeName);
if (node.SelectorName)
APPLY(KeySelectorName, String, node.SelectorName);
#define APPLY_ARRAY(Kind, Buf, Key, Off) \
do { \
sourcekitd_uid_t key = SKDUIDFromUIdent(Key); \
sourcekitd_variant_t var = { \
{(uintptr_t)getVariantFunctionsFor##Kind##Array(), (uintptr_t)Buf, \
Off}}; \
if (!applier(key, var)) \
return false; \
} while (0)
if (node.InheritedTypesOffset) {
void *buf = reader.getInheritedTypesBuffer(node.InheritedTypesOffset);
APPLY_ARRAY(InheritedTypes, buf, KeyInheritedTypes, 0);
}
if (node.AttrsOffset) {
void *buf = reader.getAttrsBuffer(node.AttrsOffset);
APPLY_ARRAY(Attributes, buf, KeyAttributes, 0);
}
if (node.ElementsOffset) {
void *buf = reader.getElementsBuffer(node.ElementsOffset);
APPLY_ARRAY(DocStructureElement, buf, KeyElements, 0);
}
if (node.ChildIndicesOffset) {
APPLY_ARRAY(DocStructure, buffer, KeySubStructure,
node.ChildIndicesOffset);
}
return true;
}
};
// data[0] = DocStructureArrayFuncs::funcs
// data[1] = buffer for DocStructureArrayReader
// data[2] = structure array offset
struct DocStructureArrayFuncs {
static sourcekitd_variant_type_t get_type(sourcekitd_variant_t var) {
return SOURCEKITD_VARIANT_TYPE_ARRAY;
}
static size_t array_get_count(sourcekitd_variant_t array) {
void *buffer = (void *)array.data[1];
size_t offset = array.data[2];
return DocStructureArrayReader(buffer)
.readStructureArray(offset)
.getCount();
}
static sourcekitd_variant_t array_get_value(sourcekitd_variant_t array,
size_t index) {
void *buffer = (void *)array.data[1];
size_t offset = array.data[2];
auto reader = DocStructureArrayReader(buffer).readStructureArray(offset);
assert(index < reader.getCount());
unsigned structureIndex;
reader.readEntries(index, structureIndex);
return {{(uintptr_t)&CompactVariantFuncs<DocStructureReader>::Funcs,
(uintptr_t)buffer, structureIndex}};
}
static VariantFunctions funcs;
};
} // end anonymous namespace
VariantFunctions DocStructureArrayFuncs::funcs = {
get_type,
nullptr /*AnnotArray_array_apply*/,
nullptr /*AnnotArray_array_get_bool*/,
array_get_count,
nullptr /*AnnotArray_array_get_int64*/,
nullptr /*AnnotArray_array_get_string*/,
nullptr /*AnnotArray_array_get_uid*/,
array_get_value,
nullptr /*AnnotArray_bool_get_value*/,
nullptr /*AnnotArray_dictionary_apply*/,
nullptr /*AnnotArray_dictionary_get_bool*/,
nullptr /*AnnotArray_dictionary_get_int64*/,
nullptr /*AnnotArray_dictionary_get_string*/,
nullptr /*AnnotArray_dictionary_get_value*/,
nullptr /*AnnotArray_dictionary_get_uid*/,
nullptr /*AnnotArray_string_get_length*/,
nullptr /*AnnotArray_string_get_ptr*/,
nullptr /*AnnotArray_int64_get_value*/,
nullptr /*AnnotArray_uid_get_value*/
};
VariantFunctions *sourcekitd::getVariantFunctionsForDocStructureElementArray() {
return &CompactArrayFuncs<ElementReader>::Funcs;
}
VariantFunctions *sourcekitd::getVariantFunctionsForInheritedTypesArray() {
return &CompactArrayFuncs<InheritedTypeReader>::Funcs;
}
VariantFunctions *sourcekitd::getVariantFunctionsForAttributesArray() {
return &CompactArrayFuncs<AttributesReader>::Funcs;
}
VariantFunctions *sourcekitd::getVariantFunctionsForDocStructureArray() {
return &DocStructureArrayFuncs::funcs;
}