mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-03 22:04:24 +00:00 
			
		
		
		
	clang-format
DEF CON 26 CTF
This commit is contained in:
		
							parent
							
								
									344ade0420
								
							
						
					
					
						commit
						8cbb317dc2
					
				@ -197,8 +197,9 @@ void BuildCompletionItemTexts(std::vector<lsCompletionItem> &out,
 | 
			
		||||
          continue;
 | 
			
		||||
 | 
			
		||||
        if (Kind == CodeCompletionString::CK_Placeholder) {
 | 
			
		||||
          out[i].insertText +=
 | 
			
		||||
            "${" + std::to_string(out[i].parameters_.size()) + ":" + text + "}";
 | 
			
		||||
          out[i].insertText += "${" +
 | 
			
		||||
                               std::to_string(out[i].parameters_.size()) + ":" +
 | 
			
		||||
                               text + "}";
 | 
			
		||||
          out[i].insertTextFormat = lsInsertTextFormat::Snippet;
 | 
			
		||||
        } else {
 | 
			
		||||
          out[i].insertText += text;
 | 
			
		||||
@ -238,7 +239,8 @@ void BuildDetailString(const CodeCompletionString &CCS, lsCompletionItem &item,
 | 
			
		||||
      item.detail += Chunk.Text;
 | 
			
		||||
      // Add parameter declarations as snippets if enabled
 | 
			
		||||
      if (include_snippets) {
 | 
			
		||||
        item.insertText += "${" + std::to_string(parameters->size()) + ":" + Chunk.Text + "}";
 | 
			
		||||
        item.insertText +=
 | 
			
		||||
            "${" + std::to_string(parameters->size()) + ":" + Chunk.Text + "}";
 | 
			
		||||
        item.insertTextFormat = lsInsertTextFormat::Snippet;
 | 
			
		||||
      } else
 | 
			
		||||
        do_insert = false;
 | 
			
		||||
@ -250,8 +252,8 @@ void BuildDetailString(const CodeCompletionString &CCS, lsCompletionItem &item,
 | 
			
		||||
    case CodeCompletionString::CK_Optional: {
 | 
			
		||||
      // Do not add text to insert string if we're in angle brackets.
 | 
			
		||||
      bool should_insert = do_insert && angle_stack == 0;
 | 
			
		||||
      BuildDetailString(*Chunk.Optional, item, should_insert,
 | 
			
		||||
                        parameters, include_snippets, angle_stack);
 | 
			
		||||
      BuildDetailString(*Chunk.Optional, item, should_insert, parameters,
 | 
			
		||||
                        include_snippets, angle_stack);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case CodeCompletionString::CK_ResultType:
 | 
			
		||||
@ -298,8 +300,7 @@ public:
 | 
			
		||||
        Alloc(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
 | 
			
		||||
        CCTUInfo(Alloc) {}
 | 
			
		||||
 | 
			
		||||
  void ProcessCodeCompleteResults(Sema &S, 
 | 
			
		||||
    CodeCompletionContext Context,
 | 
			
		||||
  void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
 | 
			
		||||
                                  CodeCompletionResult *Results,
 | 
			
		||||
                                  unsigned NumResults) override {
 | 
			
		||||
    ls_items.reserve(NumResults);
 | 
			
		||||
@ -334,8 +335,7 @@ public:
 | 
			
		||||
      } else {
 | 
			
		||||
        bool do_insert = true;
 | 
			
		||||
        int angle_stack = 0;
 | 
			
		||||
        BuildDetailString(*CCS, ls_item, do_insert,
 | 
			
		||||
                          &ls_item.parameters_,
 | 
			
		||||
        BuildDetailString(*CCS, ls_item, do_insert, &ls_item.parameters_,
 | 
			
		||||
                          g_config->client.snippetSupport, angle_stack);
 | 
			
		||||
        if (g_config->client.snippetSupport &&
 | 
			
		||||
            ls_item.insertTextFormat == lsInsertTextFormat::Snippet)
 | 
			
		||||
@ -427,7 +427,8 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
 | 
			
		||||
                                          true /*create_if_needed*/);
 | 
			
		||||
 | 
			
		||||
    std::lock_guard<std::mutex> lock(session->completion.lock);
 | 
			
		||||
    TryEnsureDocumentParsed(completion_manager, session, &session->completion.tu, false);
 | 
			
		||||
    TryEnsureDocumentParsed(completion_manager, session,
 | 
			
		||||
                            &session->completion.tu, false);
 | 
			
		||||
 | 
			
		||||
    // It is possible we failed to create the document despite
 | 
			
		||||
    // |TryEnsureDocumentParsed|.
 | 
			
		||||
@ -464,7 +465,8 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
 | 
			
		||||
                             capture, tu->PCHCO, *Diag, LangOpts, *SrcMgr,
 | 
			
		||||
                             *FileMgr, Diagnostics, TemporaryBuffers);
 | 
			
		||||
      request->on_complete(capture.ls_items, false /*is_cached_result*/);
 | 
			
		||||
      // completion_manager->on_diagnostic_(session->file.filename, Diags.take());
 | 
			
		||||
      // completion_manager->on_diagnostic_(session->file.filename,
 | 
			
		||||
      // Diags.take());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -509,7 +511,8 @@ void DiagnosticQueryMain(ClangCompleteManager *manager) {
 | 
			
		||||
      if (!FLoc.isValid()) // why?
 | 
			
		||||
        continue;
 | 
			
		||||
      const FileEntry *FE = FLoc.getFileEntry();
 | 
			
		||||
      if (!FE || FileName(*FE) != path) continue;
 | 
			
		||||
      if (!FE || FileName(*FE) != path)
 | 
			
		||||
        continue;
 | 
			
		||||
      const auto &SM = FLoc.getManager();
 | 
			
		||||
      SourceRange R;
 | 
			
		||||
      for (const auto &CR : I->getRanges()) {
 | 
			
		||||
@ -559,24 +562,25 @@ ClangCompleteManager::ClangCompleteManager(Project* project,
 | 
			
		||||
                                           WorkingFiles *working_files,
 | 
			
		||||
                                           OnDiagnostic on_diagnostic,
 | 
			
		||||
                                           OnDropped on_dropped)
 | 
			
		||||
    : project_(project),
 | 
			
		||||
      working_files_(working_files),
 | 
			
		||||
      on_diagnostic_(on_diagnostic),
 | 
			
		||||
      on_dropped_(on_dropped),
 | 
			
		||||
    : project_(project), working_files_(working_files),
 | 
			
		||||
      on_diagnostic_(on_diagnostic), on_dropped_(on_dropped),
 | 
			
		||||
      preloaded_sessions_(kMaxPreloadedSessions),
 | 
			
		||||
      completion_sessions_(kMaxCompletionSessions) {
 | 
			
		||||
  std::thread([&]() {
 | 
			
		||||
    set_thread_name("comp-query");
 | 
			
		||||
    CompletionQueryMain(this);
 | 
			
		||||
  }).detach();
 | 
			
		||||
  })
 | 
			
		||||
      .detach();
 | 
			
		||||
  std::thread([&]() {
 | 
			
		||||
    set_thread_name("comp-preload");
 | 
			
		||||
    CompletionPreloadMain(this);
 | 
			
		||||
  }).detach();
 | 
			
		||||
  })
 | 
			
		||||
      .detach();
 | 
			
		||||
  std::thread([&]() {
 | 
			
		||||
    set_thread_name("diag-query");
 | 
			
		||||
    DiagnosticQueryMain(this);
 | 
			
		||||
  }).detach();
 | 
			
		||||
  })
 | 
			
		||||
      .detach();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ClangCompleteManager::CodeComplete(
 | 
			
		||||
@ -668,8 +672,8 @@ bool ClangCompleteManager::EnsureCompletionOrCreatePreloadSession(
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::shared_ptr<CompletionSession> ClangCompleteManager::TryGetSession(
 | 
			
		||||
    const std::string& filename,
 | 
			
		||||
std::shared_ptr<CompletionSession>
 | 
			
		||||
ClangCompleteManager::TryGetSession(const std::string &filename,
 | 
			
		||||
                                    bool mark_as_completion,
 | 
			
		||||
                                    bool create_if_needed) {
 | 
			
		||||
  std::lock_guard<std::mutex> lock(sessions_lock_);
 | 
			
		||||
 | 
			
		||||
@ -36,12 +36,10 @@ struct CompletionSession
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ClangCompleteManager {
 | 
			
		||||
  using OnDiagnostic =
 | 
			
		||||
      std::function<void(std::string path,
 | 
			
		||||
                         std::vector<lsDiagnostic> diagnostics)>;
 | 
			
		||||
  using OnComplete =
 | 
			
		||||
      std::function<void(const std::vector<lsCompletionItem>& results,
 | 
			
		||||
                         bool is_cached_result)>;
 | 
			
		||||
  using OnDiagnostic = std::function<void(
 | 
			
		||||
      std::string path, std::vector<lsDiagnostic> diagnostics)>;
 | 
			
		||||
  using OnComplete = std::function<void(
 | 
			
		||||
      const std::vector<lsCompletionItem> &results, bool is_cached_result)>;
 | 
			
		||||
  using OnDropped = std::function<void(lsRequestId request_id)>;
 | 
			
		||||
 | 
			
		||||
  struct PreloadRequest {
 | 
			
		||||
@ -54,11 +52,8 @@ struct ClangCompleteManager {
 | 
			
		||||
  struct CompletionRequest {
 | 
			
		||||
    CompletionRequest(const lsRequestId &id,
 | 
			
		||||
                      const lsTextDocumentIdentifier &document,
 | 
			
		||||
                      const lsPosition& position,
 | 
			
		||||
                      const OnComplete& on_complete)
 | 
			
		||||
        : id(id),
 | 
			
		||||
          document(document),
 | 
			
		||||
          position(position),
 | 
			
		||||
                      const lsPosition &position, const OnComplete &on_complete)
 | 
			
		||||
        : id(id), document(document), position(position),
 | 
			
		||||
          on_complete(on_complete) {}
 | 
			
		||||
 | 
			
		||||
    lsRequestId id;
 | 
			
		||||
@ -70,10 +65,8 @@ struct ClangCompleteManager {
 | 
			
		||||
    lsTextDocumentIdentifier document;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  ClangCompleteManager(Project* project,
 | 
			
		||||
                       WorkingFiles* working_files,
 | 
			
		||||
                       OnDiagnostic on_diagnostic,
 | 
			
		||||
                       OnDropped on_dropped);
 | 
			
		||||
  ClangCompleteManager(Project *project, WorkingFiles *working_files,
 | 
			
		||||
                       OnDiagnostic on_diagnostic, OnDropped on_dropped);
 | 
			
		||||
 | 
			
		||||
  // Start a code completion at the given location. |on_complete| will run when
 | 
			
		||||
  // completion results are available. |on_complete| may run on any thread.
 | 
			
		||||
 | 
			
		||||
@ -103,8 +103,7 @@ std::unique_ptr<ClangTranslationUnit> ClangTranslationUnit::Create(
 | 
			
		||||
        ret->PCHCO->getRawReader().getFormat(), &ErrUnit));
 | 
			
		||||
  };
 | 
			
		||||
  if (!CRC.RunSafely(parse)) {
 | 
			
		||||
    LOG_S(ERROR)
 | 
			
		||||
        << "clang crashed for " << filepath << "\n"
 | 
			
		||||
    LOG_S(ERROR) << "clang crashed for " << filepath << "\n"
 | 
			
		||||
                 << StringJoin(args, " ") + " -fsyntax-only";
 | 
			
		||||
    return {};
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -7,9 +7,9 @@
 | 
			
		||||
#include <llvm/Support/CrashRecoveryContext.h>
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
std::vector<clang::ASTUnit::RemappedFile>
 | 
			
		||||
GetRemapped(const WorkingFiles::Snapshot &snapshot);
 | 
			
		||||
@ -19,12 +19,12 @@ Range FromCharSourceRange(const clang::SourceManager &SM,
 | 
			
		||||
                          clang::CharSourceRange R,
 | 
			
		||||
                          llvm::sys::fs::UniqueID *UniqueID = nullptr);
 | 
			
		||||
 | 
			
		||||
Range FromCharRange(const clang::SourceManager &SM, const clang::LangOptions &LangOpts,
 | 
			
		||||
                    clang::SourceRange R,
 | 
			
		||||
Range FromCharRange(const clang::SourceManager &SM,
 | 
			
		||||
                    const clang::LangOptions &LangOpts, clang::SourceRange R,
 | 
			
		||||
                    llvm::sys::fs::UniqueID *UniqueID = nullptr);
 | 
			
		||||
 | 
			
		||||
Range FromTokenRange(const clang::SourceManager &SM, const clang::LangOptions &LangOpts,
 | 
			
		||||
                     clang::SourceRange R,
 | 
			
		||||
Range FromTokenRange(const clang::SourceManager &SM,
 | 
			
		||||
                     const clang::LangOptions &LangOpts, clang::SourceRange R,
 | 
			
		||||
                     llvm::sys::fs::UniqueID *UniqueID = nullptr);
 | 
			
		||||
 | 
			
		||||
struct ClangTranslationUnit {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										50
									
								
								src/config.h
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								src/config.h
									
									
									
									
									
								
							@ -218,49 +218,23 @@ struct Config {
 | 
			
		||||
MAKE_REFLECT_STRUCT(Config::Clang, extraArgs, resourceDir);
 | 
			
		||||
MAKE_REFLECT_STRUCT(Config::ClientCapability, snippetSupport);
 | 
			
		||||
MAKE_REFLECT_STRUCT(Config::CodeLens, localVariables);
 | 
			
		||||
MAKE_REFLECT_STRUCT(Config::Completion,
 | 
			
		||||
                    caseSensitivity,
 | 
			
		||||
                    dropOldRequests,
 | 
			
		||||
                    detailedLabel,
 | 
			
		||||
                    filterAndSort,
 | 
			
		||||
                    includeBlacklist,
 | 
			
		||||
                    includeMaxPathSize,
 | 
			
		||||
                    includeSuffixWhitelist,
 | 
			
		||||
MAKE_REFLECT_STRUCT(Config::Completion, caseSensitivity, dropOldRequests,
 | 
			
		||||
                    detailedLabel, filterAndSort, includeBlacklist,
 | 
			
		||||
                    includeMaxPathSize, includeSuffixWhitelist,
 | 
			
		||||
                    includeWhitelist);
 | 
			
		||||
MAKE_REFLECT_STRUCT(Config::Diagnostics,
 | 
			
		||||
                    blacklist,
 | 
			
		||||
                    frequencyMs,
 | 
			
		||||
                    onParse,
 | 
			
		||||
                    onType,
 | 
			
		||||
                    whitelist)
 | 
			
		||||
MAKE_REFLECT_STRUCT(Config::Diagnostics, blacklist, frequencyMs, onParse,
 | 
			
		||||
                    onType, whitelist)
 | 
			
		||||
MAKE_REFLECT_STRUCT(Config::Highlight, lsRanges, blacklist, whitelist)
 | 
			
		||||
MAKE_REFLECT_STRUCT(Config::Index,
 | 
			
		||||
                    attributeMakeCallsToCtor,
 | 
			
		||||
                    blacklist,
 | 
			
		||||
                    comments,
 | 
			
		||||
                    enabled,
 | 
			
		||||
                    onDidChange,
 | 
			
		||||
                    reparseForDependency,
 | 
			
		||||
                    threads,
 | 
			
		||||
                    whitelist);
 | 
			
		||||
MAKE_REFLECT_STRUCT(Config::Index, attributeMakeCallsToCtor, blacklist,
 | 
			
		||||
                    comments, enabled, onDidChange, reparseForDependency,
 | 
			
		||||
                    threads, whitelist);
 | 
			
		||||
MAKE_REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort);
 | 
			
		||||
MAKE_REFLECT_STRUCT(Config::Xref, container, maxNum);
 | 
			
		||||
MAKE_REFLECT_STRUCT(Config,
 | 
			
		||||
                    compilationDatabaseCommand,
 | 
			
		||||
                    compilationDatabaseDirectory,
 | 
			
		||||
                    cacheDirectory,
 | 
			
		||||
                    cacheFormat,
 | 
			
		||||
MAKE_REFLECT_STRUCT(Config, compilationDatabaseCommand,
 | 
			
		||||
                    compilationDatabaseDirectory, cacheDirectory, cacheFormat,
 | 
			
		||||
 | 
			
		||||
                    clang,
 | 
			
		||||
                    client,
 | 
			
		||||
                    codeLens,
 | 
			
		||||
                    completion,
 | 
			
		||||
                    diagnostics,
 | 
			
		||||
                    highlight,
 | 
			
		||||
                    index,
 | 
			
		||||
                    largeFileSize,
 | 
			
		||||
                    workspaceSymbol,
 | 
			
		||||
                    xref);
 | 
			
		||||
                    clang, client, codeLens, completion, diagnostics, highlight,
 | 
			
		||||
                    index, largeFileSize, workspaceSymbol, xref);
 | 
			
		||||
 | 
			
		||||
extern Config *g_config;
 | 
			
		||||
thread_local extern int g_thread_id;
 | 
			
		||||
 | 
			
		||||
@ -8,8 +8,8 @@
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
std::optional<std::string> GetFileContents(
 | 
			
		||||
    const std::string& path,
 | 
			
		||||
std::optional<std::string>
 | 
			
		||||
GetFileContents(const std::string &path,
 | 
			
		||||
                std::unordered_map<std::string, FileContents> *file_contents) {
 | 
			
		||||
  auto it = file_contents->find(path);
 | 
			
		||||
  if (it == file_contents->end()) {
 | 
			
		||||
@ -115,7 +115,8 @@ IndexFile* FileConsumer::TryConsumeFile(
 | 
			
		||||
    return nullptr;
 | 
			
		||||
 | 
			
		||||
  // Build IndexFile instance.
 | 
			
		||||
  local_[UniqueID] = std::make_unique<IndexFile>(UniqueID, file_name, *contents);
 | 
			
		||||
  local_[UniqueID] =
 | 
			
		||||
      std::make_unique<IndexFile>(UniqueID, file_name, *contents);
 | 
			
		||||
  return local_[UniqueID].get();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -42,15 +42,14 @@ struct VFS {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
namespace std {
 | 
			
		||||
template <>
 | 
			
		||||
struct hash<llvm::sys::fs::UniqueID> {
 | 
			
		||||
template <> struct hash<llvm::sys::fs::UniqueID> {
 | 
			
		||||
  std::size_t operator()(llvm::sys::fs::UniqueID ID) const {
 | 
			
		||||
    size_t ret = ID.getDevice();
 | 
			
		||||
    hash_combine(ret, ID.getFile());
 | 
			
		||||
    return ret;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
} // namespace std
 | 
			
		||||
 | 
			
		||||
// FileConsumer is used by the indexer. When it encouters a file, it tries to
 | 
			
		||||
// take ownership over it. If the indexer has ownership over a file, it will
 | 
			
		||||
@ -68,14 +67,16 @@ struct FileConsumer {
 | 
			
		||||
  //
 | 
			
		||||
  // note: file_contents is passed as a parameter instead of as a member
 | 
			
		||||
  // variable since it is large and we do not want to copy it.
 | 
			
		||||
  IndexFile* TryConsumeFile(const clang::FileEntry& file,
 | 
			
		||||
  IndexFile *
 | 
			
		||||
  TryConsumeFile(const clang::FileEntry &file,
 | 
			
		||||
                 std::unordered_map<std::string, FileContents> *file_contents);
 | 
			
		||||
 | 
			
		||||
  // Returns and passes ownership of all local state.
 | 
			
		||||
  std::vector<std::unique_ptr<IndexFile>> TakeLocalState();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  std::unordered_map<llvm::sys::fs::UniqueID, std::unique_ptr<IndexFile>> local_;
 | 
			
		||||
  std::unordered_map<llvm::sys::fs::UniqueID, std::unique_ptr<IndexFile>>
 | 
			
		||||
      local_;
 | 
			
		||||
  VFS *vfs_;
 | 
			
		||||
  std::string parse_file_;
 | 
			
		||||
  int thread_id_;
 | 
			
		||||
 | 
			
		||||
@ -6,9 +6,7 @@ using namespace llvm;
 | 
			
		||||
#include <set>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
void GetFilesInFolder(std::string folder,
 | 
			
		||||
                      bool recursive,
 | 
			
		||||
                      bool dir_prefix,
 | 
			
		||||
void GetFilesInFolder(std::string folder, bool recursive, bool dir_prefix,
 | 
			
		||||
                      const std::function<void(const std::string &)> &handler) {
 | 
			
		||||
  EnsureEndsInSlash(folder);
 | 
			
		||||
  sys::fs::file_status Status;
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
#include "fuzzy_match.h"
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
enum CharClass { Other, Lower, Upper };
 | 
			
		||||
 | 
			
		||||
@ -46,8 +46,7 @@ size_t TrimCommonPathPrefix(const std::string& result,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns true iff angle brackets should be used.
 | 
			
		||||
bool TrimPath(Project* project,
 | 
			
		||||
              const std::string& project_root,
 | 
			
		||||
bool TrimPath(Project *project, const std::string &project_root,
 | 
			
		||||
              std::string *insert_path) {
 | 
			
		||||
  size_t start = TrimCommonPathPrefix(*insert_path, project_root);
 | 
			
		||||
  bool angle = false;
 | 
			
		||||
@ -68,8 +67,7 @@ bool TrimPath(Project* project,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
lsCompletionItem BuildCompletionItem(const std::string &path,
 | 
			
		||||
                                     bool use_angle_brackets,
 | 
			
		||||
                                     bool is_stl) {
 | 
			
		||||
                                     bool use_angle_brackets, bool is_stl) {
 | 
			
		||||
  lsCompletionItem item;
 | 
			
		||||
  item.label = ElideLongPath(path);
 | 
			
		||||
  item.detail = path; // the include path, used in de-duplicating
 | 
			
		||||
@ -102,7 +100,8 @@ void IncludeComplete::Rescan() {
 | 
			
		||||
 | 
			
		||||
  if (!match_ && (g_config->completion.includeWhitelist.size() ||
 | 
			
		||||
                  g_config->completion.includeBlacklist.size()))
 | 
			
		||||
    match_ = std::make_unique<GroupMatch>(g_config->completion.includeWhitelist,
 | 
			
		||||
    match_ =
 | 
			
		||||
        std::make_unique<GroupMatch>(g_config->completion.includeWhitelist,
 | 
			
		||||
                                     g_config->completion.includeBlacklist);
 | 
			
		||||
 | 
			
		||||
  is_scanning = true;
 | 
			
		||||
@ -117,7 +116,8 @@ void IncludeComplete::Rescan() {
 | 
			
		||||
      InsertIncludesFromDirectory(dir, true /*use_angle_brackets*/);
 | 
			
		||||
 | 
			
		||||
    is_scanning = false;
 | 
			
		||||
  }).detach();
 | 
			
		||||
  })
 | 
			
		||||
      .detach();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void IncludeComplete::InsertCompletionItem(const std::string &absolute_path,
 | 
			
		||||
@ -189,7 +189,8 @@ void IncludeComplete::InsertIncludesFromDirectory(std::string directory,
 | 
			
		||||
                         std::move(result.completion_item));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::optional<lsCompletionItem> IncludeComplete::FindCompletionItemForAbsolutePath(
 | 
			
		||||
std::optional<lsCompletionItem>
 | 
			
		||||
IncludeComplete::FindCompletionItemForAbsolutePath(
 | 
			
		||||
    const std::string &absolute_path) {
 | 
			
		||||
  std::lock_guard<std::mutex> lock(completion_items_mutex);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -23,8 +23,8 @@ struct IncludeComplete {
 | 
			
		||||
  void InsertIncludesFromDirectory(std::string directory,
 | 
			
		||||
                                   bool use_angle_brackets);
 | 
			
		||||
 | 
			
		||||
  std::optional<lsCompletionItem> FindCompletionItemForAbsolutePath(
 | 
			
		||||
      const std::string& absolute_path);
 | 
			
		||||
  std::optional<lsCompletionItem>
 | 
			
		||||
  FindCompletionItemForAbsolutePath(const std::string &absolute_path);
 | 
			
		||||
 | 
			
		||||
  // Insert item to |completion_items|.
 | 
			
		||||
  // Update |absolute_path_to_completion_item| and |inserted_paths|.
 | 
			
		||||
 | 
			
		||||
@ -21,9 +21,9 @@ using ccls::Intern;
 | 
			
		||||
using namespace clang;
 | 
			
		||||
using llvm::Timer;
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <unordered_set>
 | 
			
		||||
 | 
			
		||||
@ -81,8 +81,9 @@ StringRef GetSourceInRange(const SourceManager &SM, const LangOptions &LangOpts,
 | 
			
		||||
  StringRef Buf = SM.getBufferData(BInfo.first, &invalid);
 | 
			
		||||
  if (invalid)
 | 
			
		||||
    return "";
 | 
			
		||||
  return Buf.substr(BInfo.second, EInfo.second + Lexer::MeasureTokenLength(
 | 
			
		||||
                                                     ELoc, SM, LangOpts) -
 | 
			
		||||
  return Buf.substr(BInfo.second,
 | 
			
		||||
                    EInfo.second +
 | 
			
		||||
                        Lexer::MeasureTokenLength(ELoc, SM, LangOpts) -
 | 
			
		||||
                        BInfo.second);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -200,8 +201,7 @@ QualType GetBaseType(QualType T, bool deduce_auto) {
 | 
			
		||||
        BaseType = ATy->getDeducedType();
 | 
			
		||||
      else
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    } else
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
  return BaseType;
 | 
			
		||||
@ -271,14 +271,14 @@ const Decl* GetSpecialized(const Decl* D) {
 | 
			
		||||
    return D;
 | 
			
		||||
  Decl *Template = nullptr;
 | 
			
		||||
  if (const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) {
 | 
			
		||||
    if (const ClassTemplatePartialSpecializationDecl *PartialSpec
 | 
			
		||||
          = dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord))
 | 
			
		||||
    if (const ClassTemplatePartialSpecializationDecl *PartialSpec =
 | 
			
		||||
            dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord))
 | 
			
		||||
      Template = PartialSpec->getSpecializedTemplate();
 | 
			
		||||
    else if (const ClassTemplateSpecializationDecl *ClassSpec
 | 
			
		||||
               = dyn_cast<ClassTemplateSpecializationDecl>(CXXRecord)) {
 | 
			
		||||
    else if (const ClassTemplateSpecializationDecl *ClassSpec =
 | 
			
		||||
                 dyn_cast<ClassTemplateSpecializationDecl>(CXXRecord)) {
 | 
			
		||||
      llvm::PointerUnion<ClassTemplateDecl *,
 | 
			
		||||
                         ClassTemplatePartialSpecializationDecl *> Result
 | 
			
		||||
        = ClassSpec->getSpecializedTemplateOrPartial();
 | 
			
		||||
                         ClassTemplatePartialSpecializationDecl *>
 | 
			
		||||
          Result = ClassSpec->getSpecializedTemplateOrPartial();
 | 
			
		||||
      if (Result.is<ClassTemplateDecl *>())
 | 
			
		||||
        Template = Result.get<ClassTemplateDecl *>();
 | 
			
		||||
      else
 | 
			
		||||
@ -293,8 +293,8 @@ const Decl* GetSpecialized(const Decl* D) {
 | 
			
		||||
  } else if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
 | 
			
		||||
    if (Var->isStaticDataMember())
 | 
			
		||||
      Template = Var->getInstantiatedFromStaticDataMember();
 | 
			
		||||
  } else if (const RedeclarableTemplateDecl *Tmpl
 | 
			
		||||
                                        = dyn_cast<RedeclarableTemplateDecl>(D))
 | 
			
		||||
  } else if (const RedeclarableTemplateDecl *Tmpl =
 | 
			
		||||
                 dyn_cast<RedeclarableTemplateDecl>(D))
 | 
			
		||||
    Template = Tmpl->getInstantiatedFromMemberTemplate();
 | 
			
		||||
  else
 | 
			
		||||
    return nullptr;
 | 
			
		||||
@ -322,7 +322,8 @@ public:
 | 
			
		||||
  std::string GetComment(const Decl *D) {
 | 
			
		||||
    SourceManager &SM = Ctx->getSourceManager();
 | 
			
		||||
    const RawComment *RC = Ctx->getRawCommentForAnyRedecl(D);
 | 
			
		||||
    if (!RC) return "";
 | 
			
		||||
    if (!RC)
 | 
			
		||||
      return "";
 | 
			
		||||
    StringRef Raw = RC->getRawText(Ctx->getSourceManager());
 | 
			
		||||
    SourceRange R = RC->getSourceRange();
 | 
			
		||||
    std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(R.getBegin());
 | 
			
		||||
@ -536,7 +537,8 @@ public:
 | 
			
		||||
  void AddMacroUse(IndexFile *db, SourceManager &SM, Usr usr, SymbolKind kind,
 | 
			
		||||
                   SourceLocation Spell) const {
 | 
			
		||||
    const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Spell));
 | 
			
		||||
    if (!FE) return;
 | 
			
		||||
    if (!FE)
 | 
			
		||||
      return;
 | 
			
		||||
    auto UID = FE->getUniqueID();
 | 
			
		||||
    auto [it, inserted] = db->uid2lid_and_path.try_emplace(UID);
 | 
			
		||||
    if (inserted) {
 | 
			
		||||
@ -569,9 +571,7 @@ public:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  IndexDataConsumer(IndexParam ¶m) : param(param) {}
 | 
			
		||||
  void initialize(ASTContext &Ctx) override {
 | 
			
		||||
    this->Ctx = param.Ctx = &Ctx;
 | 
			
		||||
  }
 | 
			
		||||
  void initialize(ASTContext &Ctx) override { this->Ctx = param.Ctx = &Ctx; }
 | 
			
		||||
  bool handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
 | 
			
		||||
                           ArrayRef<index::SymbolRelation> Relations,
 | 
			
		||||
#if LLVM_VERSION_MAJOR >= 7
 | 
			
		||||
@ -728,7 +728,8 @@ public:
 | 
			
		||||
                it->second.instances.push_back(usr);
 | 
			
		||||
                break;
 | 
			
		||||
              }
 | 
			
		||||
              // e.g. TemplateTypeParmDecl is not handled by handleDeclOccurence.
 | 
			
		||||
              // e.g. TemplateTypeParmDecl is not handled by
 | 
			
		||||
              // handleDeclOccurence.
 | 
			
		||||
              SourceRange R1 = D1->getSourceRange();
 | 
			
		||||
              if (SM.getFileID(R1.getBegin()) == LocFID) {
 | 
			
		||||
                IndexType &type1 = db->ToType(usr1);
 | 
			
		||||
@ -1056,8 +1057,8 @@ public:
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  void MacroExpands(const Token &Tok, const MacroDefinition &MD,
 | 
			
		||||
                    SourceRange R, const MacroArgs *Args) override {
 | 
			
		||||
  void MacroExpands(const Token &Tok, const MacroDefinition &MD, SourceRange R,
 | 
			
		||||
                    const MacroArgs *Args) override {
 | 
			
		||||
    llvm::sys::fs::UniqueID UniqueID;
 | 
			
		||||
    SourceLocation L = SM.getSpellingLoc(R.getBegin());
 | 
			
		||||
    const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(L));
 | 
			
		||||
@ -1089,16 +1090,18 @@ public:
 | 
			
		||||
 | 
			
		||||
class IndexFrontendAction : public ASTFrontendAction {
 | 
			
		||||
  IndexParam ¶m;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  IndexFrontendAction(IndexParam ¶m) : param(param) {}
 | 
			
		||||
  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
 | 
			
		||||
                                                 StringRef InFile) override {
 | 
			
		||||
    Preprocessor &PP = CI.getPreprocessor();
 | 
			
		||||
    PP.addPPCallbacks(std::make_unique<IndexPPCallbacks>(PP.getSourceManager(), param));
 | 
			
		||||
    PP.addPPCallbacks(
 | 
			
		||||
        std::make_unique<IndexPPCallbacks>(PP.getSourceManager(), param));
 | 
			
		||||
    return std::make_unique<ASTConsumer>();
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
const int IndexFile::kMajorVersion = 17;
 | 
			
		||||
const int IndexFile::kMinorVersion = 1;
 | 
			
		||||
@ -1132,8 +1135,7 @@ std::string IndexFile::ToString() {
 | 
			
		||||
  return ccls::Serialize(SerializeFormat::Json, *this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
void Uniquify(std::vector<T>& a) {
 | 
			
		||||
template <typename T> void Uniquify(std::vector<T> &a) {
 | 
			
		||||
  std::unordered_set<T> seen;
 | 
			
		||||
  size_t n = 0;
 | 
			
		||||
  for (size_t i = 0; i < a.size(); i++)
 | 
			
		||||
@ -1143,10 +1145,8 @@ void Uniquify(std::vector<T>& a) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace ccls::idx {
 | 
			
		||||
std::vector<std::unique_ptr<IndexFile>> Index(
 | 
			
		||||
    VFS* vfs,
 | 
			
		||||
    const std::string& opt_wdir,
 | 
			
		||||
    const std::string& file,
 | 
			
		||||
std::vector<std::unique_ptr<IndexFile>>
 | 
			
		||||
Index(VFS *vfs, const std::string &opt_wdir, const std::string &file,
 | 
			
		||||
      const std::vector<std::string> &args,
 | 
			
		||||
      const std::vector<FileContents> &file_contents) {
 | 
			
		||||
  if (!g_config->index.enabled)
 | 
			
		||||
@ -1156,8 +1156,8 @@ std::vector<std::unique_ptr<IndexFile>> Index(
 | 
			
		||||
  for (auto &arg : args)
 | 
			
		||||
    Args.push_back(arg.c_str());
 | 
			
		||||
  auto PCHCO = std::make_shared<PCHContainerOperations>();
 | 
			
		||||
  IntrusiveRefCntPtr<DiagnosticsEngine>
 | 
			
		||||
    Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions));
 | 
			
		||||
  IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
 | 
			
		||||
      CompilerInstance::createDiagnostics(new DiagnosticOptions));
 | 
			
		||||
  std::shared_ptr<CompilerInvocation> CI =
 | 
			
		||||
      createInvocationFromCommandLine(Args, Diags);
 | 
			
		||||
  if (!CI)
 | 
			
		||||
@ -1283,7 +1283,7 @@ std::vector<std::unique_ptr<IndexFile>> Index(
 | 
			
		||||
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
} // namespace ccls::idx
 | 
			
		||||
 | 
			
		||||
// |SymbolRef| is serialized this way.
 | 
			
		||||
// |Use| also uses this though it has an extra field |file|,
 | 
			
		||||
 | 
			
		||||
@ -14,9 +14,9 @@
 | 
			
		||||
#include <clang/Basic/Specifiers.h>
 | 
			
		||||
#include <llvm/ADT/StringMap.h>
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string_view>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
@ -72,8 +72,7 @@ void Reflect(Writer& visitor, Reference& value);
 | 
			
		||||
void Reflect(Reader &visitor, Use &value);
 | 
			
		||||
void Reflect(Writer &visitor, Use &value);
 | 
			
		||||
 | 
			
		||||
template <typename D>
 | 
			
		||||
struct NameMixin {
 | 
			
		||||
template <typename D> struct NameMixin {
 | 
			
		||||
  std::string_view Name(bool qualified) const {
 | 
			
		||||
    auto self = static_cast<const D *>(this);
 | 
			
		||||
    return qualified
 | 
			
		||||
@ -112,20 +111,9 @@ struct FuncDef : NameMixin<FuncDef> {
 | 
			
		||||
 | 
			
		||||
  std::vector<Usr> GetBases() const { return bases; }
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(FuncDef,
 | 
			
		||||
                    detailed_name,
 | 
			
		||||
                    qual_name_offset,
 | 
			
		||||
                    short_name_offset,
 | 
			
		||||
                    short_name_size,
 | 
			
		||||
                    kind,
 | 
			
		||||
                    storage,
 | 
			
		||||
                    hover,
 | 
			
		||||
                    comments,
 | 
			
		||||
                    spell,
 | 
			
		||||
                    extent,
 | 
			
		||||
                    bases,
 | 
			
		||||
                    vars,
 | 
			
		||||
                    callees);
 | 
			
		||||
MAKE_REFLECT_STRUCT(FuncDef, detailed_name, qual_name_offset, short_name_offset,
 | 
			
		||||
                    short_name_size, kind, storage, hover, comments, spell,
 | 
			
		||||
                    extent, bases, vars, callees);
 | 
			
		||||
 | 
			
		||||
struct IndexFunc : NameMixin<IndexFunc> {
 | 
			
		||||
  using Def = FuncDef;
 | 
			
		||||
@ -163,21 +151,9 @@ struct TypeDef : NameMixin<TypeDef> {
 | 
			
		||||
 | 
			
		||||
  std::vector<Usr> GetBases() const { return bases; }
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(TypeDef,
 | 
			
		||||
                    detailed_name,
 | 
			
		||||
                    qual_name_offset,
 | 
			
		||||
                    short_name_offset,
 | 
			
		||||
                    short_name_size,
 | 
			
		||||
                    kind,
 | 
			
		||||
                    hover,
 | 
			
		||||
                    comments,
 | 
			
		||||
                    spell,
 | 
			
		||||
                    extent,
 | 
			
		||||
                    alias_of,
 | 
			
		||||
                    bases,
 | 
			
		||||
                    types,
 | 
			
		||||
                    funcs,
 | 
			
		||||
                    vars);
 | 
			
		||||
MAKE_REFLECT_STRUCT(TypeDef, detailed_name, qual_name_offset, short_name_offset,
 | 
			
		||||
                    short_name_size, kind, hover, comments, spell, extent,
 | 
			
		||||
                    alias_of, bases, types, funcs, vars);
 | 
			
		||||
 | 
			
		||||
struct IndexType {
 | 
			
		||||
  using Def = TypeDef;
 | 
			
		||||
@ -217,17 +193,8 @@ struct VarDef : NameMixin<VarDef> {
 | 
			
		||||
 | 
			
		||||
  std::vector<Usr> GetBases() const { return {}; }
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(VarDef,
 | 
			
		||||
                    detailed_name,
 | 
			
		||||
                    qual_name_offset,
 | 
			
		||||
                    short_name_offset,
 | 
			
		||||
                    short_name_size,
 | 
			
		||||
                    hover,
 | 
			
		||||
                    comments,
 | 
			
		||||
                    spell,
 | 
			
		||||
                    extent,
 | 
			
		||||
                    type,
 | 
			
		||||
                    kind,
 | 
			
		||||
MAKE_REFLECT_STRUCT(VarDef, detailed_name, qual_name_offset, short_name_offset,
 | 
			
		||||
                    short_name_size, hover, comments, spell, extent, type, kind,
 | 
			
		||||
                    storage);
 | 
			
		||||
 | 
			
		||||
struct IndexVar {
 | 
			
		||||
 | 
			
		||||
@ -3,11 +3,11 @@
 | 
			
		||||
#include <llvm/ADT/SmallString.h>
 | 
			
		||||
#include <llvm/Support/Threading.h>
 | 
			
		||||
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
 | 
			
		||||
namespace ccls::log {
 | 
			
		||||
static std::mutex mtx;
 | 
			
		||||
@ -52,11 +52,12 @@ Message::Message(Verbosity verbosity, const char* file, int line)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Message::~Message() {
 | 
			
		||||
  if (!file) return;
 | 
			
		||||
  if (!file)
 | 
			
		||||
    return;
 | 
			
		||||
  std::lock_guard<std::mutex> lock(mtx);
 | 
			
		||||
  stream_ << '\n';
 | 
			
		||||
  fputs(stream_.str().c_str(), file);
 | 
			
		||||
  if (verbosity_ == Verbosity_FATAL)
 | 
			
		||||
    abort();
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
} // namespace ccls::log
 | 
			
		||||
 | 
			
		||||
@ -8,8 +8,7 @@
 | 
			
		||||
 | 
			
		||||
// Cache that evicts old entries which have not been used recently. Implemented
 | 
			
		||||
// using array/linear search so this works well for small array sizes.
 | 
			
		||||
template <typename TKey, typename TValue>
 | 
			
		||||
struct LruCache {
 | 
			
		||||
template <typename TKey, typename TValue> struct LruCache {
 | 
			
		||||
  explicit LruCache(int max_entries);
 | 
			
		||||
 | 
			
		||||
  // Fetches an entry for |key|. If it does not exist, |allocator| will be
 | 
			
		||||
@ -26,8 +25,7 @@ struct LruCache {
 | 
			
		||||
 | 
			
		||||
  // Call |func| on existing entries. If |func| returns false iteration
 | 
			
		||||
  // temrinates early.
 | 
			
		||||
  template <typename TFunc>
 | 
			
		||||
  void IterateValues(TFunc func);
 | 
			
		||||
  template <typename TFunc> void IterateValues(TFunc func);
 | 
			
		||||
 | 
			
		||||
  // Empties the cache
 | 
			
		||||
  void Clear(void);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								src/lsp.cc
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/lsp.cc
									
									
									
									
									
								
							@ -17,8 +17,8 @@ lsVersionedTextDocumentIdentifier::AsTextDocumentIdentifier() const {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Reads a JsonRpc message. |read| returns the next input character.
 | 
			
		||||
std::optional<std::string> ReadJsonRpcContentFrom(
 | 
			
		||||
    std::function<std::optional<char>()> read) {
 | 
			
		||||
std::optional<std::string>
 | 
			
		||||
ReadJsonRpcContentFrom(std::function<std::optional<char>()> read) {
 | 
			
		||||
  // Read the content length. It is terminated by the "\r\n" sequence.
 | 
			
		||||
  int exit_seq = 0;
 | 
			
		||||
  std::string stringified_content_length;
 | 
			
		||||
@ -78,8 +78,8 @@ std::optional<char> ReadCharFromStdinBlocking() {
 | 
			
		||||
  return std::nullopt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::optional<std::string> MessageRegistry::ReadMessageFromStdin(
 | 
			
		||||
    std::unique_ptr<InMessage>* message) {
 | 
			
		||||
std::optional<std::string>
 | 
			
		||||
MessageRegistry::ReadMessageFromStdin(std::unique_ptr<InMessage> *message) {
 | 
			
		||||
  std::optional<std::string> content =
 | 
			
		||||
      ReadJsonRpcContentFrom(&ReadCharFromStdinBlocking);
 | 
			
		||||
  if (!content) {
 | 
			
		||||
@ -95,9 +95,8 @@ std::optional<std::string> MessageRegistry::ReadMessageFromStdin(
 | 
			
		||||
  return Parse(json_reader, message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::optional<std::string> MessageRegistry::Parse(
 | 
			
		||||
    Reader& visitor,
 | 
			
		||||
    std::unique_ptr<InMessage>* message) {
 | 
			
		||||
std::optional<std::string>
 | 
			
		||||
MessageRegistry::Parse(Reader &visitor, std::unique_ptr<InMessage> *message) {
 | 
			
		||||
  if (!visitor.HasMember("jsonrpc") ||
 | 
			
		||||
      std::string(visitor["jsonrpc"]->GetString()) != "2.0") {
 | 
			
		||||
    LOG_S(FATAL) << "Bad or missing jsonrpc version";
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										19
									
								
								src/lsp.h
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								src/lsp.h
									
									
									
									
									
								
							@ -19,14 +19,13 @@ struct MessageRegistry {
 | 
			
		||||
      std::function<void(Reader &visitor, std::unique_ptr<InMessage> *)>;
 | 
			
		||||
  std::unordered_map<std::string, Allocator> allocators;
 | 
			
		||||
 | 
			
		||||
  std::optional<std::string> ReadMessageFromStdin(
 | 
			
		||||
      std::unique_ptr<InMessage>* message);
 | 
			
		||||
  std::optional<std::string>
 | 
			
		||||
  ReadMessageFromStdin(std::unique_ptr<InMessage> *message);
 | 
			
		||||
  std::optional<std::string> Parse(Reader &visitor,
 | 
			
		||||
                                   std::unique_ptr<InMessage> *message);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct MessageRegistryRegister {
 | 
			
		||||
template <typename T> struct MessageRegistryRegister {
 | 
			
		||||
  MessageRegistryRegister() {
 | 
			
		||||
    T dummy;
 | 
			
		||||
    std::string method_name = dummy.GetMethodType();
 | 
			
		||||
@ -47,8 +46,7 @@ struct lsBaseOutMessage {
 | 
			
		||||
  void Write(std::ostream &out);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename TDerived>
 | 
			
		||||
struct lsOutMessage : lsBaseOutMessage {
 | 
			
		||||
template <typename TDerived> struct lsOutMessage : lsBaseOutMessage {
 | 
			
		||||
  // All derived types need to reflect on the |jsonrpc| member.
 | 
			
		||||
  std::string jsonrpc = "2.0";
 | 
			
		||||
 | 
			
		||||
@ -192,8 +190,7 @@ struct lsLocationEx : lsLocation {
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsLocationEx, uri, range, containerName, parentKind, role);
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct lsCommand {
 | 
			
		||||
template <typename T> struct lsCommand {
 | 
			
		||||
  // Title of the command (ie, 'save')
 | 
			
		||||
  std::string title;
 | 
			
		||||
  // Actual command identifier.
 | 
			
		||||
@ -212,8 +209,7 @@ void Reflect(TVisitor& visitor, lsCommand<T>& value) {
 | 
			
		||||
  REFLECT_MEMBER_END();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename TData, typename TCommandArguments>
 | 
			
		||||
struct lsCodeLens {
 | 
			
		||||
template <typename TData, typename TCommandArguments> struct lsCodeLens {
 | 
			
		||||
  // The range in which this code lens is valid. Should only span a single line.
 | 
			
		||||
  lsRange range;
 | 
			
		||||
  // The command this code lens represents.
 | 
			
		||||
@ -337,8 +333,7 @@ struct lsTextDocumentDidChangeParams {
 | 
			
		||||
  lsVersionedTextDocumentIdentifier textDocument;
 | 
			
		||||
  std::vector<lsTextDocumentContentChangeEvent> contentChanges;
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsTextDocumentDidChangeParams,
 | 
			
		||||
                    textDocument,
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsTextDocumentDidChangeParams, textDocument,
 | 
			
		||||
                    contentChanges);
 | 
			
		||||
 | 
			
		||||
// Show a message to the user.
 | 
			
		||||
 | 
			
		||||
@ -106,9 +106,9 @@ struct lsCompletionItem {
 | 
			
		||||
  // nor with themselves.
 | 
			
		||||
  // std::vector<TextEdit> additionalTextEdits;
 | 
			
		||||
 | 
			
		||||
  // An std::optional command that is executed *after* inserting this completion.
 | 
			
		||||
  // *Note* that additional modifications to the current document should be
 | 
			
		||||
  // described with the additionalTextEdits-property. Command command;
 | 
			
		||||
  // An std::optional command that is executed *after* inserting this
 | 
			
		||||
  // completion. *Note* that additional modifications to the current document
 | 
			
		||||
  // should be described with the additionalTextEdits-property. Command command;
 | 
			
		||||
 | 
			
		||||
  // An data entry field that is preserved on a completion item between
 | 
			
		||||
  // a completion and a completion resolve request.
 | 
			
		||||
@ -125,13 +125,6 @@ struct lsCompletionItem {
 | 
			
		||||
    return label;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsCompletionItem,
 | 
			
		||||
                    label,
 | 
			
		||||
                    kind,
 | 
			
		||||
                    detail,
 | 
			
		||||
                    documentation,
 | 
			
		||||
                    sortText,
 | 
			
		||||
                    insertText,
 | 
			
		||||
                    filterText,
 | 
			
		||||
                    insertTextFormat,
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsCompletionItem, label, kind, detail, documentation,
 | 
			
		||||
                    sortText, insertText, filterText, insertTextFormat,
 | 
			
		||||
                    textEdit);
 | 
			
		||||
 | 
			
		||||
@ -96,6 +96,5 @@ void Reflect(TVisitor& visitor, Out_TextDocumentPublishDiagnostics& value) {
 | 
			
		||||
  REFLECT_MEMBER(params);
 | 
			
		||||
  REFLECT_MEMBER_END();
 | 
			
		||||
}
 | 
			
		||||
MAKE_REFLECT_STRUCT(Out_TextDocumentPublishDiagnostics::Params,
 | 
			
		||||
                    uri,
 | 
			
		||||
MAKE_REFLECT_STRUCT(Out_TextDocumentPublishDiagnostics::Params, uri,
 | 
			
		||||
                    diagnostics);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								src/main.cc
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								src/main.cc
									
									
									
									
									
								
							@ -28,17 +28,17 @@ std::string g_init_options;
 | 
			
		||||
namespace {
 | 
			
		||||
opt<bool> opt_help("h", desc("Alias for -help"));
 | 
			
		||||
opt<int> opt_verbose("v", desc("verbosity"), init(0));
 | 
			
		||||
opt<std::string> opt_test_index("test-index", ValueOptional, init("!"), desc("run index tests"));
 | 
			
		||||
opt<std::string> opt_test_index("test-index", ValueOptional, init("!"),
 | 
			
		||||
                                desc("run index tests"));
 | 
			
		||||
 | 
			
		||||
opt<std::string> opt_init("init", desc("extra initialization options"));
 | 
			
		||||
opt<std::string> opt_log_file("log-file", desc("log"), value_desc("filename"));
 | 
			
		||||
opt<std::string> opt_log_file_append("log-file-append", desc("log"), value_desc("filename"));
 | 
			
		||||
opt<std::string> opt_log_file_append("log-file-append", desc("log"),
 | 
			
		||||
                                     value_desc("filename"));
 | 
			
		||||
 | 
			
		||||
list<std::string> opt_extra(Positional, ZeroOrMore, desc("extra"));
 | 
			
		||||
 | 
			
		||||
void CloseLog() {
 | 
			
		||||
  fclose(ccls::log::file);
 | 
			
		||||
}
 | 
			
		||||
void CloseLog() { fclose(ccls::log::file); }
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
@ -108,11 +108,13 @@ int main(int argc, char** argv) {
 | 
			
		||||
 | 
			
		||||
    sys::ChangeStdinToBinary();
 | 
			
		||||
    sys::ChangeStdoutToBinary();
 | 
			
		||||
    // The thread that reads from stdin and dispatchs commands to the main thread.
 | 
			
		||||
    // The thread that reads from stdin and dispatchs commands to the main
 | 
			
		||||
    // thread.
 | 
			
		||||
    pipeline::LaunchStdin();
 | 
			
		||||
    // The thread that writes responses from the main thread to stdout.
 | 
			
		||||
    pipeline::LaunchStdout();
 | 
			
		||||
    // Main thread which also spawns indexer threads upon the "initialize" request.
 | 
			
		||||
    // Main thread which also spawns indexer threads upon the "initialize"
 | 
			
		||||
    // request.
 | 
			
		||||
    pipeline::MainLoop();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -19,8 +19,8 @@ std::optional<Matcher> Matcher::Create(const std::string& search) {
 | 
			
		||||
  try {
 | 
			
		||||
    Matcher m;
 | 
			
		||||
    m.regex_string = search;
 | 
			
		||||
    m.regex = std::regex(
 | 
			
		||||
        search, std::regex_constants::ECMAScript | std::regex_constants::icase |
 | 
			
		||||
    m.regex = std::regex(search, std::regex_constants::ECMAScript |
 | 
			
		||||
                                     std::regex_constants::icase |
 | 
			
		||||
                                     std::regex_constants::optimize
 | 
			
		||||
                         // std::regex_constants::nosubs
 | 
			
		||||
    );
 | 
			
		||||
@ -29,8 +29,8 @@ std::optional<Matcher> Matcher::Create(const std::string& search) {
 | 
			
		||||
    Out_ShowLogMessage out;
 | 
			
		||||
    out.display_type = Out_ShowLogMessage::DisplayType::Show;
 | 
			
		||||
    out.params.type = lsMessageType::Error;
 | 
			
		||||
    out.params.message = "ccls: Parsing EMCAScript regex \"" + search +
 | 
			
		||||
                         "\" failed; " + e.what();
 | 
			
		||||
    out.params.message =
 | 
			
		||||
        "ccls: Parsing EMCAScript regex \"" + search + "\" failed; " + e.what();
 | 
			
		||||
    pipeline::WriteStdout(kMethodType_Unknown, out);
 | 
			
		||||
    return std::nullopt;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -4,10 +4,9 @@
 | 
			
		||||
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
// Like std::optional, but the stored data is responsible for containing the empty
 | 
			
		||||
// state. T should define a function `bool T::Valid()`.
 | 
			
		||||
template <typename T>
 | 
			
		||||
class Maybe {
 | 
			
		||||
// Like std::optional, but the stored data is responsible for containing the
 | 
			
		||||
// empty state. T should define a function `bool T::Valid()`.
 | 
			
		||||
template <typename T> class Maybe {
 | 
			
		||||
  T storage;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
@ -337,7 +337,8 @@ void EmitSemanticHighlighting(DB *db,
 | 
			
		||||
  out.params.uri = lsDocumentUri::FromPath(wfile->filename);
 | 
			
		||||
  // Transform lsRange into pair<int, int> (offset pairs)
 | 
			
		||||
  if (!g_config->highlight.lsRanges) {
 | 
			
		||||
    std::vector<std::pair<lsRange, Out_CclsPublishSemanticHighlighting::Symbol *>>
 | 
			
		||||
    std::vector<
 | 
			
		||||
        std::pair<lsRange, Out_CclsPublishSemanticHighlighting::Symbol *>>
 | 
			
		||||
        scratch;
 | 
			
		||||
    for (auto &entry : grouped_symbols) {
 | 
			
		||||
      for (auto &range : entry.second.lsRanges)
 | 
			
		||||
@ -357,11 +358,13 @@ void EmitSemanticHighlighting(DB *db,
 | 
			
		||||
        if (uint8_t(buf[i]) < 128 || 192 <= uint8_t(buf[i]))
 | 
			
		||||
          p++;
 | 
			
		||||
      }
 | 
			
		||||
      if (l < line) return true;
 | 
			
		||||
      if (l < line)
 | 
			
		||||
        return true;
 | 
			
		||||
      for (; c < col && i < buf.size() && buf[i] != '\n'; c++)
 | 
			
		||||
        if (p++, uint8_t(buf[i++]) >= 128)
 | 
			
		||||
          // Skip 0b10xxxxxx
 | 
			
		||||
          while (i < buf.size() && uint8_t(buf[i]) >= 128 && uint8_t(buf[i]) < 192)
 | 
			
		||||
          while (i < buf.size() && uint8_t(buf[i]) >= 128 &&
 | 
			
		||||
                 uint8_t(buf[i]) < 192)
 | 
			
		||||
            i++;
 | 
			
		||||
      return c < col;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@ -6,8 +6,8 @@
 | 
			
		||||
#include "method.h"
 | 
			
		||||
#include "query.h"
 | 
			
		||||
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
@ -79,9 +79,7 @@ struct Out_CclsPublishSemanticHighlighting
 | 
			
		||||
MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting::Symbol, stableId,
 | 
			
		||||
                    parentKind, kind, storage, ranges, lsRanges);
 | 
			
		||||
MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting::Params, uri, symbols);
 | 
			
		||||
MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting,
 | 
			
		||||
                    jsonrpc,
 | 
			
		||||
                    method,
 | 
			
		||||
MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting, jsonrpc, method,
 | 
			
		||||
                    params);
 | 
			
		||||
 | 
			
		||||
// Usage:
 | 
			
		||||
@ -121,8 +119,7 @@ struct MessageHandler {
 | 
			
		||||
  MessageHandler();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename TMessage>
 | 
			
		||||
struct BaseMessageHandler : MessageHandler {
 | 
			
		||||
template <typename TMessage> struct BaseMessageHandler : MessageHandler {
 | 
			
		||||
  virtual void Run(TMessage *message) = 0;
 | 
			
		||||
 | 
			
		||||
  // MessageHandler:
 | 
			
		||||
@ -131,17 +128,13 @@ struct BaseMessageHandler : MessageHandler {
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
bool FindFileOrFail(DB* db,
 | 
			
		||||
                    Project* project,
 | 
			
		||||
                    std::optional<lsRequestId> id,
 | 
			
		||||
bool FindFileOrFail(DB *db, Project *project, std::optional<lsRequestId> id,
 | 
			
		||||
                    const std::string &absolute_path,
 | 
			
		||||
                    QueryFile** out_query_file,
 | 
			
		||||
                    int* out_file_id = nullptr);
 | 
			
		||||
                    QueryFile **out_query_file, int *out_file_id = nullptr);
 | 
			
		||||
 | 
			
		||||
void EmitSkippedRanges(WorkingFile *working_file,
 | 
			
		||||
                       const std::vector<Range> &skipped_ranges);
 | 
			
		||||
 | 
			
		||||
void EmitSemanticHighlighting(DB *db,
 | 
			
		||||
                              SemanticHighlightSymbolCache *semantic_cache,
 | 
			
		||||
                              WorkingFile* working_file,
 | 
			
		||||
                              QueryFile* file);
 | 
			
		||||
                              WorkingFile *working_file, QueryFile *file);
 | 
			
		||||
 | 
			
		||||
@ -44,16 +44,9 @@ struct In_CclsCallHierarchy : public RequestInMessage {
 | 
			
		||||
    int levels = 1;
 | 
			
		||||
  };
 | 
			
		||||
  Params params;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_CclsCallHierarchy::Params,
 | 
			
		||||
                    textDocument,
 | 
			
		||||
                    position,
 | 
			
		||||
                    id,
 | 
			
		||||
                    callee,
 | 
			
		||||
                    callType,
 | 
			
		||||
                    qualified,
 | 
			
		||||
                    levels);
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_CclsCallHierarchy::Params, textDocument, position, id,
 | 
			
		||||
                    callee, callType, qualified, levels);
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_CclsCallHierarchy, id, params);
 | 
			
		||||
REGISTER_IN_MESSAGE(In_CclsCallHierarchy);
 | 
			
		||||
 | 
			
		||||
@ -72,24 +65,13 @@ struct Out_CclsCallHierarchy : public lsOutMessage<Out_CclsCallHierarchy> {
 | 
			
		||||
  lsRequestId id;
 | 
			
		||||
  std::optional<Entry> result;
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(Out_CclsCallHierarchy::Entry,
 | 
			
		||||
                    id,
 | 
			
		||||
                    name,
 | 
			
		||||
                    location,
 | 
			
		||||
                    callType,
 | 
			
		||||
                    numChildren,
 | 
			
		||||
                    children);
 | 
			
		||||
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsCallHierarchy,
 | 
			
		||||
                                       jsonrpc,
 | 
			
		||||
                                       id,
 | 
			
		||||
MAKE_REFLECT_STRUCT(Out_CclsCallHierarchy::Entry, id, name, location, callType,
 | 
			
		||||
                    numChildren, children);
 | 
			
		||||
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsCallHierarchy, jsonrpc, id,
 | 
			
		||||
                                       result);
 | 
			
		||||
 | 
			
		||||
bool Expand(MessageHandler* m,
 | 
			
		||||
            Out_CclsCallHierarchy::Entry* entry,
 | 
			
		||||
            bool callee,
 | 
			
		||||
            CallType call_type,
 | 
			
		||||
            bool qualified,
 | 
			
		||||
            int levels) {
 | 
			
		||||
bool Expand(MessageHandler *m, Out_CclsCallHierarchy::Entry *entry, bool callee,
 | 
			
		||||
            CallType call_type, bool qualified, int levels) {
 | 
			
		||||
  const QueryFunc &func = m->db->Func(entry->usr);
 | 
			
		||||
  const QueryFunc::Def *def = func.AnyDef();
 | 
			
		||||
  entry->numChildren = 0;
 | 
			
		||||
@ -113,8 +95,7 @@ bool Expand(MessageHandler* m,
 | 
			
		||||
      if (const auto *def = func.AnyDef())
 | 
			
		||||
        for (SymbolRef ref : def->callees)
 | 
			
		||||
          if (ref.kind == SymbolKind::Func)
 | 
			
		||||
            handle(Use{{ref.range, ref.usr, ref.kind, ref.role},
 | 
			
		||||
                       def->file_id},
 | 
			
		||||
            handle(Use{{ref.range, ref.usr, ref.kind, ref.role}, def->file_id},
 | 
			
		||||
                   call_type);
 | 
			
		||||
    } else {
 | 
			
		||||
      for (Use use : func.uses)
 | 
			
		||||
@ -165,14 +146,11 @@ bool Expand(MessageHandler* m,
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct Handler_CclsCallHierarchy
 | 
			
		||||
    : BaseMessageHandler<In_CclsCallHierarchy> {
 | 
			
		||||
struct Handler_CclsCallHierarchy : BaseMessageHandler<In_CclsCallHierarchy> {
 | 
			
		||||
  MethodType GetMethodType() const override { return kMethodType; }
 | 
			
		||||
 | 
			
		||||
  std::optional<Out_CclsCallHierarchy::Entry> BuildInitial(Usr root_usr,
 | 
			
		||||
                                                           bool callee,
 | 
			
		||||
                                                           CallType call_type,
 | 
			
		||||
                                                           bool qualified,
 | 
			
		||||
  std::optional<Out_CclsCallHierarchy::Entry>
 | 
			
		||||
  BuildInitial(Usr root_usr, bool callee, CallType call_type, bool qualified,
 | 
			
		||||
               int levels) {
 | 
			
		||||
    const auto *def = db->Func(root_usr).AnyDef();
 | 
			
		||||
    if (!def)
 | 
			
		||||
 | 
			
		||||
@ -3,14 +3,8 @@
 | 
			
		||||
#include "query_utils.h"
 | 
			
		||||
using namespace ccls;
 | 
			
		||||
 | 
			
		||||
MAKE_REFLECT_STRUCT(QueryFile::Def,
 | 
			
		||||
                    path,
 | 
			
		||||
                    args,
 | 
			
		||||
                    language,
 | 
			
		||||
                    outline,
 | 
			
		||||
                    all_symbols,
 | 
			
		||||
                    skipped_ranges,
 | 
			
		||||
                    dependencies);
 | 
			
		||||
MAKE_REFLECT_STRUCT(QueryFile::Def, path, args, language, outline, all_symbols,
 | 
			
		||||
                    skipped_ranges, dependencies);
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
MethodType kMethodType = "$ccls/fileInfo";
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
#include "match.h"
 | 
			
		||||
#include "message_handler.h"
 | 
			
		||||
#include "pipeline.hh"
 | 
			
		||||
#include "platform.h"
 | 
			
		||||
#include "project.h"
 | 
			
		||||
#include "pipeline.hh"
 | 
			
		||||
#include "working_files.h"
 | 
			
		||||
using namespace ccls;
 | 
			
		||||
 | 
			
		||||
@ -21,9 +21,7 @@ struct In_CclsFreshenIndex : public NotificationInMessage {
 | 
			
		||||
  };
 | 
			
		||||
  Params params;
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_CclsFreshenIndex::Params,
 | 
			
		||||
                    dependencies,
 | 
			
		||||
                    whitelist,
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_CclsFreshenIndex::Params, dependencies, whitelist,
 | 
			
		||||
                    blacklist);
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_CclsFreshenIndex, params);
 | 
			
		||||
REGISTER_IN_MESSAGE(In_CclsFreshenIndex);
 | 
			
		||||
 | 
			
		||||
@ -51,31 +51,17 @@ struct Out_CclsInheritanceHierarchy
 | 
			
		||||
  lsRequestId id;
 | 
			
		||||
  std::optional<Entry> result;
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(Out_CclsInheritanceHierarchy::Entry,
 | 
			
		||||
                    id,
 | 
			
		||||
                    kind,
 | 
			
		||||
                    name,
 | 
			
		||||
                    location,
 | 
			
		||||
                    numChildren,
 | 
			
		||||
                    children);
 | 
			
		||||
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsInheritanceHierarchy,
 | 
			
		||||
                                       jsonrpc,
 | 
			
		||||
                                       id,
 | 
			
		||||
                                       result);
 | 
			
		||||
MAKE_REFLECT_STRUCT(Out_CclsInheritanceHierarchy::Entry, id, kind, name,
 | 
			
		||||
                    location, numChildren, children);
 | 
			
		||||
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsInheritanceHierarchy, jsonrpc,
 | 
			
		||||
                                       id, result);
 | 
			
		||||
 | 
			
		||||
bool Expand(MessageHandler* m,
 | 
			
		||||
            Out_CclsInheritanceHierarchy::Entry* entry,
 | 
			
		||||
            bool derived,
 | 
			
		||||
            bool qualified,
 | 
			
		||||
            int levels);
 | 
			
		||||
bool Expand(MessageHandler *m, Out_CclsInheritanceHierarchy::Entry *entry,
 | 
			
		||||
            bool derived, bool qualified, int levels);
 | 
			
		||||
 | 
			
		||||
template <typename Q>
 | 
			
		||||
bool ExpandHelper(MessageHandler* m,
 | 
			
		||||
                  Out_CclsInheritanceHierarchy::Entry* entry,
 | 
			
		||||
                  bool derived,
 | 
			
		||||
                  bool qualified,
 | 
			
		||||
                  int levels,
 | 
			
		||||
                  Q& entity) {
 | 
			
		||||
bool ExpandHelper(MessageHandler *m, Out_CclsInheritanceHierarchy::Entry *entry,
 | 
			
		||||
                  bool derived, bool qualified, int levels, Q &entity) {
 | 
			
		||||
  const auto *def = entity.AnyDef();
 | 
			
		||||
  if (def) {
 | 
			
		||||
    entry->name = def->Name(qualified);
 | 
			
		||||
@ -122,11 +108,8 @@ bool ExpandHelper(MessageHandler* m,
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Expand(MessageHandler* m,
 | 
			
		||||
            Out_CclsInheritanceHierarchy::Entry* entry,
 | 
			
		||||
            bool derived,
 | 
			
		||||
            bool qualified,
 | 
			
		||||
            int levels) {
 | 
			
		||||
bool Expand(MessageHandler *m, Out_CclsInheritanceHierarchy::Entry *entry,
 | 
			
		||||
            bool derived, bool qualified, int levels) {
 | 
			
		||||
  if (entry->kind == SymbolKind::Func)
 | 
			
		||||
    return ExpandHelper(m, entry, derived, qualified, levels,
 | 
			
		||||
                        m->db->Func(entry->usr));
 | 
			
		||||
@ -173,8 +156,7 @@ struct Handler_CclsInheritanceHierarchy
 | 
			
		||||
      if (!FindFileOrFail(db, project, request->id,
 | 
			
		||||
                          params.textDocument.uri.GetPath(), &file))
 | 
			
		||||
        return;
 | 
			
		||||
      WorkingFile* wfile =
 | 
			
		||||
          working_files->GetFileByFilename(file->def->path);
 | 
			
		||||
      WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
 | 
			
		||||
 | 
			
		||||
      for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, params.position))
 | 
			
		||||
        if (sym.kind == SymbolKind::Func || sym.kind == SymbolKind::Type) {
 | 
			
		||||
 | 
			
		||||
@ -30,17 +30,12 @@ struct In_CclsMemberHierarchy : public RequestInMessage {
 | 
			
		||||
  Params params;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_CclsMemberHierarchy::Params,
 | 
			
		||||
                    textDocument,
 | 
			
		||||
                    position,
 | 
			
		||||
                    id,
 | 
			
		||||
                    qualified,
 | 
			
		||||
                    levels);
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_CclsMemberHierarchy::Params, textDocument, position, id,
 | 
			
		||||
                    qualified, levels);
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_CclsMemberHierarchy, id, params);
 | 
			
		||||
REGISTER_IN_MESSAGE(In_CclsMemberHierarchy);
 | 
			
		||||
 | 
			
		||||
struct Out_CclsMemberHierarchy
 | 
			
		||||
    : public lsOutMessage<Out_CclsMemberHierarchy> {
 | 
			
		||||
struct Out_CclsMemberHierarchy : public lsOutMessage<Out_CclsMemberHierarchy> {
 | 
			
		||||
  struct Entry {
 | 
			
		||||
    Usr usr;
 | 
			
		||||
    std::string id;
 | 
			
		||||
@ -56,30 +51,17 @@ struct Out_CclsMemberHierarchy
 | 
			
		||||
  lsRequestId id;
 | 
			
		||||
  std::optional<Entry> result;
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(Out_CclsMemberHierarchy::Entry,
 | 
			
		||||
                    id,
 | 
			
		||||
                    name,
 | 
			
		||||
                    fieldName,
 | 
			
		||||
                    location,
 | 
			
		||||
                    numChildren,
 | 
			
		||||
                    children);
 | 
			
		||||
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsMemberHierarchy,
 | 
			
		||||
                                       jsonrpc,
 | 
			
		||||
                                       id,
 | 
			
		||||
MAKE_REFLECT_STRUCT(Out_CclsMemberHierarchy::Entry, id, name, fieldName,
 | 
			
		||||
                    location, numChildren, children);
 | 
			
		||||
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsMemberHierarchy, jsonrpc, id,
 | 
			
		||||
                                       result);
 | 
			
		||||
 | 
			
		||||
bool Expand(MessageHandler* m,
 | 
			
		||||
            Out_CclsMemberHierarchy::Entry* entry,
 | 
			
		||||
            bool qualified,
 | 
			
		||||
            int levels);
 | 
			
		||||
bool Expand(MessageHandler *m, Out_CclsMemberHierarchy::Entry *entry,
 | 
			
		||||
            bool qualified, int levels);
 | 
			
		||||
 | 
			
		||||
// Add a field to |entry| which is a Func/Type.
 | 
			
		||||
void DoField(MessageHandler* m,
 | 
			
		||||
             Out_CclsMemberHierarchy::Entry* entry,
 | 
			
		||||
             const QueryVar& var,
 | 
			
		||||
             int64_t offset,
 | 
			
		||||
             bool qualified,
 | 
			
		||||
             int levels) {
 | 
			
		||||
void DoField(MessageHandler *m, Out_CclsMemberHierarchy::Entry *entry,
 | 
			
		||||
             const QueryVar &var, int64_t offset, bool qualified, int levels) {
 | 
			
		||||
  const QueryVar::Def *def1 = var.AnyDef();
 | 
			
		||||
  if (!def1)
 | 
			
		||||
    return;
 | 
			
		||||
@ -120,10 +102,8 @@ void DoField(MessageHandler* m,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Expand a type node by adding members recursively to it.
 | 
			
		||||
bool Expand(MessageHandler* m,
 | 
			
		||||
            Out_CclsMemberHierarchy::Entry* entry,
 | 
			
		||||
            bool qualified,
 | 
			
		||||
            int levels) {
 | 
			
		||||
bool Expand(MessageHandler *m, Out_CclsMemberHierarchy::Entry *entry,
 | 
			
		||||
            bool qualified, int levels) {
 | 
			
		||||
  if (0 < entry->usr && entry->usr <= BuiltinType::LastKind) {
 | 
			
		||||
    entry->name = ClangBuiltinTypeName(int(entry->usr));
 | 
			
		||||
    return true;
 | 
			
		||||
@ -193,10 +173,8 @@ struct Handler_CclsMemberHierarchy
 | 
			
		||||
    : BaseMessageHandler<In_CclsMemberHierarchy> {
 | 
			
		||||
  MethodType GetMethodType() const override { return kMethodType; }
 | 
			
		||||
 | 
			
		||||
  std::optional<Out_CclsMemberHierarchy::Entry> BuildInitial(SymbolKind kind,
 | 
			
		||||
                                                             Usr root_usr,
 | 
			
		||||
                                                             bool qualified,
 | 
			
		||||
                                                             int levels) {
 | 
			
		||||
  std::optional<Out_CclsMemberHierarchy::Entry>
 | 
			
		||||
  BuildInitial(SymbolKind kind, Usr root_usr, bool qualified, int levels) {
 | 
			
		||||
    switch (kind) {
 | 
			
		||||
    default:
 | 
			
		||||
      return {};
 | 
			
		||||
@ -260,15 +238,14 @@ struct Handler_CclsMemberHierarchy
 | 
			
		||||
      if (!FindFileOrFail(db, project, request->id,
 | 
			
		||||
                          params.textDocument.uri.GetPath(), &file))
 | 
			
		||||
        return;
 | 
			
		||||
      WorkingFile* wfile =
 | 
			
		||||
          working_files->GetFileByFilename(file->def->path);
 | 
			
		||||
      WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
 | 
			
		||||
      for (SymbolRef sym :
 | 
			
		||||
           FindSymbolsAtLocation(wfile, file, params.position)) {
 | 
			
		||||
        switch (sym.kind) {
 | 
			
		||||
        case SymbolKind::Func:
 | 
			
		||||
        case SymbolKind::Type:
 | 
			
		||||
            out.result = BuildInitial(sym.kind, sym.usr, params.qualified,
 | 
			
		||||
                                      params.levels);
 | 
			
		||||
          out.result =
 | 
			
		||||
              BuildInitial(sym.kind, sym.usr, params.qualified, params.levels);
 | 
			
		||||
          break;
 | 
			
		||||
        case SymbolKind::Var: {
 | 
			
		||||
          const QueryVar::Def *def = db->GetVar(sym).AnyDef();
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
#include "message_handler.h"
 | 
			
		||||
#include "query_utils.h"
 | 
			
		||||
#include "pipeline.hh"
 | 
			
		||||
#include "query_utils.h"
 | 
			
		||||
using namespace ccls;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
@ -15,10 +15,7 @@ struct In_CclsVars : public RequestInMessage {
 | 
			
		||||
    unsigned kind = ~0u;
 | 
			
		||||
  } params;
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_CclsVars::Params,
 | 
			
		||||
                    textDocument,
 | 
			
		||||
                    position,
 | 
			
		||||
                    kind);
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_CclsVars::Params, textDocument, position, kind);
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_CclsVars, id, params);
 | 
			
		||||
REGISTER_IN_MESSAGE(In_CclsVars);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -10,9 +10,7 @@ REGISTER_IN_MESSAGE(In_Exit);
 | 
			
		||||
struct Handler_Exit : MessageHandler {
 | 
			
		||||
  MethodType GetMethodType() const override { return kMethodType_Exit; }
 | 
			
		||||
 | 
			
		||||
  void Run(std::unique_ptr<InMessage> request) override {
 | 
			
		||||
    exit(0);
 | 
			
		||||
  }
 | 
			
		||||
  void Run(std::unique_ptr<InMessage> request) override { exit(0); }
 | 
			
		||||
};
 | 
			
		||||
REGISTER_MESSAGE_HANDLER(Handler_Exit);
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
@ -55,8 +55,7 @@ struct lsDocumentOnTypeFormattingOptions {
 | 
			
		||||
  // More trigger characters.
 | 
			
		||||
  std::vector<std::string> moreTriggerCharacter;
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsDocumentOnTypeFormattingOptions,
 | 
			
		||||
                    firstTriggerCharacter,
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsDocumentOnTypeFormattingOptions, firstTriggerCharacter,
 | 
			
		||||
                    moreTriggerCharacter);
 | 
			
		||||
 | 
			
		||||
// Document link options
 | 
			
		||||
@ -119,12 +118,8 @@ struct lsTextDocumentSyncOptions {
 | 
			
		||||
  // Save notifications are sent to the server.
 | 
			
		||||
  std::optional<lsSaveOptions> save;
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsTextDocumentSyncOptions,
 | 
			
		||||
                    openClose,
 | 
			
		||||
                    change,
 | 
			
		||||
                    willSave,
 | 
			
		||||
                    willSaveWaitUntil,
 | 
			
		||||
                    save);
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsTextDocumentSyncOptions, openClose, change, willSave,
 | 
			
		||||
                    willSaveWaitUntil, save);
 | 
			
		||||
 | 
			
		||||
struct lsServerCapabilities {
 | 
			
		||||
  // Defines how text documents are synced. Is either a detailed structure
 | 
			
		||||
@ -161,7 +156,8 @@ struct lsServerCapabilities {
 | 
			
		||||
  // The server provides document range formatting.
 | 
			
		||||
  bool documentRangeFormattingProvider = false;
 | 
			
		||||
  // The server provides document formatting on typing.
 | 
			
		||||
  std::optional<lsDocumentOnTypeFormattingOptions> documentOnTypeFormattingProvider;
 | 
			
		||||
  std::optional<lsDocumentOnTypeFormattingOptions>
 | 
			
		||||
      documentOnTypeFormattingProvider;
 | 
			
		||||
  // The server provides rename support.
 | 
			
		||||
  bool renameProvider = true;
 | 
			
		||||
  // The server provides document link support.
 | 
			
		||||
@ -169,25 +165,15 @@ struct lsServerCapabilities {
 | 
			
		||||
  // The server provides execute command support.
 | 
			
		||||
  lsExecuteCommandOptions executeCommandProvider;
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsServerCapabilities,
 | 
			
		||||
                    textDocumentSync,
 | 
			
		||||
                    hoverProvider,
 | 
			
		||||
                    completionProvider,
 | 
			
		||||
                    signatureHelpProvider,
 | 
			
		||||
                    definitionProvider,
 | 
			
		||||
                    typeDefinitionProvider,
 | 
			
		||||
                    referencesProvider,
 | 
			
		||||
                    documentHighlightProvider,
 | 
			
		||||
                    documentSymbolProvider,
 | 
			
		||||
                    workspaceSymbolProvider,
 | 
			
		||||
                    codeActionProvider,
 | 
			
		||||
                    codeLensProvider,
 | 
			
		||||
                    documentFormattingProvider,
 | 
			
		||||
                    documentRangeFormattingProvider,
 | 
			
		||||
                    documentOnTypeFormattingProvider,
 | 
			
		||||
                    renameProvider,
 | 
			
		||||
                    documentLinkProvider,
 | 
			
		||||
                    executeCommandProvider);
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsServerCapabilities, textDocumentSync, hoverProvider,
 | 
			
		||||
                    completionProvider, signatureHelpProvider,
 | 
			
		||||
                    definitionProvider, typeDefinitionProvider,
 | 
			
		||||
                    referencesProvider, documentHighlightProvider,
 | 
			
		||||
                    documentSymbolProvider, workspaceSymbolProvider,
 | 
			
		||||
                    codeActionProvider, codeLensProvider,
 | 
			
		||||
                    documentFormattingProvider, documentRangeFormattingProvider,
 | 
			
		||||
                    documentOnTypeFormattingProvider, renameProvider,
 | 
			
		||||
                    documentLinkProvider, executeCommandProvider);
 | 
			
		||||
 | 
			
		||||
// Workspace specific client capabilities.
 | 
			
		||||
struct lsWorkspaceClientCapabilites {
 | 
			
		||||
@ -226,12 +212,8 @@ MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites::lsWorkspaceEdit,
 | 
			
		||||
                    documentChanges);
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites::lsGenericDynamicReg,
 | 
			
		||||
                    dynamicRegistration);
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites,
 | 
			
		||||
                    applyEdit,
 | 
			
		||||
                    workspaceEdit,
 | 
			
		||||
                    didChangeConfiguration,
 | 
			
		||||
                    didChangeWatchedFiles,
 | 
			
		||||
                    symbol,
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites, applyEdit, workspaceEdit,
 | 
			
		||||
                    didChangeConfiguration, didChangeWatchedFiles, symbol,
 | 
			
		||||
                    executeCommand);
 | 
			
		||||
 | 
			
		||||
// Text document specific client capabilities.
 | 
			
		||||
@ -287,13 +269,9 @@ struct lsTextDocumentClientCapabilities {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsSynchronization,
 | 
			
		||||
                    dynamicRegistration,
 | 
			
		||||
                    willSave,
 | 
			
		||||
                    willSaveWaitUntil,
 | 
			
		||||
                    didSave);
 | 
			
		||||
                    dynamicRegistration, willSave, willSaveWaitUntil, didSave);
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsCompletion,
 | 
			
		||||
                    dynamicRegistration,
 | 
			
		||||
                    completionItem);
 | 
			
		||||
                    dynamicRegistration, completionItem);
 | 
			
		||||
MAKE_REFLECT_STRUCT(
 | 
			
		||||
    lsTextDocumentClientCapabilities::lsCompletion::lsCompletionItem,
 | 
			
		||||
    snippetSupport);
 | 
			
		||||
@ -301,12 +279,9 @@ MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsGenericDynamicReg,
 | 
			
		||||
                    dynamicRegistration);
 | 
			
		||||
MAKE_REFLECT_STRUCT(
 | 
			
		||||
    lsTextDocumentClientCapabilities::CodeLensRegistrationOptions,
 | 
			
		||||
    dynamicRegistration,
 | 
			
		||||
    resolveProvider);
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities,
 | 
			
		||||
                    synchronization,
 | 
			
		||||
                    completion,
 | 
			
		||||
                    rename);
 | 
			
		||||
    dynamicRegistration, resolveProvider);
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities, synchronization,
 | 
			
		||||
                    completion, rename);
 | 
			
		||||
 | 
			
		||||
struct lsClientCapabilities {
 | 
			
		||||
  // Workspace specific client capabilities.
 | 
			
		||||
@ -382,13 +357,8 @@ void Reflect(Writer& writer, lsInitializeParams::lsTrace& value) {
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsInitializeParams,
 | 
			
		||||
                    processId,
 | 
			
		||||
                    rootPath,
 | 
			
		||||
                    rootUri,
 | 
			
		||||
                    initializationOptions,
 | 
			
		||||
                    capabilities,
 | 
			
		||||
                    trace);
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsInitializeParams, processId, rootPath, rootUri,
 | 
			
		||||
                    initializationOptions, capabilities, trace);
 | 
			
		||||
 | 
			
		||||
struct lsInitializeError {
 | 
			
		||||
  // Indicates whether the client should retry to send the
 | 
			
		||||
@ -508,7 +478,8 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
 | 
			
		||||
        std::string name = "indexer" + std::to_string(i);
 | 
			
		||||
        set_thread_name(name.c_str());
 | 
			
		||||
        pipeline::Indexer_Main(diag_pub, vfs, project, working_files);
 | 
			
		||||
      }).detach();
 | 
			
		||||
      })
 | 
			
		||||
          .detach();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Start scanning include directories before dispatching project
 | 
			
		||||
 | 
			
		||||
@ -33,10 +33,8 @@ struct In_TextDocumentCodeAction : public RequestInMessage {
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction::lsCodeActionContext,
 | 
			
		||||
                    diagnostics);
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction::lsCodeActionParams,
 | 
			
		||||
                    textDocument,
 | 
			
		||||
                    range,
 | 
			
		||||
                    context);
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction::lsCodeActionParams, textDocument,
 | 
			
		||||
                    range, context);
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction, id, params);
 | 
			
		||||
REGISTER_IN_MESSAGE(In_TextDocumentCodeAction);
 | 
			
		||||
 | 
			
		||||
@ -74,4 +72,4 @@ struct Handler_TextDocumentCodeAction
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeAction);
 | 
			
		||||
}
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
#include "clang_complete.h"
 | 
			
		||||
#include "lsp_code_action.h"
 | 
			
		||||
#include "message_handler.h"
 | 
			
		||||
#include "query_utils.h"
 | 
			
		||||
#include "pipeline.hh"
 | 
			
		||||
#include "query_utils.h"
 | 
			
		||||
using namespace ccls;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
@ -41,12 +41,9 @@ Use OffsetStartColumn(Use use, int16_t offset) {
 | 
			
		||||
  return use;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AddCodeLens(const char* singular,
 | 
			
		||||
                 const char* plural,
 | 
			
		||||
                 CommonCodeLensParams* common,
 | 
			
		||||
                 Use use,
 | 
			
		||||
                 const std::vector<Use>& uses,
 | 
			
		||||
                 bool force_display) {
 | 
			
		||||
void AddCodeLens(const char *singular, const char *plural,
 | 
			
		||||
                 CommonCodeLensParams *common, Use use,
 | 
			
		||||
                 const std::vector<Use> &uses, bool force_display) {
 | 
			
		||||
  TCodeLens code_lens;
 | 
			
		||||
  std::optional<lsRange> range = GetLsRange(common->working_file, use.range);
 | 
			
		||||
  if (!range)
 | 
			
		||||
@ -166,10 +163,9 @@ struct Handler_TextDocumentCodeLens
 | 
			
		||||
                        false /*force_display*/);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
          AddCodeLens("derived", "derived", &common,
 | 
			
		||||
                      OffsetStartColumn(use, offset++),
 | 
			
		||||
                      GetFuncDeclarations(db, func.derived),
 | 
			
		||||
                      false /*force_display*/);
 | 
			
		||||
        AddCodeLens(
 | 
			
		||||
            "derived", "derived", &common, OffsetStartColumn(use, offset++),
 | 
			
		||||
            GetFuncDeclarations(db, func.derived), false /*force_display*/);
 | 
			
		||||
 | 
			
		||||
        // "Base"
 | 
			
		||||
        if (def->bases.size() == 1) {
 | 
			
		||||
@ -214,8 +210,8 @@ struct Handler_TextDocumentCodeLens
 | 
			
		||||
        if (def->kind == lsSymbolKind::Macro)
 | 
			
		||||
          force_display = false;
 | 
			
		||||
 | 
			
		||||
          AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0),
 | 
			
		||||
                      var.uses, force_display);
 | 
			
		||||
        AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0), var.uses,
 | 
			
		||||
                    force_display);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case SymbolKind::File:
 | 
			
		||||
 | 
			
		||||
@ -104,8 +104,7 @@ struct ParseIncludeLineResult {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ParseIncludeLineResult ParseIncludeLine(const std::string &line) {
 | 
			
		||||
  static const std::regex pattern(
 | 
			
		||||
      "(\\s*)"        // [1]: spaces before '#'
 | 
			
		||||
  static const std::regex pattern("(\\s*)"       // [1]: spaces before '#'
 | 
			
		||||
                                  "#"            //
 | 
			
		||||
                                  "(\\s*)"       // [2]: spaces after '#'
 | 
			
		||||
                                  "([^\\s\"<]*)" // [3]: "include"
 | 
			
		||||
@ -123,8 +122,8 @@ static const std::vector<std::string> preprocessorKeywords = {
 | 
			
		||||
    "define", "undef", "include", "if",   "ifdef", "ifndef",
 | 
			
		||||
    "else",   "elif",  "endif",   "line", "error", "pragma"};
 | 
			
		||||
 | 
			
		||||
std::vector<lsCompletionItem> PreprocessorKeywordCompletionItems(
 | 
			
		||||
    const std::smatch& match) {
 | 
			
		||||
std::vector<lsCompletionItem>
 | 
			
		||||
PreprocessorKeywordCompletionItems(const std::smatch &match) {
 | 
			
		||||
  std::vector<lsCompletionItem> items;
 | 
			
		||||
  for (auto &keyword : preprocessorKeywords) {
 | 
			
		||||
    lsCompletionItem item;
 | 
			
		||||
@ -140,10 +139,8 @@ std::vector<lsCompletionItem> PreprocessorKeywordCompletionItems(
 | 
			
		||||
  return items;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
char* tofixedbase64(T input, char* out) {
 | 
			
		||||
  const char* digits =
 | 
			
		||||
      "./0123456789"
 | 
			
		||||
template <typename T> char *tofixedbase64(T input, char *out) {
 | 
			
		||||
  const char *digits = "./0123456789"
 | 
			
		||||
                       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 | 
			
		||||
                       "abcdefghijklmnopqrstuvwxyz";
 | 
			
		||||
  int len = (sizeof(T) * 8 - 1) / 6 + 1;
 | 
			
		||||
@ -160,8 +157,7 @@ char* tofixedbase64(T input, char* out) {
 | 
			
		||||
// when given 1000+ completion items.
 | 
			
		||||
void FilterAndSortCompletionResponse(
 | 
			
		||||
    Out_TextDocumentComplete *complete_response,
 | 
			
		||||
    const std::string& complete_text,
 | 
			
		||||
    bool has_open_paren) {
 | 
			
		||||
    const std::string &complete_text, bool has_open_paren) {
 | 
			
		||||
  if (!g_config->completion.filterAndSort)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
@ -240,7 +236,8 @@ bool IsOpenParenOrAngle(const std::vector<std::string>& lines,
 | 
			
		||||
      return false;
 | 
			
		||||
    if (line[c] == '(' || line[c] == '<')
 | 
			
		||||
      return true;
 | 
			
		||||
    if (!isspace(line[c])) break;
 | 
			
		||||
    if (!isspace(line[c]))
 | 
			
		||||
      break;
 | 
			
		||||
    if (++c >= line.size()) {
 | 
			
		||||
      c = 0;
 | 
			
		||||
      l++;
 | 
			
		||||
@ -351,7 +348,8 @@ struct Handler_TextDocumentCompletion : MessageHandler {
 | 
			
		||||
            lock.lock();
 | 
			
		||||
          std::string quote = result.match[5];
 | 
			
		||||
          for (auto &item : include_complete->completion_items)
 | 
			
		||||
            if (quote.empty() || quote == (item.use_angle_brackets_ ? "<" : "\""))
 | 
			
		||||
            if (quote.empty() ||
 | 
			
		||||
                quote == (item.use_angle_brackets_ ? "<" : "\""))
 | 
			
		||||
              out.result.items.push_back(item);
 | 
			
		||||
        }
 | 
			
		||||
        FilterAndSortCompletionResponse(&out, result.pattern, has_open_paren);
 | 
			
		||||
@ -376,7 +374,8 @@ struct Handler_TextDocumentCompletion : MessageHandler {
 | 
			
		||||
            out.result.items = results;
 | 
			
		||||
 | 
			
		||||
            // Emit completion results.
 | 
			
		||||
            FilterAndSortCompletionResponse(&out, existing_completion, has_open_paren);
 | 
			
		||||
            FilterAndSortCompletionResponse(&out, existing_completion,
 | 
			
		||||
                                            has_open_paren);
 | 
			
		||||
            pipeline::WriteStdout(kMethodType, out);
 | 
			
		||||
 | 
			
		||||
            // Cache completion results.
 | 
			
		||||
 | 
			
		||||
@ -3,9 +3,9 @@
 | 
			
		||||
#include "query_utils.h"
 | 
			
		||||
using namespace ccls;
 | 
			
		||||
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
MethodType kMethodType = "textDocument/definition";
 | 
			
		||||
@ -62,8 +62,7 @@ struct Handler_TextDocumentDefinition
 | 
			
		||||
 | 
			
		||||
    Maybe<Use> on_def;
 | 
			
		||||
    bool has_symbol = false;
 | 
			
		||||
    WorkingFile* wfile =
 | 
			
		||||
        working_files->GetFileByFilename(file->def->path);
 | 
			
		||||
    WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
 | 
			
		||||
    lsPosition &ls_pos = params.position;
 | 
			
		||||
 | 
			
		||||
    for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, ls_pos)) {
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
#include "clang_complete.h"
 | 
			
		||||
#include "message_handler.h"
 | 
			
		||||
#include "pipeline.hh"
 | 
			
		||||
#include "project.h"
 | 
			
		||||
#include "working_files.h"
 | 
			
		||||
#include "pipeline.hh"
 | 
			
		||||
using namespace ccls;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
#include "clang_complete.h"
 | 
			
		||||
#include "include_complete.h"
 | 
			
		||||
#include "message_handler.h"
 | 
			
		||||
#include "project.h"
 | 
			
		||||
#include "pipeline.hh"
 | 
			
		||||
#include "project.h"
 | 
			
		||||
#include "working_files.h"
 | 
			
		||||
using namespace ccls;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
#include "clang_complete.h"
 | 
			
		||||
#include "message_handler.h"
 | 
			
		||||
#include "project.h"
 | 
			
		||||
#include "pipeline.hh"
 | 
			
		||||
#include "project.h"
 | 
			
		||||
using namespace ccls;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
@ -21,8 +21,7 @@ std::optional<lsMarkedString> GetComments(DB* db, SymbolRef sym) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns the hover or detailed name for `sym`, if any.
 | 
			
		||||
std::optional<lsMarkedString> GetHoverOrName(DB* db,
 | 
			
		||||
                                             LanguageId lang,
 | 
			
		||||
std::optional<lsMarkedString> GetHoverOrName(DB *db, LanguageId lang,
 | 
			
		||||
                                             SymbolRef sym) {
 | 
			
		||||
  std::optional<lsMarkedString> ret;
 | 
			
		||||
  WithEntity(db, sym, [&](const auto &entity) {
 | 
			
		||||
@ -58,9 +57,7 @@ struct Out_TextDocumentHover : public lsOutMessage<Out_TextDocumentHover> {
 | 
			
		||||
  std::optional<Result> result;
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(Out_TextDocumentHover::Result, contents, range);
 | 
			
		||||
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_TextDocumentHover,
 | 
			
		||||
                                       jsonrpc,
 | 
			
		||||
                                       id,
 | 
			
		||||
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_TextDocumentHover, jsonrpc, id,
 | 
			
		||||
                                       result);
 | 
			
		||||
 | 
			
		||||
struct Handler_TextDocumentHover : BaseMessageHandler<In_TextDocumentHover> {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
#include "message_handler.h"
 | 
			
		||||
#include "query_utils.h"
 | 
			
		||||
#include "pipeline.hh"
 | 
			
		||||
#include "query_utils.h"
 | 
			
		||||
using namespace ccls;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
@ -27,14 +27,9 @@ struct In_TextDocumentReferences : public RequestInMessage {
 | 
			
		||||
 | 
			
		||||
  Params params;
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_TextDocumentReferences::lsReferenceContext,
 | 
			
		||||
                    base,
 | 
			
		||||
                    excludeRole,
 | 
			
		||||
                    includeDeclaration,
 | 
			
		||||
                    role);
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_TextDocumentReferences::Params,
 | 
			
		||||
                    textDocument,
 | 
			
		||||
                    position,
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_TextDocumentReferences::lsReferenceContext, base,
 | 
			
		||||
                    excludeRole, includeDeclaration, role);
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_TextDocumentReferences::Params, textDocument, position,
 | 
			
		||||
                    context);
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_TextDocumentReferences, id, params);
 | 
			
		||||
REGISTER_IN_MESSAGE(In_TextDocumentReferences);
 | 
			
		||||
@ -57,8 +52,7 @@ struct Handler_TextDocumentReferences
 | 
			
		||||
                        params.textDocument.uri.GetPath(), &file))
 | 
			
		||||
      return;
 | 
			
		||||
 | 
			
		||||
    WorkingFile* wfile =
 | 
			
		||||
        working_files->GetFileByFilename(file->def->path);
 | 
			
		||||
    WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
 | 
			
		||||
 | 
			
		||||
    Out_TextDocumentReferences out;
 | 
			
		||||
    out.id = request->id;
 | 
			
		||||
@ -133,8 +127,7 @@ struct Handler_TextDocumentReferences
 | 
			
		||||
                // Another file |file1| has the same include line.
 | 
			
		||||
                lsLocationEx result;
 | 
			
		||||
                result.uri = lsDocumentUri::FromPath(file1.def->path);
 | 
			
		||||
                result.range.start.line = result.range.end.line =
 | 
			
		||||
                  include.line;
 | 
			
		||||
                result.range.start.line = result.range.end.line = include.line;
 | 
			
		||||
                out.result.push_back(std::move(result));
 | 
			
		||||
                break;
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
@ -1,19 +1,18 @@
 | 
			
		||||
#include "message_handler.h"
 | 
			
		||||
#include "query_utils.h"
 | 
			
		||||
#include "pipeline.hh"
 | 
			
		||||
#include "query_utils.h"
 | 
			
		||||
using namespace ccls;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
MethodType kMethodType = "textDocument/rename";
 | 
			
		||||
 | 
			
		||||
lsWorkspaceEdit BuildWorkspaceEdit(DB* db,
 | 
			
		||||
                                   WorkingFiles* working_files,
 | 
			
		||||
                                   SymbolRef sym,
 | 
			
		||||
                                   const std::string& new_text) {
 | 
			
		||||
lsWorkspaceEdit BuildWorkspaceEdit(DB *db, WorkingFiles *working_files,
 | 
			
		||||
                                   SymbolRef sym, const std::string &new_text) {
 | 
			
		||||
  std::unordered_map<int, lsTextDocumentEdit> path_to_edit;
 | 
			
		||||
 | 
			
		||||
  EachOccurrence(db, sym, true, [&](Use use) {
 | 
			
		||||
    std::optional<lsLocation> ls_location = GetLsLocation(db, working_files, use);
 | 
			
		||||
    std::optional<lsLocation> ls_location =
 | 
			
		||||
        GetLsLocation(db, working_files, use);
 | 
			
		||||
    if (!ls_location)
 | 
			
		||||
      return;
 | 
			
		||||
 | 
			
		||||
@ -65,9 +64,7 @@ struct In_TextDocumentRename : public RequestInMessage {
 | 
			
		||||
  };
 | 
			
		||||
  Params params;
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_TextDocumentRename::Params,
 | 
			
		||||
                    textDocument,
 | 
			
		||||
                    position,
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_TextDocumentRename::Params, textDocument, position,
 | 
			
		||||
                    newName);
 | 
			
		||||
MAKE_REFLECT_STRUCT(In_TextDocumentRename, id, params);
 | 
			
		||||
REGISTER_IN_MESSAGE(In_TextDocumentRename);
 | 
			
		||||
 | 
			
		||||
@ -70,9 +70,7 @@ struct lsSignatureHelp {
 | 
			
		||||
  // active signature does have any.
 | 
			
		||||
  std::optional<int> activeParameter;
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsSignatureHelp,
 | 
			
		||||
                    signatures,
 | 
			
		||||
                    activeSignature,
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsSignatureHelp, signatures, activeSignature,
 | 
			
		||||
                    activeParameter);
 | 
			
		||||
 | 
			
		||||
struct Out_TextDocumentSignatureHelp
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
#include "clang_complete.h"
 | 
			
		||||
#include "message_handler.h"
 | 
			
		||||
#include "project.h"
 | 
			
		||||
#include "pipeline.hh"
 | 
			
		||||
#include "project.h"
 | 
			
		||||
#include "working_files.h"
 | 
			
		||||
using namespace ccls;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
#include "clang_complete.h"
 | 
			
		||||
#include "message_handler.h"
 | 
			
		||||
#include "project.h"
 | 
			
		||||
#include "pipeline.hh"
 | 
			
		||||
#include "project.h"
 | 
			
		||||
#include "working_files.h"
 | 
			
		||||
using namespace ccls;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
#include "lsp_code_action.h"
 | 
			
		||||
#include "message_handler.h"
 | 
			
		||||
#include "query_utils.h"
 | 
			
		||||
#include "pipeline.hh"
 | 
			
		||||
#include "query_utils.h"
 | 
			
		||||
using namespace ccls;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
@ -4,20 +4,17 @@
 | 
			
		||||
#include "query_utils.h"
 | 
			
		||||
using namespace ccls;
 | 
			
		||||
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
MethodType kMethodType = "workspace/symbol";
 | 
			
		||||
 | 
			
		||||
// Lookup |symbol| in |db| and insert the value into |result|.
 | 
			
		||||
bool AddSymbol(
 | 
			
		||||
    DB* db,
 | 
			
		||||
    WorkingFiles* working_files,
 | 
			
		||||
    SymbolIdx sym,
 | 
			
		||||
    bool use_detailed,
 | 
			
		||||
    DB *db, WorkingFiles *working_files, SymbolIdx sym, bool use_detailed,
 | 
			
		||||
    std::vector<std::tuple<lsSymbolInformation, int, SymbolIdx>> *result) {
 | 
			
		||||
  std::optional<lsSymbolInformation> info =
 | 
			
		||||
      GetSymbolInfo(db, working_files, sym, true);
 | 
			
		||||
@ -102,7 +99,8 @@ struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
 | 
			
		||||
        goto done_add;
 | 
			
		||||
  done_add:
 | 
			
		||||
 | 
			
		||||
    if (g_config->workspaceSymbol.sort && query.size() <= FuzzyMatcher::kMaxPat) {
 | 
			
		||||
    if (g_config->workspaceSymbol.sort &&
 | 
			
		||||
        query.size() <= FuzzyMatcher::kMaxPat) {
 | 
			
		||||
      // Sort results with a fuzzy matching algorithm.
 | 
			
		||||
      int longest = 0;
 | 
			
		||||
      for (auto &cand : cands)
 | 
			
		||||
 | 
			
		||||
@ -4,8 +4,7 @@ MethodType kMethodType_Unknown = "$unknown";
 | 
			
		||||
MethodType kMethodType_Exit = "exit";
 | 
			
		||||
MethodType kMethodType_TextDocumentPublishDiagnostics =
 | 
			
		||||
    "textDocument/publishDiagnostics";
 | 
			
		||||
MethodType kMethodType_CclsPublishSkippedRanges =
 | 
			
		||||
    "$ccls/publishSkippedRanges";
 | 
			
		||||
MethodType kMethodType_CclsPublishSkippedRanges = "$ccls/publishSkippedRanges";
 | 
			
		||||
MethodType kMethodType_CclsPublishSemanticHighlighting =
 | 
			
		||||
    "$ccls/publishSemanticHighlighting";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -35,14 +35,10 @@ struct InMessage {
 | 
			
		||||
struct RequestInMessage : public InMessage {
 | 
			
		||||
  // number or string, actually no null
 | 
			
		||||
  lsRequestId id;
 | 
			
		||||
  lsRequestId GetRequestId() const override {
 | 
			
		||||
    return id;
 | 
			
		||||
  }
 | 
			
		||||
  lsRequestId GetRequestId() const override { return id; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// NotificationInMessage does not have |id|.
 | 
			
		||||
struct NotificationInMessage : public InMessage {
 | 
			
		||||
  lsRequestId GetRequestId() const override {
 | 
			
		||||
    return lsRequestId();
 | 
			
		||||
  }
 | 
			
		||||
  lsRequestId GetRequestId() const override { return lsRequestId(); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -6,10 +6,10 @@
 | 
			
		||||
#include "log.hh"
 | 
			
		||||
#include "lsp.h"
 | 
			
		||||
#include "message_handler.h"
 | 
			
		||||
#include "pipeline.hh"
 | 
			
		||||
#include "platform.h"
 | 
			
		||||
#include "project.h"
 | 
			
		||||
#include "query_utils.h"
 | 
			
		||||
#include "pipeline.hh"
 | 
			
		||||
 | 
			
		||||
#include <llvm/ADT/Twine.h>
 | 
			
		||||
#include <llvm/Support/Threading.h>
 | 
			
		||||
@ -52,7 +52,8 @@ void DiagnosticsPublisher::Publish(WorkingFiles* working_files,
 | 
			
		||||
    Out_TextDocumentPublishDiagnostics out;
 | 
			
		||||
    out.params.uri = lsDocumentUri::FromPath(path);
 | 
			
		||||
    out.params.diagnostics = diagnostics;
 | 
			
		||||
    ccls::pipeline::WriteStdout(kMethodType_TextDocumentPublishDiagnostics, out);
 | 
			
		||||
    ccls::pipeline::WriteStdout(kMethodType_TextDocumentPublishDiagnostics,
 | 
			
		||||
                                out);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -92,7 +93,8 @@ bool CacheInvalid(VFS *vfs, IndexFile *prev, const std::string &path,
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (prev->args != args) {
 | 
			
		||||
    LOG_S(INFO) << "args changed for " << path << (from ? " (via " + *from + ")" : std::string());
 | 
			
		||||
    LOG_S(INFO) << "args changed for " << path
 | 
			
		||||
                << (from ? " (via " + *from + ")" : std::string());
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -122,8 +124,7 @@ std::string GetCachePath(const std::string& source_file) {
 | 
			
		||||
  return g_config->cacheDirectory + cache_file;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<IndexFile> RawCacheLoad(
 | 
			
		||||
    const std::string& path) {
 | 
			
		||||
std::unique_ptr<IndexFile> RawCacheLoad(const std::string &path) {
 | 
			
		||||
  std::string cache_path = GetCachePath(path);
 | 
			
		||||
  std::optional<std::string> file_content = ReadContent(cache_path);
 | 
			
		||||
  std::optional<std::string> serialized_indexed_content =
 | 
			
		||||
@ -136,10 +137,8 @@ std::unique_ptr<IndexFile> RawCacheLoad(
 | 
			
		||||
                           IndexFile::kMajorVersion);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Indexer_Parse(DiagnosticsPublisher* diag_pub,
 | 
			
		||||
                   WorkingFiles* working_files,
 | 
			
		||||
                   Project* project,
 | 
			
		||||
                   VFS* vfs) {
 | 
			
		||||
bool Indexer_Parse(DiagnosticsPublisher *diag_pub, WorkingFiles *working_files,
 | 
			
		||||
                   Project *project, VFS *vfs) {
 | 
			
		||||
  std::optional<Index_Request> opt_request = index_request->TryPopFront();
 | 
			
		||||
  if (!opt_request)
 | 
			
		||||
    return false;
 | 
			
		||||
@ -218,7 +217,8 @@ bool Indexer_Parse(DiagnosticsPublisher* diag_pub,
 | 
			
		||||
 | 
			
		||||
  LOG_S(INFO) << "parse " << path_to_index;
 | 
			
		||||
 | 
			
		||||
  auto indexes = idx::Index(vfs, entry.directory, path_to_index, entry.args, {});
 | 
			
		||||
  auto indexes =
 | 
			
		||||
      idx::Index(vfs, entry.directory, path_to_index, entry.args, {});
 | 
			
		||||
 | 
			
		||||
  if (indexes.empty()) {
 | 
			
		||||
    if (g_config->index.enabled && request.id.Valid()) {
 | 
			
		||||
@ -288,22 +288,19 @@ void Init() {
 | 
			
		||||
  for_stdout = new ThreadedQueue<Stdout_Request>(stdout_waiter);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Indexer_Main(DiagnosticsPublisher* diag_pub,
 | 
			
		||||
                  VFS* vfs,
 | 
			
		||||
                  Project* project,
 | 
			
		||||
void Indexer_Main(DiagnosticsPublisher *diag_pub, VFS *vfs, Project *project,
 | 
			
		||||
                  WorkingFiles *working_files) {
 | 
			
		||||
  while (true)
 | 
			
		||||
    if (!Indexer_Parse(diag_pub, working_files, project, vfs))
 | 
			
		||||
      indexer_waiter->Wait(index_request);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Main_OnIndexed(DB* db,
 | 
			
		||||
                    SemanticHighlightSymbolCache* semantic_cache,
 | 
			
		||||
                    WorkingFiles* working_files,
 | 
			
		||||
                    IndexUpdate* update) {
 | 
			
		||||
void Main_OnIndexed(DB *db, SemanticHighlightSymbolCache *semantic_cache,
 | 
			
		||||
                    WorkingFiles *working_files, IndexUpdate *update) {
 | 
			
		||||
  if (update->refresh) {
 | 
			
		||||
    Project::loaded = true;
 | 
			
		||||
    LOG_S(INFO) << "loaded project. Refresh semantic highlight for all working file.";
 | 
			
		||||
    LOG_S(INFO)
 | 
			
		||||
        << "loaded project. Refresh semantic highlight for all working file.";
 | 
			
		||||
    std::lock_guard<std::mutex> lock(working_files->files_mutex);
 | 
			
		||||
    for (auto &f : working_files->files) {
 | 
			
		||||
      std::string filename = LowerPathIfInsensitive(f->filename);
 | 
			
		||||
@ -369,7 +366,8 @@ void LaunchStdin() {
 | 
			
		||||
      if (method_type == kMethodType_Exit)
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }).detach();
 | 
			
		||||
  })
 | 
			
		||||
      .detach();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LaunchStdout() {
 | 
			
		||||
@ -392,7 +390,8 @@ void LaunchStdout() {
 | 
			
		||||
#endif
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }).detach();
 | 
			
		||||
  })
 | 
			
		||||
      .detach();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MainLoop() {
 | 
			
		||||
@ -412,8 +411,7 @@ void MainLoop() {
 | 
			
		||||
          Out_Error out;
 | 
			
		||||
          out.id = id;
 | 
			
		||||
          out.error.code = lsErrorCodes::InternalError;
 | 
			
		||||
          out.error.message =
 | 
			
		||||
              "Dropping completion request; a newer request "
 | 
			
		||||
          out.error.message = "Dropping completion request; a newer request "
 | 
			
		||||
                              "has come in that will be serviced instead.";
 | 
			
		||||
          pipeline::WriteStdout(kMethodType_Unknown, out);
 | 
			
		||||
        }
 | 
			
		||||
@ -473,10 +471,8 @@ void MainLoop() {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Index(const std::string& path,
 | 
			
		||||
           const std::vector<std::string>& args,
 | 
			
		||||
           bool interactive,
 | 
			
		||||
           lsRequestId id) {
 | 
			
		||||
void Index(const std::string &path, const std::vector<std::string> &args,
 | 
			
		||||
           bool interactive, lsRequestId id) {
 | 
			
		||||
  index_request->PushBack({path, args, interactive, id}, interactive);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -494,4 +490,4 @@ void WriteStdout(MethodType method, lsBaseOutMessage& response) {
 | 
			
		||||
  for_stdout->PushBack(std::move(out));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
} // namespace ccls::pipeline
 | 
			
		||||
 | 
			
		||||
@ -14,10 +14,10 @@
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/types.h> // required for stat.h
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#ifdef __GLIBC__
 | 
			
		||||
#include <malloc.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -49,8 +49,7 @@ struct Range {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
namespace std {
 | 
			
		||||
template <>
 | 
			
		||||
struct hash<Range> {
 | 
			
		||||
template <> struct hash<Range> {
 | 
			
		||||
  std::size_t operator()(Range x) const {
 | 
			
		||||
    union U {
 | 
			
		||||
      Range range = {};
 | 
			
		||||
@ -61,7 +60,7 @@ struct hash<Range> {
 | 
			
		||||
    return hash<uint64_t>()(u.u64);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
} // namespace std
 | 
			
		||||
 | 
			
		||||
// Reflection
 | 
			
		||||
class Reader;
 | 
			
		||||
 | 
			
		||||
@ -5,8 +5,8 @@
 | 
			
		||||
#include "language.h"
 | 
			
		||||
#include "log.hh"
 | 
			
		||||
#include "match.h"
 | 
			
		||||
#include "platform.h"
 | 
			
		||||
#include "pipeline.hh"
 | 
			
		||||
#include "platform.h"
 | 
			
		||||
#include "serializers/json.h"
 | 
			
		||||
#include "utils.h"
 | 
			
		||||
#include "working_files.h"
 | 
			
		||||
@ -67,8 +67,8 @@ enum OptionClass {
 | 
			
		||||
  Separate,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Project::Entry GetCompilationEntryFromCompileCommandEntry(
 | 
			
		||||
    ProjectConfig* config,
 | 
			
		||||
Project::Entry
 | 
			
		||||
GetCompilationEntryFromCompileCommandEntry(ProjectConfig *config,
 | 
			
		||||
                                           const CompileCommandsEntry &entry) {
 | 
			
		||||
  Project::Entry result;
 | 
			
		||||
  result.filename = entry.file;
 | 
			
		||||
@ -155,7 +155,8 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  // if (!sys::fs::exists(HeaderOpts.ResourceDir) && HeaderOpts.UseBuiltinIncludes)
 | 
			
		||||
  // if (!sys::fs::exists(HeaderOpts.ResourceDir) &&
 | 
			
		||||
  // HeaderOpts.UseBuiltinIncludes)
 | 
			
		||||
  args.push_back("-resource-dir=" + g_config->clang.resourceDir);
 | 
			
		||||
  if (CI->getFileSystemOpts().WorkingDir.empty())
 | 
			
		||||
    args.push_back("-working-directory=" + entry.directory);
 | 
			
		||||
@ -169,10 +170,11 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<std::string> ReadCompilerArgumentsFromFile(
 | 
			
		||||
    const std::string& path) {
 | 
			
		||||
std::vector<std::string>
 | 
			
		||||
ReadCompilerArgumentsFromFile(const std::string &path) {
 | 
			
		||||
  auto MBOrErr = MemoryBuffer::getFile(path);
 | 
			
		||||
  if (!MBOrErr) return {};
 | 
			
		||||
  if (!MBOrErr)
 | 
			
		||||
    return {};
 | 
			
		||||
  std::vector<std::string> args;
 | 
			
		||||
  for (line_iterator I(*MBOrErr.get(), true, '#'), E; I != E; ++I)
 | 
			
		||||
    args.push_back(*I);
 | 
			
		||||
@ -209,7 +211,8 @@ std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig* config) {
 | 
			
		||||
  LOG_IF_S(INFO, !project_dir_args.empty())
 | 
			
		||||
      << "Using .ccls arguments " << StringJoin(project_dir_args);
 | 
			
		||||
 | 
			
		||||
  auto GetCompilerArgumentForFile = [&project_dir, &folder_args](std::string cur) {
 | 
			
		||||
  auto GetCompilerArgumentForFile = [&project_dir,
 | 
			
		||||
                                     &folder_args](std::string cur) {
 | 
			
		||||
    while (!(cur = sys::path::parent_path(cur)).empty()) {
 | 
			
		||||
      auto it = folder_args.find(cur);
 | 
			
		||||
      if (it != folder_args.end())
 | 
			
		||||
@ -237,8 +240,8 @@ std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig* config) {
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
 | 
			
		||||
    ProjectConfig* project,
 | 
			
		||||
std::vector<Project::Entry>
 | 
			
		||||
LoadCompilationEntriesFromDirectory(ProjectConfig *project,
 | 
			
		||||
                                    const std::string &opt_compilation_db_dir) {
 | 
			
		||||
  // If there is a .ccls file always load using directory listing.
 | 
			
		||||
  SmallString<256> Path;
 | 
			
		||||
@ -362,8 +365,7 @@ void Project::Load(const std::string& root_directory) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Project::SetFlagsForFile(
 | 
			
		||||
    const std::vector<std::string>& flags,
 | 
			
		||||
void Project::SetFlagsForFile(const std::vector<std::string> &flags,
 | 
			
		||||
                              const std::string &path) {
 | 
			
		||||
  std::lock_guard<std::mutex> lock(mutex_);
 | 
			
		||||
  auto it = absolute_path_to_entry_index_.find(path);
 | 
			
		||||
@ -380,8 +382,8 @@ void Project::SetFlagsForFile(
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Project::Entry Project::FindCompilationEntryForFile(
 | 
			
		||||
    const std::string& filename) {
 | 
			
		||||
Project::Entry
 | 
			
		||||
Project::FindCompilationEntryForFile(const std::string &filename) {
 | 
			
		||||
  {
 | 
			
		||||
    std::lock_guard<std::mutex> lock(mutex_);
 | 
			
		||||
    auto it = absolute_path_to_entry_index_.find(filename);
 | 
			
		||||
@ -412,7 +414,8 @@ Project::Entry Project::FindCompilationEntryForFile(
 | 
			
		||||
 | 
			
		||||
    // |best_entry| probably has its own path in the arguments. We need to remap
 | 
			
		||||
    // that path to the new filename.
 | 
			
		||||
    std::string best_entry_base_name = sys::path::filename(best_entry->filename);
 | 
			
		||||
    std::string best_entry_base_name =
 | 
			
		||||
        sys::path::filename(best_entry->filename);
 | 
			
		||||
    for (std::string &arg : result.args) {
 | 
			
		||||
      try {
 | 
			
		||||
        if (arg == best_entry->filename ||
 | 
			
		||||
@ -441,8 +444,7 @@ void Project::ForAllFilteredFiles(
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Project::Index(WorkingFiles* wfiles,
 | 
			
		||||
                    lsRequestId id) {
 | 
			
		||||
void Project::Index(WorkingFiles *wfiles, lsRequestId id) {
 | 
			
		||||
  ForAllFilteredFiles([&](int i, const Project::Entry &entry) {
 | 
			
		||||
    bool is_interactive = wfiles->GetFileByFilename(entry.filename) != nullptr;
 | 
			
		||||
    pipeline::Index(entry.filename, entry.args, is_interactive, id);
 | 
			
		||||
 | 
			
		||||
@ -49,13 +49,12 @@ struct Project {
 | 
			
		||||
  // If the client has overridden the flags, or specified them for a file
 | 
			
		||||
  // that is not in the compilation_database.json make sure those changes
 | 
			
		||||
  // are permanent.
 | 
			
		||||
  void SetFlagsForFile(
 | 
			
		||||
      const std::vector<std::string>& flags,
 | 
			
		||||
  void SetFlagsForFile(const std::vector<std::string> &flags,
 | 
			
		||||
                       const std::string &path);
 | 
			
		||||
 | 
			
		||||
  // Run |action| on every file in the project.
 | 
			
		||||
  void ForAllFilteredFiles(
 | 
			
		||||
      std::function<void(int i, const Entry& entry)> action);
 | 
			
		||||
  void
 | 
			
		||||
  ForAllFilteredFiles(std::function<void(int i, const Entry &entry)> action);
 | 
			
		||||
 | 
			
		||||
  void Index(WorkingFiles *wfiles, lsRequestId id);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								src/query.cc
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								src/query.cc
									
									
									
									
									
								
							@ -164,8 +164,7 @@ bool TryReplaceDef(llvm::SmallVectorImpl<Q>& def_list, Q&& def) {
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
 | 
			
		||||
                                     IndexFile* current) {
 | 
			
		||||
IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
 | 
			
		||||
  IndexUpdate r;
 | 
			
		||||
  static IndexFile empty(llvm::sys::fs::UniqueID(0, 0), current->path,
 | 
			
		||||
                         "<empty>");
 | 
			
		||||
@ -233,14 +232,14 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DB::RemoveUsrs(SymbolKind kind,
 | 
			
		||||
                    int file_id,
 | 
			
		||||
void DB::RemoveUsrs(SymbolKind kind, int file_id,
 | 
			
		||||
                    const std::vector<Usr> &to_remove) {
 | 
			
		||||
  switch (kind) {
 | 
			
		||||
  case SymbolKind::Func: {
 | 
			
		||||
    for (Usr usr : to_remove) {
 | 
			
		||||
      // FIXME
 | 
			
		||||
        if (!HasFunc(usr)) continue;
 | 
			
		||||
      if (!HasFunc(usr))
 | 
			
		||||
        continue;
 | 
			
		||||
      QueryFunc &func = Func(usr);
 | 
			
		||||
      auto it = llvm::find_if(func.def, [=](const QueryFunc::Def &def) {
 | 
			
		||||
        return def.file_id == file_id;
 | 
			
		||||
@ -253,7 +252,8 @@ void DB::RemoveUsrs(SymbolKind kind,
 | 
			
		||||
  case SymbolKind::Type: {
 | 
			
		||||
    for (Usr usr : to_remove) {
 | 
			
		||||
      // FIXME
 | 
			
		||||
        if (!HasType(usr)) continue;
 | 
			
		||||
      if (!HasType(usr))
 | 
			
		||||
        continue;
 | 
			
		||||
      QueryType &type = Type(usr);
 | 
			
		||||
      auto it = llvm::find_if(type.def, [=](const QueryType::Def &def) {
 | 
			
		||||
        return def.file_id == file_id;
 | 
			
		||||
@ -266,7 +266,8 @@ void DB::RemoveUsrs(SymbolKind kind,
 | 
			
		||||
  case SymbolKind::Var: {
 | 
			
		||||
    for (Usr usr : to_remove) {
 | 
			
		||||
      // FIXME
 | 
			
		||||
        if (!HasVar(usr)) continue;
 | 
			
		||||
      if (!HasVar(usr))
 | 
			
		||||
        continue;
 | 
			
		||||
      QueryVar &var = Var(usr);
 | 
			
		||||
      auto it = llvm::find_if(var.def, [=](const QueryVar::Def &def) {
 | 
			
		||||
        return def.file_id == file_id;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								src/query.h
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								src/query.h
									
									
									
									
									
								
							@ -30,8 +30,7 @@ struct QueryFile {
 | 
			
		||||
  std::unordered_map<SymbolRef, int> symbol2refcnt;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Q, typename QDef>
 | 
			
		||||
struct QueryEntity {
 | 
			
		||||
template <typename Q, typename QDef> struct QueryEntity {
 | 
			
		||||
  using Def = QDef;
 | 
			
		||||
  Def *AnyDef() {
 | 
			
		||||
    Def *ret = nullptr;
 | 
			
		||||
@ -42,7 +41,9 @@ struct QueryEntity {
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
  }
 | 
			
		||||
  const Def* AnyDef() const { return const_cast<QueryEntity*>(this)->AnyDef(); }
 | 
			
		||||
  const Def *AnyDef() const {
 | 
			
		||||
    return const_cast<QueryEntity *>(this)->AnyDef();
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using UseUpdate =
 | 
			
		||||
@ -77,8 +78,7 @@ struct QueryVar : QueryEntity<QueryVar, VarDef> {
 | 
			
		||||
struct IndexUpdate {
 | 
			
		||||
  // Creates a new IndexUpdate based on the delta from previous to current. If
 | 
			
		||||
  // no delta computation should be done just pass null for previous.
 | 
			
		||||
  static IndexUpdate CreateDelta(IndexFile* previous,
 | 
			
		||||
                                 IndexFile* current);
 | 
			
		||||
  static IndexUpdate CreateDelta(IndexFile *previous, IndexFile *current);
 | 
			
		||||
 | 
			
		||||
  int file_id;
 | 
			
		||||
 | 
			
		||||
@ -120,8 +120,7 @@ struct IndexUpdate {
 | 
			
		||||
struct WrappedUsr {
 | 
			
		||||
  Usr usr;
 | 
			
		||||
};
 | 
			
		||||
template <>
 | 
			
		||||
struct llvm::DenseMapInfo<WrappedUsr> {
 | 
			
		||||
template <> struct llvm::DenseMapInfo<WrappedUsr> {
 | 
			
		||||
  static inline WrappedUsr getEmptyKey() { return {0}; }
 | 
			
		||||
  static inline WrappedUsr getTombstoneKey() { return {~0ULL}; }
 | 
			
		||||
  static unsigned getHashValue(WrappedUsr w) { return w.usr; }
 | 
			
		||||
@ -140,7 +139,8 @@ struct DB {
 | 
			
		||||
  std::vector<QueryType> types;
 | 
			
		||||
  std::vector<QueryVar> vars;
 | 
			
		||||
 | 
			
		||||
  void RemoveUsrs(SymbolKind kind, int file_id, const std::vector<Usr>& to_remove);
 | 
			
		||||
  void RemoveUsrs(SymbolKind kind, int file_id,
 | 
			
		||||
                  const std::vector<Usr> &to_remove);
 | 
			
		||||
  // Insert the contents of |update| into |db|.
 | 
			
		||||
  void ApplyIndexUpdate(IndexUpdate *update);
 | 
			
		||||
  int GetFileId(const std::string &path);
 | 
			
		||||
 | 
			
		||||
@ -59,8 +59,7 @@ std::vector<Use> GetFuncDeclarations(DB* db, const std::vector<Usr>& usrs) {
 | 
			
		||||
std::vector<Use> GetTypeDeclarations(DB *db, const std::vector<Usr> &usrs) {
 | 
			
		||||
  return GetDeclarations(db->type_usr, db->types, usrs);
 | 
			
		||||
}
 | 
			
		||||
std::vector<Use> GetVarDeclarations(DB* db,
 | 
			
		||||
                                    const std::vector<Usr>& usrs,
 | 
			
		||||
std::vector<Use> GetVarDeclarations(DB *db, const std::vector<Usr> &usrs,
 | 
			
		||||
                                    unsigned kind) {
 | 
			
		||||
  std::vector<Use> ret;
 | 
			
		||||
  ret.reserve(usrs.size());
 | 
			
		||||
@ -207,8 +206,7 @@ lsDocumentUri GetLsDocumentUri(DB* db, int file_id) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::optional<lsLocation> GetLsLocation(DB* db,
 | 
			
		||||
                                        WorkingFiles* working_files,
 | 
			
		||||
std::optional<lsLocation> GetLsLocation(DB *db, WorkingFiles *working_files,
 | 
			
		||||
                                        Use use) {
 | 
			
		||||
  std::string path;
 | 
			
		||||
  lsDocumentUri uri = GetLsDocumentUri(db, use.file_id, &path);
 | 
			
		||||
@ -219,10 +217,8 @@ std::optional<lsLocation> GetLsLocation(DB* db,
 | 
			
		||||
  return lsLocation{uri, *range};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::optional<lsLocationEx> GetLsLocationEx(DB* db,
 | 
			
		||||
                                            WorkingFiles* working_files,
 | 
			
		||||
                                            Use use,
 | 
			
		||||
                                            bool container) {
 | 
			
		||||
std::optional<lsLocationEx> GetLsLocationEx(DB *db, WorkingFiles *working_files,
 | 
			
		||||
                                            Use use, bool container) {
 | 
			
		||||
  std::optional<lsLocation> ls_loc = GetLsLocation(db, working_files, use);
 | 
			
		||||
  if (!ls_loc)
 | 
			
		||||
    return std::nullopt;
 | 
			
		||||
@ -238,8 +234,7 @@ std::optional<lsLocationEx> GetLsLocationEx(DB* db,
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<lsLocationEx> GetLsLocationExs(DB* db,
 | 
			
		||||
                                           WorkingFiles* working_files,
 | 
			
		||||
std::vector<lsLocationEx> GetLsLocationExs(DB *db, WorkingFiles *working_files,
 | 
			
		||||
                                           const std::vector<Use> &uses) {
 | 
			
		||||
  std::vector<lsLocationEx> ret;
 | 
			
		||||
  for (Use use : uses)
 | 
			
		||||
@ -337,7 +332,8 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
 | 
			
		||||
  //
 | 
			
		||||
  // Then order functions before other types, which makes goto definition work
 | 
			
		||||
  // better on constructors.
 | 
			
		||||
  std::sort(symbols.begin(), symbols.end(),
 | 
			
		||||
  std::sort(
 | 
			
		||||
      symbols.begin(), symbols.end(),
 | 
			
		||||
      [](const SymbolRef &a, const SymbolRef &b) {
 | 
			
		||||
        int t = ComputeRangeSize(a.range) - ComputeRangeSize(b.range);
 | 
			
		||||
        if (t)
 | 
			
		||||
 | 
			
		||||
@ -26,15 +26,11 @@ std::optional<lsRange> GetLsRange(WorkingFile* working_file,
 | 
			
		||||
lsDocumentUri GetLsDocumentUri(DB *db, int file_id, std::string *path);
 | 
			
		||||
lsDocumentUri GetLsDocumentUri(DB *db, int file_id);
 | 
			
		||||
 | 
			
		||||
std::optional<lsLocation> GetLsLocation(DB* db,
 | 
			
		||||
                                        WorkingFiles* working_files,
 | 
			
		||||
std::optional<lsLocation> GetLsLocation(DB *db, WorkingFiles *working_files,
 | 
			
		||||
                                        Use use);
 | 
			
		||||
std::optional<lsLocationEx> GetLsLocationEx(DB* db,
 | 
			
		||||
                                            WorkingFiles* working_files,
 | 
			
		||||
                                            Use use,
 | 
			
		||||
                                            bool container);
 | 
			
		||||
std::vector<lsLocationEx> GetLsLocationExs(DB* db,
 | 
			
		||||
                                           WorkingFiles* working_files,
 | 
			
		||||
std::optional<lsLocationEx> GetLsLocationEx(DB *db, WorkingFiles *working_files,
 | 
			
		||||
                                            Use use, bool container);
 | 
			
		||||
std::vector<lsLocationEx> GetLsLocationExs(DB *db, WorkingFiles *working_files,
 | 
			
		||||
                                           const std::vector<Use> &refs);
 | 
			
		||||
// Returns a symbol. The symbol will have *NOT* have a location assigned.
 | 
			
		||||
std::optional<lsSymbolInformation> GetSymbolInfo(DB *db,
 | 
			
		||||
@ -46,8 +42,7 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
 | 
			
		||||
                                             QueryFile *file,
 | 
			
		||||
                                             lsPosition &ls_pos);
 | 
			
		||||
 | 
			
		||||
template <typename Fn>
 | 
			
		||||
void WithEntity(DB* db, SymbolIdx sym, Fn&& fn) {
 | 
			
		||||
template <typename Fn> void WithEntity(DB *db, SymbolIdx sym, Fn &&fn) {
 | 
			
		||||
  switch (sym.kind) {
 | 
			
		||||
  case SymbolKind::Invalid:
 | 
			
		||||
  case SymbolKind::File:
 | 
			
		||||
@ -64,8 +59,7 @@ void WithEntity(DB* db, SymbolIdx sym, Fn&& fn) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Fn>
 | 
			
		||||
void EachEntityDef(DB* db, SymbolIdx sym, Fn&& fn) {
 | 
			
		||||
template <typename Fn> void EachEntityDef(DB *db, SymbolIdx sym, Fn &&fn) {
 | 
			
		||||
  WithEntity(db, sym, [&](const auto &entity) {
 | 
			
		||||
    for (auto &def : entity.def)
 | 
			
		||||
      if (!fn(def))
 | 
			
		||||
@ -99,7 +93,6 @@ void EachDefinedFunc(DB* db, const std::vector<Usr>& usrs, Fn&& fn) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename Fn>
 | 
			
		||||
void EachDefinedType(DB *db, const std::vector<Usr> &usrs, Fn &&fn) {
 | 
			
		||||
  for (Usr usr : usrs) {
 | 
			
		||||
 | 
			
		||||
@ -18,75 +18,57 @@ bool gTestOutputMode = false;
 | 
			
		||||
 | 
			
		||||
//// Elementary types
 | 
			
		||||
 | 
			
		||||
void Reflect(Reader& visitor, uint8_t& value) {
 | 
			
		||||
  value = visitor.GetUInt8();
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer& visitor, uint8_t& value) {
 | 
			
		||||
  visitor.UInt8(value);
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Reader &visitor, uint8_t &value) { value = visitor.GetUInt8(); }
 | 
			
		||||
void Reflect(Writer &visitor, uint8_t &value) { visitor.UInt8(value); }
 | 
			
		||||
 | 
			
		||||
void Reflect(Reader &visitor, short &value) {
 | 
			
		||||
  if (!visitor.IsInt())
 | 
			
		||||
    throw std::invalid_argument("short");
 | 
			
		||||
  value = (short)visitor.GetInt();
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer& visitor, short& value) {
 | 
			
		||||
  visitor.Int(value);
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer &visitor, short &value) { visitor.Int(value); }
 | 
			
		||||
 | 
			
		||||
void Reflect(Reader &visitor, unsigned short &value) {
 | 
			
		||||
  if (!visitor.IsInt())
 | 
			
		||||
    throw std::invalid_argument("unsigned short");
 | 
			
		||||
  value = (unsigned short)visitor.GetInt();
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer& visitor, unsigned short& value) {
 | 
			
		||||
  visitor.Int(value);
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer &visitor, unsigned short &value) { visitor.Int(value); }
 | 
			
		||||
 | 
			
		||||
void Reflect(Reader &visitor, int &value) {
 | 
			
		||||
  if (!visitor.IsInt())
 | 
			
		||||
    throw std::invalid_argument("int");
 | 
			
		||||
  value = visitor.GetInt();
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer& visitor, int& value) {
 | 
			
		||||
  visitor.Int(value);
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer &visitor, int &value) { visitor.Int(value); }
 | 
			
		||||
 | 
			
		||||
void Reflect(Reader &visitor, unsigned &value) {
 | 
			
		||||
  if (!visitor.IsUInt64())
 | 
			
		||||
    throw std::invalid_argument("unsigned");
 | 
			
		||||
  value = visitor.GetUInt32();
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer& visitor, unsigned& value) {
 | 
			
		||||
  visitor.UInt32(value);
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer &visitor, unsigned &value) { visitor.UInt32(value); }
 | 
			
		||||
 | 
			
		||||
void Reflect(Reader &visitor, long &value) {
 | 
			
		||||
  if (!visitor.IsInt64())
 | 
			
		||||
    throw std::invalid_argument("long");
 | 
			
		||||
  value = long(visitor.GetInt64());
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer& visitor, long& value) {
 | 
			
		||||
  visitor.Int64(value);
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer &visitor, long &value) { visitor.Int64(value); }
 | 
			
		||||
 | 
			
		||||
void Reflect(Reader &visitor, unsigned long &value) {
 | 
			
		||||
  if (!visitor.IsUInt64())
 | 
			
		||||
    throw std::invalid_argument("unsigned long");
 | 
			
		||||
  value = (unsigned long)visitor.GetUInt64();
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer& visitor, unsigned long& value) {
 | 
			
		||||
  visitor.UInt64(value);
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer &visitor, unsigned long &value) { visitor.UInt64(value); }
 | 
			
		||||
 | 
			
		||||
void Reflect(Reader &visitor, long long &value) {
 | 
			
		||||
  if (!visitor.IsInt64())
 | 
			
		||||
    throw std::invalid_argument("long long");
 | 
			
		||||
  value = visitor.GetInt64();
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer& visitor, long long& value) {
 | 
			
		||||
  visitor.Int64(value);
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer &visitor, long long &value) { visitor.Int64(value); }
 | 
			
		||||
 | 
			
		||||
void Reflect(Reader &visitor, unsigned long long &value) {
 | 
			
		||||
  if (!visitor.IsUInt64())
 | 
			
		||||
@ -102,18 +84,14 @@ void Reflect(Reader& visitor, double& value) {
 | 
			
		||||
    throw std::invalid_argument("double");
 | 
			
		||||
  value = visitor.GetDouble();
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer& visitor, double& value) {
 | 
			
		||||
  visitor.Double(value);
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer &visitor, double &value) { visitor.Double(value); }
 | 
			
		||||
 | 
			
		||||
void Reflect(Reader &visitor, bool &value) {
 | 
			
		||||
  if (!visitor.IsBool())
 | 
			
		||||
    throw std::invalid_argument("bool");
 | 
			
		||||
  value = visitor.GetBool();
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer& visitor, bool& value) {
 | 
			
		||||
  visitor.Bool(value);
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer &visitor, bool &value) { visitor.Bool(value); }
 | 
			
		||||
 | 
			
		||||
void Reflect(Reader &visitor, std::string &value) {
 | 
			
		||||
  if (!visitor.IsString())
 | 
			
		||||
@ -124,9 +102,7 @@ void Reflect(Writer& visitor, std::string& value) {
 | 
			
		||||
  visitor.String(value.c_str(), (rapidjson::SizeType)value.size());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Reflect(Reader&, std::string_view&) {
 | 
			
		||||
  assert(0);
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Reader &, std::string_view &) { assert(0); }
 | 
			
		||||
void Reflect(Writer &visitor, std::string_view &data) {
 | 
			
		||||
  if (data.empty())
 | 
			
		||||
    visitor.String("");
 | 
			
		||||
@ -138,18 +114,14 @@ void Reflect(Reader& vis, const char*& v) {
 | 
			
		||||
  const char *str = vis.GetString();
 | 
			
		||||
  v = ccls::Intern(str);
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer& vis, const char*& v) {
 | 
			
		||||
  vis.String(v);
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer &vis, const char *&v) { vis.String(v); }
 | 
			
		||||
 | 
			
		||||
void Reflect(Reader &visitor, JsonNull &value) {
 | 
			
		||||
  assert(visitor.Format() == SerializeFormat::Json);
 | 
			
		||||
  visitor.GetNull();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Reflect(Writer& visitor, JsonNull& value) {
 | 
			
		||||
  visitor.Null();
 | 
			
		||||
}
 | 
			
		||||
void Reflect(Writer &visitor, JsonNull &value) { visitor.Null(); }
 | 
			
		||||
 | 
			
		||||
// std::unordered_map
 | 
			
		||||
template <typename V>
 | 
			
		||||
@ -230,12 +202,12 @@ void ReflectHoverAndComments(Writer& visitor, Def& def) {
 | 
			
		||||
    ReflectMember(visitor, "comments", def.comments);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Def>
 | 
			
		||||
void ReflectShortName(Reader& visitor, Def& def) {
 | 
			
		||||
template <typename Def> void ReflectShortName(Reader &visitor, Def &def) {
 | 
			
		||||
  if (gTestOutputMode) {
 | 
			
		||||
    std::string short_name;
 | 
			
		||||
    ReflectMember(visitor, "short_name", short_name);
 | 
			
		||||
    def.short_name_offset = std::string_view(def.detailed_name).find(short_name);
 | 
			
		||||
    def.short_name_offset =
 | 
			
		||||
        std::string_view(def.detailed_name).find(short_name);
 | 
			
		||||
    assert(def.short_name_offset != std::string::npos);
 | 
			
		||||
    def.short_name_size = short_name.size();
 | 
			
		||||
  } else {
 | 
			
		||||
@ -244,8 +216,7 @@ void ReflectShortName(Reader& visitor, Def& def) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Def>
 | 
			
		||||
void ReflectShortName(Writer& visitor, Def& def) {
 | 
			
		||||
template <typename Def> void ReflectShortName(Writer &visitor, Def &def) {
 | 
			
		||||
  if (gTestOutputMode) {
 | 
			
		||||
    std::string_view short_name(def.detailed_name + def.short_name_offset,
 | 
			
		||||
                                def.short_name_size);
 | 
			
		||||
@ -256,8 +227,7 @@ void ReflectShortName(Writer& visitor, Def& def) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename TVisitor>
 | 
			
		||||
void Reflect(TVisitor& visitor, IndexType& value) {
 | 
			
		||||
template <typename TVisitor> void Reflect(TVisitor &visitor, IndexType &value) {
 | 
			
		||||
  REFLECT_MEMBER_START();
 | 
			
		||||
  REFLECT_MEMBER2("usr", value.usr);
 | 
			
		||||
  REFLECT_MEMBER2("detailed_name", value.def.detailed_name);
 | 
			
		||||
@ -279,8 +249,7 @@ void Reflect(TVisitor& visitor, IndexType& value) {
 | 
			
		||||
  REFLECT_MEMBER_END();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename TVisitor>
 | 
			
		||||
void Reflect(TVisitor& visitor, IndexFunc& value) {
 | 
			
		||||
template <typename TVisitor> void Reflect(TVisitor &visitor, IndexFunc &value) {
 | 
			
		||||
  REFLECT_MEMBER_START();
 | 
			
		||||
  REFLECT_MEMBER2("usr", value.usr);
 | 
			
		||||
  REFLECT_MEMBER2("detailed_name", value.def.detailed_name);
 | 
			
		||||
@ -300,8 +269,7 @@ void Reflect(TVisitor& visitor, IndexFunc& value) {
 | 
			
		||||
  REFLECT_MEMBER_END();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename TVisitor>
 | 
			
		||||
void Reflect(TVisitor& visitor, IndexVar& value) {
 | 
			
		||||
template <typename TVisitor> void Reflect(TVisitor &visitor, IndexVar &value) {
 | 
			
		||||
  REFLECT_MEMBER_START();
 | 
			
		||||
  REFLECT_MEMBER2("usr", value.usr);
 | 
			
		||||
  REFLECT_MEMBER2("detailed_name", value.def.detailed_name);
 | 
			
		||||
@ -323,8 +291,7 @@ bool ReflectMemberStart(Writer& visitor, IndexFile& value) {
 | 
			
		||||
  visitor.StartObject();
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
template <typename TVisitor>
 | 
			
		||||
void Reflect(TVisitor& visitor, IndexFile& value) {
 | 
			
		||||
template <typename TVisitor> void Reflect(TVisitor &visitor, IndexFile &value) {
 | 
			
		||||
  REFLECT_MEMBER_START();
 | 
			
		||||
  if (!gTestOutputMode) {
 | 
			
		||||
    REFLECT_MEMBER(last_write_time);
 | 
			
		||||
@ -364,7 +331,8 @@ static DenseSet<StringRef> Strings;
 | 
			
		||||
static std::mutex AllocMutex;
 | 
			
		||||
 | 
			
		||||
const char *Intern(const std::string &str) {
 | 
			
		||||
  if (str.empty()) return "";
 | 
			
		||||
  if (str.empty())
 | 
			
		||||
    return "";
 | 
			
		||||
  StringRef Str(str.data(), str.size() + 1);
 | 
			
		||||
  std::lock_guard lock(AllocMutex);
 | 
			
		||||
  auto R = Strings.insert(Str);
 | 
			
		||||
@ -404,9 +372,8 @@ std::string Serialize(SerializeFormat format, IndexFile& file) {
 | 
			
		||||
  return "";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<IndexFile> Deserialize(
 | 
			
		||||
    SerializeFormat format,
 | 
			
		||||
    const std::string& path,
 | 
			
		||||
std::unique_ptr<IndexFile>
 | 
			
		||||
Deserialize(SerializeFormat format, const std::string &path,
 | 
			
		||||
            const std::string &serialized_index_content,
 | 
			
		||||
            const std::string &file_content,
 | 
			
		||||
            std::optional<int> expected_version) {
 | 
			
		||||
@ -430,8 +397,7 @@ std::unique_ptr<IndexFile> Deserialize(
 | 
			
		||||
                                         file_content);
 | 
			
		||||
      Reflect(reader, *file);
 | 
			
		||||
    } catch (std::invalid_argument &e) {
 | 
			
		||||
        LOG_S(INFO) << "failed to deserialize '" << path
 | 
			
		||||
                    << "': " << e.what();
 | 
			
		||||
      LOG_S(INFO) << "failed to deserialize '" << path << "': " << e.what();
 | 
			
		||||
      return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
    break;
 | 
			
		||||
@ -469,4 +435,4 @@ std::unique_ptr<IndexFile> Deserialize(
 | 
			
		||||
  file->path = path;
 | 
			
		||||
  return file;
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
} // namespace ccls
 | 
			
		||||
 | 
			
		||||
@ -99,23 +99,20 @@ struct IndexFile;
 | 
			
		||||
  REFLECT_MEMBER_MANDATORY_OPTIONAL(name);
 | 
			
		||||
 | 
			
		||||
#define MAKE_REFLECT_EMPTY_STRUCT(type, ...)                                   \
 | 
			
		||||
  template <typename TVisitor>                   \
 | 
			
		||||
  void Reflect(TVisitor& visitor, type& value) { \
 | 
			
		||||
  template <typename TVisitor> void Reflect(TVisitor &visitor, type &value) {  \
 | 
			
		||||
    REFLECT_MEMBER_START();                                                    \
 | 
			
		||||
    REFLECT_MEMBER_END();                                                      \
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#define MAKE_REFLECT_STRUCT(type, ...)                                         \
 | 
			
		||||
  template <typename TVisitor>                       \
 | 
			
		||||
  void Reflect(TVisitor& visitor, type& value) {     \
 | 
			
		||||
  template <typename TVisitor> void Reflect(TVisitor &visitor, type &value) {  \
 | 
			
		||||
    REFLECT_MEMBER_START();                                                    \
 | 
			
		||||
    MACRO_MAP(_MAPPABLE_REFLECT_MEMBER, __VA_ARGS__)                           \
 | 
			
		||||
    REFLECT_MEMBER_END();                                                      \
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#define MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(type, ...)                      \
 | 
			
		||||
  template <typename TVisitor>                                          \
 | 
			
		||||
  void Reflect(TVisitor& visitor, type& value) {                        \
 | 
			
		||||
  template <typename TVisitor> void Reflect(TVisitor &visitor, type &value) {  \
 | 
			
		||||
    REFLECT_MEMBER_START();                                                    \
 | 
			
		||||
    MACRO_MAP(_MAPPABLE_REFLECT_MEMBER_MANDATORY_OPTIONAL, __VA_ARGS__)        \
 | 
			
		||||
    REFLECT_MEMBER_END();                                                      \
 | 
			
		||||
@ -190,12 +187,11 @@ void Reflect(Writer& visitor, SerializeFormat& value);
 | 
			
		||||
 | 
			
		||||
//// Type constructors
 | 
			
		||||
 | 
			
		||||
// ReflectMember std::optional<T> is used to represent TypeScript optional properties
 | 
			
		||||
// (in `key: value` context).
 | 
			
		||||
// Reflect std::optional<T> is used for a different purpose, whether an object is
 | 
			
		||||
// nullable (possibly in `value` context).
 | 
			
		||||
template <typename T>
 | 
			
		||||
void Reflect(Reader& visitor, std::optional<T>& value) {
 | 
			
		||||
// ReflectMember std::optional<T> is used to represent TypeScript optional
 | 
			
		||||
// properties (in `key: value` context). Reflect std::optional<T> is used for a
 | 
			
		||||
// different purpose, whether an object is nullable (possibly in `value`
 | 
			
		||||
// context).
 | 
			
		||||
template <typename T> void Reflect(Reader &visitor, std::optional<T> &value) {
 | 
			
		||||
  if (visitor.IsNull()) {
 | 
			
		||||
    visitor.GetNull();
 | 
			
		||||
    return;
 | 
			
		||||
@ -204,8 +200,7 @@ void Reflect(Reader& visitor, std::optional<T>& value) {
 | 
			
		||||
  Reflect(visitor, real_value);
 | 
			
		||||
  value = std::move(real_value);
 | 
			
		||||
}
 | 
			
		||||
template <typename T>
 | 
			
		||||
void Reflect(Writer& visitor, std::optional<T>& value) {
 | 
			
		||||
template <typename T> void Reflect(Writer &visitor, std::optional<T> &value) {
 | 
			
		||||
  if (value) {
 | 
			
		||||
    if (visitor.Format() != SerializeFormat::Json)
 | 
			
		||||
      visitor.UInt8(1);
 | 
			
		||||
@ -215,8 +210,7 @@ void Reflect(Writer& visitor, std::optional<T>& value) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The same as std::optional
 | 
			
		||||
template <typename T>
 | 
			
		||||
void Reflect(Reader& visitor, Maybe<T>& value) {
 | 
			
		||||
template <typename T> void Reflect(Reader &visitor, Maybe<T> &value) {
 | 
			
		||||
  if (visitor.IsNull()) {
 | 
			
		||||
    visitor.GetNull();
 | 
			
		||||
    return;
 | 
			
		||||
@ -225,8 +219,7 @@ void Reflect(Reader& visitor, Maybe<T>& value) {
 | 
			
		||||
  Reflect(visitor, real_value);
 | 
			
		||||
  value = std::move(real_value);
 | 
			
		||||
}
 | 
			
		||||
template <typename T>
 | 
			
		||||
void Reflect(Writer& visitor, Maybe<T>& value) {
 | 
			
		||||
template <typename T> void Reflect(Writer &visitor, Maybe<T> &value) {
 | 
			
		||||
  if (value) {
 | 
			
		||||
    if (visitor.Format() != SerializeFormat::Json)
 | 
			
		||||
      visitor.UInt8(1);
 | 
			
		||||
@ -256,9 +249,7 @@ void ReflectMember(Writer& visitor, const char* name, Maybe<T>& value) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
void ReflectMember(Writer& visitor,
 | 
			
		||||
                   const char* name,
 | 
			
		||||
                   T& value,
 | 
			
		||||
void ReflectMember(Writer &visitor, const char *name, T &value,
 | 
			
		||||
                   mandatory_optional_tag) {
 | 
			
		||||
  visitor.Key(name);
 | 
			
		||||
  Reflect(visitor, value);
 | 
			
		||||
@ -278,16 +269,14 @@ void Reflect(Writer& vis, std::pair<L, R>& v) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// std::vector
 | 
			
		||||
template <typename T>
 | 
			
		||||
void Reflect(Reader& visitor, std::vector<T>& values) {
 | 
			
		||||
template <typename T> void Reflect(Reader &visitor, std::vector<T> &values) {
 | 
			
		||||
  visitor.IterArray([&](Reader &entry) {
 | 
			
		||||
    T entry_value;
 | 
			
		||||
    Reflect(entry, entry_value);
 | 
			
		||||
    values.push_back(std::move(entry_value));
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
template <typename T>
 | 
			
		||||
void Reflect(Writer& visitor, std::vector<T>& values) {
 | 
			
		||||
template <typename T> void Reflect(Writer &visitor, std::vector<T> &values) {
 | 
			
		||||
  visitor.StartArray(values.size());
 | 
			
		||||
  for (auto &value : values)
 | 
			
		||||
    Reflect(visitor, value);
 | 
			
		||||
@ -296,25 +285,19 @@ void Reflect(Writer& visitor, std::vector<T>& values) {
 | 
			
		||||
 | 
			
		||||
// ReflectMember
 | 
			
		||||
 | 
			
		||||
inline bool ReflectMemberStart(Reader& vis) {
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
inline bool ReflectMemberStart(Reader &vis) { return false; }
 | 
			
		||||
inline bool ReflectMemberStart(Writer &vis) {
 | 
			
		||||
  vis.StartObject();
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void ReflectMemberEnd(Reader &vis) {}
 | 
			
		||||
inline void ReflectMemberEnd(Writer& vis) {
 | 
			
		||||
  vis.EndObject();
 | 
			
		||||
}
 | 
			
		||||
inline void ReflectMemberEnd(Writer &vis) { vis.EndObject(); }
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
void ReflectMember(Reader& vis, const char* name, T& v) {
 | 
			
		||||
template <typename T> void ReflectMember(Reader &vis, const char *name, T &v) {
 | 
			
		||||
  vis.Member(name, [&]() { Reflect(vis, v); });
 | 
			
		||||
}
 | 
			
		||||
template <typename T>
 | 
			
		||||
void ReflectMember(Writer& vis, const char* name, T& v) {
 | 
			
		||||
template <typename T> void ReflectMember(Writer &vis, const char *name, T &v) {
 | 
			
		||||
  vis.Key(name);
 | 
			
		||||
  Reflect(vis, v);
 | 
			
		||||
}
 | 
			
		||||
@ -324,10 +307,9 @@ void ReflectMember(Writer& vis, const char* name, T& v) {
 | 
			
		||||
namespace ccls {
 | 
			
		||||
const char *Intern(const std::string &str);
 | 
			
		||||
std::string Serialize(SerializeFormat format, IndexFile &file);
 | 
			
		||||
std::unique_ptr<IndexFile> Deserialize(
 | 
			
		||||
    SerializeFormat format,
 | 
			
		||||
    const std::string& path,
 | 
			
		||||
std::unique_ptr<IndexFile>
 | 
			
		||||
Deserialize(SerializeFormat format, const std::string &path,
 | 
			
		||||
            const std::string &serialized_index_content,
 | 
			
		||||
            const std::string &file_content,
 | 
			
		||||
            std::optional<int> expected_version);
 | 
			
		||||
}
 | 
			
		||||
} // namespace ccls
 | 
			
		||||
 | 
			
		||||
@ -7,8 +7,7 @@
 | 
			
		||||
class BinaryReader : public Reader {
 | 
			
		||||
  const char *p_;
 | 
			
		||||
 | 
			
		||||
  template <typename T>
 | 
			
		||||
  T Get() {
 | 
			
		||||
  template <typename T> T Get() {
 | 
			
		||||
    auto ret = *reinterpret_cast<const T *>(p_);
 | 
			
		||||
    p_ += sizeof(T);
 | 
			
		||||
    return ret;
 | 
			
		||||
@ -31,9 +30,7 @@ class BinaryReader : public Reader {
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  BinaryReader(std::string_view buf) : p_(buf.data()) {}
 | 
			
		||||
  SerializeFormat Format() const override {
 | 
			
		||||
    return SerializeFormat::Binary;
 | 
			
		||||
  }
 | 
			
		||||
  SerializeFormat Format() const override { return SerializeFormat::Binary; }
 | 
			
		||||
 | 
			
		||||
  bool IsBool() override { return true; }
 | 
			
		||||
  // Abuse how the function is called in serializer.h
 | 
			
		||||
@ -68,16 +65,13 @@ class BinaryReader : public Reader {
 | 
			
		||||
      fn(*this);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void Member(const char*, std::function<void()> fn) override {
 | 
			
		||||
    fn();
 | 
			
		||||
  }
 | 
			
		||||
  void Member(const char *, std::function<void()> fn) override { fn(); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class BinaryWriter : public Writer {
 | 
			
		||||
  std::string buf_;
 | 
			
		||||
 | 
			
		||||
  template <typename T>
 | 
			
		||||
  void Pack(T x) {
 | 
			
		||||
  template <typename T> void Pack(T x) {
 | 
			
		||||
    auto i = buf_.size();
 | 
			
		||||
    buf_.resize(i + sizeof(x));
 | 
			
		||||
    *reinterpret_cast<T *>(buf_.data() + i) = x;
 | 
			
		||||
@ -97,14 +91,10 @@ class BinaryWriter : public Writer {
 | 
			
		||||
      Pack<uint64_t>(n);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  void VarInt(int64_t n) {
 | 
			
		||||
    VarUInt(uint64_t(n) << 1 ^ n >> 63);
 | 
			
		||||
  }
 | 
			
		||||
  void VarInt(int64_t n) { VarUInt(uint64_t(n) << 1 ^ n >> 63); }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  SerializeFormat Format() const override {
 | 
			
		||||
    return SerializeFormat::Binary;
 | 
			
		||||
  }
 | 
			
		||||
  SerializeFormat Format() const override { return SerializeFormat::Binary; }
 | 
			
		||||
  std::string Take() { return std::move(buf_); }
 | 
			
		||||
 | 
			
		||||
  void Null() override { Pack(uint8_t(0)); }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								src/test.cc
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								src/test.cc
									
									
									
									
									
								
							@ -13,9 +13,9 @@
 | 
			
		||||
#include <rapidjson/stringbuffer.h>
 | 
			
		||||
#include <rapidjson/writer.h>
 | 
			
		||||
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
 | 
			
		||||
// The 'diff' utility is available and we can use dprintf(3).
 | 
			
		||||
#if _POSIX_C_SOURCE >= 200809L
 | 
			
		||||
@ -66,8 +66,7 @@ struct TextReplacer {
 | 
			
		||||
 | 
			
		||||
void ParseTestExpectation(
 | 
			
		||||
    const std::string &filename,
 | 
			
		||||
    const std::vector<std::string>& lines_with_endings,
 | 
			
		||||
    TextReplacer* replacer,
 | 
			
		||||
    const std::vector<std::string> &lines_with_endings, TextReplacer *replacer,
 | 
			
		||||
    std::vector<std::string> *flags,
 | 
			
		||||
    std::unordered_map<std::string, std::string> *output_sections) {
 | 
			
		||||
  // Scan for EXTRA_FLAGS:
 | 
			
		||||
@ -148,10 +147,8 @@ void UpdateTestExpectation(const std::string& filename,
 | 
			
		||||
  WriteToFile(filename, str);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DiffDocuments(std::string path,
 | 
			
		||||
                   std::string path_section,
 | 
			
		||||
                   rapidjson::Document& expected,
 | 
			
		||||
                   rapidjson::Document& actual) {
 | 
			
		||||
void DiffDocuments(std::string path, std::string path_section,
 | 
			
		||||
                   rapidjson::Document &expected, rapidjson::Document &actual) {
 | 
			
		||||
  std::string joined_actual_output = ToString(actual);
 | 
			
		||||
  std::string joined_expected_output = ToString(expected);
 | 
			
		||||
  printf("[FAILED] %s (section %s)\n", path.c_str(), path_section.c_str());
 | 
			
		||||
@ -217,8 +214,8 @@ std::string FindExpectedOutputForFilename(
 | 
			
		||||
  return "{}";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IndexFile* FindDbForPathEnding(
 | 
			
		||||
    const std::string& path,
 | 
			
		||||
IndexFile *
 | 
			
		||||
FindDbForPathEnding(const std::string &path,
 | 
			
		||||
                    const std::vector<std::unique_ptr<IndexFile>> &dbs) {
 | 
			
		||||
  for (auto &db : dbs) {
 | 
			
		||||
    if (EndsWith(db->path, path))
 | 
			
		||||
@ -353,8 +350,7 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
 | 
			
		||||
            DiffDocuments(path, expected_path, expected, actual);
 | 
			
		||||
            puts("\n");
 | 
			
		||||
            if (enable_update) {
 | 
			
		||||
              printf(
 | 
			
		||||
                  "[Enter to continue - type u to update test, a to update "
 | 
			
		||||
              printf("[Enter to continue - type u to update test, a to update "
 | 
			
		||||
                     "all]");
 | 
			
		||||
              char c = 'u';
 | 
			
		||||
              if (!update_all) {
 | 
			
		||||
 | 
			
		||||
@ -18,27 +18,21 @@ struct BaseThreadQueue {
 | 
			
		||||
// std::lock accepts two or more arguments. We define an overload for one
 | 
			
		||||
// argument.
 | 
			
		||||
namespace std {
 | 
			
		||||
template <typename Lockable>
 | 
			
		||||
void lock(Lockable& l) {
 | 
			
		||||
  l.lock();
 | 
			
		||||
}
 | 
			
		||||
template <typename Lockable> void lock(Lockable &l) { l.lock(); }
 | 
			
		||||
} // namespace std
 | 
			
		||||
 | 
			
		||||
template <typename... Queue>
 | 
			
		||||
struct MultiQueueLock {
 | 
			
		||||
template <typename... Queue> struct MultiQueueLock {
 | 
			
		||||
  MultiQueueLock(Queue... lockable) : tuple_{lockable...} { lock(); }
 | 
			
		||||
  ~MultiQueueLock() { unlock(); }
 | 
			
		||||
  void lock() { lock_impl(typename std::index_sequence_for<Queue...>{}); }
 | 
			
		||||
  void unlock() { unlock_impl(typename std::index_sequence_for<Queue...>{}); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  template <size_t... Is>
 | 
			
		||||
  void lock_impl(std::index_sequence<Is...>) {
 | 
			
		||||
  template <size_t... Is> void lock_impl(std::index_sequence<Is...>) {
 | 
			
		||||
    std::lock(std::get<Is>(tuple_)->mutex_...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template <size_t... Is>
 | 
			
		||||
  void unlock_impl(std::index_sequence<Is...>) {
 | 
			
		||||
  template <size_t... Is> void unlock_impl(std::index_sequence<Is...>) {
 | 
			
		||||
    (void)std::initializer_list<int>{
 | 
			
		||||
        (std::get<Is>(tuple_)->mutex_.unlock(), 0)...};
 | 
			
		||||
  }
 | 
			
		||||
@ -57,8 +51,7 @@ struct MultiQueueWaiter {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template <typename... BaseThreadQueue>
 | 
			
		||||
  void Wait(BaseThreadQueue... queues) {
 | 
			
		||||
  template <typename... BaseThreadQueue> void Wait(BaseThreadQueue... queues) {
 | 
			
		||||
    MultiQueueLock<BaseThreadQueue...> l(queues...);
 | 
			
		||||
    while (!HasState({queues...}))
 | 
			
		||||
      cv.wait(l);
 | 
			
		||||
@ -66,8 +59,7 @@ struct MultiQueueWaiter {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// A threadsafe-queue. http://stackoverflow.com/a/16075550
 | 
			
		||||
template <class T>
 | 
			
		||||
struct ThreadedQueue : public BaseThreadQueue {
 | 
			
		||||
template <class T> struct ThreadedQueue : public BaseThreadQueue {
 | 
			
		||||
public:
 | 
			
		||||
  ThreadedQueue() {
 | 
			
		||||
    owned_waiter_ = std::make_unique<MultiQueueWaiter>();
 | 
			
		||||
@ -79,8 +71,7 @@ struct ThreadedQueue : public BaseThreadQueue {
 | 
			
		||||
  size_t Size() const { return total_count_; }
 | 
			
		||||
 | 
			
		||||
  // Add an element to the queue.
 | 
			
		||||
  template <void (std::deque<T>::*push)(T&&)>
 | 
			
		||||
  void Push(T&& t, bool priority) {
 | 
			
		||||
  template <void (std::deque<T>::*push)(T &&)> void Push(T &&t, bool priority) {
 | 
			
		||||
    std::lock_guard<std::mutex> lock(mutex_);
 | 
			
		||||
    if (priority)
 | 
			
		||||
      (priority_.*push)(std::move(t));
 | 
			
		||||
@ -151,8 +142,7 @@ struct ThreadedQueue : public BaseThreadQueue {
 | 
			
		||||
    return std::nullopt;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template <typename Fn>
 | 
			
		||||
  void Iterate(Fn fn) {
 | 
			
		||||
  template <typename Fn> void Iterate(Fn fn) {
 | 
			
		||||
    std::lock_guard<std::mutex> lock(mutex_);
 | 
			
		||||
    for (auto &entry : priority_)
 | 
			
		||||
      fn(entry);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								src/utils.cc
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								src/utils.cc
									
									
									
									
									
								
							@ -7,12 +7,12 @@ using namespace llvm;
 | 
			
		||||
 | 
			
		||||
#include <siphash.h>
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
using namespace std::placeholders;
 | 
			
		||||
 | 
			
		||||
@ -34,7 +34,8 @@ uint64_t HashUsr(std::string_view s) {
 | 
			
		||||
  // k is an arbitrary key. Don't change it.
 | 
			
		||||
  const uint8_t k[16] = {0xd0, 0xe5, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x52,
 | 
			
		||||
                         0x61, 0x79, 0xea, 0x70, 0xca, 0x70, 0xf0, 0x0d};
 | 
			
		||||
  (void)siphash(reinterpret_cast<const uint8_t*>(s.data()), s.size(), k, out, 8);
 | 
			
		||||
  (void)siphash(reinterpret_cast<const uint8_t *>(s.data()), s.size(), k, out,
 | 
			
		||||
                8);
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -112,7 +113,8 @@ std::optional<std::string> ReadContent(const std::string& filename) {
 | 
			
		||||
  char buf[4096];
 | 
			
		||||
  std::string ret;
 | 
			
		||||
  FILE *f = fopen(filename.c_str(), "rb");
 | 
			
		||||
  if (!f) return {};
 | 
			
		||||
  if (!f)
 | 
			
		||||
    return {};
 | 
			
		||||
  size_t n;
 | 
			
		||||
  while ((n = fread(buf, 1, sizeof buf, f)) > 0)
 | 
			
		||||
    ret.append(buf, n);
 | 
			
		||||
@ -139,8 +141,7 @@ std::optional<int64_t> LastWriteTime(const std::string& filename) {
 | 
			
		||||
 | 
			
		||||
// 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,
 | 
			
		||||
int ReverseSubseqMatch(std::string_view pat, std::string_view text,
 | 
			
		||||
                       int case_sensitivity) {
 | 
			
		||||
  if (case_sensitivity == 1)
 | 
			
		||||
    case_sensitivity = std::any_of(pat.begin(), pat.end(), isupper) ? 2 : 0;
 | 
			
		||||
@ -155,6 +156,4 @@ int ReverseSubseqMatch(std::string_view pat,
 | 
			
		||||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string GetDefaultResourceDirectory() {
 | 
			
		||||
  return DEFAULT_RESOURCE_DIRECTORY;
 | 
			
		||||
}
 | 
			
		||||
std::string GetDefaultResourceDirectory() { return DEFAULT_RESOURCE_DIRECTORY; }
 | 
			
		||||
 | 
			
		||||
@ -32,8 +32,7 @@ std::vector<std::string> SplitString(const std::string& str,
 | 
			
		||||
std::string LowerPathIfInsensitive(const std::string &path);
 | 
			
		||||
 | 
			
		||||
template <typename TValues, typename TMap>
 | 
			
		||||
std::string StringJoinMap(const TValues& values,
 | 
			
		||||
                          const TMap& map,
 | 
			
		||||
std::string StringJoinMap(const TValues &values, const TMap &map,
 | 
			
		||||
                          const std::string &sep = ", ") {
 | 
			
		||||
  std::string result;
 | 
			
		||||
  bool first = true;
 | 
			
		||||
@ -63,8 +62,7 @@ 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 ReverseSubseqMatch(std::string_view pat, std::string_view text,
 | 
			
		||||
                       int case_sensitivity);
 | 
			
		||||
 | 
			
		||||
// http://stackoverflow.com/a/38140932
 | 
			
		||||
@ -87,8 +85,7 @@ inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
 | 
			
		||||
 | 
			
		||||
#define MAKE_HASHABLE(type, ...)                                               \
 | 
			
		||||
  namespace std {                                                              \
 | 
			
		||||
  template <>                                     \
 | 
			
		||||
  struct hash<type> {                             \
 | 
			
		||||
  template <> struct hash<type> {                                              \
 | 
			
		||||
    std::size_t operator()(const type &t) const {                              \
 | 
			
		||||
      std::size_t ret = 0;                                                     \
 | 
			
		||||
      hash_combine(ret, __VA_ARGS__);                                          \
 | 
			
		||||
 | 
			
		||||
@ -149,12 +149,10 @@ int AlignColumn(const std::string& a, int column, std::string b, bool is_end) {
 | 
			
		||||
// Find matching buffer line of index_lines[line].
 | 
			
		||||
// By symmetry, this can also be used to find matching index line of a buffer
 | 
			
		||||
// line.
 | 
			
		||||
std::optional<int> FindMatchingLine(const std::vector<std::string>& index_lines,
 | 
			
		||||
                               const std::vector<int>& index_to_buffer,
 | 
			
		||||
                               int line,
 | 
			
		||||
                               int* column,
 | 
			
		||||
                               const std::vector<std::string>& buffer_lines,
 | 
			
		||||
                               bool is_end) {
 | 
			
		||||
std::optional<int>
 | 
			
		||||
FindMatchingLine(const std::vector<std::string> &index_lines,
 | 
			
		||||
                 const std::vector<int> &index_to_buffer, int line, int *column,
 | 
			
		||||
                 const std::vector<std::string> &buffer_lines, bool is_end) {
 | 
			
		||||
  // If this is a confident mapping, returns.
 | 
			
		||||
  if (index_to_buffer[line] >= 0) {
 | 
			
		||||
    int ret = index_to_buffer[line];
 | 
			
		||||
@ -300,8 +298,7 @@ void WorkingFile::ComputeLineMapping() {
 | 
			
		||||
      buffer_to_index[index_to_buffer[i]] = i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::optional<int> WorkingFile::GetBufferPosFromIndexPos(int line,
 | 
			
		||||
                                                    int* column,
 | 
			
		||||
std::optional<int> WorkingFile::GetBufferPosFromIndexPos(int line, int *column,
 | 
			
		||||
                                                         bool is_end) {
 | 
			
		||||
  if (line < 0 || line >= (int)index_lines.size()) {
 | 
			
		||||
    LOG_S(WARNING) << "bad index_line (got " << line << ", expected [0, "
 | 
			
		||||
@ -315,8 +312,7 @@ std::optional<int> WorkingFile::GetBufferPosFromIndexPos(int line,
 | 
			
		||||
                          buffer_lines, is_end);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::optional<int> WorkingFile::GetIndexPosFromBufferPos(int line,
 | 
			
		||||
                                                    int* column,
 | 
			
		||||
std::optional<int> WorkingFile::GetIndexPosFromBufferPos(int line, int *column,
 | 
			
		||||
                                                         bool is_end) {
 | 
			
		||||
  // See GetBufferLineFromIndexLine for additional comments.
 | 
			
		||||
  if (line < 0 || line >= (int)buffer_lines.size())
 | 
			
		||||
@ -329,8 +325,7 @@ std::optional<int> WorkingFile::GetIndexPosFromBufferPos(int line,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string WorkingFile::FindClosestCallNameInBuffer(
 | 
			
		||||
    lsPosition position,
 | 
			
		||||
    int* active_parameter,
 | 
			
		||||
    lsPosition position, int *active_parameter,
 | 
			
		||||
    lsPosition *completion_position) const {
 | 
			
		||||
  *active_parameter = 0;
 | 
			
		||||
 | 
			
		||||
@ -378,10 +373,8 @@ std::string WorkingFile::FindClosestCallNameInBuffer(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
lsPosition WorkingFile::FindStableCompletionSource(
 | 
			
		||||
    lsPosition position,
 | 
			
		||||
    bool* is_global_completion,
 | 
			
		||||
    std::string* existing_completion,
 | 
			
		||||
    lsPosition* replace_end_pos) const {
 | 
			
		||||
    lsPosition position, bool *is_global_completion,
 | 
			
		||||
    std::string *existing_completion, lsPosition *replace_end_pos) const {
 | 
			
		||||
  *is_global_completion = true;
 | 
			
		||||
 | 
			
		||||
  int start_offset = GetOffsetForPosition(position, buffer_content);
 | 
			
		||||
@ -410,7 +403,8 @@ lsPosition WorkingFile::FindStableCompletionSource(
 | 
			
		||||
  *replace_end_pos = position;
 | 
			
		||||
  for (int i = start_offset; i < buffer_content.size(); i++) {
 | 
			
		||||
    char c = buffer_content[i];
 | 
			
		||||
    if (!isalnum(c) && c != '_') break;
 | 
			
		||||
    if (!isalnum(c) && c != '_')
 | 
			
		||||
      break;
 | 
			
		||||
    // We know that replace_end_pos and position are on the same line.
 | 
			
		||||
    replace_end_pos->character++;
 | 
			
		||||
  }
 | 
			
		||||
@ -424,8 +418,8 @@ WorkingFile* WorkingFiles::GetFileByFilename(const std::string& filename) {
 | 
			
		||||
  return GetFileByFilenameNoLock(filename);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WorkingFile* WorkingFiles::GetFileByFilenameNoLock(
 | 
			
		||||
    const std::string& filename) {
 | 
			
		||||
WorkingFile *
 | 
			
		||||
WorkingFiles::GetFileByFilenameNoLock(const std::string &filename) {
 | 
			
		||||
  for (auto &file : files) {
 | 
			
		||||
    if (file->filename == filename)
 | 
			
		||||
      return file.get();
 | 
			
		||||
@ -516,8 +510,8 @@ void WorkingFiles::OnClose(const lsTextDocumentIdentifier& close) {
 | 
			
		||||
                 << " because it was not open";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WorkingFiles::Snapshot WorkingFiles::AsSnapshot(
 | 
			
		||||
    const std::vector<std::string>& filter_paths) {
 | 
			
		||||
WorkingFiles::Snapshot
 | 
			
		||||
WorkingFiles::AsSnapshot(const std::vector<std::string> &filter_paths) {
 | 
			
		||||
  std::lock_guard<std::mutex> lock(files_mutex);
 | 
			
		||||
 | 
			
		||||
  Snapshot result;
 | 
			
		||||
 | 
			
		||||
@ -40,10 +40,12 @@ struct WorkingFile {
 | 
			
		||||
  // Also resolves |column| if not NULL.
 | 
			
		||||
  // When resolving a range, use is_end = false for begin() and is_end =
 | 
			
		||||
  // true for end() to get a better alignment of |column|.
 | 
			
		||||
  std::optional<int> GetBufferPosFromIndexPos(int line, int* column, bool is_end);
 | 
			
		||||
  std::optional<int> GetBufferPosFromIndexPos(int line, int *column,
 | 
			
		||||
                                              bool is_end);
 | 
			
		||||
  // Finds the index line number which maps to buffer line number |line|.
 | 
			
		||||
  // Also resolves |column| if not NULL.
 | 
			
		||||
  std::optional<int> GetIndexPosFromBufferPos(int line, int* column, bool is_end);
 | 
			
		||||
  std::optional<int> GetIndexPosFromBufferPos(int line, int *column,
 | 
			
		||||
                                              bool is_end);
 | 
			
		||||
 | 
			
		||||
  // TODO: Move FindClosestCallNameInBuffer and FindStableCompletionSource into
 | 
			
		||||
  // lex_utils.h/cc
 | 
			
		||||
@ -53,9 +55,8 @@ struct WorkingFile {
 | 
			
		||||
  //
 | 
			
		||||
  // |completion_position| will be point to a good code completion location to
 | 
			
		||||
  // for fetching signatures.
 | 
			
		||||
  std::string FindClosestCallNameInBuffer(
 | 
			
		||||
      lsPosition position,
 | 
			
		||||
      int* active_parameter,
 | 
			
		||||
  std::string
 | 
			
		||||
  FindClosestCallNameInBuffer(lsPosition position, int *active_parameter,
 | 
			
		||||
                              lsPosition *completion_position = nullptr) const;
 | 
			
		||||
 | 
			
		||||
  // Returns a relatively stable completion position (it jumps back until there
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user