blob: 422652499c994c7aa8dac75d0d0f53c1d57e4cd8 [file] [log] [blame]
//===- IndexStore.cpp - Index store API -----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the API for the index store.
//
//===----------------------------------------------------------------------===//
#include "indexstore/indexstore.h"
#include "clang/Index/IndexDataStore.h"
#include "clang/Index/IndexDataStoreSymbolUtils.h"
#include "clang/Index/IndexRecordReader.h"
#include "clang/Index/IndexUnitReader.h"
#include "clang/Index/IndexUnitWriter.h"
#include "clang/DirectoryWatcher/DirectoryWatcher.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Chrono.h"
#include <Block.h>
using namespace clang;
using namespace clang::index;
using namespace llvm;
static indexstore_string_ref_t toIndexStoreString(StringRef str) {
return indexstore_string_ref_t{ str.data(), str.size() };
}
static timespec toTimeSpec(sys::TimePoint<> tp) {
std::chrono::seconds sec = std::chrono::time_point_cast<std::chrono::seconds>(
tp).time_since_epoch();
std::chrono::nanoseconds nsec =
std::chrono::time_point_cast<std::chrono::nanoseconds>(tp - sec)
.time_since_epoch();
timespec ts;
ts.tv_sec = sec.count();
ts.tv_nsec = nsec.count();
return ts;
}
namespace {
struct IndexStoreError {
std::string Error;
};
} // anonymous namespace
const char *
indexstore_error_get_description(indexstore_error_t err) {
return static_cast<IndexStoreError*>(err)->Error.c_str();
}
void
indexstore_error_dispose(indexstore_error_t err) {
delete static_cast<IndexStoreError*>(err);
}
unsigned
indexstore_format_version(void) {
return IndexDataStore::getFormatVersion();
}
indexstore_t
indexstore_store_create(const char *store_path, indexstore_error_t *c_error) {
std::unique_ptr<IndexDataStore> store;
std::string error;
store = IndexDataStore::create(store_path, error);
if (!store) {
if (c_error)
*c_error = new IndexStoreError{ error };
return nullptr;
}
return store.release();
}
void
indexstore_store_dispose(indexstore_t store) {
delete static_cast<IndexDataStore*>(store);
}
#if INDEXSTORE_HAS_BLOCKS
bool
indexstore_store_units_apply(indexstore_t c_store, unsigned sorted,
bool(^applier)(indexstore_string_ref_t unit_name)) {
IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
return store->foreachUnitName(sorted, [&](StringRef unitName) -> bool {
return applier(toIndexStoreString(unitName));
});
}
size_t
indexstore_unit_event_notification_get_events_count(indexstore_unit_event_notification_t c_evtnote) {
auto *evtnote = static_cast<IndexDataStore::UnitEventNotification*>(c_evtnote);
return evtnote->Events.size();
}
indexstore_unit_event_t
indexstore_unit_event_notification_get_event(indexstore_unit_event_notification_t c_evtnote, size_t index) {
auto *evtnote = static_cast<IndexDataStore::UnitEventNotification*>(c_evtnote);
return (indexstore_unit_event_t)&evtnote->Events[index];
}
bool
indexstore_unit_event_notification_is_initial(indexstore_unit_event_notification_t c_evtnote) {
auto *evtnote = static_cast<IndexDataStore::UnitEventNotification*>(c_evtnote);
return evtnote->IsInitial;
}
indexstore_unit_event_kind_t
indexstore_unit_event_get_kind(indexstore_unit_event_t c_evt) {
auto *evt = static_cast<IndexDataStore::UnitEvent*>(c_evt);
indexstore_unit_event_kind_t k;
switch (evt->Kind) {
case IndexDataStore::UnitEventKind::Added:
k = INDEXSTORE_UNIT_EVENT_ADDED; break;
case IndexDataStore::UnitEventKind::Removed:
k = INDEXSTORE_UNIT_EVENT_REMOVED; break;
case IndexDataStore::UnitEventKind::Modified:
k = INDEXSTORE_UNIT_EVENT_MODIFIED; break;
case IndexDataStore::UnitEventKind::DirectoryDeleted:
k = INDEXSTORE_UNIT_EVENT_DIRECTORY_DELETED; break;
}
return k;
}
indexstore_string_ref_t
indexstore_unit_event_get_unit_name(indexstore_unit_event_t c_evt) {
auto *evt = static_cast<IndexDataStore::UnitEvent*>(c_evt);
return toIndexStoreString(evt->UnitName);
}
timespec
indexstore_unit_event_get_modification_time(indexstore_unit_event_t c_evt) {
auto *evt = static_cast<IndexDataStore::UnitEvent*>(c_evt);
return evt->ModTime;
}
void
indexstore_store_set_unit_event_handler(indexstore_t c_store,
indexstore_unit_event_handler_t blk_handler) {
IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
if (!blk_handler) {
store->setUnitEventHandler(nullptr);
return;
}
class BlockWrapper {
indexstore_unit_event_handler_t blk_handler;
public:
BlockWrapper(indexstore_unit_event_handler_t handler) {
blk_handler = Block_copy(handler);
}
BlockWrapper(const BlockWrapper &other) {
blk_handler = Block_copy(other.blk_handler);
}
~BlockWrapper() {
Block_release(blk_handler);
}
void operator()(indexstore_unit_event_notification_t evt_note) const {
blk_handler(evt_note);
}
};
BlockWrapper handler(blk_handler);
store->setUnitEventHandler([handler](IndexDataStore::UnitEventNotification evtNote) {
handler(&evtNote);
});
}
#endif
bool
indexstore_store_start_unit_event_listening(indexstore_t c_store,
indexstore_unit_event_listen_options_t *client_opts,
size_t listen_options_struct_size,
indexstore_error_t *c_error) {
IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
indexstore_unit_event_listen_options_t listen_opts;
memset(&listen_opts, 0, sizeof(listen_opts));
unsigned clientOptSize = listen_options_struct_size < sizeof(listen_opts)
? listen_options_struct_size : sizeof(listen_opts);
memcpy(&listen_opts, client_opts, clientOptSize);
std::string error;
auto createFn = [](StringRef Path, AbstractDirectoryWatcher::EventReceiver Receiver, bool waitInitialSync, std::string &Error)
-> std::unique_ptr<AbstractDirectoryWatcher> {
return DirectoryWatcher::create(Path, std::move(Receiver), waitInitialSync, Error);
};
bool err = store->startEventListening(createFn, listen_opts.wait_initial_sync, error);
if (err && c_error)
*c_error = new IndexStoreError{ error };
return err;
}
void
indexstore_store_stop_unit_event_listening(indexstore_t c_store) {
IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
store->stopEventListening();
}
void
indexstore_store_discard_unit(indexstore_t c_store, const char *unit_name) {
IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
store->discardUnit(unit_name);
}
void
indexstore_store_discard_record(indexstore_t c_store, const char *record_name) {
IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
store->discardRecord(record_name);
}
void
indexstore_store_purge_stale_data(indexstore_t c_store) {
IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
store->purgeStaleData();
}
indexstore_symbol_kind_t
indexstore_symbol_get_kind(indexstore_symbol_t sym) {
return getIndexStoreKind(static_cast<IndexRecordDecl *>(sym)->SymInfo.Kind);
}
indexstore_symbol_subkind_t
indexstore_symbol_get_subkind(indexstore_symbol_t sym) {
return getIndexStoreSubKind(static_cast<IndexRecordDecl *>(sym)->SymInfo.SubKind);
}
indexstore_symbol_language_t
indexstore_symbol_get_language(indexstore_symbol_t sym) {
return getIndexStoreLang(static_cast<IndexRecordDecl *>(sym)->SymInfo.Lang);
}
uint64_t
indexstore_symbol_get_properties(indexstore_symbol_t sym) {
return getIndexStoreProperties(static_cast<IndexRecordDecl *>(sym)->SymInfo.Properties);
}
uint64_t
indexstore_symbol_get_roles(indexstore_symbol_t sym) {
return getIndexStoreRoles(static_cast<IndexRecordDecl *>(sym)->Roles);
}
uint64_t
indexstore_symbol_get_related_roles(indexstore_symbol_t sym) {
return getIndexStoreRoles(static_cast<IndexRecordDecl *>(sym)->RelatedRoles);
}
indexstore_string_ref_t
indexstore_symbol_get_name(indexstore_symbol_t sym) {
auto *D = static_cast<IndexRecordDecl*>(sym);
return toIndexStoreString(D->Name);
}
indexstore_string_ref_t
indexstore_symbol_get_usr(indexstore_symbol_t sym) {
auto *D = static_cast<IndexRecordDecl*>(sym);
return toIndexStoreString(D->USR);
}
indexstore_string_ref_t
indexstore_symbol_get_codegen_name(indexstore_symbol_t sym) {
auto *D = static_cast<IndexRecordDecl*>(sym);
return toIndexStoreString(D->CodeGenName);
}
uint64_t
indexstore_symbol_relation_get_roles(indexstore_symbol_relation_t sym_rel) {
return getIndexStoreRoles(static_cast<IndexRecordRelation *>(sym_rel)->Roles);
}
indexstore_symbol_t
indexstore_symbol_relation_get_symbol(indexstore_symbol_relation_t sym_rel) {
return (indexstore_symbol_t)static_cast<IndexRecordRelation*>(sym_rel)->Dcl;
}
indexstore_symbol_t
indexstore_occurrence_get_symbol(indexstore_occurrence_t occur) {
return (indexstore_symbol_t)static_cast<IndexRecordOccurrence*>(occur)->Dcl;
}
#if INDEXSTORE_HAS_BLOCKS
bool
indexstore_occurrence_relations_apply(indexstore_occurrence_t occur,
bool(^applier)(indexstore_symbol_relation_t symbol_rel)) {
auto *recOccur = static_cast<IndexRecordOccurrence*>(occur);
for (auto &rel : recOccur->Relations) {
if (!applier(&rel))
return false;
}
return true;
}
#endif
uint64_t
indexstore_occurrence_get_roles(indexstore_occurrence_t occur) {
return static_cast<IndexRecordOccurrence*>(occur)->Roles;
}
void
indexstore_occurrence_get_line_col(indexstore_occurrence_t occur,
unsigned *line, unsigned *column) {
auto *recOccur = static_cast<IndexRecordOccurrence*>(occur);
if (line)
*line = recOccur->Line;
if (column)
*column = recOccur->Column;
}
typedef void *indexstore_record_reader_t;
indexstore_record_reader_t
indexstore_record_reader_create(indexstore_t c_store, const char *record_name,
indexstore_error_t *c_error) {
IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
std::unique_ptr<IndexRecordReader> reader;
std::string error;
reader = IndexRecordReader::createWithRecordFilename(record_name,
store->getFilePath(),
error);
if (!reader) {
if (c_error)
*c_error = new IndexStoreError{ error };
return nullptr;
}
return reader.release();
}
void
indexstore_record_reader_dispose(indexstore_record_reader_t rdr) {
auto *reader = static_cast<IndexRecordReader *>(rdr);
delete reader;
}
#if INDEXSTORE_HAS_BLOCKS
/// Goes through the symbol data and passes symbols to \c receiver, for the
/// symbol data that \c filter returns true on.
///
/// This allows allocating memory only for the record symbols that the caller is
/// interested in.
bool
indexstore_record_reader_search_symbols(indexstore_record_reader_t rdr,
bool(^filter)(indexstore_symbol_t symbol, bool *stop),
void(^receiver)(indexstore_symbol_t symbol)) {
auto *reader = static_cast<IndexRecordReader *>(rdr);
auto filterFn = [&](const IndexRecordDecl &D) -> IndexRecordReader::DeclSearchReturn {
bool stop = false;
bool accept = filter((indexstore_symbol_t)&D, &stop);
return { accept, !stop };
};
auto receiverFn = [&](const IndexRecordDecl *D) {
receiver((indexstore_symbol_t)D);
};
return reader->searchDecls(filterFn, receiverFn);
}
bool
indexstore_record_reader_symbols_apply(indexstore_record_reader_t rdr,
bool nocache,
bool(^applier)(indexstore_symbol_t symbol)) {
auto *reader = static_cast<IndexRecordReader *>(rdr);
auto receiverFn = [&](const IndexRecordDecl *D) -> bool {
return applier((indexstore_symbol_t)D);
};
return reader->foreachDecl(nocache, receiverFn);
}
bool
indexstore_record_reader_occurrences_apply(indexstore_record_reader_t rdr,
bool(^applier)(indexstore_occurrence_t occur)) {
auto *reader = static_cast<IndexRecordReader *>(rdr);
auto receiverFn = [&](const IndexRecordOccurrence &RO) -> bool {
return applier((indexstore_occurrence_t)&RO);
};
return reader->foreachOccurrence(receiverFn);
}
bool
indexstore_record_reader_occurrences_in_line_range_apply(indexstore_record_reader_t rdr,
unsigned line_start,
unsigned line_count,
bool(^applier)(indexstore_occurrence_t occur)) {
auto *reader = static_cast<IndexRecordReader *>(rdr);
auto receiverFn = [&](const IndexRecordOccurrence &RO) -> bool {
return applier((indexstore_occurrence_t)&RO);
};
return reader->foreachOccurrenceInLineRange(line_start, line_count, receiverFn);
}
/// \param symbols if non-zero \c symbols_count, indicates the list of symbols
/// that we want to get occurrences for. An empty array indicates that we want
/// occurrences for all symbols.
/// \param related_symbols Same as \c symbols but for related symbols.
bool
indexstore_record_reader_occurrences_of_symbols_apply(indexstore_record_reader_t rdr,
indexstore_symbol_t *symbols, size_t symbols_count,
indexstore_symbol_t *related_symbols, size_t related_symbols_count,
bool(^applier)(indexstore_occurrence_t occur)) {
auto *reader = static_cast<IndexRecordReader *>(rdr);
auto receiverFn = [&](const IndexRecordOccurrence &RO) -> bool {
return applier((indexstore_occurrence_t)&RO);
};
return reader->foreachOccurrence({(IndexRecordDecl**)symbols, symbols_count},
{(IndexRecordDecl**)related_symbols, related_symbols_count},
receiverFn);
}
#endif
size_t
indexstore_store_get_unit_name_from_output_path(indexstore_t store,
const char *output_path,
char *name_buf,
size_t buf_size) {
SmallString<256> unitName;
IndexUnitWriter::getUnitNameForAbsoluteOutputFile(output_path, unitName);
size_t nameLen = unitName.size();
strlcpy(name_buf, unitName.c_str(), buf_size);
return nameLen;
}
bool
indexstore_store_get_unit_modification_time(indexstore_t c_store,
const char *unit_name,
int64_t *seconds,
int64_t *nanoseconds,
indexstore_error_t *c_error) {
IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
std::string error;
// FIXME: This provides mod time with second-only accuracy.
auto optModTime = IndexUnitReader::getModificationTimeForUnit(unit_name,
store->getFilePath(), error);
if (!optModTime) {
if (c_error)
*c_error = new IndexStoreError{ error };
return true;
}
timespec ts = toTimeSpec(*optModTime);
if (seconds)
*seconds = ts.tv_sec;
if (nanoseconds)
*nanoseconds = ts.tv_nsec;
return false;
}
indexstore_unit_reader_t
indexstore_unit_reader_create(indexstore_t c_store, const char *unit_name,
indexstore_error_t *c_error) {
IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
std::unique_ptr<IndexUnitReader> reader;
std::string error;
reader = IndexUnitReader::createWithUnitFilename(unit_name,
store->getFilePath(), error);
if (!reader) {
if (c_error)
*c_error = new IndexStoreError{ error };
return nullptr;
}
return reader.release();
}
void
indexstore_unit_reader_dispose(indexstore_unit_reader_t rdr) {
auto reader = static_cast<IndexUnitReader*>(rdr);
delete reader;
}
indexstore_string_ref_t
indexstore_unit_reader_get_provider_identifier(indexstore_unit_reader_t rdr) {
auto reader = static_cast<IndexUnitReader*>(rdr);
return toIndexStoreString(reader->getProviderIdentifier());
}
indexstore_string_ref_t
indexstore_unit_reader_get_provider_version(indexstore_unit_reader_t rdr) {
auto reader = static_cast<IndexUnitReader*>(rdr);
return toIndexStoreString(reader->getProviderVersion());
}
void
indexstore_unit_reader_get_modification_time(indexstore_unit_reader_t rdr,
int64_t *seconds,
int64_t *nanoseconds) {
auto reader = static_cast<IndexUnitReader*>(rdr);
// FIXME: This provides mod time with second-only accuracy.
sys::TimePoint<> timeVal = reader->getModificationTime();
timespec ts = toTimeSpec(timeVal);
if (seconds)
*seconds = ts.tv_sec;
if (nanoseconds)
*nanoseconds = ts.tv_nsec;
}
bool
indexstore_unit_reader_is_system_unit(indexstore_unit_reader_t rdr) {
auto reader = static_cast<IndexUnitReader*>(rdr);
return reader->isSystemUnit();
}
bool
indexstore_unit_reader_is_module_unit(indexstore_unit_reader_t rdr) {
auto reader = static_cast<IndexUnitReader*>(rdr);
return reader->isModuleUnit();
}
bool
indexstore_unit_reader_is_debug_compilation(indexstore_unit_reader_t rdr) {
auto reader = static_cast<IndexUnitReader*>(rdr);
return reader->isDebugCompilation();
}
bool
indexstore_unit_reader_has_main_file(indexstore_unit_reader_t rdr) {
auto reader = static_cast<IndexUnitReader*>(rdr);
return reader->hasMainFile();
}
indexstore_string_ref_t
indexstore_unit_reader_get_main_file(indexstore_unit_reader_t rdr) {
auto reader = static_cast<IndexUnitReader*>(rdr);
return toIndexStoreString(reader->getMainFilePath());
}
indexstore_string_ref_t
indexstore_unit_reader_get_module_name(indexstore_unit_reader_t rdr) {
auto reader = static_cast<IndexUnitReader*>(rdr);
return toIndexStoreString(reader->getModuleName());
}
indexstore_string_ref_t
indexstore_unit_reader_get_working_dir(indexstore_unit_reader_t rdr) {
auto reader = static_cast<IndexUnitReader*>(rdr);
return toIndexStoreString(reader->getWorkingDirectory());
}
indexstore_string_ref_t
indexstore_unit_reader_get_output_file(indexstore_unit_reader_t rdr) {
auto reader = static_cast<IndexUnitReader*>(rdr);
return toIndexStoreString(reader->getOutputFile());
}
indexstore_string_ref_t
indexstore_unit_reader_get_sysroot_path(indexstore_unit_reader_t rdr) {
auto reader = static_cast<IndexUnitReader*>(rdr);
return toIndexStoreString(reader->getSysrootPath());
}
indexstore_string_ref_t
indexstore_unit_reader_get_target(indexstore_unit_reader_t rdr) {
auto reader = static_cast<IndexUnitReader*>(rdr);
return toIndexStoreString(reader->getTarget());
}
indexstore_unit_dependency_kind_t
indexstore_unit_dependency_get_kind(indexstore_unit_dependency_t c_dep) {
auto dep = static_cast<const IndexUnitReader::DependencyInfo*>(c_dep);
switch (dep->Kind) {
case IndexUnitReader::DependencyKind::Unit: return INDEXSTORE_UNIT_DEPENDENCY_UNIT;
case IndexUnitReader::DependencyKind::Record: return INDEXSTORE_UNIT_DEPENDENCY_RECORD;
case IndexUnitReader::DependencyKind::File: return INDEXSTORE_UNIT_DEPENDENCY_FILE;
}
}
bool
indexstore_unit_dependency_is_system(indexstore_unit_dependency_t c_dep) {
auto dep = static_cast<const IndexUnitReader::DependencyInfo*>(c_dep);
return dep->IsSystem;
}
indexstore_string_ref_t
indexstore_unit_dependency_get_filepath(indexstore_unit_dependency_t c_dep) {
auto dep = static_cast<const IndexUnitReader::DependencyInfo*>(c_dep);
return toIndexStoreString(dep->FilePath);
}
indexstore_string_ref_t
indexstore_unit_dependency_get_modulename(indexstore_unit_dependency_t c_dep) {
auto dep = static_cast<const IndexUnitReader::DependencyInfo*>(c_dep);
return toIndexStoreString(dep->ModuleName);
}
indexstore_string_ref_t
indexstore_unit_dependency_get_name(indexstore_unit_dependency_t c_dep) {
auto dep = static_cast<const IndexUnitReader::DependencyInfo*>(c_dep);
return toIndexStoreString(dep->UnitOrRecordName);
}
time_t
indexstore_unit_dependency_get_modification_time(indexstore_unit_dependency_t c_dep) {
auto dep = static_cast<const IndexUnitReader::DependencyInfo*>(c_dep);
return dep->ModTime;
}
size_t
indexstore_unit_dependency_get_file_size(indexstore_unit_dependency_t c_dep) {
auto dep = static_cast<const IndexUnitReader::DependencyInfo*>(c_dep);
return dep->FileSize;
}
indexstore_string_ref_t
indexstore_unit_include_get_source_path(indexstore_unit_include_t c_inc) {
auto inc = static_cast<const IndexUnitReader::IncludeInfo*>(c_inc);
return toIndexStoreString(inc->SourcePath);
}
indexstore_string_ref_t
indexstore_unit_include_get_target_path(indexstore_unit_include_t c_inc) {
auto inc = static_cast<const IndexUnitReader::IncludeInfo*>(c_inc);
return toIndexStoreString(inc->TargetPath);
}
unsigned
indexstore_unit_include_get_source_line(indexstore_unit_include_t c_inc) {
auto inc = static_cast<const IndexUnitReader::IncludeInfo*>(c_inc);
return inc->SourceLine;
}
#if INDEXSTORE_HAS_BLOCKS
bool
indexstore_unit_reader_dependencies_apply(indexstore_unit_reader_t rdr,
bool(^applier)(indexstore_unit_dependency_t)) {
auto reader = static_cast<IndexUnitReader*>(rdr);
return reader->foreachDependency([&](const IndexUnitReader::DependencyInfo &depInfo) -> bool {
return applier((void*)&depInfo);
});
}
bool
indexstore_unit_reader_includes_apply(indexstore_unit_reader_t rdr,
bool(^applier)(indexstore_unit_include_t)) {
auto reader = static_cast<IndexUnitReader*>(rdr);
return reader->foreachInclude([&](const IndexUnitReader::IncludeInfo &incInfo) -> bool {
return applier((void*)&incInfo);
});
}
#endif