//===- 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/DirectoryWatcher/DirectoryWatcher.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 "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Chrono.h" #if INDEXSTORE_HAS_BLOCKS #include #endif 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(tp).time_since_epoch(); std::chrono::nanoseconds nsec = std::chrono::time_point_cast(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(err)->Error.c_str(); } void indexstore_error_dispose(indexstore_error_t err) { delete static_cast(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 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(store); } bool indexstore_store_units_apply( indexstore_t c_store, unsigned sorted, #if INDEXSTORE_HAS_BLOCKS bool (^applier)(indexstore_string_ref_t unit_name)) { #else llvm::function_ref applier) { #endif IndexDataStore *store = static_cast(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(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(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(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(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(c_evt); return toIndexStoreString(evt->UnitName); } timespec indexstore_unit_event_get_modification_time(indexstore_unit_event_t c_evt) { auto *evt = static_cast(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(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 = handler; } BlockWrapper(const BlockWrapper &other) { blk_handler = other.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); }); } 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(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 { 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(c_store); store->stopEventListening(); } void indexstore_store_discard_unit(indexstore_t c_store, const char *unit_name) { IndexDataStore *store = static_cast(c_store); store->discardUnit(unit_name); } void indexstore_store_discard_record(indexstore_t c_store, const char *record_name) { IndexDataStore *store = static_cast(c_store); store->discardRecord(record_name); } void indexstore_store_purge_stale_data(indexstore_t c_store) { IndexDataStore *store = static_cast(c_store); store->purgeStaleData(); } indexstore_symbol_kind_t indexstore_symbol_get_kind(indexstore_symbol_t sym) { return getIndexStoreKind(static_cast(sym)->SymInfo.Kind); } indexstore_symbol_subkind_t indexstore_symbol_get_subkind(indexstore_symbol_t sym) { return getIndexStoreSubKind( static_cast(sym)->SymInfo.SubKind); } indexstore_symbol_language_t indexstore_symbol_get_language(indexstore_symbol_t sym) { return getIndexStoreLang(static_cast(sym)->SymInfo.Lang); } uint64_t indexstore_symbol_get_properties(indexstore_symbol_t sym) { return getIndexStoreProperties( static_cast(sym)->SymInfo.Properties); } uint64_t indexstore_symbol_get_roles(indexstore_symbol_t sym) { return getIndexStoreRoles(static_cast(sym)->Roles); } uint64_t indexstore_symbol_get_related_roles(indexstore_symbol_t sym) { return getIndexStoreRoles(static_cast(sym)->RelatedRoles); } indexstore_string_ref_t indexstore_symbol_get_name(indexstore_symbol_t sym) { auto *D = static_cast(sym); return toIndexStoreString(D->Name); } indexstore_string_ref_t indexstore_symbol_get_usr(indexstore_symbol_t sym) { auto *D = static_cast(sym); return toIndexStoreString(D->USR); } indexstore_string_ref_t indexstore_symbol_get_codegen_name(indexstore_symbol_t sym) { auto *D = static_cast(sym); return toIndexStoreString(D->CodeGenName); } uint64_t indexstore_symbol_relation_get_roles(indexstore_symbol_relation_t sym_rel) { return getIndexStoreRoles(static_cast(sym_rel)->Roles); } indexstore_symbol_t indexstore_symbol_relation_get_symbol(indexstore_symbol_relation_t sym_rel) { return (indexstore_symbol_t) static_cast(sym_rel)->Dcl; } indexstore_symbol_t indexstore_occurrence_get_symbol(indexstore_occurrence_t occur) { return (indexstore_symbol_t) static_cast(occur)->Dcl; } bool indexstore_occurrence_relations_apply( indexstore_occurrence_t occur, #if INDEXSTORE_HAS_BLOCKS bool (^applier)(indexstore_symbol_relation_t symbol_rel)) { #else llvm::function_ref applier) { #endif auto *recOccur = static_cast(occur); for (auto &rel : recOccur->Relations) { if (!applier(&rel)) return false; } return true; } uint64_t indexstore_occurrence_get_roles(indexstore_occurrence_t occur) { return static_cast(occur)->Roles; } void indexstore_occurrence_get_line_col(indexstore_occurrence_t occur, unsigned *line, unsigned *column) { auto *recOccur = static_cast(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(c_store); std::unique_ptr 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(rdr); delete reader; } /// 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, #if INDEXSTORE_HAS_BLOCKS bool (^filter)(indexstore_symbol_t symbol, bool *stop), void (^receiver)(indexstore_symbol_t symbol)) { #else llvm::function_ref filter, llvm::function_ref receiver) { #endif auto *reader = static_cast(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, #if INDEXSTORE_HAS_BLOCKS bool (^applier)(indexstore_symbol_t symbol)) { #else llvm::function_ref applier) { #endif auto *reader = static_cast(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, #if INDEXSTORE_HAS_BLOCKS bool (^applier)(indexstore_occurrence_t occur)) { #else llvm::function_ref applier) { #endif auto *reader = static_cast(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, #if INDEXSTORE_HAS_BLOCKS bool (^applier)(indexstore_occurrence_t occur)) { #else llvm::function_ref applier) { #endif auto *reader = static_cast(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, #if INDEXSTORE_HAS_BLOCKS bool (^applier)(indexstore_occurrence_t occur)) { #else llvm::function_ref applier) { #endif auto *reader = static_cast(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); } 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(); strncpy(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(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(c_store); std::unique_ptr 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(rdr); delete reader; } indexstore_string_ref_t indexstore_unit_reader_get_provider_identifier(indexstore_unit_reader_t rdr) { auto reader = static_cast(rdr); return toIndexStoreString(reader->getProviderIdentifier()); } indexstore_string_ref_t indexstore_unit_reader_get_provider_version(indexstore_unit_reader_t rdr) { auto reader = static_cast(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(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(rdr); return reader->isSystemUnit(); } bool indexstore_unit_reader_is_module_unit(indexstore_unit_reader_t rdr) { auto reader = static_cast(rdr); return reader->isModuleUnit(); } bool indexstore_unit_reader_is_debug_compilation(indexstore_unit_reader_t rdr) { auto reader = static_cast(rdr); return reader->isDebugCompilation(); } bool indexstore_unit_reader_has_main_file(indexstore_unit_reader_t rdr) { auto reader = static_cast(rdr); return reader->hasMainFile(); } indexstore_string_ref_t indexstore_unit_reader_get_main_file(indexstore_unit_reader_t rdr) { auto reader = static_cast(rdr); return toIndexStoreString(reader->getMainFilePath()); } indexstore_string_ref_t indexstore_unit_reader_get_module_name(indexstore_unit_reader_t rdr) { auto reader = static_cast(rdr); return toIndexStoreString(reader->getModuleName()); } indexstore_string_ref_t indexstore_unit_reader_get_working_dir(indexstore_unit_reader_t rdr) { auto reader = static_cast(rdr); return toIndexStoreString(reader->getWorkingDirectory()); } indexstore_string_ref_t indexstore_unit_reader_get_output_file(indexstore_unit_reader_t rdr) { auto reader = static_cast(rdr); return toIndexStoreString(reader->getOutputFile()); } indexstore_string_ref_t indexstore_unit_reader_get_sysroot_path(indexstore_unit_reader_t rdr) { auto reader = static_cast(rdr); return toIndexStoreString(reader->getSysrootPath()); } indexstore_string_ref_t indexstore_unit_reader_get_target(indexstore_unit_reader_t rdr) { auto reader = static_cast(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(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(c_dep); return dep->IsSystem; } indexstore_string_ref_t indexstore_unit_dependency_get_filepath(indexstore_unit_dependency_t c_dep) { auto dep = static_cast(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(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(c_dep); return toIndexStoreString(dep->UnitOrRecordName); } time_t indexstore_unit_dependency_get_modification_time( indexstore_unit_dependency_t c_dep) { auto dep = static_cast(c_dep); return dep->ModTime; } size_t indexstore_unit_dependency_get_file_size(indexstore_unit_dependency_t c_dep) { auto dep = static_cast(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(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(c_inc); return toIndexStoreString(inc->TargetPath); } unsigned indexstore_unit_include_get_source_line(indexstore_unit_include_t c_inc) { auto inc = static_cast(c_inc); return inc->SourceLine; } bool indexstore_unit_reader_dependencies_apply( indexstore_unit_reader_t rdr, #if INDEXSTORE_HAS_BLOCKS bool (^applier)(indexstore_unit_dependency_t)) { #else llvm::function_ref applier) { #endif auto reader = static_cast(rdr); return reader->foreachDependency( [&](const IndexUnitReader::DependencyInfo &depInfo) -> bool { return applier((void *)&depInfo); }); } bool indexstore_unit_reader_includes_apply( indexstore_unit_reader_t rdr, #if INDEXSTORE_HAS_BLOCKS bool (^applier)(indexstore_unit_include_t)) { #else llvm::function_ref applier) { #endif auto reader = static_cast(rdr); return reader->foreachInclude( [&](const IndexUnitReader::IncludeInfo &incInfo) -> bool { return applier((void *)&incInfo); }); }