mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-04 14:17:07 +00:00 
			
		
		
		
	Support empty cacheDirectory and fix cache load
This commit is contained in:
		
							parent
							
								
									82d31a2012
								
							
						
					
					
						commit
						58191fd335
					
				@ -573,7 +573,6 @@ void CompletionMain(ClangCompleteManager *completion_manager) {
 | 
			
		||||
        BuildCompilerInvocation(session->file.args, session->FS);
 | 
			
		||||
    if (!CI)
 | 
			
		||||
      continue;
 | 
			
		||||
    CI->getDiagnosticOpts().IgnoreWarnings = true;
 | 
			
		||||
    clang::CodeCompleteOptions CCOpts;
 | 
			
		||||
    CCOpts.IncludeBriefComments = true;
 | 
			
		||||
#if LLVM_VERSION_MAJOR >= 7
 | 
			
		||||
@ -612,8 +611,6 @@ void DiagnosticMain(ClangCompleteManager *manager) {
 | 
			
		||||
    // Fetching the completion request blocks until we have a request.
 | 
			
		||||
    ClangCompleteManager::DiagnosticRequest request =
 | 
			
		||||
        manager->diagnostic_request_.Dequeue();
 | 
			
		||||
    if (!g_config->diagnostics.onChange)
 | 
			
		||||
      continue;
 | 
			
		||||
    std::string path = request.document.uri.GetPath();
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<CompletionSession> session = manager->TryGetSession(
 | 
			
		||||
@ -623,7 +620,8 @@ void DiagnosticMain(ClangCompleteManager *manager) {
 | 
			
		||||
        BuildCompilerInvocation(session->file.args, session->FS);
 | 
			
		||||
    if (!CI)
 | 
			
		||||
      continue;
 | 
			
		||||
    CI->getLangOpts()->SpellChecking = true;
 | 
			
		||||
    CI->getDiagnosticOpts().IgnoreWarnings = false;
 | 
			
		||||
    CI->getLangOpts()->SpellChecking = g_config->diagnostics.spellChecking;
 | 
			
		||||
    StoreDiags DC;
 | 
			
		||||
    WorkingFiles::Snapshot snapshot =
 | 
			
		||||
        manager->working_files_->AsSnapshot({StripFileType(path)});
 | 
			
		||||
@ -680,6 +678,7 @@ void CompletionSession::BuildPreamble(CompilerInvocation &CI) {
 | 
			
		||||
  auto Bounds = ComputePreambleBounds(*CI.getLangOpts(), Buf.get(), 0);
 | 
			
		||||
  if (OldP && OldP->Preamble.CanReuse(CI, Buf.get(), Bounds, FS.get()))
 | 
			
		||||
    return;
 | 
			
		||||
  CI.getDiagnosticOpts().IgnoreWarnings = false;
 | 
			
		||||
  CI.getFrontendOpts().SkipFunctionBodies = true;
 | 
			
		||||
  CI.getLangOpts()->CommentOpts.ParseAllComments = true;
 | 
			
		||||
#if LLVM_VERSION_MAJOR >= 7
 | 
			
		||||
 | 
			
		||||
@ -75,6 +75,7 @@ BuildCompilerInvocation(const std::vector<std::string> &args,
 | 
			
		||||
  std::unique_ptr<CompilerInvocation> CI =
 | 
			
		||||
      createInvocationFromCommandLine(cargs, Diags, VFS);
 | 
			
		||||
  if (CI) {
 | 
			
		||||
    CI->getDiagnosticOpts().IgnoreWarnings = true;
 | 
			
		||||
    CI->getFrontendOpts().DisableFree = false;
 | 
			
		||||
    CI->getLangOpts()->SpellChecking = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								src/config.h
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								src/config.h
									
									
									
									
									
								
							@ -21,14 +21,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
The language client plugin needs to send initialization options in the
 | 
			
		||||
`initialize` request to the ccls language server. The only required option is
 | 
			
		||||
`cacheDirectory`, which is where index files will be stored.
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    "initializationOptions": {
 | 
			
		||||
      "cacheDirectory": "/tmp/ccls"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
`initialize` request to the ccls language server.
 | 
			
		||||
 | 
			
		||||
If necessary, the command line option --init can be used to override
 | 
			
		||||
initialization options specified by the client. For example, in shell syntax:
 | 
			
		||||
@ -47,6 +40,7 @@ struct Config {
 | 
			
		||||
  std::string compilationDatabaseDirectory;
 | 
			
		||||
  // Cache directory for indexed files, either absolute or relative to the
 | 
			
		||||
  // project root.
 | 
			
		||||
  // If empty, cache will be stored in memory.
 | 
			
		||||
  std::string cacheDirectory = ".ccls-cache";
 | 
			
		||||
  // Cache serialization format.
 | 
			
		||||
  //
 | 
			
		||||
@ -54,12 +48,14 @@ struct Config {
 | 
			
		||||
  // printed with jq.
 | 
			
		||||
  //
 | 
			
		||||
  // "binary" uses a compact binary serialization format.
 | 
			
		||||
  // It is not schema-aware and you need to re-index whenever a struct
 | 
			
		||||
  // It is not schema-aware and you need to re-index whenever an internal struct
 | 
			
		||||
  // member has changed.
 | 
			
		||||
  SerializeFormat cacheFormat = SerializeFormat::Binary;
 | 
			
		||||
 | 
			
		||||
  struct Clang {
 | 
			
		||||
    // Arguments that should be excluded, e.g. ["-fopenmp", "-Wall"]
 | 
			
		||||
    //
 | 
			
		||||
    // e.g. If your project is built by GCC and has an option thag clang does not understand.
 | 
			
		||||
    std::vector<std::string> excludeArgs;
 | 
			
		||||
 | 
			
		||||
    // Additional arguments to pass to clang.
 | 
			
		||||
 | 
			
		||||
@ -45,6 +45,7 @@ struct VFS {
 | 
			
		||||
    int64_t timestamp;
 | 
			
		||||
    int owner;
 | 
			
		||||
    int stage;
 | 
			
		||||
    bool loaded = false;
 | 
			
		||||
  };
 | 
			
		||||
  mutable std::unordered_map<std::string, State> state;
 | 
			
		||||
  mutable std::mutex mutex;
 | 
			
		||||
 | 
			
		||||
@ -51,7 +51,7 @@ struct IndexParam {
 | 
			
		||||
  std::unordered_map<llvm::sys::fs::UniqueID, std::string> SeenUniqueID;
 | 
			
		||||
  std::unordered_map<llvm::sys::fs::UniqueID, bool> UID2multi;
 | 
			
		||||
  std::unordered_map<std::string, FileContents> file_contents;
 | 
			
		||||
  std::unordered_map<std::string, int64_t> file2write_time;
 | 
			
		||||
  std::unordered_map<std::string, int64_t> file2mtime;
 | 
			
		||||
  struct DeclInfo {
 | 
			
		||||
    Usr usr;
 | 
			
		||||
    std::string short_name;
 | 
			
		||||
@ -71,13 +71,7 @@ struct IndexParam {
 | 
			
		||||
    if (inserted) {
 | 
			
		||||
      std::string file_name = FileName(File);
 | 
			
		||||
      it->second = file_name;
 | 
			
		||||
 | 
			
		||||
      // Set modification time.
 | 
			
		||||
      std::optional<int64_t> write_time = LastWriteTime(file_name);
 | 
			
		||||
      LOG_IF_S(ERROR, !write_time)
 | 
			
		||||
          << "failed to fetch write time for " << file_name;
 | 
			
		||||
      if (write_time)
 | 
			
		||||
        file2write_time[file_name] = *write_time;
 | 
			
		||||
      file2mtime[file_name] = File.getModificationTime();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -1307,13 +1301,13 @@ Index(VFS *vfs, const std::string &opt_wdir, const std::string &file,
 | 
			
		||||
      Uniquify(it.second.uses);
 | 
			
		||||
 | 
			
		||||
    // Update file contents and modification time.
 | 
			
		||||
    entry->last_write_time = param.file2write_time[entry->path];
 | 
			
		||||
    entry->mtime = param.file2mtime[entry->path];
 | 
			
		||||
 | 
			
		||||
    // Update dependencies for the file. Do not include the file in its own
 | 
			
		||||
    // dependency set.
 | 
			
		||||
    for (auto &[_, path] : param.SeenUniqueID)
 | 
			
		||||
      if (path != entry->path && path != entry->import_file)
 | 
			
		||||
        entry->dependencies[path] = param.file2write_time[path];
 | 
			
		||||
        entry->dependencies[path] = param.file2mtime[path];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return result;
 | 
			
		||||
 | 
			
		||||
@ -247,7 +247,8 @@ struct IndexFile {
 | 
			
		||||
  llvm::sys::fs::UniqueID UniqueID;
 | 
			
		||||
  std::string path;
 | 
			
		||||
  std::vector<std::string> args;
 | 
			
		||||
  int64_t last_write_time = 0;
 | 
			
		||||
  // This is unfortunately time_t as used by clang::FileEntry
 | 
			
		||||
  int64_t mtime = 0;
 | 
			
		||||
  LanguageId language = LanguageId::C;
 | 
			
		||||
 | 
			
		||||
  // uid2lid_and_path is used to generate lid2path, but not serialized.
 | 
			
		||||
 | 
			
		||||
@ -69,7 +69,8 @@ struct Handler_CclsFreshenIndex : BaseMessageHandler<In_CclsFreshenIndex> {
 | 
			
		||||
      q.pop();
 | 
			
		||||
      need_index.insert(file->def->path);
 | 
			
		||||
 | 
			
		||||
      std::optional<int64_t> write_time = LastWriteTime(file->def->path);
 | 
			
		||||
      std::optional<int64_t> write_time =
 | 
			
		||||
          pipeline::LastWriteTime(file->def->path);
 | 
			
		||||
      if (!write_time)
 | 
			
		||||
        continue;
 | 
			
		||||
      {
 | 
			
		||||
 | 
			
		||||
@ -438,10 +438,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
 | 
			
		||||
      Reflect(json_writer, *g_config);
 | 
			
		||||
      LOG_S(INFO) << "initializationOptions: " << output.GetString();
 | 
			
		||||
 | 
			
		||||
      if (g_config->cacheDirectory.empty()) {
 | 
			
		||||
        LOG_S(ERROR) << "cacheDirectory cannot be empty.";
 | 
			
		||||
        exit(1);
 | 
			
		||||
      } else {
 | 
			
		||||
      if (g_config->cacheDirectory.size()) {
 | 
			
		||||
        g_config->cacheDirectory = NormalizePath(g_config->cacheDirectory);
 | 
			
		||||
        EnsureEndsInSlash(g_config->cacheDirectory);
 | 
			
		||||
      }
 | 
			
		||||
@ -470,12 +467,14 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
 | 
			
		||||
    // Set project root.
 | 
			
		||||
    EnsureEndsInSlash(project_path);
 | 
			
		||||
    g_config->projectRoot = project_path;
 | 
			
		||||
    // Create two cache directories for files inside and outside of the
 | 
			
		||||
    // project.
 | 
			
		||||
    sys::fs::create_directories(g_config->cacheDirectory +
 | 
			
		||||
                                EscapeFileName(g_config->projectRoot));
 | 
			
		||||
    sys::fs::create_directories(g_config->cacheDirectory + '@' +
 | 
			
		||||
                                EscapeFileName(g_config->projectRoot));
 | 
			
		||||
    if (g_config->cacheDirectory.size()) {
 | 
			
		||||
      // Create two cache directories for files inside and outside of the
 | 
			
		||||
      // project.
 | 
			
		||||
      sys::fs::create_directories(g_config->cacheDirectory +
 | 
			
		||||
        EscapeFileName(g_config->projectRoot));
 | 
			
		||||
      sys::fs::create_directories(g_config->cacheDirectory + '@' +
 | 
			
		||||
                                  EscapeFileName(g_config->projectRoot));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    diag_pub->Init();
 | 
			
		||||
    idx::Init();
 | 
			
		||||
 | 
			
		||||
@ -36,15 +36,17 @@ struct Handler_TextDocumentDidChange
 | 
			
		||||
  MethodType GetMethodType() const override { return kMethodType; }
 | 
			
		||||
 | 
			
		||||
  void Run(In_TextDocumentDidChange *request) override {
 | 
			
		||||
    std::string path = request->params.textDocument.uri.GetPath();
 | 
			
		||||
    working_files->OnChange(request->params);
 | 
			
		||||
    const auto ¶ms = request->params;
 | 
			
		||||
    std::string path = params.textDocument.uri.GetPath();
 | 
			
		||||
    working_files->OnChange(params);
 | 
			
		||||
    if (g_config->index.onChange) {
 | 
			
		||||
      Project::Entry entry = project->FindCompilationEntryForFile(path);
 | 
			
		||||
      pipeline::Index(entry.filename, entry.args, IndexMode::OnChange);
 | 
			
		||||
    }
 | 
			
		||||
    clang_complete->NotifyEdit(path);
 | 
			
		||||
    clang_complete->DiagnosticsUpdate(
 | 
			
		||||
        request->params.textDocument.AsTextDocumentIdentifier());
 | 
			
		||||
    clang_complete->NotifyView(path);
 | 
			
		||||
    if (g_config->diagnostics.onChange)
 | 
			
		||||
      clang_complete->DiagnosticsUpdate(
 | 
			
		||||
          params.textDocument.AsTextDocumentIdentifier());
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidChange);
 | 
			
		||||
 | 
			
		||||
@ -53,7 +53,7 @@ struct Handler_TextDocumentDidOpen
 | 
			
		||||
 | 
			
		||||
    WorkingFile *working_file = working_files->OnOpen(params.textDocument);
 | 
			
		||||
    if (std::optional<std::string> cached_file_contents =
 | 
			
		||||
            pipeline::LoadCachedFileContents(path))
 | 
			
		||||
            pipeline::LoadIndexedContent(path))
 | 
			
		||||
      working_file->SetIndexContent(*cached_file_contents);
 | 
			
		||||
 | 
			
		||||
    QueryFile *file = nullptr;
 | 
			
		||||
 | 
			
		||||
@ -95,12 +95,18 @@ ThreadedQueue<Index_Request> *index_request;
 | 
			
		||||
ThreadedQueue<IndexUpdate> *on_indexed;
 | 
			
		||||
ThreadedQueue<Stdout_Request> *for_stdout;
 | 
			
		||||
 | 
			
		||||
struct InMemoryIndexFile {
 | 
			
		||||
  std::string content;
 | 
			
		||||
  IndexFile index;
 | 
			
		||||
};
 | 
			
		||||
std::unordered_map<std::string, InMemoryIndexFile> g_index;
 | 
			
		||||
 | 
			
		||||
bool CacheInvalid(VFS *vfs, IndexFile *prev, const std::string &path,
 | 
			
		||||
                  const std::vector<std::string> &args,
 | 
			
		||||
                  const std::optional<std::string> &from) {
 | 
			
		||||
  {
 | 
			
		||||
    std::lock_guard<std::mutex> lock(vfs->mutex);
 | 
			
		||||
    if (prev->last_write_time < vfs->state[path].timestamp) {
 | 
			
		||||
    if (prev->mtime < vfs->state[path].timestamp) {
 | 
			
		||||
      LOG_S(INFO) << "timestamp changed for " << path
 | 
			
		||||
                  << (from ? " (via " + *from + ")" : std::string());
 | 
			
		||||
      return true;
 | 
			
		||||
@ -140,6 +146,13 @@ std::string GetCachePath(const std::string &source_file) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<IndexFile> RawCacheLoad(const std::string &path) {
 | 
			
		||||
  if (g_config->cacheDirectory.empty()) {
 | 
			
		||||
    auto it = g_index.find(path);
 | 
			
		||||
    if (it == g_index.end())
 | 
			
		||||
      return nullptr;
 | 
			
		||||
    return std::make_unique<IndexFile>(it->second.index);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::string cache_path = GetCachePath(path);
 | 
			
		||||
  std::optional<std::string> file_content = ReadContent(cache_path);
 | 
			
		||||
  std::optional<std::string> serialized_indexed_content =
 | 
			
		||||
@ -267,7 +280,18 @@ bool Indexer_Parse(DiagnosticsPublisher *diag_pub, WorkingFiles *working_files,
 | 
			
		||||
 | 
			
		||||
  for (std::unique_ptr<IndexFile> &curr : indexes) {
 | 
			
		||||
    std::string path = curr->path;
 | 
			
		||||
    if (!(vfs->Stamp(path, curr->last_write_time) || path == path_to_index))
 | 
			
		||||
    bool do_update = path == path_to_index, loaded;
 | 
			
		||||
    {
 | 
			
		||||
      std::lock_guard<std::mutex> lock(vfs->mutex);
 | 
			
		||||
      VFS::State &st = vfs->state[path];
 | 
			
		||||
      if (st.timestamp < curr->mtime) {
 | 
			
		||||
        st.timestamp = curr->mtime;
 | 
			
		||||
        do_update = true;
 | 
			
		||||
      }
 | 
			
		||||
      loaded = st.loaded;
 | 
			
		||||
      st.loaded = true;
 | 
			
		||||
    }
 | 
			
		||||
    if (!do_update)
 | 
			
		||||
      continue;
 | 
			
		||||
    if (std::string reason; !matcher.IsMatch(path, &reason)) {
 | 
			
		||||
      LOG_IF_S(INFO, loud) << "skip emitting and storing index of " << path << " for "
 | 
			
		||||
@ -275,15 +299,22 @@ bool Indexer_Parse(DiagnosticsPublisher *diag_pub, WorkingFiles *working_files,
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LOG_IF_S(INFO, loud) << "emit index for " << path;
 | 
			
		||||
    prev = RawCacheLoad(path);
 | 
			
		||||
    prev.reset();
 | 
			
		||||
    if (loaded)
 | 
			
		||||
      prev = RawCacheLoad(path);
 | 
			
		||||
 | 
			
		||||
    // Write current index to disk if requested.
 | 
			
		||||
    {
 | 
			
		||||
    // Store current index.
 | 
			
		||||
    LOG_IF_S(INFO, loud) << "store index for " << path << " (delta: " << !!prev
 | 
			
		||||
                         << ")";
 | 
			
		||||
    if (g_config->cacheDirectory.empty()) {
 | 
			
		||||
      auto it = g_index.insert_or_assign(
 | 
			
		||||
        path, InMemoryIndexFile{curr->file_contents, *curr});
 | 
			
		||||
      std::string().swap(it.first->second.index.file_contents);
 | 
			
		||||
    } else {
 | 
			
		||||
      std::string cache_path = GetCachePath(path);
 | 
			
		||||
      WriteToFile(cache_path, curr->file_contents);
 | 
			
		||||
      WriteToFile(AppendSerializationFormat(cache_path),
 | 
			
		||||
                  Serialize(g_config->cacheFormat, *curr));
 | 
			
		||||
        Serialize(g_config->cacheFormat, *curr));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfs->Reset(path);
 | 
			
		||||
@ -295,8 +326,6 @@ bool Indexer_Parse(DiagnosticsPublisher *diag_pub, WorkingFiles *working_files,
 | 
			
		||||
 | 
			
		||||
    // Build delta update.
 | 
			
		||||
    IndexUpdate update = IndexUpdate::CreateDelta(prev.get(), curr.get());
 | 
			
		||||
    LOG_IF_S(INFO, loud) << "store index for " << path << " (delta: " << !!prev
 | 
			
		||||
                         << ")";
 | 
			
		||||
 | 
			
		||||
    on_indexed->PushBack(std::move(update),
 | 
			
		||||
                         request.mode != IndexMode::NonInteractive);
 | 
			
		||||
@ -510,7 +539,20 @@ void Index(const std::string &path, const std::vector<std::string> &args,
 | 
			
		||||
  index_request->PushBack({path, args, mode, id}, mode != IndexMode::NonInteractive);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::optional<std::string> LoadCachedFileContents(const std::string &path) {
 | 
			
		||||
std::optional<int64_t> LastWriteTime(const std::string &path) {
 | 
			
		||||
  sys::fs::file_status Status;
 | 
			
		||||
  if (sys::fs::status(path, Status))
 | 
			
		||||
    return {};
 | 
			
		||||
  return sys::toTimeT(Status.getLastModificationTime());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::optional<std::string> LoadIndexedContent(const std::string &path) {
 | 
			
		||||
  if (g_config->cacheDirectory.empty()) {
 | 
			
		||||
    auto it = g_index.find(path);
 | 
			
		||||
    if (it == g_index.end())
 | 
			
		||||
      return {};
 | 
			
		||||
    return it->second.content;
 | 
			
		||||
  }
 | 
			
		||||
  return ReadContent(GetCachePath(path));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -46,7 +46,8 @@ void MainLoop();
 | 
			
		||||
void Index(const std::string &path, const std::vector<std::string> &args,
 | 
			
		||||
           IndexMode mode, lsRequestId id = {});
 | 
			
		||||
 | 
			
		||||
std::optional<std::string> LoadCachedFileContents(const std::string& path);
 | 
			
		||||
void WriteStdout(MethodType method, lsBaseOutMessage& response);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
std::optional<int64_t> LastWriteTime(const std::string &path);
 | 
			
		||||
std::optional<std::string> LoadIndexedContent(const std::string& path);
 | 
			
		||||
void WriteStdout(MethodType method, lsBaseOutMessage &response);
 | 
			
		||||
} // namespace pipeline
 | 
			
		||||
} // namespace ccls
 | 
			
		||||
 | 
			
		||||
@ -309,7 +309,7 @@ bool ReflectMemberStart(Writer &visitor, IndexFile &value) {
 | 
			
		||||
template <typename TVisitor> void Reflect(TVisitor &visitor, IndexFile &value) {
 | 
			
		||||
  REFLECT_MEMBER_START();
 | 
			
		||||
  if (!gTestOutputMode) {
 | 
			
		||||
    REFLECT_MEMBER(last_write_time);
 | 
			
		||||
    REFLECT_MEMBER(mtime);
 | 
			
		||||
    REFLECT_MEMBER(language);
 | 
			
		||||
    REFLECT_MEMBER(lid2path);
 | 
			
		||||
    REFLECT_MEMBER(import_file);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								src/utils.cc
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								src/utils.cc
									
									
									
									
									
								
							@ -15,13 +15,13 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
#include "utils.h"
 | 
			
		||||
 | 
			
		||||
#include "filesystem.hh"
 | 
			
		||||
using namespace llvm;
 | 
			
		||||
#include "log.hh"
 | 
			
		||||
#include "platform.h"
 | 
			
		||||
 | 
			
		||||
#include <siphash.h>
 | 
			
		||||
 | 
			
		||||
#include "llvm/ADT/StringRef.h"
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
@ -29,7 +29,6 @@ using namespace llvm;
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
using namespace std::placeholders;
 | 
			
		||||
 | 
			
		||||
void TrimInPlace(std::string &s) {
 | 
			
		||||
  auto f = [](char c) { return !isspace(c); };
 | 
			
		||||
@ -69,7 +68,8 @@ bool StartsWith(std::string_view s, std::string_view prefix) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool EndsWithAny(std::string_view s, const std::vector<std::string> &ss) {
 | 
			
		||||
  return std::any_of(ss.begin(), ss.end(), std::bind(EndsWith, s, _1));
 | 
			
		||||
  return std::any_of(ss.begin(), ss.end(),
 | 
			
		||||
                     std::bind(EndsWith, s, std::placeholders::_1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool FindAnyPartial(const std::string &value,
 | 
			
		||||
@ -147,13 +147,6 @@ void WriteToFile(const std::string &filename, const std::string &content) {
 | 
			
		||||
  fclose(f);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::optional<int64_t> LastWriteTime(const std::string &filename) {
 | 
			
		||||
  sys::fs::file_status Status;
 | 
			
		||||
  if (sys::fs::status(filename, Status))
 | 
			
		||||
    return {};
 | 
			
		||||
  return Status.getLastModificationTime().time_since_epoch().count();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Find discontinous |search| in |content|.
 | 
			
		||||
// Return |found| and the count of skipped chars before found.
 | 
			
		||||
int ReverseSubseqMatch(std::string_view pat, std::string_view text,
 | 
			
		||||
 | 
			
		||||
@ -75,7 +75,6 @@ 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);
 | 
			
		||||
 | 
			
		||||
int ReverseSubseqMatch(std::string_view pat, std::string_view text,
 | 
			
		||||
                       int case_sensitivity);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user