| //===- 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 |