mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-04 06:15:20 +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)
 | 
					find_package(Threads REQUIRED)
 | 
				
			||||||
target_link_libraries(ccls PRIVATE Threads::Threads)
 | 
					target_link_libraries(ccls PRIVATE Threads::Threads)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL Darwin)
 | 
					if(${CMAKE_SYSTEM_NAME} STREQUAL Linux)
 | 
				
			||||||
  target_link_libraries(ccls PRIVATE -lc++experimental)
 | 
					  target_link_libraries(ccls PRIVATE -lstdc++fs)
 | 
				
			||||||
elseif(MSVC)
 | 
					elseif(MSVC)
 | 
				
			||||||
else()
 | 
					else()
 | 
				
			||||||
  target_link_libraries(ccls PRIVATE -lstdc++fs)
 | 
					  # e.g. Darwin, FreeBSD
 | 
				
			||||||
 | 
					  target_link_libraries(ccls PRIVATE -lc++experimental)
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL Linux)
 | 
					if(${CMAKE_SYSTEM_NAME} STREQUAL Linux)
 | 
				
			||||||
@ -212,7 +213,6 @@ target_sources(ccls PRIVATE
 | 
				
			|||||||
               src/file_consumer.cc
 | 
					               src/file_consumer.cc
 | 
				
			||||||
               src/filesystem.cc
 | 
					               src/filesystem.cc
 | 
				
			||||||
               src/fuzzy_match.cc
 | 
					               src/fuzzy_match.cc
 | 
				
			||||||
               src/iindexer.cc
 | 
					 | 
				
			||||||
               src/import_pipeline.cc
 | 
					               src/import_pipeline.cc
 | 
				
			||||||
               src/include_complete.cc
 | 
					               src/include_complete.cc
 | 
				
			||||||
               src/method.cc
 | 
					               src/method.cc
 | 
				
			||||||
@ -229,11 +229,9 @@ target_sources(ccls PRIVATE
 | 
				
			|||||||
               src/query.cc
 | 
					               src/query.cc
 | 
				
			||||||
               src/queue_manager.cc
 | 
					               src/queue_manager.cc
 | 
				
			||||||
               src/serializer.cc
 | 
					               src/serializer.cc
 | 
				
			||||||
               src/standard_includes.cc
 | 
					 | 
				
			||||||
               src/test.cc
 | 
					               src/test.cc
 | 
				
			||||||
               src/third_party_impl.cc
 | 
					               src/third_party_impl.cc
 | 
				
			||||||
               src/timer.cc
 | 
					               src/timer.cc
 | 
				
			||||||
               src/timestamp_manager.cc
 | 
					 | 
				
			||||||
               src/type_printer.cc
 | 
					               src/type_printer.cc
 | 
				
			||||||
               src/utils.cc
 | 
					               src/utils.cc
 | 
				
			||||||
               src/working_files.cc)
 | 
					               src/working_files.cc)
 | 
				
			||||||
 | 
				
			|||||||
