summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIvan Donchevskii <ivan.donchevskii@qt.io>2018-08-01 10:49:29 +0200
committerIvan Donchevskii <ivan.donchevskii@qt.io>2018-08-01 12:39:28 +0000
commit61f9ff7bb83fe0e09b576b30c85ce88ca83e7b77 (patch)
tree5ab31c663f803a6f282c00727a80815e8ad69ba6 /tools
parent5093ff0b282ace605d44a1553a61a82afc921055 (diff)
Index whild build. Part 3
https://reviews.llvm.org/D41407 Change-Id: I73563f2318d48e70f96b1082337f3b5a7a6c62b2 Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
Diffstat (limited to 'tools')
-rw-r--r--tools/CMakeLists.txt1
-rw-r--r--tools/IndexStore/CMakeLists.txt94
-rw-r--r--tools/IndexStore/IndexStore.cpp636
-rw-r--r--tools/IndexStore/IndexStore.exports69
-rw-r--r--tools/c-index-test/CMakeLists.txt20
-rw-r--r--tools/c-index-test/JSONAggregation.cpp421
-rw-r--r--tools/c-index-test/JSONAggregation.h24
-rw-r--r--tools/c-index-test/core_main.cpp639
8 files changed, 1900 insertions, 4 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 9f76d36dba..f50305c2f1 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -10,6 +10,7 @@ add_clang_subdirectory(clang-import-test)
add_clang_subdirectory(clang-offload-bundler)
add_clang_subdirectory(c-index-test)
+add_clang_subdirectory(IndexStore)
add_clang_subdirectory(clang-rename)
add_clang_subdirectory(clang-refactor)
diff --git a/tools/IndexStore/CMakeLists.txt b/tools/IndexStore/CMakeLists.txt
new file mode 100644
index 0000000000..8ad6499117
--- /dev/null
+++ b/tools/IndexStore/CMakeLists.txt
@@ -0,0 +1,94 @@
+include(CheckIncludeFiles)
+
+set(SOURCES
+ IndexStore.cpp
+
+ ADDITIONAL_HEADERS
+ ../../include/indexstore/indexstore.h
+ ../../include/indexstore/IndexStoreCXX.h
+ )
+
+set(LIBS
+ clangDirectoryWatcher
+ clangIndex
+)
+
+set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/IndexStore.exports)
+
+set(ENABLE_SHARED SHARED)
+
+if(WIN32)
+ set(output_name "libIndexStore")
+else()
+ set(output_name "IndexStore")
+endif()
+
+# FIXME: needs to be ported to non-Apple platforms.
+if(APPLE)
+
+add_clang_library(IndexStore ${ENABLE_SHARED} ${ENABLE_STATIC}
+ OUTPUT_NAME ${output_name}
+ ${SOURCES}
+
+ LINK_LIBS
+ ${LIBS}
+
+ LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ Core
+ Support
+ )
+
+set(INDEXSTORE_LIBRARY_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}")
+
+if(ENABLE_SHARED)
+ if(WIN32)
+ set_target_properties(IndexStore
+ PROPERTIES
+ VERSION ${INDEXSTORE_LIBRARY_VERSION}
+ DEFINE_SYMBOL _CINDEX_LIB_)
+ elseif(APPLE)
+ set(INDEXSTORE_LINK_FLAGS " -Wl,-compatibility_version -Wl,1")
+ set(INDEXSTORE_LINK_FLAGS "${INDEXSTORE_LINK_FLAGS} -Wl,-current_version -Wl,${INDEXSTORE_LIBRARY_VERSION}")
+
+ check_include_files("CoreServices/CoreServices.h" HAVE_CORESERVICES_H)
+ if(HAVE_CORESERVICES_H)
+ set(INDEXSTORE_LINK_FLAGS "${INDEXSTORE_LINK_FLAGS} -framework CoreServices")
+ endif()
+
+ set_property(TARGET IndexStore APPEND_STRING PROPERTY
+ LINK_FLAGS ${INDEXSTORE_LINK_FLAGS})
+ else()
+ set_target_properties(IndexStore
+ PROPERTIES
+ VERSION ${INDEXSTORE_LIBRARY_VERSION}
+ DEFINE_SYMBOL _CINDEX_LIB_)
+ endif()
+endif()
+
+if (LLVM_INSTALL_TOOLCHAIN_ONLY)
+ install(TARGETS IndexStore
+ COMPONENT IndexStore
+ LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
+ ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
+ RUNTIME DESTINATION bin)
+
+ if (NOT CMAKE_CONFIGURATION_TYPES)
+ add_custom_target(install-IndexStore
+ DEPENDS IndexStore
+ COMMAND "${CMAKE_COMMAND}"
+ -DCMAKE_INSTALL_COMPONENT=IndexStore
+ -P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
+ endif()
+endif()
+
+set(INDEXSTORE_HEADERS_INSTALL_DESTINATION "local/include")
+
+install(DIRECTORY ../../include/indexstore
+ COMPONENT IndexStore
+ DESTINATION "${INDEXSTORE_HEADERS_INSTALL_DESTINATION}"
+ FILES_MATCHING
+ PATTERN "*.h"
+ PATTERN ".svn" EXCLUDE
+ )
+endif()
diff --git a/tools/IndexStore/IndexStore.cpp b/tools/IndexStore/IndexStore.cpp
new file mode 100644
index 0000000000..c73b9a9aa7
--- /dev/null
+++ b/tools/IndexStore/IndexStore.cpp
@@ -0,0 +1,636 @@
+//===- 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"
+#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
diff --git a/tools/IndexStore/IndexStore.exports b/tools/IndexStore/IndexStore.exports
new file mode 100644
index 0000000000..70c174f360
--- /dev/null
+++ b/tools/IndexStore/IndexStore.exports
@@ -0,0 +1,69 @@
+indexstore_error_get_description
+indexstore_error_dispose
+indexstore_format_version
+indexstore_store_create
+indexstore_store_dispose
+indexstore_store_get_unit_modification_time
+indexstore_store_get_unit_name_from_output_path
+indexstore_store_units_apply
+indexstore_store_set_unit_event_handler
+indexstore_store_start_unit_event_listening
+indexstore_store_stop_unit_event_listening
+indexstore_store_discard_unit
+indexstore_store_discard_record
+indexstore_store_purge_stale_data
+indexstore_symbol_get_kind
+indexstore_symbol_get_language
+indexstore_symbol_get_properties
+indexstore_symbol_get_roles
+indexstore_symbol_get_related_roles
+indexstore_symbol_get_subkind
+indexstore_symbol_get_name
+indexstore_symbol_get_usr
+indexstore_symbol_get_codegen_name
+indexstore_symbol_relation_get_roles
+indexstore_symbol_relation_get_symbol
+indexstore_occurrence_get_symbol
+indexstore_occurrence_get_roles
+indexstore_occurrence_get_line_col
+indexstore_occurrence_relations_apply
+indexstore_record_reader_create
+indexstore_record_reader_dispose
+indexstore_record_reader_search_symbols
+indexstore_record_reader_symbols_apply
+indexstore_record_reader_occurrences_apply
+indexstore_record_reader_occurrences_in_line_range_apply
+indexstore_record_reader_occurrences_of_symbols_apply
+indexstore_unit_dependency_get_kind
+indexstore_unit_dependency_get_filepath
+indexstore_unit_dependency_get_file_size
+indexstore_unit_dependency_get_modification_time
+indexstore_unit_dependency_get_modulename
+indexstore_unit_dependency_get_name
+indexstore_unit_dependency_is_system
+indexstore_unit_event_get_kind
+indexstore_unit_event_get_modification_time
+indexstore_unit_event_get_unit_name
+indexstore_unit_event_notification_get_event
+indexstore_unit_event_notification_get_events_count
+indexstore_unit_event_notification_is_initial
+indexstore_unit_reader_create
+indexstore_unit_reader_dispose
+indexstore_unit_reader_get_main_file
+indexstore_unit_reader_get_modification_time
+indexstore_unit_reader_get_module_name
+indexstore_unit_reader_get_provider_identifier
+indexstore_unit_reader_get_provider_version
+indexstore_unit_reader_get_working_dir
+indexstore_unit_reader_get_output_file
+indexstore_unit_reader_get_sysroot_path
+indexstore_unit_reader_get_target
+indexstore_unit_reader_dependencies_apply
+indexstore_unit_reader_includes_apply
+indexstore_unit_reader_has_main_file
+indexstore_unit_reader_is_debug_compilation
+indexstore_unit_reader_is_module_unit
+indexstore_unit_reader_is_system_unit
+indexstore_unit_include_get_source_path
+indexstore_unit_include_get_target_path
+indexstore_unit_include_get_source_line
diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt
index d38c7bb287..82245dc08a 100644
--- a/tools/c-index-test/CMakeLists.txt
+++ b/tools/c-index-test/CMakeLists.txt
@@ -1,3 +1,5 @@
+include(CheckIncludeFiles)
+
set(LLVM_LINK_COMPONENTS
support
)
@@ -5,8 +7,15 @@ set(LLVM_LINK_COMPONENTS
add_clang_executable(c-index-test
c-index-test.c
core_main.cpp
+ JSONAggregation.cpp
)
+set(INDEXSTORE_LIB)
+set(CINDEXTEST_LIBS)
+if(APPLE)
+ set(INDEXSTORE_LIB IndexStore)
+endif()
+
if(NOT MSVC)
set_property(
SOURCE c-index-test.c
@@ -20,17 +29,21 @@ if (LLVM_BUILD_STATIC)
libclang_static
clangCodeGen
clangIndex
+ ${CINDEXTEST_LIBS}
)
else()
target_link_libraries(c-index-test
PRIVATE
libclang
+ ${INDEXSTORE_LIB}
clangAST
clangBasic
clangCodeGen
+ clangDirectoryWatcher
clangFrontend
clangIndex
clangSerialization
+ ${CINDEXTEST_LIBS}
)
endif()
@@ -44,6 +57,13 @@ if (CLANG_HAVE_LIBXML)
target_link_libraries(c-index-test PRIVATE ${LIBXML2_LIBRARIES})
endif()
+if(APPLE)
+ check_include_files("CoreServices/CoreServices.h" HAVE_CORESERVICES_H)
+ if(HAVE_CORESERVICES_H)
+ target_link_libraries(c-index-test PRIVATE "-framework CoreServices")
+ endif()
+endif()
+
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
if(INTERNAL_INSTALL_PREFIX)
set(INSTALL_DESTINATION "${INTERNAL_INSTALL_PREFIX}/bin")
diff --git a/tools/c-index-test/JSONAggregation.cpp b/tools/c-index-test/JSONAggregation.cpp
new file mode 100644
index 0000000000..4c761b6f8f
--- /dev/null
+++ b/tools/c-index-test/JSONAggregation.cpp
@@ -0,0 +1,421 @@
+//===--- JSONAggregation.cpp - Index data aggregation in JSON format ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JSONAggregation.h"
+#include "indexstore/IndexStoreCXX.h"
+#include "clang/Index/IndexDataStoreSymbolUtils.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::index;
+using namespace indexstore;
+using namespace llvm;
+
+#if INDEXSTORE_HAS_BLOCKS
+
+namespace {
+
+typedef size_t FilePathIndex;
+typedef size_t RecordIndex;
+typedef size_t SymbolIndex;
+
+struct UnitSourceInfo {
+ FilePathIndex FilePath;
+ SmallVector<RecordIndex, 2> AssociatedRecords;
+};
+
+struct UnitInfo {
+ std::string Name;
+ SmallVector<UnitSourceInfo, 8> Sources;
+ SmallVector<std::string, 3> UnitDepends;
+ FilePathIndex OutFile;
+ StringRef Triple;
+};
+
+struct SymbolInfo {
+ SymbolKind Kind;
+ SymbolLanguage Lang;
+ StringRef USR;
+ StringRef Name;
+ StringRef CodegenName;
+ SymbolRoleSet Roles = 0;
+ SymbolRoleSet RelatedRoles = 0;
+};
+
+struct SymbolRelationInfo {
+ SymbolIndex RelatedSymbol;
+ SymbolRoleSet Roles;
+ SymbolRelationInfo(SymbolIndex relSymbol, SymbolRoleSet roles)
+ : RelatedSymbol(relSymbol), Roles(roles) {}
+};
+
+struct SymbolOccurrenceInfo {
+ SymbolIndex Symbol;
+ SymbolRoleSet Roles = 0;
+ std::vector<SymbolRelationInfo> Relations;
+ unsigned Line;
+ unsigned Column;
+};
+
+struct RecordInfo {
+ SmallVector<SymbolOccurrenceInfo, 8> Occurrences;
+};
+
+class Aggregator {
+ IndexStore Store;
+
+ BumpPtrAllocator Allocator;
+
+ StringMap<FilePathIndex, BumpPtrAllocator &> FilePathIndices;
+ std::vector<StringRef> FilePaths;
+ StringMap<char, BumpPtrAllocator &> Triples;
+
+ std::vector<std::unique_ptr<UnitInfo>> Units;
+
+ StringMap<RecordIndex, BumpPtrAllocator &> RecordIndices;
+ std::vector<std::unique_ptr<RecordInfo>> Records;
+
+ StringMap<SymbolIndex, BumpPtrAllocator &> SymbolIndices;
+ std::vector<SymbolInfo> Symbols;
+
+public:
+ explicit Aggregator(IndexStore store)
+ : Store(std::move(store)), FilePathIndices(Allocator), Triples(Allocator),
+ RecordIndices(Allocator), SymbolIndices(Allocator) {}
+
+ bool process();
+ void processUnit(StringRef name, IndexUnitReader &UnitReader);
+ void dumpJSON(raw_ostream &OS);
+
+private:
+ StringRef copyStr(StringRef str) {
+ if (str.empty())
+ return StringRef();
+ char *buf = Allocator.Allocate<char>(str.size());
+ std::copy(str.begin(), str.end(), buf);
+ return StringRef(buf, str.size());
+ }
+
+ StringRef getTripleString(StringRef inputTriple) {
+ return Triples.insert(std::make_pair(inputTriple, 0)).first->first();
+ }
+
+ FilePathIndex getFilePathIndex(StringRef path, StringRef workingDir);
+ RecordIndex getRecordIndex(StringRef recordFile);
+ SymbolIndex getSymbolIndex(IndexRecordSymbol sym);
+ std::unique_ptr<RecordInfo> processRecord(StringRef recordFile);
+};
+
+} // anonymous namespace
+
+bool Aggregator::process() {
+ bool succ =
+ Store.foreachUnit(/*sorted=*/true, [&](StringRef unitName) -> bool {
+ std::string error;
+ auto unitReader = IndexUnitReader(Store, unitName, error);
+ if (!unitReader) {
+ errs() << "error opening unit file '" << unitName << "': " << error
+ << '\n';
+ return false;
+ }
+
+ processUnit(unitName, unitReader);
+ return true;
+ });
+
+ return !succ;
+}
+
+void Aggregator::processUnit(StringRef name, IndexUnitReader &UnitReader) {
+ auto workDir = UnitReader.getWorkingDirectory();
+ auto unit = llvm::make_unique<UnitInfo>();
+ unit->Name = name;
+ unit->Triple = getTripleString(UnitReader.getTarget());
+ unit->OutFile = getFilePathIndex(UnitReader.getOutputFile(), workDir);
+
+ struct DepInfo {
+ UnitSourceInfo source;
+ std::string unitName;
+ };
+ SmallVector<DepInfo, 32> Deps;
+ UnitReader.foreachDependency([&](IndexUnitDependency dep) -> bool {
+ Deps.resize(Deps.size() + 1);
+ auto &depInfo = Deps.back();
+ switch (dep.getKind()) {
+ case IndexUnitDependency::DependencyKind::Unit: {
+ depInfo.unitName = dep.getName();
+ StringRef filePath = dep.getFilePath();
+ if (!filePath.empty())
+ depInfo.source.FilePath = getFilePathIndex(filePath, workDir);
+ break;
+ }
+ case IndexUnitDependency::DependencyKind::Record: {
+ depInfo.source.FilePath = getFilePathIndex(dep.getFilePath(), workDir);
+ RecordIndex recIndex = getRecordIndex(dep.getName());
+ depInfo.source.AssociatedRecords.push_back(recIndex);
+ break;
+ }
+ case IndexUnitDependency::DependencyKind::File:
+ depInfo.source.FilePath = getFilePathIndex(dep.getFilePath(), workDir);
+ }
+ return true;
+ });
+
+ unit->Sources.reserve(Deps.size());
+ for (auto &dep : Deps) {
+ if (!dep.unitName.empty()) {
+ unit->UnitDepends.emplace_back(std::move(dep.unitName));
+ } else {
+ unit->Sources.push_back(std::move(dep.source));
+ }
+ }
+
+ Units.push_back(std::move(unit));
+}
+
+FilePathIndex Aggregator::getFilePathIndex(StringRef path,
+ StringRef workingDir) {
+ StringRef absPath;
+ SmallString<128> absPathBuf;
+ if (sys::path::is_absolute(path) || workingDir.empty()) {
+ absPath = path;
+ } else {
+ absPathBuf = workingDir;
+ sys::path::append(absPathBuf, path);
+ absPath = absPathBuf.str();
+ }
+
+ auto pair = FilePathIndices.insert(std::make_pair(absPath, FilePaths.size()));
+ bool wasInserted = pair.second;
+ if (wasInserted) {
+ FilePaths.push_back(pair.first->first());
+ }
+ return pair.first->second;
+}
+
+RecordIndex Aggregator::getRecordIndex(StringRef recordFile) {
+ auto pair = RecordIndices.insert(std::make_pair(recordFile, Records.size()));
+ bool wasInserted = pair.second;
+ if (wasInserted) {
+ Records.push_back(processRecord(recordFile));
+ }
+ return pair.first->second;
+}
+
+std::unique_ptr<RecordInfo> Aggregator::processRecord(StringRef recordFile) {
+ std::string error;
+ auto recordReader = IndexRecordReader(Store, recordFile, error);
+ if (!recordReader) {
+ errs() << "failed reading record file: " << recordFile << '\n';
+ ::exit(1);
+ }
+ auto record = llvm::make_unique<RecordInfo>();
+ recordReader.foreachOccurrence([&](IndexRecordOccurrence idxOccur) -> bool {
+ SymbolIndex symIdx = getSymbolIndex(idxOccur.getSymbol());
+ SymbolInfo &symInfo = Symbols[symIdx];
+ symInfo.Roles |= idxOccur.getRoles();
+ SymbolOccurrenceInfo occurInfo;
+ occurInfo.Symbol = symIdx;
+ idxOccur.foreachRelation([&](IndexSymbolRelation rel) -> bool {
+ SymbolIndex relsymIdx = getSymbolIndex(rel.getSymbol());
+ SymbolInfo &relsymInfo = Symbols[relsymIdx];
+ relsymInfo.RelatedRoles |= rel.getRoles();
+ occurInfo.Relations.emplace_back(relsymIdx, rel.getRoles());
+ return true;
+ });
+ occurInfo.Roles = idxOccur.getRoles();
+ std::tie(occurInfo.Line, occurInfo.Column) = idxOccur.getLineCol();
+ record->Occurrences.push_back(std::move(occurInfo));
+ return true;
+ });
+ return record;
+}
+
+SymbolIndex Aggregator::getSymbolIndex(IndexRecordSymbol sym) {
+ auto pair =
+ SymbolIndices.insert(std::make_pair(sym.getUSR(), Symbols.size()));
+ bool wasInserted = pair.second;
+ if (wasInserted) {
+ SymbolInfo symInfo;
+ symInfo.Kind = getSymbolKind(sym.getKind());
+ symInfo.Lang = getSymbolLanguage(sym.getLanguage());
+ symInfo.USR = pair.first->first();
+ symInfo.Name = copyStr(sym.getName());
+ symInfo.CodegenName = copyStr(sym.getCodegenName());
+ Symbols.push_back(std::move(symInfo));
+ }
+ return pair.first->second;
+}
+
+void Aggregator::dumpJSON(raw_ostream &OS) {
+ OS << "{\n";
+ OS.indent(2) << "\"files\": [\n";
+ for (unsigned i = 0, e = FilePaths.size(); i != e; ++i) {
+ OS.indent(4) << '\"' << FilePaths[i] << '\"';
+ if (i < e - 1)
+ OS << ',';
+ OS << '\n';
+ }
+ OS.indent(2) << "],\n";
+
+ OS.indent(2) << "\"symbols\": [\n";
+ for (unsigned i = 0, e = Symbols.size(); i != e; ++i) {
+ OS.indent(4) << "{\n";
+ SymbolInfo &symInfo = Symbols[i];
+ OS.indent(6) << "\"kind\": \"" << getSymbolKindString(symInfo.Kind)
+ << "\",\n";
+ OS.indent(6) << "\"lang\": \"" << getSymbolLanguageString(symInfo.Lang)
+ << "\",\n";
+ OS.indent(6) << "\"usr\": \"" << symInfo.USR << "\",\n";
+ OS.indent(6) << "\"name\": \"" << symInfo.Name << "\",\n";
+ if (!symInfo.CodegenName.empty())
+ OS.indent(6) << "\"codegen\": \"" << symInfo.CodegenName << "\",\n";
+ OS.indent(6) << "\"roles\": \"";
+ printSymbolRoles(symInfo.Roles, OS);
+ OS << '\"';
+ if (symInfo.RelatedRoles != 0) {
+ OS << ",\n";
+ OS.indent(6) << "\"rel-roles\": \"";
+ printSymbolRoles(symInfo.RelatedRoles, OS);
+ OS << '\"';
+ }
+ OS << '\n';
+ OS.indent(4) << "}";
+ if (i < e - 1)
+ OS << ',';
+ OS << '\n';
+ }
+ OS.indent(2) << "],\n";
+
+ OS.indent(2) << "\"records\": [\n";
+ for (unsigned i = 0, e = Records.size(); i != e; ++i) {
+ OS.indent(4) << "{\n";
+ RecordInfo &recInfo = *Records[i];
+ OS.indent(6) << "\"occurrences\": [\n";
+ for (unsigned oi = 0, oe = recInfo.Occurrences.size(); oi != oe; ++oi) {
+ OS.indent(8) << "{\n";
+ SymbolOccurrenceInfo &occurInfo = recInfo.Occurrences[oi];
+ OS.indent(10) << "\"symbol\": " << occurInfo.Symbol << ",\n";
+ OS.indent(10) << "\"line\": " << occurInfo.Line << ",\n";
+ OS.indent(10) << "\"col\": " << occurInfo.Column << ",\n";
+ OS.indent(10) << "\"roles\": \"";
+ printSymbolRoles(occurInfo.Roles, OS);
+ OS << '\"';
+ if (!occurInfo.Relations.empty()) {
+ OS << ",\n";
+ OS.indent(10) << "\"relations\": [\n";
+ for (unsigned ri = 0, re = occurInfo.Relations.size(); ri != re; ++ri) {
+ OS.indent(12) << "{\n";
+ SymbolRelationInfo &relInfo = occurInfo.Relations[ri];
+ OS.indent(14) << "\"symbol\": " << relInfo.RelatedSymbol << ",\n";
+ OS.indent(14) << "\"rel-roles\": \"";
+ printSymbolRoles(relInfo.Roles, OS);
+ OS << "\"\n";
+ OS.indent(12) << "}";
+ if (ri < re - 1)
+ OS << ',';
+ OS << '\n';
+ }
+ OS.indent(10) << "]\n";
+ }
+ OS << '\n';
+ OS.indent(8) << "}";
+ if (oi < oe - 1)
+ OS << ',';
+ OS << '\n';
+ }
+ OS.indent(6) << "]\n";
+ OS.indent(4) << "}";
+ if (i < e - 1)
+ OS << ',';
+ OS << '\n';
+ }
+ OS.indent(2) << "],\n";
+
+ StringMap<size_t> UnitIndicesByName;
+ for (unsigned i = 0, e = Units.size(); i != e; ++i) {
+ UnitInfo &unit = *Units[i];
+ UnitIndicesByName[unit.Name] = i;
+ }
+
+ OS.indent(2) << "\"units\": [\n";
+ for (unsigned i = 0, e = Units.size(); i != e; ++i) {
+ OS.indent(4) << "{\n";
+ UnitInfo &unit = *Units[i];
+ OS.indent(6) << "\"triple\": \"" << unit.Triple << "\",\n";
+ OS.indent(6) << "\"out-file\": " << unit.OutFile << ",\n";
+ if (!unit.UnitDepends.empty()) {
+ OS.indent(6) << "\"unit-dependencies\": [";
+ for (unsigned ui = 0, ue = unit.UnitDepends.size(); ui != ue; ++ui) {
+ OS << UnitIndicesByName[unit.UnitDepends[ui]];
+ if (ui < ue - 1)
+ OS << ", ";
+ }
+ OS << "],\n";
+ }
+ OS.indent(6) << "\"sources\": [\n";
+ for (unsigned si = 0, se = unit.Sources.size(); si != se; ++si) {
+ OS.indent(8) << "{\n";
+ UnitSourceInfo &source = unit.Sources[si];
+ OS.indent(10) << "\"file\": " << source.FilePath;
+ if (!source.AssociatedRecords.empty()) {
+ OS << ",\n";
+ OS.indent(10) << "\"records\": [";
+ for (unsigned ri = 0, re = source.AssociatedRecords.size(); ri != re;
+ ++ri) {
+ OS << source.AssociatedRecords[ri];
+ if (ri < re - 1)
+ OS << ", ";
+ }
+ OS << ']';
+ }
+ OS << '\n';
+ OS.indent(8) << "}";
+ if (si < se - 1)
+ OS << ',';
+ OS << '\n';
+ }
+ OS.indent(6) << "]\n";
+ OS.indent(4) << "}";
+ if (i < e - 1)
+ OS << ',';
+ OS << '\n';
+ }
+ OS.indent(2) << "]\n";
+ OS << "}\n";
+}
+
+bool index::aggregateDataAsJSON(StringRef StorePath, raw_ostream &OS) {
+ std::string error;
+ auto dataStore = IndexStore(StorePath, error);
+ if (!dataStore) {
+ errs() << "error opening store path '" << StorePath << "': " << error
+ << '\n';
+ return true;
+ }
+
+ // Explicitely avoid doing any memory cleanup for aggregator since the process
+ // is going to exit when we are done.
+ Aggregator *aggregator = new Aggregator(std::move(dataStore));
+ bool err = aggregator->process();
+ if (err)
+ return true;
+ aggregator->dumpJSON(OS);
+ return false;
+}
+
+#else
+
+bool index::aggregateDataAsJSON(StringRef StorePath, raw_ostream &OS) {
+ return true;
+}
+#endif
diff --git a/tools/c-index-test/JSONAggregation.h b/tools/c-index-test/JSONAggregation.h
new file mode 100644
index 0000000000..5224ce8e87
--- /dev/null
+++ b/tools/c-index-test/JSONAggregation.h
@@ -0,0 +1,24 @@
+//===--- JSONAggregation.h - Index data aggregation in JSON format --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_CINDEXTEST_JSONAGGREGATION_H
+#define LLVM_CLANG_TOOLS_CINDEXTEST_JSONAGGREGATION_H
+
+#include "clang/Basic/LLVM.h"
+
+namespace clang {
+namespace index {
+
+/// Returns true if an error occurred, false otherwise.
+bool aggregateDataAsJSON(StringRef StorePath, raw_ostream &OS);
+
+} // end namespace index
+} // end namespace clang
+
+#endif
diff --git a/tools/c-index-test/core_main.cpp b/tools/c-index-test/core_main.cpp
index 805f21cc77..d89b2116d5 100644
--- a/tools/c-index-test/core_main.cpp
+++ b/tools/c-index-test/core_main.cpp
@@ -7,23 +7,42 @@
//
//===----------------------------------------------------------------------===//
+#include "JSONAggregation.h"
+#include "indexstore/IndexStoreCXX.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
+#include "clang/DirectoryWatcher/DirectoryWatcher.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Index/CodegenNameGenerator.h"
#include "clang/Index/IndexDataConsumer.h"
+#include "clang/Index/IndexDataStoreSymbolUtils.h"
+#include "clang/Index/IndexRecordReader.h"
+#include "clang/Index/IndexUnitReader.h"
#include "clang/Index/USRGeneration.h"
#include "clang/Index/UnitIndexDataConsumer.h"
#include "clang/Index/UnitIndexingAction.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
+#define HAVE_CORESERVICES 0
+
+#if defined(__has_include)
+#if __has_include(<CoreServices/CoreServices.h>)
+
+#include <CoreServices/CoreServices.h>
+#undef HAVE_CORESERVICES
+#define HAVE_CORESERVICES 1
+
+#endif
+#endif
+
using namespace clang;
using namespace clang::index;
using namespace llvm;
@@ -36,6 +55,11 @@ enum class ActionType {
None,
PrintSourceSymbols,
PrintSourceUnit,
+ PrintRecord,
+ PrintUnit,
+ PrintStoreFormatVersion,
+ AggregateAsJSON,
+ WatchDir,
};
namespace options {
@@ -44,12 +68,28 @@ static cl::OptionCategory IndexTestCoreCategory("index-test-core options");
static cl::opt<ActionType> Action(
cl::desc("Action:"), cl::init(ActionType::None),
- cl::values(clEnumValN(ActionType::PrintSourceSymbols,
- "print-source-symbols", "Print symbols from source"),
- clEnumValN(ActionType::PrintSourceUnit, "print-source-unit",
- "Print unit info from source")),
+ cl::values(
+ clEnumValN(ActionType::PrintSourceSymbols, "print-source-symbols",
+ "Print symbols from source"),
+ clEnumValN(ActionType::PrintSourceUnit, "print-source-unit",
+ "Print unit info from source"),
+ clEnumValN(ActionType::PrintRecord, "print-record",
+ "Print record file info"),
+ clEnumValN(ActionType::PrintUnit, "print-unit", "Print unit file info"),
+ clEnumValN(ActionType::PrintStoreFormatVersion,
+ "print-store-format-version", "Print store format version"),
+ clEnumValN(ActionType::AggregateAsJSON, "aggregate-json",
+ "Aggregate index data in JSON format"),
+ clEnumValN(ActionType::WatchDir, "watch-dir",
+ "Watch directory for file events")),
cl::cat(IndexTestCoreCategory));
+static cl::opt<std::string> OutputFile("o", cl::desc("output file"),
+ cl::cat(IndexTestCoreCategory));
+
+static cl::list<std::string> InputFiles(cl::Positional,
+ cl::desc("<filename>..."));
+
static cl::extrahelp MoreHelp(
"\nAdd \"-- <compiler arguments>\" at the end to setup the compiler "
"invocation\n"
@@ -69,6 +109,8 @@ static cl::opt<std::string>
ModuleFormat("fmodule-format", cl::init("raw"),
cl::desc("Container format for clang modules and PCH, 'raw' or 'obj'"));
+static cl::opt<std::string> FilePathAndRange(
+ "filepath", cl::desc("File path that can optionally include a line range"));
}
} // anonymous namespace
@@ -400,6 +442,324 @@ static bool printSourceUnit(ArrayRef<const char *> Args, bool IndexLocals,
return !Unit;
}
+#if INDEXSTORE_HAS_BLOCKS
+
+//===----------------------------------------------------------------------===//
+// Print Record
+//===----------------------------------------------------------------------===//
+
+static void printSymbol(const IndexRecordDecl &Rec, raw_ostream &OS);
+static void printSymbol(const IndexRecordOccurrence &Rec, raw_ostream &OS);
+
+static int printRecord(StringRef Filename, raw_ostream &OS) {
+ std::string Error;
+ auto Reader = IndexRecordReader::createWithFilePath(Filename, Error);
+ if (!Reader) {
+ errs() << Error << '\n';
+ return true;
+ }
+
+ Reader->foreachDecl(/*noCache=*/true,
+ [&](const IndexRecordDecl *Rec) -> bool {
+ printSymbol(*Rec, OS);
+ return true;
+ });
+ OS << "------------\n";
+ Reader->foreachOccurrence([&](const IndexRecordOccurrence &Rec) -> bool {
+ printSymbol(Rec, OS);
+ return true;
+ });
+
+ return false;
+};
+
+//===----------------------------------------------------------------------===//
+// Print Store Records
+//===----------------------------------------------------------------------===//
+
+static void printSymbol(indexstore::IndexRecordSymbol Sym, raw_ostream &OS);
+static void printSymbol(indexstore::IndexRecordOccurrence Occur,
+ raw_ostream &OS);
+
+static bool printStoreRecord(indexstore::IndexStore &Store, StringRef RecName,
+ StringRef FilePath, raw_ostream &OS) {
+ std::string Error;
+ indexstore::IndexRecordReader Reader(Store, RecName, Error);
+ if (!Reader) {
+ errs() << "error loading record: " << Error << "\n";
+ return true;
+ }
+
+ StringRef Filename = sys::path::filename(FilePath);
+ OS << Filename << '\n';
+ OS << "------------\n";
+ Reader.foreachSymbol(/*noCache=*/true,
+ [&](indexstore::IndexRecordSymbol Sym) -> bool {
+ printSymbol(Sym, OS);
+ return true;
+ });
+ OS << "------------\n";
+ Reader.foreachOccurrence(
+ [&](indexstore::IndexRecordOccurrence Occur) -> bool {
+ printSymbol(Occur, OS);
+ return true;
+ });
+
+ return false;
+}
+
+static int printStoreRecords(StringRef StorePath, raw_ostream &OS) {
+ std::string Error;
+ indexstore::IndexStore Store(StorePath, Error);
+ if (!Store) {
+ errs() << "error loading store: " << Error << "\n";
+ return 1;
+ }
+
+ bool Success =
+ Store.foreachUnit(/*sorted=*/true, [&](StringRef UnitName) -> bool {
+ indexstore::IndexUnitReader Reader(Store, UnitName, Error);
+ if (!Reader) {
+ errs() << "error loading unit: " << Error << "\n";
+ return false;
+ }
+ return Reader.foreachDependency(
+ [&](indexstore::IndexUnitDependency Dep) -> bool {
+ if (Dep.getKind() ==
+ indexstore::IndexUnitDependency::DependencyKind::Record) {
+ bool Err = printStoreRecord(Store, Dep.getName(),
+ Dep.getFilePath(), OS);
+ OS << '\n';
+ return !Err;
+ }
+ return true;
+ });
+ });
+
+ return !Success;
+}
+
+static std::string findRecordNameForFile(indexstore::IndexStore &store,
+ StringRef filePath) {
+ std::string recName;
+ store.foreachUnit(/*sorted=*/false, [&](StringRef unitName) -> bool {
+ std::string error;
+ indexstore::IndexUnitReader Reader(store, unitName, error);
+ if (!Reader) {
+ errs() << "error loading unit: " << error << "\n";
+ return false;
+ }
+ Reader.foreachDependency([&](indexstore::IndexUnitDependency Dep) -> bool {
+ if (Dep.getKind() ==
+ indexstore::IndexUnitDependency::DependencyKind::Record) {
+ if (Dep.getFilePath() == filePath) {
+ recName = Dep.getName();
+ return false;
+ }
+ return true;
+ }
+ return true;
+ });
+ return true;
+ });
+ return recName;
+}
+
+static int printStoreFileRecord(StringRef storePath, StringRef filePath,
+ Optional<unsigned> lineStart,
+ unsigned lineCount, raw_ostream &OS) {
+ std::string error;
+ indexstore::IndexStore store(storePath, error);
+ if (!store) {
+ errs() << "error loading store: " << error << "\n";
+ return 1;
+ }
+
+ std::string recName = findRecordNameForFile(store, filePath);
+ if (recName.empty()) {
+ errs() << "could not find record for '" << filePath << "'\n";
+ return 1;
+ }
+
+ if (!lineStart.hasValue())
+ return printStoreRecord(store, recName, filePath, OS);
+
+ indexstore::IndexRecordReader Reader(store, recName, error);
+ if (!Reader) {
+ errs() << "error loading record: " << error << "\n";
+ return 1;
+ }
+
+ Reader.foreachOccurrenceInLineRange(
+ *lineStart, lineCount,
+ [&](indexstore::IndexRecordOccurrence Occur) -> bool {
+ printSymbol(Occur, OS);
+ return true;
+ });
+
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// Print Unit
+//===----------------------------------------------------------------------===//
+
+static int printUnit(StringRef Filename, raw_ostream &OS) {
+ std::string Error;
+ auto Reader = IndexUnitReader::createWithFilePath(Filename, Error);
+ if (!Reader) {
+ errs() << Error << '\n';
+ return true;
+ }
+
+ OS << "provider: " << Reader->getProviderIdentifier() << '-'
+ << Reader->getProviderVersion() << '\n';
+ OS << "is-system: " << Reader->isSystemUnit() << '\n';
+ OS << "is-module: " << Reader->isModuleUnit() << '\n';
+ OS << "module-name: "
+ << (Reader->getModuleName().empty() ? "<none>" : Reader->getModuleName())
+ << '\n';
+ OS << "has-main: " << Reader->hasMainFile() << '\n';
+ OS << "main-path: " << Reader->getMainFilePath() << '\n';
+ OS << "work-dir: " << Reader->getWorkingDirectory() << '\n';
+ OS << "out-file: " << Reader->getOutputFile() << '\n';
+ OS << "target: " << Reader->getTarget() << '\n';
+ OS << "is-debug: " << Reader->isDebugCompilation() << '\n';
+ OS << "DEPEND START\n";
+ unsigned NumDepends = 0;
+ Reader->foreachDependency(
+ [&](const IndexUnitReader::DependencyInfo &Dep) -> bool {
+ switch (Dep.Kind) {
+ case IndexUnitReader::DependencyKind::Unit:
+ OS << "Unit | ";
+ break;
+ case IndexUnitReader::DependencyKind::Record:
+ OS << "Record | ";
+ break;
+ case IndexUnitReader::DependencyKind::File:
+ OS << "File | ";
+ break;
+ }
+ OS << (Dep.IsSystem ? "system" : "user");
+ OS << " | ";
+ if (!Dep.ModuleName.empty())
+ OS << Dep.ModuleName << " | ";
+ OS << Dep.FilePath << " | " << Dep.UnitOrRecordName << " | ";
+ OS << Dep.ModTime << " | " << Dep.FileSize << '\n';
+ ++NumDepends;
+ return true;
+ });
+ OS << "DEPEND END (" << NumDepends << ")\n";
+ OS << "INCLUDE START\n";
+ unsigned NumIncludes = 0;
+ Reader->foreachInclude([&](const IndexUnitReader::IncludeInfo &Inc) -> bool {
+ OS << Inc.SourcePath << ":" << Inc.SourceLine << " | ";
+ OS << Inc.TargetPath << '\n';
+ ++NumIncludes;
+ return true;
+ });
+ OS << "INCLUDE END (" << NumIncludes << ")\n";
+
+ return false;
+};
+
+//===----------------------------------------------------------------------===//
+// Print Store Units
+//===----------------------------------------------------------------------===//
+
+static bool printStoreUnit(indexstore::IndexStore &Store, StringRef UnitName,
+ raw_ostream &OS) {
+ std::string Error;
+ indexstore::IndexUnitReader Reader(Store, UnitName, Error);
+ if (!Reader) {
+ errs() << "error loading unit: " << Error << "\n";
+ return true;
+ }
+
+ OS << "provider: " << Reader.getProviderIdentifier() << '-'
+ << Reader.getProviderVersion() << '\n';
+ OS << "is-system: " << Reader.isSystemUnit() << '\n';
+ OS << "is-module: " << Reader.isModuleUnit() << '\n';
+ OS << "module-name: "
+ << (Reader.getModuleName().empty() ? "<none>" : Reader.getModuleName())
+ << '\n';
+ OS << "has-main: " << Reader.hasMainFile() << '\n';
+ OS << "main-path: " << Reader.getMainFilePath() << '\n';
+ OS << "work-dir: " << Reader.getWorkingDirectory() << '\n';
+ OS << "out-file: " << Reader.getOutputFile() << '\n';
+ OS << "target: " << Reader.getTarget() << '\n';
+ OS << "is-debug: " << Reader.isDebugCompilation() << '\n';
+ OS << "DEPEND START\n";
+ unsigned NumDepends = 0;
+ Reader.foreachDependency([&](indexstore::IndexUnitDependency Dep) -> bool {
+ switch (Dep.getKind()) {
+ case indexstore::IndexUnitDependency::DependencyKind::Unit:
+ OS << "Unit | ";
+ break;
+ case indexstore::IndexUnitDependency::DependencyKind::Record:
+ OS << "Record | ";
+ break;
+ case indexstore::IndexUnitDependency::DependencyKind::File:
+ OS << "File | ";
+ break;
+ }
+ OS << (Dep.isSystem() ? "system" : "user");
+ OS << " | ";
+ if (!Dep.getModuleName().empty())
+ OS << Dep.getModuleName() << " | ";
+ OS << Dep.getFilePath() << " | " << Dep.getName() << " | ";
+ OS << Dep.getModificationTime() << '\n';
+ ++NumDepends;
+ return true;
+ });
+ OS << "DEPEND END (" << NumDepends << ")\n";
+ OS << "INCLUDE START\n";
+ unsigned NumIncludes = 0;
+ Reader.foreachInclude([&](indexstore::IndexUnitInclude Inc) -> bool {
+ OS << Inc.getSourcePath() << ":" << Inc.getSourceLine() << " | ";
+ OS << Inc.getTargetPath() << '\n';
+ ++NumIncludes;
+ return true;
+ });
+ OS << "INCLUDE END (" << NumIncludes << ")\n";
+
+ return false;
+}
+
+static int printStoreUnits(StringRef StorePath, raw_ostream &OS) {
+ std::string Error;
+ indexstore::IndexStore Store(StorePath, Error);
+ if (!Store) {
+ errs() << "error loading store: " << Error << "\n";
+ return 1;
+ }
+
+ bool Success =
+ Store.foreachUnit(/*sorted=*/true, [&](StringRef UnitName) -> bool {
+ OS << UnitName << '\n';
+ OS << "--------\n";
+ bool err = printStoreUnit(Store, UnitName, OS);
+ OS << '\n';
+ return !err;
+ });
+
+ return !Success;
+}
+
+#else
+
+static int printUnit(StringRef Filename, raw_ostream &OS) { return 1; }
+
+static int printStoreUnits(StringRef StorePath, raw_ostream &OS) { return 1; }
+
+static int printStoreFileRecord(StringRef storePath, StringRef filePath,
+ Optional<unsigned> lineStart,
+ unsigned lineCount, raw_ostream &OS) {
+ return 1;
+}
+
+#endif
+
//===----------------------------------------------------------------------===//
// Helper Utils
//===----------------------------------------------------------------------===//
@@ -431,10 +791,210 @@ static void printSymbolNameAndUSR(const Decl *D, ASTContext &Ctx,
}
}
+#if INDEXSTORE_HAS_BLOCKS
+
+static void printSymbol(const IndexRecordDecl &Rec, raw_ostream &OS) {
+ printSymbolInfo(Rec.SymInfo, OS);
+ OS << " | ";
+
+ if (Rec.Name.empty())
+ OS << "<no-name>";
+ else
+ OS << Rec.Name;
+ OS << " | ";
+
+ if (Rec.USR.empty())
+ OS << "<no-usr>";
+ else
+ OS << Rec.USR;
+ OS << " | ";
+
+ if (Rec.CodeGenName.empty())
+ OS << "<no-cgname>";
+ else
+ OS << Rec.CodeGenName;
+ OS << " | ";
+
+ printSymbolRoles(Rec.Roles, OS);
+ OS << " - ";
+ printSymbolRoles(Rec.RelatedRoles, OS);
+ OS << '\n';
+}
+
+static void printSymbol(const IndexRecordOccurrence &Rec, raw_ostream &OS) {
+ OS << Rec.Line << ':' << Rec.Column << " | ";
+ printSymbolInfo(Rec.Dcl->SymInfo, OS);
+ OS << " | ";
+
+ if (Rec.Dcl->USR.empty())
+ OS << "<no-usr>";
+ else
+ OS << Rec.Dcl->USR;
+ OS << " | ";
+
+ printSymbolRoles(Rec.Roles, OS);
+ OS << " | ";
+ OS << "rel: " << Rec.Relations.size() << '\n';
+ for (auto &Rel : Rec.Relations) {
+ OS << '\t';
+ printSymbolRoles(Rel.Roles, OS);
+ OS << " | ";
+ if (Rel.Dcl->USR.empty())
+ OS << "<no-usr>";
+ else
+ OS << Rel.Dcl->USR;
+ OS << '\n';
+ }
+}
+
+static void printSymbol(indexstore::IndexRecordSymbol Sym, raw_ostream &OS) {
+ SymbolInfo SymInfo{getSymbolKind(Sym.getKind()),
+ getSymbolSubKind(Sym.getSubKind()),
+ getSymbolLanguage(Sym.getLanguage()),
+ SymbolPropertySet(Sym.getProperties())};
+
+ printSymbolInfo(SymInfo, OS);
+ OS << " | ";
+
+ if (Sym.getName().empty())
+ OS << "<no-name>";
+ else
+ OS << Sym.getName();
+ OS << " | ";
+
+ if (Sym.getUSR().empty())
+ OS << "<no-usr>";
+ else
+ OS << Sym.getUSR();
+ OS << " | ";
+
+ if (Sym.getCodegenName().empty())
+ OS << "<no-cgname>";
+ else
+ OS << Sym.getCodegenName();
+ OS << " | ";
+
+ printSymbolRoles(Sym.getRoles(), OS);
+ OS << " - ";
+ printSymbolRoles(Sym.getRelatedRoles(), OS);
+ OS << '\n';
+}
+
+static void printSymbol(indexstore::IndexRecordOccurrence Occur,
+ raw_ostream &OS) {
+ OS << Occur.getLineCol().first << ':' << Occur.getLineCol().second << " | ";
+ auto Sym = Occur.getSymbol();
+ SymbolInfo SymInfo{getSymbolKind(Sym.getKind()),
+ getSymbolSubKind(Sym.getSubKind()),
+ getSymbolLanguage(Sym.getLanguage()),
+ SymbolPropertySet(Sym.getProperties())};
+
+ printSymbolInfo(SymInfo, OS);
+ OS << " | ";
+
+ if (Sym.getUSR().empty())
+ OS << "<no-usr>";
+ else
+ OS << Sym.getUSR();
+ OS << " | ";
+
+ unsigned NumRelations = 0;
+ Occur.foreachRelation([&](indexstore::IndexSymbolRelation) {
+ ++NumRelations;
+ return true;
+ });
+
+ printSymbolRoles(Occur.getRoles(), OS);
+ OS << " | ";
+ OS << "rel: " << NumRelations << '\n';
+ Occur.foreachRelation([&](indexstore::IndexSymbolRelation Rel) {
+ OS << '\t';
+ printSymbolRoles(Rel.getRoles(), OS);
+ OS << " | ";
+ auto Sym = Rel.getSymbol();
+ if (Sym.getUSR().empty())
+ OS << "<no-usr>";
+ else
+ OS << Sym.getUSR();
+ OS << '\n';
+ return true;
+ });
+}
+
+#else
+
+static int printRecord(StringRef Filename, raw_ostream &OS) { return 1; }
+static int printStoreRecords(StringRef StorePath, raw_ostream &OS) { return 1; }
+
+#endif
+
+static int watchDirectory(StringRef dirPath) {
+ raw_ostream &OS = outs();
+ auto receiver = [&](ArrayRef<DirectoryWatcher::Event> Events,
+ bool isInitial) {
+ for (auto evt : Events) {
+ switch (evt.Kind) {
+ case DirectoryWatcher::EventKind::Added:
+ OS << "added: ";
+ break;
+ case DirectoryWatcher::EventKind::Modified:
+ OS << "modified: ";
+ break;
+ case DirectoryWatcher::EventKind::Removed:
+ OS << "removed: ";
+ break;
+ case DirectoryWatcher::EventKind::DirectoryDeleted:
+ OS << "dir deleted: ";
+ break;
+ }
+ OS << evt.Filename << '\n';
+ }
+ };
+ std::string Error;
+ auto watcher = DirectoryWatcher::create(dirPath, receiver,
+ /*waitInitialSync=*/true, Error);
+ if (!watcher) {
+ errs() << "failed creating directory watcher: " << Error << '\n';
+ return 1;
+ }
+#if HAVE_CORESERVICES
+ dispatch_main();
+#else
+ return 1;
+#endif
+}
+
//===----------------------------------------------------------------------===//
// Command line processing.
//===----------------------------------------------------------------------===//
+bool deconstructPathAndRange(StringRef input, std::string &filepath,
+ Optional<unsigned> &lineStart,
+ unsigned &lineCount) {
+ StringRef path, range;
+ std::tie(path, range) = input.split(':');
+ StringRef start, end;
+ std::tie(start, end) = range.split(':');
+ filepath = path;
+ lineCount = 0;
+ if (start.empty())
+ return false;
+ unsigned num;
+ if (start.getAsInteger(10, num)) {
+ errs() << "couldn't convert to integer: " << start << '\n';
+ return true;
+ }
+ lineStart = num;
+ if (end.empty())
+ return false;
+ if (end.getAsInteger(10, num)) {
+ errs() << "couldn't convert to integer: " << end << '\n';
+ return true;
+ }
+ lineCount = num - lineStart.getValue();
+ return false;
+}
+
int indextest_core_main(int argc, const char **argv) {
sys::PrintStackTraceOnErrorSignal(argv[0]);
PrettyStackTraceProgram X(argc, argv);
@@ -480,5 +1040,76 @@ int indextest_core_main(int argc, const char **argv) {
/*IndexModDepedencies=*/true);
}
+ if (options::Action == ActionType::PrintRecord) {
+ if (!options::FilePathAndRange.empty()) {
+ std::string filepath;
+ Optional<unsigned> lineStart;
+ unsigned lineCount;
+ if (deconstructPathAndRange(options::FilePathAndRange, filepath,
+ lineStart, lineCount))
+ return 1;
+
+ if (options::InputFiles.empty()) {
+ errs() << "error: missing index store path\n";
+ return 1;
+ }
+ return printStoreFileRecord(options::InputFiles[0], filepath, lineStart,
+ lineCount, outs());
+ }
+
+ if (options::InputFiles.empty()) {
+ errs() << "error: missing input file or directory\n";
+ return 1;
+ }
+
+ if (sys::fs::is_directory(options::InputFiles[0]))
+ return printStoreRecords(options::InputFiles[0], outs());
+ else
+ return printRecord(options::InputFiles[0], outs());
+ }
+
+ if (options::Action == ActionType::PrintUnit) {
+ if (options::InputFiles.empty()) {
+ errs() << "error: missing input file or directory\n";
+ return 1;
+ }
+
+ if (sys::fs::is_directory(options::InputFiles[0]))
+ return printStoreUnits(options::InputFiles[0], outs());
+ else
+ return printUnit(options::InputFiles[0], outs());
+ }
+
+#if INDEXSTORE_HAS_BLOCKS
+ if (options::Action == ActionType::PrintStoreFormatVersion) {
+ outs() << indexstore::IndexStore::formatVersion() << '\n';
+ }
+#endif
+
+ if (options::Action == ActionType::AggregateAsJSON) {
+ if (options::InputFiles.empty()) {
+ errs() << "error: missing input data store directory\n";
+ return 1;
+ }
+ StringRef storePath = options::InputFiles[0];
+ if (options::OutputFile.empty())
+ return aggregateDataAsJSON(storePath, outs());
+ std::error_code EC;
+ raw_fd_ostream OS(options::OutputFile, EC, llvm::sys::fs::F_None);
+ if (EC) {
+ errs() << "failed to open output file: " << EC.message() << '\n';
+ return 1;
+ }
+ return aggregateDataAsJSON(storePath, OS);
+ }
+
+ if (options::Action == ActionType::WatchDir) {
+ if (options::InputFiles.empty()) {
+ errs() << "error: missing directory path\n";
+ return 1;
+ }
+ return watchDirectory(options::InputFiles[0]);
+ }
+
return 0;
}