mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-21 23:25:07 +00:00
Merge {timestamp_manager,iindexer}.{cc,h}; remove standard_includes.*; use last_write_time
This commit is contained in:
parent
38eccf79ec
commit
f73100adf3
@ -96,11 +96,12 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(ccls PRIVATE Threads::Threads)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL Darwin)
|
||||
target_link_libraries(ccls PRIVATE -lc++experimental)
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL Linux)
|
||||
target_link_libraries(ccls PRIVATE -lstdc++fs)
|
||||
elseif(MSVC)
|
||||
else()
|
||||
target_link_libraries(ccls PRIVATE -lstdc++fs)
|
||||
# e.g. Darwin, FreeBSD
|
||||
target_link_libraries(ccls PRIVATE -lc++experimental)
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL Linux)
|
||||
@ -212,7 +213,6 @@ target_sources(ccls PRIVATE
|
||||
src/file_consumer.cc
|
||||
src/filesystem.cc
|
||||
src/fuzzy_match.cc
|
||||
src/iindexer.cc
|
||||
src/import_pipeline.cc
|
||||
src/include_complete.cc
|
||||
src/method.cc
|
||||
@ -229,11 +229,9 @@ target_sources(ccls PRIVATE
|
||||
src/query.cc
|
||||
src/queue_manager.cc
|
||||
src/serializer.cc
|
||||
src/standard_includes.cc
|
||||
src/test.cc
|
||||
src/third_party_impl.cc
|
||||
src/timer.cc
|
||||
src/timestamp_manager.cc
|
||||
src/type_printer.cc
|
||||
src/utils.cc
|
||||
src/working_files.cc)
|
||||
|
@ -143,10 +143,3 @@ std::unique_ptr<IndexFile> ICacheManager::TakeOrLoad(const std::string& path) {
|
||||
assert(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void ICacheManager::IterateLoadedCaches(std::function<void(IndexFile*)> fn) {
|
||||
for (const auto& cache : caches_) {
|
||||
assert(cache.second);
|
||||
fn(cache.second.get());
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
@ -41,8 +40,11 @@ struct ICacheManager {
|
||||
virtual std::optional<std::string> LoadCachedFileContents(
|
||||
const std::string& path) = 0;
|
||||
|
||||
// Iterate over all loaded caches.
|
||||
void IterateLoadedCaches(std::function<void(IndexFile*)> fn);
|
||||
template <typename Fn>
|
||||
void IterateLoadedCaches(Fn fn) {
|
||||
for (const auto& cache : caches_)
|
||||
fn(cache.second.get());
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual std::unique_ptr<IndexFile> RawCacheLoad(const std::string& path) = 0;
|
||||
|
@ -371,7 +371,7 @@ IndexFile* ConsumeFile(IndexParam* param, CXFile file) {
|
||||
param->seen_files.push_back(file_name);
|
||||
|
||||
// Set modification time.
|
||||
std::optional<int64_t> modification_time = GetLastModificationTime(file_name);
|
||||
std::optional<int64_t> modification_time = LastWriteTime(file_name);
|
||||
LOG_IF_S(ERROR, !modification_time)
|
||||
<< "Failed fetching modification time for " << file_name;
|
||||
if (modification_time)
|
||||
@ -2358,3 +2358,60 @@ void Reflect(Writer& visitor, Reference& value) {
|
||||
Reflect(visitor, value.role);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct TestIndexer : IIndexer {
|
||||
static std::unique_ptr<TestIndexer> FromEntries(
|
||||
const std::vector<TestEntry>& entries) {
|
||||
auto result = std::make_unique<TestIndexer>();
|
||||
|
||||
for (const TestEntry& entry : entries) {
|
||||
std::vector<std::unique_ptr<IndexFile>> indexes;
|
||||
|
||||
if (entry.num_indexes > 0)
|
||||
indexes.push_back(std::make_unique<IndexFile>(entry.path, "<empty>"));
|
||||
for (int i = 1; i < entry.num_indexes; ++i) {
|
||||
indexes.push_back(std::make_unique<IndexFile>(
|
||||
entry.path + "_extra_" + std::to_string(i) + ".h", "<empty>"));
|
||||
}
|
||||
|
||||
result->indexes.insert(std::make_pair(entry.path, std::move(indexes)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
~TestIndexer() override = default;
|
||||
|
||||
std::vector<std::unique_ptr<IndexFile>> Index(
|
||||
FileConsumerSharedState* file_consumer_shared,
|
||||
std::string file,
|
||||
const std::vector<std::string>& args,
|
||||
const std::vector<FileContents>& file_contents,
|
||||
PerformanceImportFile* perf) override {
|
||||
auto it = indexes.find(file);
|
||||
if (it == indexes.end()) {
|
||||
// Don't return any indexes for unexpected data.
|
||||
assert(false && "no indexes");
|
||||
return {};
|
||||
}
|
||||
|
||||
// FIXME: allow user to control how many times we return the index for a
|
||||
// specific file (atm it is always 1)
|
||||
auto result = std::move(it->second);
|
||||
indexes.erase(it);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::vector<std::unique_ptr<IndexFile>>>
|
||||
indexes;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
std::unique_ptr<IIndexer> IIndexer::MakeTestIndexer(
|
||||
std::initializer_list<TestEntry> entries) {
|
||||
return TestIndexer::FromEntries(entries);
|
||||
}
|
||||
|
@ -138,6 +138,8 @@ const char* ClangBuiltinTypeName(CXTypeKind kind) {
|
||||
case CXType_Bool: return "bool";
|
||||
case CXType_Char_U: return "char";
|
||||
case CXType_UChar: return "unsigned char";
|
||||
case CXType_Char16: return "char16_t";
|
||||
case CXType_Char32: return "char32_t";
|
||||
case CXType_UShort: return "unsigned short";
|
||||
case CXType_UInt: return "unsigned int";
|
||||
case CXType_ULong: return "unsigned long";
|
||||
@ -146,6 +148,7 @@ const char* ClangBuiltinTypeName(CXTypeKind kind) {
|
||||
case CXType_Char_S: return "char";
|
||||
case CXType_SChar: return "signed char";
|
||||
case CXType_WChar: return "wchar_t";
|
||||
case CXType_Short: return "short";
|
||||
case CXType_Int: return "int";
|
||||
case CXType_Long: return "long";
|
||||
case CXType_LongLong: return "long long";
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "serializers/json.h"
|
||||
#include "test.h"
|
||||
#include "timer.h"
|
||||
#include "timestamp_manager.h"
|
||||
#include "working_files.h"
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
@ -29,8 +29,6 @@ bool operator==(const CXFileUniqueID& a, const CXFileUniqueID& b) {
|
||||
a.data[2] == b.data[2];
|
||||
}
|
||||
|
||||
FileContents::FileContents() : line_offsets_{0} {}
|
||||
|
||||
FileContents::FileContents(const std::string& path, const std::string& content)
|
||||
: path(path), content(content) {
|
||||
line_offsets_.push_back(0);
|
||||
|
@ -18,7 +18,7 @@ MAKE_HASHABLE(CXFileUniqueID, t.data[0], t.data[1], t.data[2]);
|
||||
bool operator==(const CXFileUniqueID& a, const CXFileUniqueID& b);
|
||||
|
||||
struct FileContents {
|
||||
FileContents();
|
||||
FileContents() = default;
|
||||
FileContents(const std::string& path, const std::string& content);
|
||||
|
||||
std::optional<int> ToOffset(Position p) const;
|
||||
|
@ -1,83 +0,0 @@
|
||||
#include "iindexer.h"
|
||||
|
||||
#include "indexer.h"
|
||||
|
||||
namespace {
|
||||
struct ClangIndexer : IIndexer {
|
||||
~ClangIndexer() override = default;
|
||||
|
||||
std::vector<std::unique_ptr<IndexFile>> Index(
|
||||
FileConsumerSharedState* file_consumer_shared,
|
||||
std::string file,
|
||||
const std::vector<std::string>& args,
|
||||
const std::vector<FileContents>& file_contents,
|
||||
PerformanceImportFile* perf) override {
|
||||
return Parse(file_consumer_shared, file, args, file_contents, perf, &index);
|
||||
}
|
||||
|
||||
// Note: constructing this acquires a global lock
|
||||
ClangIndex index;
|
||||
};
|
||||
|
||||
struct TestIndexer : IIndexer {
|
||||
static std::unique_ptr<TestIndexer> FromEntries(
|
||||
const std::vector<TestEntry>& entries) {
|
||||
auto result = std::make_unique<TestIndexer>();
|
||||
|
||||
for (const TestEntry& entry : entries) {
|
||||
std::vector<std::unique_ptr<IndexFile>> indexes;
|
||||
|
||||
if (entry.num_indexes > 0)
|
||||
indexes.push_back(std::make_unique<IndexFile>(entry.path, "<empty>"));
|
||||
for (int i = 1; i < entry.num_indexes; ++i) {
|
||||
indexes.push_back(std::make_unique<IndexFile>(
|
||||
entry.path + "_extra_" + std::to_string(i) + ".h", "<empty>"));
|
||||
}
|
||||
|
||||
result->indexes.insert(std::make_pair(entry.path, std::move(indexes)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
~TestIndexer() override = default;
|
||||
|
||||
std::vector<std::unique_ptr<IndexFile>> Index(
|
||||
FileConsumerSharedState* file_consumer_shared,
|
||||
std::string file,
|
||||
const std::vector<std::string>& args,
|
||||
const std::vector<FileContents>& file_contents,
|
||||
PerformanceImportFile* perf) override {
|
||||
auto it = indexes.find(file);
|
||||
if (it == indexes.end()) {
|
||||
// Don't return any indexes for unexpected data.
|
||||
assert(false && "no indexes");
|
||||
return {};
|
||||
}
|
||||
|
||||
// FIXME: allow user to control how many times we return the index for a
|
||||
// specific file (atm it is always 1)
|
||||
auto result = std::move(it->second);
|
||||
indexes.erase(it);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::vector<std::unique_ptr<IndexFile>>>
|
||||
indexes;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
IIndexer::TestEntry::TestEntry(const std::string& path, int num_indexes)
|
||||
: path(path), num_indexes(num_indexes) {}
|
||||
|
||||
// static
|
||||
std::unique_ptr<IIndexer> IIndexer::MakeClangIndexer() {
|
||||
return std::make_unique<ClangIndexer>();
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<IIndexer> IIndexer::MakeTestIndexer(
|
||||
std::initializer_list<TestEntry> entries) {
|
||||
return TestIndexer::FromEntries(entries);
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// TODO:
|
||||
// - rename indexer.h to clang_indexer.h and pull out non-clang specific code
|
||||
// like IndexFile
|
||||
// - rename this file to indexer.h
|
||||
|
||||
struct IndexFile;
|
||||
struct FileContents;
|
||||
struct FileConsumerSharedState;
|
||||
struct PerformanceImportFile;
|
||||
|
||||
// Abstracts away the actual indexing process. Each IIndexer instance is
|
||||
// per-thread and constructing an instance may be extremely expensive (ie,
|
||||
// acquire a lock) and should be done as rarely as possible.
|
||||
struct IIndexer {
|
||||
struct TestEntry {
|
||||
std::string path;
|
||||
int num_indexes = 0;
|
||||
|
||||
TestEntry(const std::string& path, int num_indexes);
|
||||
};
|
||||
|
||||
static std::unique_ptr<IIndexer> MakeClangIndexer();
|
||||
static std::unique_ptr<IIndexer> MakeTestIndexer(
|
||||
std::initializer_list<TestEntry> entries);
|
||||
|
||||
virtual ~IIndexer() = default;
|
||||
virtual std::vector<std::unique_ptr<IndexFile>> Index(
|
||||
FileConsumerSharedState* file_consumer_shared,
|
||||
std::string file,
|
||||
const std::vector<std::string>& args,
|
||||
const std::vector<FileContents>& file_contents,
|
||||
PerformanceImportFile* perf) = 0;
|
||||
};
|
@ -3,7 +3,6 @@
|
||||
#include "cache_manager.h"
|
||||
#include "config.h"
|
||||
#include "diagnostics_engine.h"
|
||||
#include "iindexer.h"
|
||||
#include "import_manager.h"
|
||||
#include "lsp.h"
|
||||
#include "message_handler.h"
|
||||
@ -12,15 +11,11 @@
|
||||
#include "query_utils.h"
|
||||
#include "queue_manager.h"
|
||||
#include "timer.h"
|
||||
#include "timestamp_manager.h"
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
#include <loguru.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
@ -63,14 +58,14 @@ struct IterationLoop {
|
||||
|
||||
struct IModificationTimestampFetcher {
|
||||
virtual ~IModificationTimestampFetcher() = default;
|
||||
virtual std::optional<int64_t> GetModificationTime(const std::string& path) = 0;
|
||||
virtual std::optional<int64_t> LastWriteTime(const std::string& path) = 0;
|
||||
};
|
||||
struct RealModificationTimestampFetcher : IModificationTimestampFetcher {
|
||||
~RealModificationTimestampFetcher() override = default;
|
||||
|
||||
// IModificationTimestamp:
|
||||
std::optional<int64_t> GetModificationTime(const std::string& path) override {
|
||||
return GetLastModificationTime(path);
|
||||
std::optional<int64_t> LastWriteTime(const std::string& path) override {
|
||||
return ::LastWriteTime(path);
|
||||
}
|
||||
};
|
||||
struct FakeModificationTimestampFetcher : IModificationTimestampFetcher {
|
||||
@ -79,7 +74,7 @@ struct FakeModificationTimestampFetcher : IModificationTimestampFetcher {
|
||||
~FakeModificationTimestampFetcher() override = default;
|
||||
|
||||
// IModificationTimestamp:
|
||||
std::optional<int64_t> GetModificationTime(const std::string& path) override {
|
||||
std::optional<int64_t> LastWriteTime(const std::string& path) override {
|
||||
auto it = entries.find(path);
|
||||
assert(it != entries.end());
|
||||
return it->second;
|
||||
@ -174,7 +169,7 @@ ShouldParse FileNeedsParse(
|
||||
}
|
||||
|
||||
std::optional<int64_t> modification_timestamp =
|
||||
modification_timestamp_fetcher->GetModificationTime(path);
|
||||
modification_timestamp_fetcher->LastWriteTime(path);
|
||||
|
||||
// Cannot find file.
|
||||
if (!modification_timestamp)
|
||||
@ -327,7 +322,7 @@ std::vector<FileContents> PreloadFileContents(
|
||||
// still valid. if so, we can use it, otherwise we need to load from disk.
|
||||
auto get_latest_content = [](const std::string& path, int64_t cached_time,
|
||||
const std::string& cached) -> std::string {
|
||||
std::optional<int64_t> mod_time = GetLastModificationTime(path);
|
||||
std::optional<int64_t> mod_time = LastWriteTime(path);
|
||||
if (!mod_time)
|
||||
return "";
|
||||
|
||||
@ -533,6 +528,29 @@ bool IndexMergeIndexUpdates() {
|
||||
|
||||
} // namespace
|
||||
|
||||
std::optional<int64_t> TimestampManager::GetLastCachedModificationTime(
|
||||
ICacheManager* cache_manager,
|
||||
const std::string& path) {
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
auto it = timestamps_.find(path);
|
||||
if (it != timestamps_.end())
|
||||
return it->second;
|
||||
}
|
||||
IndexFile* file = cache_manager->TryLoad(path);
|
||||
if (!file)
|
||||
return std::nullopt;
|
||||
|
||||
UpdateCachedModificationTime(path, file->last_modification_time);
|
||||
return file->last_modification_time;
|
||||
}
|
||||
|
||||
void TimestampManager::UpdateCachedModificationTime(const std::string& path,
|
||||
int64_t timestamp) {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
timestamps_[path] = timestamp;
|
||||
}
|
||||
|
||||
ImportPipelineStatus::ImportPipelineStatus()
|
||||
: num_active_threads(0), next_progress_output(0) {}
|
||||
|
||||
@ -586,7 +604,7 @@ void Indexer_Main(DiagnosticsEngine* diag_engine,
|
||||
RealModificationTimestampFetcher modification_timestamp_fetcher;
|
||||
auto* queue = QueueManager::instance();
|
||||
// Build one index per-indexer, as building the index acquires a global lock.
|
||||
auto indexer = IIndexer::MakeClangIndexer();
|
||||
auto indexer = std::make_unique<ClangIndexer>();
|
||||
|
||||
while (true) {
|
||||
bool did_work = false;
|
||||
|
@ -5,20 +5,37 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
struct ClangTranslationUnit;
|
||||
class DiagnosticsEngine;
|
||||
struct FileConsumerSharedState;
|
||||
struct ICacheManager;
|
||||
struct ImportManager;
|
||||
struct MultiQueueWaiter;
|
||||
struct Project;
|
||||
struct QueryDatabase;
|
||||
struct SemanticHighlightSymbolCache;
|
||||
struct TimestampManager;
|
||||
struct WorkingFiles;
|
||||
|
||||
// Caches timestamps of cc files so we can avoid a filesystem reads. This is
|
||||
// important for import perf, as during dependency checking the same files are
|
||||
// checked over and over again if they are common headers.
|
||||
struct TimestampManager {
|
||||
std::optional<int64_t> GetLastCachedModificationTime(ICacheManager* cache_manager,
|
||||
const std::string& path);
|
||||
|
||||
void UpdateCachedModificationTime(const std::string& path, int64_t timestamp);
|
||||
|
||||
// TODO: use std::shared_mutex so we can have multiple readers.
|
||||
std::mutex mutex_;
|
||||
std::unordered_map<std::string, int64_t> timestamps_;
|
||||
};
|
||||
|
||||
struct ImportPipelineStatus {
|
||||
std::atomic<int> num_active_threads;
|
||||
std::atomic<long long> next_progress_output;
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include "match.h"
|
||||
#include "platform.h"
|
||||
#include "project.h"
|
||||
#include "standard_includes.h"
|
||||
#include "timer.h"
|
||||
|
||||
#include <thread>
|
||||
@ -107,7 +106,6 @@ void IncludeComplete::Rescan() {
|
||||
SetThreadName("scan_includes");
|
||||
Timer timer;
|
||||
|
||||
InsertStlIncludes();
|
||||
InsertIncludesFromDirectory(g_config->projectRoot,
|
||||
false /*use_angle_brackets*/);
|
||||
for (const std::string& dir : project_->quote_include_directories)
|
||||
@ -189,14 +187,6 @@ void IncludeComplete::InsertIncludesFromDirectory(std::string directory,
|
||||
std::move(result.completion_item));
|
||||
}
|
||||
|
||||
void IncludeComplete::InsertStlIncludes() {
|
||||
std::lock_guard<std::mutex> lock(completion_items_mutex);
|
||||
for (const char* stl_header : kStandardLibraryIncludes) {
|
||||
completion_items.push_back(BuildCompletionItem(
|
||||
stl_header, true /*use_angle_brackets*/, true /*is_stl*/));
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<lsCompletionItem> IncludeComplete::FindCompletionItemForAbsolutePath(
|
||||
const std::string& absolute_path) {
|
||||
std::lock_guard<std::mutex> lock(completion_items_mutex);
|
||||
|
@ -22,7 +22,6 @@ struct IncludeComplete {
|
||||
// blocking function and should be run off the querydb thread.
|
||||
void InsertIncludesFromDirectory(std::string directory,
|
||||
bool use_angle_brackets);
|
||||
void InsertStlIncludes();
|
||||
|
||||
std::optional<lsCompletionItem> FindCompletionItemForAbsolutePath(
|
||||
const std::string& absolute_path);
|
||||
|
@ -488,3 +488,40 @@ std::vector<std::unique_ptr<IndexFile>> ParseWithTu(
|
||||
bool ConcatTypeAndName(std::string& type, const std::string& name);
|
||||
|
||||
void IndexInit();
|
||||
|
||||
// Abstracts away the actual indexing process. Each IIndexer instance is
|
||||
// per-thread and constructing an instance may be extremely expensive (ie,
|
||||
// acquire a lock) and should be done as rarely as possible.
|
||||
struct IIndexer {
|
||||
struct TestEntry {
|
||||
std::string path;
|
||||
int num_indexes = 0;
|
||||
};
|
||||
|
||||
static std::unique_ptr<IIndexer> MakeTestIndexer(
|
||||
std::initializer_list<TestEntry> entries);
|
||||
|
||||
virtual ~IIndexer() = default;
|
||||
virtual std::vector<std::unique_ptr<IndexFile>> Index(
|
||||
FileConsumerSharedState* file_consumer_shared,
|
||||
std::string file,
|
||||
const std::vector<std::string>& args,
|
||||
const std::vector<FileContents>& file_contents,
|
||||
PerformanceImportFile* perf) = 0;
|
||||
};
|
||||
|
||||
struct ClangIndexer : IIndexer {
|
||||
~ClangIndexer() override = default;
|
||||
|
||||
std::vector<std::unique_ptr<IndexFile>> Index(
|
||||
FileConsumerSharedState* file_consumer_shared,
|
||||
std::string file,
|
||||
const std::vector<std::string>& args,
|
||||
const std::vector<FileContents>& file_contents,
|
||||
PerformanceImportFile* perf) override {
|
||||
return Parse(file_consumer_shared, file, args, file_contents, perf, &index);
|
||||
}
|
||||
|
||||
// Note: constructing this acquires a global lock
|
||||
ClangIndex index;
|
||||
};
|
||||
|
@ -18,29 +18,4 @@ struct lsCodeLensCommandArguments {
|
||||
lsPosition position;
|
||||
std::vector<lsLocation> locations;
|
||||
};
|
||||
|
||||
// FIXME Don't use array in vscode-ccls
|
||||
inline void Reflect(Writer& visitor, lsCodeLensCommandArguments& value) {
|
||||
visitor.StartArray(3);
|
||||
Reflect(visitor, value.uri);
|
||||
Reflect(visitor, value.position);
|
||||
Reflect(visitor, value.locations);
|
||||
visitor.EndArray();
|
||||
}
|
||||
|
||||
inline void Reflect(Reader& visitor, lsCodeLensCommandArguments& value) {
|
||||
int i = 0;
|
||||
visitor.IterArray([&](Reader& visitor) {
|
||||
switch (i++) {
|
||||
case 0:
|
||||
Reflect(visitor, value.uri);
|
||||
break;
|
||||
case 1:
|
||||
Reflect(visitor, value.position);
|
||||
break;
|
||||
case 2:
|
||||
Reflect(visitor, value.locations);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
MAKE_REFLECT_STRUCT(lsCodeLensCommandArguments, uri, position, locations)
|
||||
|
@ -1,11 +1,11 @@
|
||||
#include "cache_manager.h"
|
||||
#include "import_pipeline.h"
|
||||
#include "match.h"
|
||||
#include "message_handler.h"
|
||||
#include "platform.h"
|
||||
#include "project.h"
|
||||
#include "queue_manager.h"
|
||||
#include "timer.h"
|
||||
#include "timestamp_manager.h"
|
||||
#include "working_files.h"
|
||||
|
||||
#include <loguru.hpp>
|
||||
@ -66,7 +66,7 @@ struct Handler_CclsFreshenIndex : BaseMessageHandler<In_CclsFreshenIndex> {
|
||||
need_index.insert(file->def->path);
|
||||
|
||||
std::optional<int64_t> modification_timestamp =
|
||||
GetLastModificationTime(file->def->path);
|
||||
LastWriteTime(file->def->path);
|
||||
if (!modification_timestamp)
|
||||
continue;
|
||||
std::optional<int64_t> cached_modification =
|
||||
|
@ -166,28 +166,6 @@ void SetThreadName(const std::string& thread_name) {
|
||||
#endif
|
||||
}
|
||||
|
||||
std::optional<int64_t> GetLastModificationTime(const std::string& absolute_path) {
|
||||
struct stat buf;
|
||||
if (stat(absolute_path.c_str(), &buf) != 0) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
// std::cerr << "GetLastModificationTime: unable to find file " <<
|
||||
// absolute_path << std::endl;
|
||||
return std::nullopt;
|
||||
case EINVAL:
|
||||
// std::cerr << "GetLastModificationTime: invalid param to _stat for
|
||||
// file file " << absolute_path << std::endl;
|
||||
return std::nullopt;
|
||||
default:
|
||||
// std::cerr << "GetLastModificationTime: unhandled for " <<
|
||||
// absolute_path << std::endl; exit(1);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
return buf.st_mtime;
|
||||
}
|
||||
|
||||
void FreeUnusedMemory() {
|
||||
#if defined(__GLIBC__)
|
||||
malloc_trim(0);
|
||||
|
@ -79,28 +79,6 @@ void SetThreadName(const std::string& thread_name) {
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<int64_t> GetLastModificationTime(const std::string& absolute_path) {
|
||||
struct _stat buf;
|
||||
if (_stat(absolute_path.c_str(), &buf) != 0) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
// std::cerr << "GetLastModificationTime: unable to find file " <<
|
||||
// absolute_path << std::endl;
|
||||
return std::nullopt;
|
||||
case EINVAL:
|
||||
// std::cerr << "GetLastModificationTime: invalid param to _stat for
|
||||
// file file " << absolute_path << std::endl;
|
||||
return std::nullopt;
|
||||
default:
|
||||
// std::cerr << "GetLastModificationTime: unhandled for " <<
|
||||
// absolute_path << std::endl; exit(1);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
return buf.st_mtime;
|
||||
}
|
||||
|
||||
void FreeUnusedMemory() {}
|
||||
|
||||
// TODO Wait for debugger to attach
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include <sparsepp/spp.h>
|
||||
|
||||
#include <forward_list>
|
||||
#include <functional>
|
||||
|
||||
struct QueryFile;
|
||||
struct QueryType;
|
||||
|
@ -1,182 +0,0 @@
|
||||
#include "standard_includes.h"
|
||||
|
||||
// See http://stackoverflow.com/a/2029106.
|
||||
const char* kStandardLibraryIncludes[177] = {
|
||||
"aio.h",
|
||||
"algorithm",
|
||||
"any",
|
||||
"arpa/inet.h",
|
||||
"array",
|
||||
"assert.h",
|
||||
"atomic",
|
||||
"bitset",
|
||||
"cassert",
|
||||
"ccomplex",
|
||||
"cctype",
|
||||
"cerrno",
|
||||
"cfenv",
|
||||
"cfloat",
|
||||
"chrono",
|
||||
"cinttypes",
|
||||
"ciso646",
|
||||
"climits",
|
||||
"clocale",
|
||||
"cmath",
|
||||
"codecvt",
|
||||
"complex",
|
||||
"complex.h",
|
||||
"condition_variable",
|
||||
"cpio.h",
|
||||
"csetjmp",
|
||||
"csignal",
|
||||
"cstdalign",
|
||||
"cstdarg",
|
||||
"cstdbool",
|
||||
"cstddef",
|
||||
"cstdint",
|
||||
"cstdio",
|
||||
"cstdlib",
|
||||
"cstring",
|
||||
"ctgmath",
|
||||
"ctime",
|
||||
"ctype.h",
|
||||
"cuchar",
|
||||
"curses.h",
|
||||
"cwchar",
|
||||
"cwctype",
|
||||
"deque",
|
||||
"dirent.h",
|
||||
"dlfcn.h",
|
||||
"errno.h",
|
||||
"exception",
|
||||
"execution",
|
||||
"fcntl.h",
|
||||
"fenv.h",
|
||||
"filesystem",
|
||||
"float.h",
|
||||
"fmtmsg.h",
|
||||
"fnmatch.h",
|
||||
"forward_list",
|
||||
"fstream",
|
||||
"ftw.h",
|
||||
"functional",
|
||||
"future",
|
||||
"glob.h",
|
||||
"grp.h",
|
||||
"iconv.h",
|
||||
"initializer_list",
|
||||
"inttypes.h",
|
||||
"iomanip",
|
||||
"ios",
|
||||
"iosfwd",
|
||||
"iostream",
|
||||
"iso646.h",
|
||||
"istream",
|
||||
"iterator",
|
||||
"langinfo.h",
|
||||
"libgen.h",
|
||||
"limits",
|
||||
"limits.h",
|
||||
"list",
|
||||
"locale",
|
||||
"locale.h",
|
||||
"map",
|
||||
"math.h",
|
||||
"memory",
|
||||
"memory_resource",
|
||||
"monetary.h",
|
||||
"mqueue.h",
|
||||
"mutex",
|
||||
"ndbm.h",
|
||||
"net/if.h",
|
||||
"netdb.h",
|
||||
"netinet/in.h",
|
||||
"netinet/tcp.h",
|
||||
"new",
|
||||
"nl_types.h",
|
||||
"numeric",
|
||||
"std::optional",
|
||||
"ostream",
|
||||
"poll.h",
|
||||
"pthread.h",
|
||||
"pwd.h",
|
||||
"queue",
|
||||
"random",
|
||||
"ratio",
|
||||
"regex",
|
||||
"regex.h",
|
||||
"sched.h",
|
||||
"scoped_allocator",
|
||||
"search.h",
|
||||
"semaphore.h",
|
||||
"set",
|
||||
"setjmp.h",
|
||||
"shared_mutex",
|
||||
"signal.h",
|
||||
"spawn.h",
|
||||
"sstream",
|
||||
"stack",
|
||||
"stdalign.h",
|
||||
"stdarg.h",
|
||||
"stdatomic.h",
|
||||
"stdbool.h",
|
||||
"stddef.h",
|
||||
"stdexcept",
|
||||
"stdint.h",
|
||||
"stdio.h",
|
||||
"stdlib.h",
|
||||
"stdnoreturn.h",
|
||||
"streambuf",
|
||||
"string",
|
||||
"string.h",
|
||||
"string_view",
|
||||
"strings.h",
|
||||
"stropts.h",
|
||||
"strstream",
|
||||
"sys/ipc.h",
|
||||
"sys/mman.h",
|
||||
"sys/msg.h",
|
||||
"sys/resource.h",
|
||||
"sys/select.h",
|
||||
"sys/sem.h",
|
||||
"sys/shm.h",
|
||||
"sys/socket.h",
|
||||
"sys/stat.h",
|
||||
"sys/statvfs.h",
|
||||
"sys/time.h",
|
||||
"sys/times.h",
|
||||
"sys/types.h",
|
||||
"sys/uio.h",
|
||||
"sys/un.h",
|
||||
"sys/utsname.h",
|
||||
"sys/wait.h",
|
||||
"syslog.h",
|
||||
"system_error",
|
||||
"tar.h",
|
||||
"term.h",
|
||||
"termios.h",
|
||||
"tgmath.h",
|
||||
"thread",
|
||||
"threads.h",
|
||||
"time.h",
|
||||
"trace.h",
|
||||
"tuple",
|
||||
"type_traits",
|
||||
"typeindex",
|
||||
"typeinfo",
|
||||
"uchar.h",
|
||||
"ulimit.h",
|
||||
"uncntrl.h",
|
||||
"unistd.h",
|
||||
"unordered_map",
|
||||
"unordered_set",
|
||||
"utility",
|
||||
"utime.h",
|
||||
"utmpx.h",
|
||||
"valarray",
|
||||
"variant",
|
||||
"vector",
|
||||
"wchar.h",
|
||||
"wctype.h",
|
||||
"wordexp.h",
|
||||
};
|
@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// A set of standard libary header names, ie, "vector".
|
||||
extern const char* kStandardLibraryIncludes[177];
|
@ -7,7 +7,6 @@
|
||||
// front of others.
|
||||
enum class SymbolKind : uint8_t { Invalid, File, Type, Func, Var };
|
||||
MAKE_REFLECT_TYPE_PROXY(SymbolKind);
|
||||
MAKE_ENUM_HASHABLE(SymbolKind);
|
||||
|
||||
// clang/Basic/Specifiers.h clang::StorageClass
|
||||
enum class StorageClass : uint8_t {
|
||||
@ -44,7 +43,6 @@ enum class Role : uint16_t {
|
||||
All = (1 << 9) - 1,
|
||||
};
|
||||
MAKE_REFLECT_TYPE_PROXY(Role);
|
||||
MAKE_ENUM_HASHABLE(Role);
|
||||
|
||||
inline uint16_t operator&(Role lhs, Role rhs) {
|
||||
return uint16_t(lhs) & uint16_t(rhs);
|
||||
|
@ -1,27 +0,0 @@
|
||||
#include "timestamp_manager.h"
|
||||
|
||||
#include "cache_manager.h"
|
||||
#include "indexer.h"
|
||||
|
||||
std::optional<int64_t> TimestampManager::GetLastCachedModificationTime(
|
||||
ICacheManager* cache_manager,
|
||||
const std::string& path) {
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
auto it = timestamps_.find(path);
|
||||
if (it != timestamps_.end())
|
||||
return it->second;
|
||||
}
|
||||
IndexFile* file = cache_manager->TryLoad(path);
|
||||
if (!file)
|
||||
return std::nullopt;
|
||||
|
||||
UpdateCachedModificationTime(path, file->last_modification_time);
|
||||
return file->last_modification_time;
|
||||
}
|
||||
|
||||
void TimestampManager::UpdateCachedModificationTime(const std::string& path,
|
||||
int64_t timestamp) {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
timestamps_[path] = timestamp;
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
struct ICacheManager;
|
||||
|
||||
// Caches timestamps of cc files so we can avoid a filesystem reads. This is
|
||||
// important for import perf, as during dependency checking the same files are
|
||||
// checked over and over again if they are common headers.
|
||||
struct TimestampManager {
|
||||
std::optional<int64_t> GetLastCachedModificationTime(ICacheManager* cache_manager,
|
||||
const std::string& path);
|
||||
|
||||
void UpdateCachedModificationTime(const std::string& path, int64_t timestamp);
|
||||
|
||||
// TODO: use std::shared_mutex so we can have multiple readers.
|
||||
std::mutex mutex_;
|
||||
std::unordered_map<std::string, int64_t> timestamps_;
|
||||
};
|
11
src/utils.cc
11
src/utils.cc
@ -1,5 +1,6 @@
|
||||
#include "utils.h"
|
||||
|
||||
#include "filesystem.hh"
|
||||
#include "platform.h"
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
@ -130,6 +131,7 @@ std::optional<std::string> ReadContent(const std::string& filename) {
|
||||
size_t n;
|
||||
while ((n = fread(buf, 1, sizeof buf, f)) > 0)
|
||||
ret.append(buf, n);
|
||||
fclose(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -142,6 +144,15 @@ void WriteToFile(const std::string& filename, const std::string& content) {
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
std::optional<int64_t> LastWriteTime(const std::string& filename) {
|
||||
std::error_code ec;
|
||||
auto ftime = fs::last_write_time(filename, ec);
|
||||
if (ec) return std::nullopt;
|
||||
return std::chrono::time_point_cast<std::chrono::nanoseconds>(ftime)
|
||||
.time_since_epoch()
|
||||
.count();
|
||||
}
|
||||
|
||||
std::string GetDefaultResourceDirectory() {
|
||||
std::string result;
|
||||
|
||||
|
12
src/utils.h
12
src/utils.h
@ -62,8 +62,8 @@ void EnsureEndsInSlash(std::string& path);
|
||||
std::string EscapeFileName(std::string path);
|
||||
|
||||
std::optional<std::string> ReadContent(const std::string& filename);
|
||||
|
||||
void WriteToFile(const std::string& filename, const std::string& content);
|
||||
std::optional<int64_t> LastWriteTime(const std::string& filename);
|
||||
|
||||
// http://stackoverflow.com/a/38140932
|
||||
//
|
||||
@ -95,14 +95,4 @@ inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
|
||||
}; \
|
||||
}
|
||||
|
||||
#define MAKE_ENUM_HASHABLE(type) \
|
||||
namespace std { \
|
||||
template <> \
|
||||
struct hash<type> { \
|
||||
std::size_t operator()(const type& t) const { \
|
||||
return hash<int>()(static_cast<int>(t)); \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
std::string GetDefaultResourceDirectory();
|
||||
|
Loading…
Reference in New Issue
Block a user