@ -143,10 +143,3 @@ std::unique_ptr<IndexFile> ICacheManager::TakeOrLoad(const std::string& path) {
 | 
				
			|||||||
  assert(result);
 | 
					  assert(result);
 | 
				
			||||||
  return 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 <optional>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <functional>
 | 
					 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <unordered_map>
 | 
					#include <unordered_map>
 | 
				
			||||||
@ -41,8 +40,11 @@ struct ICacheManager {
 | 
				
			|||||||
  virtual std::optional<std::string> LoadCachedFileContents(
 | 
					  virtual std::optional<std::string> LoadCachedFileContents(
 | 
				
			||||||
      const std::string& path) = 0;
 | 
					      const std::string& path) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Iterate over all loaded caches.
 | 
					  template <typename Fn>
 | 
				
			||||||
  void IterateLoadedCaches(std::function<void(IndexFile*)> fn);
 | 
					  void IterateLoadedCaches(Fn fn) {
 | 
				
			||||||
 | 
					    for (const auto& cache : caches_)
 | 
				
			||||||
 | 
					      fn(cache.second.get());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 protected:
 | 
					 protected:
 | 
				
			||||||
  virtual std::unique_ptr<IndexFile> RawCacheLoad(const std::string& path) = 0;
 | 
					  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);
 | 
					      param->seen_files.push_back(file_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Set modification time.
 | 
					      // 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)
 | 
					      LOG_IF_S(ERROR, !modification_time)
 | 
				
			||||||
          << "Failed fetching modification time for " << file_name;
 | 
					          << "Failed fetching modification time for " << file_name;
 | 
				
			||||||
      if (modification_time)
 | 
					      if (modification_time)
 | 
				
			||||||
@ -2358,3 +2358,60 @@ void Reflect(Writer& visitor, Reference& value) {
 | 
				
			|||||||
    Reflect(visitor, value.role);
 | 
					    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_Bool: return "bool";
 | 
				
			||||||
    case CXType_Char_U: return "char";
 | 
					    case CXType_Char_U: return "char";
 | 
				
			||||||
    case CXType_UChar: return "unsigned 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_UShort: return "unsigned short";
 | 
				
			||||||
    case CXType_UInt: return "unsigned int";
 | 
					    case CXType_UInt: return "unsigned int";
 | 
				
			||||||
    case CXType_ULong: return "unsigned long";
 | 
					    case CXType_ULong: return "unsigned long";
 | 
				
			||||||
@ -146,6 +148,7 @@ const char* ClangBuiltinTypeName(CXTypeKind kind) {
 | 
				
			|||||||
    case CXType_Char_S: return "char";
 | 
					    case CXType_Char_S: return "char";
 | 
				
			||||||
    case CXType_SChar: return "signed char";
 | 
					    case CXType_SChar: return "signed char";
 | 
				
			||||||
    case CXType_WChar: return "wchar_t";
 | 
					    case CXType_WChar: return "wchar_t";
 | 
				
			||||||
 | 
					    case CXType_Short: return "short";
 | 
				
			||||||
    case CXType_Int: return "int";
 | 
					    case CXType_Int: return "int";
 | 
				
			||||||
    case CXType_Long: return "long";
 | 
					    case CXType_Long: return "long";
 | 
				
			||||||
    case CXType_LongLong: return "long long";
 | 
					    case CXType_LongLong: return "long long";
 | 
				
			||||||
 | 
				
			|||||||
@ -21,7 +21,6 @@
 | 
				
			|||||||
#include "serializers/json.h"
 | 
					#include "serializers/json.h"
 | 
				
			||||||
#include "test.h"
 | 
					#include "test.h"
 | 
				
			||||||
#include "timer.h"
 | 
					#include "timer.h"
 | 
				
			||||||
#include "timestamp_manager.h"
 | 
					 | 
				
			||||||
#include "working_files.h"
 | 
					#include "working_files.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <doctest/doctest.h>
 | 
					#include <doctest/doctest.h>
 | 
				
			||||||
 | 
				
			|||||||
@ -29,8 +29,6 @@ bool operator==(const CXFileUniqueID& a, const CXFileUniqueID& b) {
 | 
				
			|||||||
         a.data[2] == b.data[2];
 | 
					         a.data[2] == b.data[2];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FileContents::FileContents() : line_offsets_{0} {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FileContents::FileContents(const std::string& path, const std::string& content)
 | 
					FileContents::FileContents(const std::string& path, const std::string& content)
 | 
				
			||||||
    : path(path), content(content) {
 | 
					    : path(path), content(content) {
 | 
				
			||||||
  line_offsets_.push_back(0);
 | 
					  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);
 | 
					bool operator==(const CXFileUniqueID& a, const CXFileUniqueID& b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct FileContents {
 | 
					struct FileContents {
 | 
				
			||||||
  FileContents();
 | 
					  FileContents() = default;
 | 
				
			||||||
  FileContents(const std::string& path, const std::string& content);
 | 
					  FileContents(const std::string& path, const std::string& content);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::optional<int> ToOffset(Position p) const;
 | 
					  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 "cache_manager.h"
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
#include "diagnostics_engine.h"
 | 
					#include "diagnostics_engine.h"
 | 
				
			||||||
#include "iindexer.h"
 | 
					 | 
				
			||||||
#include "import_manager.h"
 | 
					#include "import_manager.h"
 | 
				
			||||||
#include "lsp.h"
 | 
					#include "lsp.h"
 | 
				
			||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
@ -12,15 +11,11 @@
 | 
				
			|||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "queue_manager.h"
 | 
				
			||||||
#include "timer.h"
 | 
					#include "timer.h"
 | 
				
			||||||
#include "timestamp_manager.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <doctest/doctest.h>
 | 
					#include <doctest/doctest.h>
 | 
				
			||||||
#include <loguru.hpp>
 | 
					#include <loguru.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <atomic>
 | 
					 | 
				
			||||||
#include <chrono>
 | 
					#include <chrono>
 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -63,14 +58,14 @@ struct IterationLoop {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct IModificationTimestampFetcher {
 | 
					struct IModificationTimestampFetcher {
 | 
				
			||||||
  virtual ~IModificationTimestampFetcher() = default;
 | 
					  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 {
 | 
					struct RealModificationTimestampFetcher : IModificationTimestampFetcher {
 | 
				
			||||||
  ~RealModificationTimestampFetcher() override = default;
 | 
					  ~RealModificationTimestampFetcher() override = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // IModificationTimestamp:
 | 
					  // IModificationTimestamp:
 | 
				
			||||||
  std::optional<int64_t> GetModificationTime(const std::string& path) override {
 | 
					  std::optional<int64_t> LastWriteTime(const std::string& path) override {
 | 
				
			||||||
    return GetLastModificationTime(path);
 | 
					    return ::LastWriteTime(path);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
struct FakeModificationTimestampFetcher : IModificationTimestampFetcher {
 | 
					struct FakeModificationTimestampFetcher : IModificationTimestampFetcher {
 | 
				
			||||||
@ -79,7 +74,7 @@ struct FakeModificationTimestampFetcher : IModificationTimestampFetcher {
 | 
				
			|||||||
  ~FakeModificationTimestampFetcher() override = default;
 | 
					  ~FakeModificationTimestampFetcher() override = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // IModificationTimestamp:
 | 
					  // 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);
 | 
					    auto it = entries.find(path);
 | 
				
			||||||
    assert(it != entries.end());
 | 
					    assert(it != entries.end());
 | 
				
			||||||
    return it->second;
 | 
					    return it->second;
 | 
				
			||||||
@ -174,7 +169,7 @@ ShouldParse FileNeedsParse(
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::optional<int64_t> modification_timestamp =
 | 
					  std::optional<int64_t> modification_timestamp =
 | 
				
			||||||
      modification_timestamp_fetcher->GetModificationTime(path);
 | 
					      modification_timestamp_fetcher->LastWriteTime(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Cannot find file.
 | 
					  // Cannot find file.
 | 
				
			||||||
  if (!modification_timestamp)
 | 
					  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.
 | 
					  // 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,
 | 
					  auto get_latest_content = [](const std::string& path, int64_t cached_time,
 | 
				
			||||||
                               const std::string& cached) -> std::string {
 | 
					                               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)
 | 
					    if (!mod_time)
 | 
				
			||||||
      return "";
 | 
					      return "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -533,6 +528,29 @@ bool IndexMergeIndexUpdates() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}  // namespace
 | 
					}  // 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()
 | 
					ImportPipelineStatus::ImportPipelineStatus()
 | 
				
			||||||
    : num_active_threads(0), next_progress_output(0) {}
 | 
					    : num_active_threads(0), next_progress_output(0) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -586,7 +604,7 @@ void Indexer_Main(DiagnosticsEngine* diag_engine,
 | 
				
			|||||||
  RealModificationTimestampFetcher modification_timestamp_fetcher;
 | 
					  RealModificationTimestampFetcher modification_timestamp_fetcher;
 | 
				
			||||||
  auto* queue = QueueManager::instance();
 | 
					  auto* queue = QueueManager::instance();
 | 
				
			||||||
  // Build one index per-indexer, as building the index acquires a global lock.
 | 
					  // 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) {
 | 
					  while (true) {
 | 
				
			||||||
    bool did_work = false;
 | 
					    bool did_work = false;
 | 
				
			||||||
 | 
				
			|||||||
@ -5,20 +5,37 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <atomic>
 | 
					#include <atomic>
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include <optional>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					#include <unordered_map>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ClangTranslationUnit;
 | 
					struct ClangTranslationUnit;
 | 
				
			||||||
class DiagnosticsEngine;
 | 
					class DiagnosticsEngine;
 | 
				
			||||||
struct FileConsumerSharedState;
 | 
					struct FileConsumerSharedState;
 | 
				
			||||||
 | 
					struct ICacheManager;
 | 
				
			||||||
struct ImportManager;
 | 
					struct ImportManager;
 | 
				
			||||||
struct MultiQueueWaiter;
 | 
					struct MultiQueueWaiter;
 | 
				
			||||||
struct Project;
 | 
					struct Project;
 | 
				
			||||||
struct QueryDatabase;
 | 
					struct QueryDatabase;
 | 
				
			||||||
struct SemanticHighlightSymbolCache;
 | 
					struct SemanticHighlightSymbolCache;
 | 
				
			||||||
struct TimestampManager;
 | 
					 | 
				
			||||||
struct WorkingFiles;
 | 
					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 {
 | 
					struct ImportPipelineStatus {
 | 
				
			||||||
  std::atomic<int> num_active_threads;
 | 
					  std::atomic<int> num_active_threads;
 | 
				
			||||||
  std::atomic<long long> next_progress_output;
 | 
					  std::atomic<long long> next_progress_output;
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,6 @@
 | 
				
			|||||||
#include "match.h"
 | 
					#include "match.h"
 | 
				
			||||||
#include "platform.h"
 | 
					#include "platform.h"
 | 
				
			||||||
#include "project.h"
 | 
					#include "project.h"
 | 
				
			||||||
#include "standard_includes.h"
 | 
					 | 
				
			||||||
#include "timer.h"
 | 
					#include "timer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <thread>
 | 
					#include <thread>
 | 
				
			||||||
@ -107,7 +106,6 @@ void IncludeComplete::Rescan() {
 | 
				
			|||||||
    SetThreadName("scan_includes");
 | 
					    SetThreadName("scan_includes");
 | 
				
			||||||
    Timer timer;
 | 
					    Timer timer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    InsertStlIncludes();
 | 
					 | 
				
			||||||
    InsertIncludesFromDirectory(g_config->projectRoot,
 | 
					    InsertIncludesFromDirectory(g_config->projectRoot,
 | 
				
			||||||
                                false /*use_angle_brackets*/);
 | 
					                                false /*use_angle_brackets*/);
 | 
				
			||||||
    for (const std::string& dir : project_->quote_include_directories)
 | 
					    for (const std::string& dir : project_->quote_include_directories)
 | 
				
			||||||
@ -189,14 +187,6 @@ void IncludeComplete::InsertIncludesFromDirectory(std::string directory,
 | 
				
			|||||||
                         std::move(result.completion_item));
 | 
					                         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(
 | 
					std::optional<lsCompletionItem> IncludeComplete::FindCompletionItemForAbsolutePath(
 | 
				
			||||||
    const std::string& absolute_path) {
 | 
					    const std::string& absolute_path) {
 | 
				
			||||||
  std::lock_guard<std::mutex> lock(completion_items_mutex);
 | 
					  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.
 | 
					  // blocking function and should be run off the querydb thread.
 | 
				
			||||||
  void InsertIncludesFromDirectory(std::string directory,
 | 
					  void InsertIncludesFromDirectory(std::string directory,
 | 
				
			||||||
                                   bool use_angle_brackets);
 | 
					                                   bool use_angle_brackets);
 | 
				
			||||||
  void InsertStlIncludes();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::optional<lsCompletionItem> FindCompletionItemForAbsolutePath(
 | 
					  std::optional<lsCompletionItem> FindCompletionItemForAbsolutePath(
 | 
				
			||||||
      const std::string& absolute_path);
 | 
					      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);
 | 
					bool ConcatTypeAndName(std::string& type, const std::string& name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void IndexInit();
 | 
					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;
 | 
					  lsPosition position;
 | 
				
			||||||
  std::vector<lsLocation> locations;
 | 
					  std::vector<lsLocation> locations;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					MAKE_REFLECT_STRUCT(lsCodeLensCommandArguments, uri, position, 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;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,11 @@
 | 
				
			|||||||
#include "cache_manager.h"
 | 
					#include "cache_manager.h"
 | 
				
			||||||
 | 
					#include "import_pipeline.h"
 | 
				
			||||||
#include "match.h"
 | 
					#include "match.h"
 | 
				
			||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "platform.h"
 | 
					#include "platform.h"
 | 
				
			||||||
#include "project.h"
 | 
					#include "project.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "queue_manager.h"
 | 
				
			||||||
#include "timer.h"
 | 
					#include "timer.h"
 | 
				
			||||||
#include "timestamp_manager.h"
 | 
					 | 
				
			||||||
#include "working_files.h"
 | 
					#include "working_files.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <loguru.hpp>
 | 
					#include <loguru.hpp>
 | 
				
			||||||
@ -66,7 +66,7 @@ struct Handler_CclsFreshenIndex : BaseMessageHandler<In_CclsFreshenIndex> {
 | 
				
			|||||||
      need_index.insert(file->def->path);
 | 
					      need_index.insert(file->def->path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      std::optional<int64_t> modification_timestamp =
 | 
					      std::optional<int64_t> modification_timestamp =
 | 
				
			||||||
          GetLastModificationTime(file->def->path);
 | 
					          LastWriteTime(file->def->path);
 | 
				
			||||||
      if (!modification_timestamp)
 | 
					      if (!modification_timestamp)
 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
      std::optional<int64_t> cached_modification =
 | 
					      std::optional<int64_t> cached_modification =
 | 
				
			||||||
 | 
				
			|||||||
@ -166,28 +166,6 @@ void SetThreadName(const std::string& thread_name) {
 | 
				
			|||||||
#endif
 | 
					#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() {
 | 
					void FreeUnusedMemory() {
 | 
				
			||||||
#if defined(__GLIBC__)
 | 
					#if defined(__GLIBC__)
 | 
				
			||||||
  malloc_trim(0);
 | 
					  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() {}
 | 
					void FreeUnusedMemory() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO Wait for debugger to attach
 | 
					// TODO Wait for debugger to attach
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,6 @@
 | 
				
			|||||||
#include <sparsepp/spp.h>
 | 
					#include <sparsepp/spp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <forward_list>
 | 
					#include <forward_list>
 | 
				
			||||||
#include <functional>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct QueryFile;
 | 
					struct QueryFile;
 | 
				
			||||||
struct QueryType;
 | 
					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.
 | 
					// front of others.
 | 
				
			||||||
enum class SymbolKind : uint8_t { Invalid, File, Type, Func, Var };
 | 
					enum class SymbolKind : uint8_t { Invalid, File, Type, Func, Var };
 | 
				
			||||||
MAKE_REFLECT_TYPE_PROXY(SymbolKind);
 | 
					MAKE_REFLECT_TYPE_PROXY(SymbolKind);
 | 
				
			||||||
MAKE_ENUM_HASHABLE(SymbolKind);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// clang/Basic/Specifiers.h clang::StorageClass
 | 
					// clang/Basic/Specifiers.h clang::StorageClass
 | 
				
			||||||
enum class StorageClass : uint8_t {
 | 
					enum class StorageClass : uint8_t {
 | 
				
			||||||
@ -44,7 +43,6 @@ enum class Role : uint16_t {
 | 
				
			|||||||
  All = (1 << 9) - 1,
 | 
					  All = (1 << 9) - 1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
MAKE_REFLECT_TYPE_PROXY(Role);
 | 
					MAKE_REFLECT_TYPE_PROXY(Role);
 | 
				
			||||||
MAKE_ENUM_HASHABLE(Role);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline uint16_t operator&(Role lhs, Role rhs) {
 | 
					inline uint16_t operator&(Role lhs, Role rhs) {
 | 
				
			||||||
  return uint16_t(lhs) & uint16_t(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 "utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "filesystem.hh"
 | 
				
			||||||
#include "platform.h"
 | 
					#include "platform.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <doctest/doctest.h>
 | 
					#include <doctest/doctest.h>
 | 
				
			||||||
@ -130,6 +131,7 @@ std::optional<std::string> ReadContent(const std::string& filename) {
 | 
				
			|||||||
  size_t n;
 | 
					  size_t n;
 | 
				
			||||||
  while ((n = fread(buf, 1, sizeof buf, f)) > 0)
 | 
					  while ((n = fread(buf, 1, sizeof buf, f)) > 0)
 | 
				
			||||||
    ret.append(buf, n);
 | 
					    ret.append(buf, n);
 | 
				
			||||||
 | 
					  fclose(f);
 | 
				
			||||||
  return ret;
 | 
					  return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -142,6 +144,15 @@ void WriteToFile(const std::string& filename, const std::string& content) {
 | 
				
			|||||||
  fclose(f);
 | 
					  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 GetDefaultResourceDirectory() {
 | 
				
			||||||
  std::string result;
 | 
					  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::string EscapeFileName(std::string path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::optional<std::string> ReadContent(const std::string& filename);
 | 
					std::optional<std::string> ReadContent(const std::string& filename);
 | 
				
			||||||
 | 
					 | 
				
			||||||
void WriteToFile(const std::string& filename, const std::string& content);
 | 
					void WriteToFile(const std::string& filename, const std::string& content);
 | 
				
			||||||
 | 
					std::optional<int64_t> LastWriteTime(const std::string& filename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// http://stackoverflow.com/a/38140932
 | 
					// 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();
 | 
					std::string GetDefaultResourceDirectory();
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user