mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-03 22:04:24 +00:00 
			
		
		
		
	Simplify pipeline
This commit is contained in:
		
							parent
							
								
									8fabe3d1ae
								
							
						
					
					
						commit
						c9f0b65062
					
				@ -189,11 +189,8 @@ file(GLOB SOURCES src/*.cc src/*.h src/serializers/*.cc src/serializers/*.h
 | 
				
			|||||||
target_sources(ccls PRIVATE third_party/siphash.cc)
 | 
					target_sources(ccls PRIVATE third_party/siphash.cc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
target_sources(ccls PRIVATE
 | 
					target_sources(ccls PRIVATE
 | 
				
			||||||
               src/cache_manager.cc
 | 
					 | 
				
			||||||
               src/clang_complete.cc
 | 
					               src/clang_complete.cc
 | 
				
			||||||
               src/clang_cursor.cc
 | 
					               src/clang_tu.cc
 | 
				
			||||||
               src/clang_indexer.cc
 | 
					 | 
				
			||||||
               src/clang_translation_unit.cc
 | 
					 | 
				
			||||||
               src/clang_utils.cc
 | 
					               src/clang_utils.cc
 | 
				
			||||||
               src/config.cc
 | 
					               src/config.cc
 | 
				
			||||||
               src/diagnostics_engine.cc
 | 
					               src/diagnostics_engine.cc
 | 
				
			||||||
@ -202,6 +199,7 @@ target_sources(ccls PRIVATE
 | 
				
			|||||||
               src/fuzzy_match.cc
 | 
					               src/fuzzy_match.cc
 | 
				
			||||||
               src/main.cc
 | 
					               src/main.cc
 | 
				
			||||||
               src/include_complete.cc
 | 
					               src/include_complete.cc
 | 
				
			||||||
 | 
					               src/indexer.cc
 | 
				
			||||||
               src/method.cc
 | 
					               src/method.cc
 | 
				
			||||||
               src/language.cc
 | 
					               src/language.cc
 | 
				
			||||||
               src/lex_utils.cc
 | 
					               src/lex_utils.cc
 | 
				
			||||||
@ -212,12 +210,10 @@ target_sources(ccls PRIVATE
 | 
				
			|||||||
               src/pipeline.cc
 | 
					               src/pipeline.cc
 | 
				
			||||||
               src/platform_posix.cc
 | 
					               src/platform_posix.cc
 | 
				
			||||||
               src/platform_win.cc
 | 
					               src/platform_win.cc
 | 
				
			||||||
               src/port.cc
 | 
					 | 
				
			||||||
               src/position.cc
 | 
					               src/position.cc
 | 
				
			||||||
               src/project.cc
 | 
					               src/project.cc
 | 
				
			||||||
               src/query_utils.cc
 | 
					               src/query_utils.cc
 | 
				
			||||||
               src/query.cc
 | 
					               src/query.cc
 | 
				
			||||||
               src/queue_manager.cc
 | 
					 | 
				
			||||||
               src/serializer.cc
 | 
					               src/serializer.cc
 | 
				
			||||||
               src/test.cc
 | 
					               src/test.cc
 | 
				
			||||||
               src/third_party_impl.cc
 | 
					               src/third_party_impl.cc
 | 
				
			||||||
 | 
				
			|||||||
@ -1,62 +0,0 @@
 | 
				
			|||||||
#include "cache_manager.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
#include "indexer.h"
 | 
					 | 
				
			||||||
#include "lsp.h"
 | 
					 | 
				
			||||||
#include "platform.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <algorithm>
 | 
					 | 
				
			||||||
#include <unordered_map>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace {
 | 
					 | 
				
			||||||
std::string GetCachePath(const std::string& source_file) {
 | 
					 | 
				
			||||||
  assert(!g_config->cacheDirectory.empty());
 | 
					 | 
				
			||||||
  std::string cache_file;
 | 
					 | 
				
			||||||
  size_t len = g_config->projectRoot.size();
 | 
					 | 
				
			||||||
  if (StartsWith(source_file, g_config->projectRoot)) {
 | 
					 | 
				
			||||||
    cache_file = EscapeFileName(g_config->projectRoot) +
 | 
					 | 
				
			||||||
                 EscapeFileName(source_file.substr(len));
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    cache_file = '@' + EscapeFileName(g_config->projectRoot) +
 | 
					 | 
				
			||||||
                 EscapeFileName(source_file);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return g_config->cacheDirectory + cache_file;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::string AppendSerializationFormat(const std::string& base) {
 | 
					 | 
				
			||||||
  switch (g_config->cacheFormat) {
 | 
					 | 
				
			||||||
    case SerializeFormat::Binary:
 | 
					 | 
				
			||||||
      return base + ".blob";
 | 
					 | 
				
			||||||
    case SerializeFormat::Json:
 | 
					 | 
				
			||||||
      return base + ".json";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Manages loading caches from file paths for the indexer process.
 | 
					 | 
				
			||||||
void ICacheManager::WriteToCache(IndexFile& file) {
 | 
					 | 
				
			||||||
  std::string cache_path = GetCachePath(file.path);
 | 
					 | 
				
			||||||
  WriteToFile(cache_path, file.file_contents);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::string indexed_content = Serialize(g_config->cacheFormat, file);
 | 
					 | 
				
			||||||
  WriteToFile(AppendSerializationFormat(cache_path), indexed_content);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::optional<std::string> ICacheManager::LoadCachedFileContents(
 | 
					 | 
				
			||||||
    const std::string& path) {
 | 
					 | 
				
			||||||
  return ReadContent(GetCachePath(path));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::unique_ptr<IndexFile> ICacheManager::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 =
 | 
					 | 
				
			||||||
      ReadContent(AppendSerializationFormat(cache_path));
 | 
					 | 
				
			||||||
  if (!file_content || !serialized_indexed_content)
 | 
					 | 
				
			||||||
    return nullptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return Deserialize(g_config->cacheFormat, path, *serialized_indexed_content,
 | 
					 | 
				
			||||||
                     *file_content, IndexFile::kMajorVersion);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,26 +0,0 @@
 | 
				
			|||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <optional>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <unordered_map>
 | 
					 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct IndexFile;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct ICacheManager {
 | 
					 | 
				
			||||||
  void WriteToCache(IndexFile& file);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::optional<std::string> LoadCachedFileContents(const std::string& path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  template <typename Fn>
 | 
					 | 
				
			||||||
  void IterateLoadedCaches(Fn fn) {
 | 
					 | 
				
			||||||
    for (const auto& cache : caches_)
 | 
					 | 
				
			||||||
      fn(cache.second.get());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::unique_ptr<IndexFile> RawCacheLoad(const std::string& path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::unordered_map<std::string, std::unique_ptr<IndexFile>> caches_;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@ -21,14 +21,8 @@ unsigned Flags() {
 | 
				
			|||||||
         CXTranslationUnit_CacheCompletionResults |
 | 
					         CXTranslationUnit_CacheCompletionResults |
 | 
				
			||||||
         CXTranslationUnit_PrecompiledPreamble |
 | 
					         CXTranslationUnit_PrecompiledPreamble |
 | 
				
			||||||
         CXTranslationUnit_IncludeBriefCommentsInCodeCompletion |
 | 
					         CXTranslationUnit_IncludeBriefCommentsInCodeCompletion |
 | 
				
			||||||
         CXTranslationUnit_DetailedPreprocessingRecord
 | 
					         CXTranslationUnit_DetailedPreprocessingRecord |
 | 
				
			||||||
#if !defined(_WIN32)
 | 
					         CXTranslationUnit_CreatePreambleOnFirstParse;
 | 
				
			||||||
         // For whatever reason, CreatePreambleOnFirstParse causes clang to
 | 
					 | 
				
			||||||
         // become very crashy on windows.
 | 
					 | 
				
			||||||
         // TODO: do more investigation, submit fixes to clang.
 | 
					 | 
				
			||||||
         | CXTranslationUnit_CreatePreambleOnFirstParse
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
      ;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string StripFileType(const std::string& path) {
 | 
					std::string StripFileType(const std::string& path) {
 | 
				
			||||||
@ -57,23 +51,6 @@ unsigned GetCompletionPriority(const CXCompletionString& str,
 | 
				
			|||||||
  return priority;
 | 
					  return priority;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
bool IsCallKind(CXCursorKind kind) {
 | 
					 | 
				
			||||||
  switch (kind) {
 | 
					 | 
				
			||||||
    case CXCursor_ObjCInstanceMethodDecl:
 | 
					 | 
				
			||||||
    case CXCursor_CXXMethod:
 | 
					 | 
				
			||||||
    case CXCursor_FunctionTemplate:
 | 
					 | 
				
			||||||
    case CXCursor_FunctionDecl:
 | 
					 | 
				
			||||||
    case CXCursor_Constructor:
 | 
					 | 
				
			||||||
    case CXCursor_Destructor:
 | 
					 | 
				
			||||||
    case CXCursor_ConversionFunction:
 | 
					 | 
				
			||||||
      return true;
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      return false;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
lsCompletionItemKind GetCompletionKind(CXCursorKind cursor_kind) {
 | 
					lsCompletionItemKind GetCompletionKind(CXCursorKind cursor_kind) {
 | 
				
			||||||
  switch (cursor_kind) {
 | 
					  switch (cursor_kind) {
 | 
				
			||||||
    case CXCursor_UnexposedDecl:
 | 
					    case CXCursor_UnexposedDecl:
 | 
				
			||||||
@ -383,8 +360,8 @@ void TryEnsureDocumentParsed(ClangCompleteManager* manager,
 | 
				
			|||||||
  std::vector<std::string> args = session->file.args;
 | 
					  std::vector<std::string> args = session->file.args;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // -fspell-checking enables FixIts for, ie, misspelled types.
 | 
					  // -fspell-checking enables FixIts for, ie, misspelled types.
 | 
				
			||||||
  if (!AnyStartsWith(args, "-fno-spell-checking") &&
 | 
					  if (!std::count(args.begin(), args.end(), "-fno-spell-checking") &&
 | 
				
			||||||
      !AnyStartsWith(args, "-fspell-checking")) {
 | 
					      !std::count(args.begin(), args.end(), "-fspell-checking")) {
 | 
				
			||||||
    args.push_back("-fspell-checking");
 | 
					    args.push_back("-fspell-checking");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,6 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "clang_cursor.h"
 | 
					#include "clang_tu.h"
 | 
				
			||||||
#include "clang_translation_unit.h"
 | 
					 | 
				
			||||||
#include "lru_cache.h"
 | 
					#include "lru_cache.h"
 | 
				
			||||||
#include "lsp_completion.h"
 | 
					#include "lsp_completion.h"
 | 
				
			||||||
#include "lsp_diagnostic.h"
 | 
					#include "lsp_diagnostic.h"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,155 +0,0 @@
 | 
				
			|||||||
#include "clang_translation_unit.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "clang_utils.h"
 | 
					 | 
				
			||||||
#include "log.hh"
 | 
					 | 
				
			||||||
#include "platform.h"
 | 
					 | 
				
			||||||
#include "utils.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void EmitDiagnostics(std::string path,
 | 
					 | 
				
			||||||
                     std::vector<const char*> args,
 | 
					 | 
				
			||||||
                     CXTranslationUnit tu) {
 | 
					 | 
				
			||||||
  std::string output = "Fatal errors while trying to parse " + path + "\n";
 | 
					 | 
				
			||||||
  output +=
 | 
					 | 
				
			||||||
      "Args: " +
 | 
					 | 
				
			||||||
      StringJoinMap(args, [](const char* arg) { return std::string(arg); }) +
 | 
					 | 
				
			||||||
      "\n";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  size_t num_diagnostics = clang_getNumDiagnostics(tu);
 | 
					 | 
				
			||||||
  for (unsigned i = 0; i < num_diagnostics; ++i) {
 | 
					 | 
				
			||||||
    output += "  - ";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    CXDiagnostic diagnostic = clang_getDiagnostic(tu, i);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Location.
 | 
					 | 
				
			||||||
    CXFile file;
 | 
					 | 
				
			||||||
    unsigned int line, column;
 | 
					 | 
				
			||||||
    clang_getSpellingLocation(clang_getDiagnosticLocation(diagnostic), &file,
 | 
					 | 
				
			||||||
                              &line, &column, nullptr);
 | 
					 | 
				
			||||||
    std::string path = FileName(file);
 | 
					 | 
				
			||||||
    output += path + ":" + std::to_string(line - 1) + ":" +
 | 
					 | 
				
			||||||
              std::to_string(column) + " ";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Severity
 | 
					 | 
				
			||||||
    switch (clang_getDiagnosticSeverity(diagnostic)) {
 | 
					 | 
				
			||||||
      case CXDiagnostic_Ignored:
 | 
					 | 
				
			||||||
      case CXDiagnostic_Note:
 | 
					 | 
				
			||||||
        output += "[info]";
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case CXDiagnostic_Warning:
 | 
					 | 
				
			||||||
        output += "[warning]";
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case CXDiagnostic_Error:
 | 
					 | 
				
			||||||
        output += "[error]";
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case CXDiagnostic_Fatal:
 | 
					 | 
				
			||||||
        output += "[fatal]";
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Content.
 | 
					 | 
				
			||||||
    output += " " + ToString(clang_getDiagnosticSpelling(diagnostic));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    clang_disposeDiagnostic(diagnostic);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    output += "\n";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  LOG_S(WARNING) << output;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
}  // namespace
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// static
 | 
					 | 
				
			||||||
std::unique_ptr<ClangTranslationUnit> ClangTranslationUnit::Create(
 | 
					 | 
				
			||||||
    ClangIndex* index,
 | 
					 | 
				
			||||||
    const std::string& filepath,
 | 
					 | 
				
			||||||
    const std::vector<std::string>& arguments,
 | 
					 | 
				
			||||||
    std::vector<CXUnsavedFile>& unsaved_files,
 | 
					 | 
				
			||||||
    unsigned flags) {
 | 
					 | 
				
			||||||
  std::vector<const char*> args;
 | 
					 | 
				
			||||||
  for (auto& arg : arguments)
 | 
					 | 
				
			||||||
    args.push_back(arg.c_str());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  CXTranslationUnit cx_tu;
 | 
					 | 
				
			||||||
  CXErrorCode error_code;
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    error_code = clang_parseTranslationUnit2FullArgv(
 | 
					 | 
				
			||||||
        index->cx_index, nullptr, args.data(), (int)args.size(),
 | 
					 | 
				
			||||||
        unsaved_files.data(), (unsigned)unsaved_files.size(), flags, &cx_tu);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (error_code != CXError_Success && cx_tu)
 | 
					 | 
				
			||||||
    EmitDiagnostics(filepath, args, cx_tu);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // We sometimes dump the command to logs and ask the user to run it. Include
 | 
					 | 
				
			||||||
  // -fsyntax-only so they don't do a full compile.
 | 
					 | 
				
			||||||
  auto make_msg = [&]() {
 | 
					 | 
				
			||||||
    return "Please try running the following, identify which flag causes the "
 | 
					 | 
				
			||||||
           "issue, and report a bug. ccls will then filter the flag for you "
 | 
					 | 
				
			||||||
           " automatically:\n " +
 | 
					 | 
				
			||||||
           StringJoin(args, " ") + " -fsyntax-only";
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (error_code) {
 | 
					 | 
				
			||||||
    case CXError_Success:
 | 
					 | 
				
			||||||
      return std::make_unique<ClangTranslationUnit>(cx_tu);
 | 
					 | 
				
			||||||
    case CXError_Failure:
 | 
					 | 
				
			||||||
      LOG_S(ERROR) << "libclang generic failure for " << filepath << ". "
 | 
					 | 
				
			||||||
                   << make_msg();
 | 
					 | 
				
			||||||
      return nullptr;
 | 
					 | 
				
			||||||
    case CXError_Crashed:
 | 
					 | 
				
			||||||
      LOG_S(ERROR) << "libclang crashed for " << filepath << ". " << make_msg();
 | 
					 | 
				
			||||||
      return nullptr;
 | 
					 | 
				
			||||||
    case CXError_InvalidArguments:
 | 
					 | 
				
			||||||
      LOG_S(ERROR) << "libclang had invalid arguments for " << filepath << ". "
 | 
					 | 
				
			||||||
                   << make_msg();
 | 
					 | 
				
			||||||
      return nullptr;
 | 
					 | 
				
			||||||
    case CXError_ASTReadError:
 | 
					 | 
				
			||||||
      LOG_S(ERROR) << "libclang had ast read error for " << filepath << ". "
 | 
					 | 
				
			||||||
                   << make_msg();
 | 
					 | 
				
			||||||
      return nullptr;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return nullptr;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// static
 | 
					 | 
				
			||||||
std::unique_ptr<ClangTranslationUnit> ClangTranslationUnit::Reparse(
 | 
					 | 
				
			||||||
    std::unique_ptr<ClangTranslationUnit> tu,
 | 
					 | 
				
			||||||
    std::vector<CXUnsavedFile>& unsaved) {
 | 
					 | 
				
			||||||
  int error_code;
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    error_code = clang_reparseTranslationUnit(
 | 
					 | 
				
			||||||
        tu->cx_tu, (unsigned)unsaved.size(), unsaved.data(),
 | 
					 | 
				
			||||||
        clang_defaultReparseOptions(tu->cx_tu));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (error_code != CXError_Success && tu->cx_tu)
 | 
					 | 
				
			||||||
    EmitDiagnostics("<unknown>", {}, tu->cx_tu);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (error_code) {
 | 
					 | 
				
			||||||
    case CXError_Success:
 | 
					 | 
				
			||||||
      return tu;
 | 
					 | 
				
			||||||
    case CXError_Failure:
 | 
					 | 
				
			||||||
      LOG_S(ERROR) << "libclang reparse generic failure";
 | 
					 | 
				
			||||||
      return nullptr;
 | 
					 | 
				
			||||||
    case CXError_Crashed:
 | 
					 | 
				
			||||||
      LOG_S(ERROR) << "libclang reparse crashed";
 | 
					 | 
				
			||||||
      return nullptr;
 | 
					 | 
				
			||||||
    case CXError_InvalidArguments:
 | 
					 | 
				
			||||||
      LOG_S(ERROR) << "libclang reparse had invalid arguments";
 | 
					 | 
				
			||||||
      return nullptr;
 | 
					 | 
				
			||||||
    case CXError_ASTReadError:
 | 
					 | 
				
			||||||
      LOG_S(ERROR) << "libclang reparse had ast read error";
 | 
					 | 
				
			||||||
      return nullptr;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return nullptr;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ClangTranslationUnit::ClangTranslationUnit(CXTranslationUnit tu) : cx_tu(tu) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ClangTranslationUnit::~ClangTranslationUnit() {
 | 
					 | 
				
			||||||
  clang_disposeTranslationUnit(cx_tu);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,30 +0,0 @@
 | 
				
			|||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "clang_cursor.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <clang-c/Index.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// RAII wrapper around CXTranslationUnit which also makes it much more
 | 
					 | 
				
			||||||
// challenging to use a CXTranslationUnit instance that is not correctly
 | 
					 | 
				
			||||||
// initialized.
 | 
					 | 
				
			||||||
struct ClangTranslationUnit {
 | 
					 | 
				
			||||||
  static std::unique_ptr<ClangTranslationUnit> Create(
 | 
					 | 
				
			||||||
      ClangIndex* index,
 | 
					 | 
				
			||||||
      const std::string& filepath,
 | 
					 | 
				
			||||||
      const std::vector<std::string>& arguments,
 | 
					 | 
				
			||||||
      std::vector<CXUnsavedFile>& unsaved_files,
 | 
					 | 
				
			||||||
      unsigned flags);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  static std::unique_ptr<ClangTranslationUnit> Reparse(
 | 
					 | 
				
			||||||
      std::unique_ptr<ClangTranslationUnit> tu,
 | 
					 | 
				
			||||||
      std::vector<CXUnsavedFile>& unsaved);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  explicit ClangTranslationUnit(CXTranslationUnit tu);
 | 
					 | 
				
			||||||
  ~ClangTranslationUnit();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  CXTranslationUnit cx_tu;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@ -1,12 +1,70 @@
 | 
				
			|||||||
#include "clang_cursor.h"
 | 
					#include "clang_tu.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "clang_utils.h"
 | 
					#include "clang_utils.h"
 | 
				
			||||||
 | 
					#include "log.hh"
 | 
				
			||||||
 | 
					#include "platform.h"
 | 
				
			||||||
 | 
					#include "utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <mutex>
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EmitDiagnostics(std::string path,
 | 
				
			||||||
 | 
					                     std::vector<const char*> args,
 | 
				
			||||||
 | 
					                     CXTranslationUnit tu) {
 | 
				
			||||||
 | 
					  std::string output = "Fatal errors while trying to parse " + path + "\n";
 | 
				
			||||||
 | 
					  output +=
 | 
				
			||||||
 | 
					      "Args: " +
 | 
				
			||||||
 | 
					      StringJoinMap(args, [](const char* arg) { return std::string(arg); }) +
 | 
				
			||||||
 | 
					      "\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  size_t num_diagnostics = clang_getNumDiagnostics(tu);
 | 
				
			||||||
 | 
					  for (unsigned i = 0; i < num_diagnostics; ++i) {
 | 
				
			||||||
 | 
					    output += "  - ";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CXDiagnostic diagnostic = clang_getDiagnostic(tu, i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Location.
 | 
				
			||||||
 | 
					    CXFile file;
 | 
				
			||||||
 | 
					    unsigned int line, column;
 | 
				
			||||||
 | 
					    clang_getSpellingLocation(clang_getDiagnosticLocation(diagnostic), &file,
 | 
				
			||||||
 | 
					                              &line, &column, nullptr);
 | 
				
			||||||
 | 
					    std::string path = FileName(file);
 | 
				
			||||||
 | 
					    output += path + ":" + std::to_string(line - 1) + ":" +
 | 
				
			||||||
 | 
					              std::to_string(column) + " ";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Severity
 | 
				
			||||||
 | 
					    switch (clang_getDiagnosticSeverity(diagnostic)) {
 | 
				
			||||||
 | 
					      case CXDiagnostic_Ignored:
 | 
				
			||||||
 | 
					      case CXDiagnostic_Note:
 | 
				
			||||||
 | 
					        output += "[info]";
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case CXDiagnostic_Warning:
 | 
				
			||||||
 | 
					        output += "[warning]";
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case CXDiagnostic_Error:
 | 
				
			||||||
 | 
					        output += "[error]";
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case CXDiagnostic_Fatal:
 | 
				
			||||||
 | 
					        output += "[fatal]";
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Content.
 | 
				
			||||||
 | 
					    output += " " + ToString(clang_getDiagnosticSpelling(diagnostic));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    clang_disposeDiagnostic(diagnostic);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    output += "\n";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LOG_S(WARNING) << output;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}  // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Range ResolveCXSourceRange(const CXSourceRange& range, CXFile* cx_file) {
 | 
					Range ResolveCXSourceRange(const CXSourceRange& range, CXFile* cx_file) {
 | 
				
			||||||
  CXSourceLocation start = clang_getRangeStart(range);
 | 
					  CXSourceLocation start = clang_getRangeStart(range);
 | 
				
			||||||
  CXSourceLocation end = clang_getRangeEnd(range);
 | 
					  CXSourceLocation end = clang_getRangeEnd(range);
 | 
				
			||||||
@ -284,3 +342,97 @@ ClangIndex::ClangIndex(int exclude_declarations_from_pch,
 | 
				
			|||||||
ClangIndex::~ClangIndex() {
 | 
					ClangIndex::~ClangIndex() {
 | 
				
			||||||
  clang_disposeIndex(cx_index);
 | 
					  clang_disposeIndex(cx_index);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					std::unique_ptr<ClangTranslationUnit> ClangTranslationUnit::Create(
 | 
				
			||||||
 | 
					    ClangIndex* index,
 | 
				
			||||||
 | 
					    const std::string& filepath,
 | 
				
			||||||
 | 
					    const std::vector<std::string>& arguments,
 | 
				
			||||||
 | 
					    std::vector<CXUnsavedFile>& unsaved_files,
 | 
				
			||||||
 | 
					    unsigned flags) {
 | 
				
			||||||
 | 
					  std::vector<const char*> args;
 | 
				
			||||||
 | 
					  for (auto& arg : arguments)
 | 
				
			||||||
 | 
					    args.push_back(arg.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  CXTranslationUnit cx_tu;
 | 
				
			||||||
 | 
					  CXErrorCode error_code;
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    error_code = clang_parseTranslationUnit2FullArgv(
 | 
				
			||||||
 | 
					        index->cx_index, nullptr, args.data(), (int)args.size(),
 | 
				
			||||||
 | 
					        unsaved_files.data(), (unsigned)unsaved_files.size(), flags, &cx_tu);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (error_code != CXError_Success && cx_tu)
 | 
				
			||||||
 | 
					    EmitDiagnostics(filepath, args, cx_tu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // We sometimes dump the command to logs and ask the user to run it. Include
 | 
				
			||||||
 | 
					  // -fsyntax-only so they don't do a full compile.
 | 
				
			||||||
 | 
					  auto make_msg = [&]() {
 | 
				
			||||||
 | 
					    return "Please try running the following, identify which flag causes the "
 | 
				
			||||||
 | 
					           "issue, and report a bug. ccls will then filter the flag for you "
 | 
				
			||||||
 | 
					           " automatically:\n " +
 | 
				
			||||||
 | 
					           StringJoin(args, " ") + " -fsyntax-only";
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  switch (error_code) {
 | 
				
			||||||
 | 
					    case CXError_Success:
 | 
				
			||||||
 | 
					      return std::make_unique<ClangTranslationUnit>(cx_tu);
 | 
				
			||||||
 | 
					    case CXError_Failure:
 | 
				
			||||||
 | 
					      LOG_S(ERROR) << "libclang generic failure for " << filepath << ". "
 | 
				
			||||||
 | 
					                   << make_msg();
 | 
				
			||||||
 | 
					      return nullptr;
 | 
				
			||||||
 | 
					    case CXError_Crashed:
 | 
				
			||||||
 | 
					      LOG_S(ERROR) << "libclang crashed for " << filepath << ". " << make_msg();
 | 
				
			||||||
 | 
					      return nullptr;
 | 
				
			||||||
 | 
					    case CXError_InvalidArguments:
 | 
				
			||||||
 | 
					      LOG_S(ERROR) << "libclang had invalid arguments for " << filepath << ". "
 | 
				
			||||||
 | 
					                   << make_msg();
 | 
				
			||||||
 | 
					      return nullptr;
 | 
				
			||||||
 | 
					    case CXError_ASTReadError:
 | 
				
			||||||
 | 
					      LOG_S(ERROR) << "libclang had ast read error for " << filepath << ". "
 | 
				
			||||||
 | 
					                   << make_msg();
 | 
				
			||||||
 | 
					      return nullptr;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					std::unique_ptr<ClangTranslationUnit> ClangTranslationUnit::Reparse(
 | 
				
			||||||
 | 
					    std::unique_ptr<ClangTranslationUnit> tu,
 | 
				
			||||||
 | 
					    std::vector<CXUnsavedFile>& unsaved) {
 | 
				
			||||||
 | 
					  int error_code;
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    error_code = clang_reparseTranslationUnit(
 | 
				
			||||||
 | 
					        tu->cx_tu, (unsigned)unsaved.size(), unsaved.data(),
 | 
				
			||||||
 | 
					        clang_defaultReparseOptions(tu->cx_tu));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (error_code != CXError_Success && tu->cx_tu)
 | 
				
			||||||
 | 
					    EmitDiagnostics("<unknown>", {}, tu->cx_tu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  switch (error_code) {
 | 
				
			||||||
 | 
					    case CXError_Success:
 | 
				
			||||||
 | 
					      return tu;
 | 
				
			||||||
 | 
					    case CXError_Failure:
 | 
				
			||||||
 | 
					      LOG_S(ERROR) << "libclang reparse generic failure";
 | 
				
			||||||
 | 
					      return nullptr;
 | 
				
			||||||
 | 
					    case CXError_Crashed:
 | 
				
			||||||
 | 
					      LOG_S(ERROR) << "libclang reparse crashed";
 | 
				
			||||||
 | 
					      return nullptr;
 | 
				
			||||||
 | 
					    case CXError_InvalidArguments:
 | 
				
			||||||
 | 
					      LOG_S(ERROR) << "libclang reparse had invalid arguments";
 | 
				
			||||||
 | 
					      return nullptr;
 | 
				
			||||||
 | 
					    case CXError_ASTReadError:
 | 
				
			||||||
 | 
					      LOG_S(ERROR) << "libclang reparse had ast read error";
 | 
				
			||||||
 | 
					      return nullptr;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ClangTranslationUnit::ClangTranslationUnit(CXTranslationUnit tu) : cx_tu(tu) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ClangTranslationUnit::~ClangTranslationUnit() {
 | 
				
			||||||
 | 
					  clang_disposeTranslationUnit(cx_tu);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,12 +1,10 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "nt_string.h"
 | 
					#include "nt_string.h"
 | 
				
			||||||
#include "position.h"
 | 
					#include "position.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <clang-c/Index.h>
 | 
					#include <clang-c/Index.h>
 | 
				
			||||||
#include <optional>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <array>
 | 
					#include <memory>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -119,3 +117,24 @@ class ClangIndex {
 | 
				
			|||||||
  ~ClangIndex();
 | 
					  ~ClangIndex();
 | 
				
			||||||
  CXIndex cx_index;
 | 
					  CXIndex cx_index;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RAII wrapper around CXTranslationUnit which also makes it much more
 | 
				
			||||||
 | 
					// challenging to use a CXTranslationUnit instance that is not correctly
 | 
				
			||||||
 | 
					// initialized.
 | 
				
			||||||
 | 
					struct ClangTranslationUnit {
 | 
				
			||||||
 | 
					  static std::unique_ptr<ClangTranslationUnit> Create(
 | 
				
			||||||
 | 
					      ClangIndex* index,
 | 
				
			||||||
 | 
					      const std::string& filepath,
 | 
				
			||||||
 | 
					      const std::vector<std::string>& arguments,
 | 
				
			||||||
 | 
					      std::vector<CXUnsavedFile>& unsaved_files,
 | 
				
			||||||
 | 
					      unsigned flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static std::unique_ptr<ClangTranslationUnit> Reparse(
 | 
				
			||||||
 | 
					      std::unique_ptr<ClangTranslationUnit> tu,
 | 
				
			||||||
 | 
					      std::vector<CXUnsavedFile>& unsaved);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  explicit ClangTranslationUnit(CXTranslationUnit tu);
 | 
				
			||||||
 | 
					  ~ClangTranslationUnit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  CXTranslationUnit cx_tu;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "diagnostics_engine.h"
 | 
					#include "diagnostics_engine.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <chrono>
 | 
					#include <chrono>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -30,6 +31,6 @@ void DiagnosticsEngine::Publish(WorkingFiles* working_files,
 | 
				
			|||||||
    Out_TextDocumentPublishDiagnostics out;
 | 
					    Out_TextDocumentPublishDiagnostics out;
 | 
				
			||||||
    out.params.uri = lsDocumentUri::FromPath(path);
 | 
					    out.params.uri = lsDocumentUri::FromPath(path);
 | 
				
			||||||
    out.params.diagnostics = diagnostics;
 | 
					    out.params.diagnostics = diagnostics;
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType_TextDocumentPublishDiagnostics, out);
 | 
					    pipeline::WriteStdout(kMethodType_TextDocumentPublishDiagnostics, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -107,7 +107,7 @@ void IncludeComplete::Rescan() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  is_scanning = true;
 | 
					  is_scanning = true;
 | 
				
			||||||
  std::thread([this]() {
 | 
					  std::thread([this]() {
 | 
				
			||||||
    set_thread_name("scan_includes");
 | 
					    set_thread_name("include");
 | 
				
			||||||
    Timer timer;
 | 
					    Timer timer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (const std::string& dir : project_->quote_include_directories)
 | 
					    for (const std::string& dir : project_->quote_include_directories)
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,5 @@
 | 
				
			|||||||
#include "indexer.h"
 | 
					#include "indexer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "clang_cursor.h"
 | 
					 | 
				
			||||||
#include "clang_utils.h"
 | 
					 | 
				
			||||||
#include "log.hh"
 | 
					#include "log.hh"
 | 
				
			||||||
#include "platform.h"
 | 
					#include "platform.h"
 | 
				
			||||||
#include "serializer.h"
 | 
					#include "serializer.h"
 | 
				
			||||||
@ -1,7 +1,6 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "clang_cursor.h"
 | 
					#include "clang_tu.h"
 | 
				
			||||||
#include "clang_translation_unit.h"
 | 
					 | 
				
			||||||
#include "clang_utils.h"
 | 
					#include "clang_utils.h"
 | 
				
			||||||
#include "file_consumer.h"
 | 
					#include "file_consumer.h"
 | 
				
			||||||
#include "language.h"
 | 
					#include "language.h"
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										10
									
								
								src/main.cc
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/main.cc
									
									
									
									
									
								
							@ -5,6 +5,7 @@
 | 
				
			|||||||
#include "serializers/json.h"
 | 
					#include "serializers/json.h"
 | 
				
			||||||
#include "test.h"
 | 
					#include "test.h"
 | 
				
			||||||
#include "working_files.h"
 | 
					#include "working_files.h"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <llvm/Support/CommandLine.h>
 | 
					#include <llvm/Support/CommandLine.h>
 | 
				
			||||||
#include <llvm/Support/Process.h>
 | 
					#include <llvm/Support/Process.h>
 | 
				
			||||||
@ -56,8 +57,7 @@ int main(int argc, char** argv) {
 | 
				
			|||||||
      return 0;
 | 
					      return 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  MultiQueueWaiter querydb_waiter, indexer_waiter, stdout_waiter;
 | 
					  pipeline::Init();
 | 
				
			||||||
  QueueManager::Init(&querydb_waiter, &indexer_waiter, &stdout_waiter);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
  // We need to write to stdout in binary mode because in Windows, writing
 | 
					  // We need to write to stdout in binary mode because in Windows, writing
 | 
				
			||||||
@ -132,11 +132,11 @@ int main(int argc, char** argv) {
 | 
				
			|||||||
    std::unordered_map<MethodType, Timer> request_times;
 | 
					    std::unordered_map<MethodType, Timer> request_times;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 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.
 | 
				
			||||||
    LaunchStdinLoop(&request_times);
 | 
					    pipeline::LaunchStdin(&request_times);
 | 
				
			||||||
    // The thread that writes responses from the main thread to stdout.
 | 
					    // The thread that writes responses from the main thread to stdout.
 | 
				
			||||||
    LaunchStdoutThread(&request_times, &stdout_waiter);
 | 
					    pipeline::LaunchStdout(&request_times);
 | 
				
			||||||
    // Main thread which also spawns indexer threads upon the "initialize" request.
 | 
					    // Main thread which also spawns indexer threads upon the "initialize" request.
 | 
				
			||||||
    MainLoop(&querydb_waiter, &indexer_waiter);
 | 
					    pipeline::MainLoop();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return 0;
 | 
					  return 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,8 @@
 | 
				
			|||||||
#include "match.h"
 | 
					#include "match.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "lsp.h"
 | 
					#include "lsp.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <doctest/doctest.h>
 | 
					#include <doctest/doctest.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -32,7 +33,7 @@ std::optional<Matcher> Matcher::Create(const std::string& search) {
 | 
				
			|||||||
    out.params.type = lsMessageType::Error;
 | 
					    out.params.type = lsMessageType::Error;
 | 
				
			||||||
    out.params.message = "ccls: Parsing EMCAScript regex \"" + search +
 | 
					    out.params.message = "ccls: Parsing EMCAScript regex \"" + search +
 | 
				
			||||||
                         "\" failed; " + e.what();
 | 
					                         "\" failed; " + e.what();
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType_Unknown, out);
 | 
					    pipeline::WriteStdout(kMethodType_Unknown, out);
 | 
				
			||||||
    return std::nullopt;
 | 
					    return std::nullopt;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,8 @@
 | 
				
			|||||||
#include "log.hh"
 | 
					#include "log.hh"
 | 
				
			||||||
#include "project.h"
 | 
					#include "project.h"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -167,7 +168,7 @@ bool FindFileOrFail(QueryDatabase* db,
 | 
				
			|||||||
      out.error.code = lsErrorCodes::InternalError;
 | 
					      out.error.code = lsErrorCodes::InternalError;
 | 
				
			||||||
      out.error.message = "Unable to find file " + absolute_path;
 | 
					      out.error.message = "Unable to find file " + absolute_path;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType_Unknown, out);
 | 
					    pipeline::WriteStdout(kMethodType_Unknown, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return false;
 | 
					  return false;
 | 
				
			||||||
@ -182,7 +183,7 @@ void EmitInactiveLines(WorkingFile* working_file,
 | 
				
			|||||||
    if (ls_skipped)
 | 
					    if (ls_skipped)
 | 
				
			||||||
      out.params.inactiveRegions.push_back(*ls_skipped);
 | 
					      out.params.inactiveRegions.push_back(*ls_skipped);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  QueueManager::WriteStdout(kMethodType_CclsPublishInactiveRegions, out);
 | 
					  pipeline::WriteStdout(kMethodType_CclsPublishInactiveRegions, out);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EmitSemanticHighlighting(QueryDatabase* db,
 | 
					void EmitSemanticHighlighting(QueryDatabase* db,
 | 
				
			||||||
@ -343,5 +344,5 @@ void EmitSemanticHighlighting(QueryDatabase* db,
 | 
				
			|||||||
  for (auto& entry : grouped_symbols)
 | 
					  for (auto& entry : grouped_symbols)
 | 
				
			||||||
    if (entry.second.ranges.size())
 | 
					    if (entry.second.ranges.size())
 | 
				
			||||||
      out.params.symbols.push_back(entry.second);
 | 
					      out.params.symbols.push_back(entry.second);
 | 
				
			||||||
  QueueManager::WriteStdout(kMethodType_CclsPublishSemanticHighlighting, out);
 | 
					  pipeline::WriteStdout(kMethodType_CclsPublishSemanticHighlighting, out);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -43,7 +44,7 @@ struct Handler_CclsBase : BaseMessageHandler<In_CclsBase> {
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_CclsBase);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_CclsBase);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,8 @@
 | 
				
			|||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <unordered_set>
 | 
					#include <unordered_set>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -225,7 +227,7 @@ struct Handler_CclsCallHierarchy
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_CclsCallHierarchy);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_CclsCallHierarchy);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
MethodType kMethodType = "$ccls/callers";
 | 
					MethodType kMethodType = "$ccls/callers";
 | 
				
			||||||
@ -39,7 +40,7 @@ struct Handler_CclsCallers : BaseMessageHandler<In_CclsCallers> {
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_CclsCallers);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_CclsCallers);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MAKE_REFLECT_STRUCT(QueryFile::Def,
 | 
					MAKE_REFLECT_STRUCT(QueryFile::Def,
 | 
				
			||||||
                    path,
 | 
					                    path,
 | 
				
			||||||
@ -49,7 +50,7 @@ struct Handler_CclsFileInfo : BaseMessageHandler<In_CclsFileInfo> {
 | 
				
			|||||||
    out.result.language = file->def->language;
 | 
					    out.result.language = file->def->language;
 | 
				
			||||||
    out.result.includes = file->def->includes;
 | 
					    out.result.includes = file->def->includes;
 | 
				
			||||||
    out.result.inactive_regions = file->def->inactive_regions;
 | 
					    out.result.inactive_regions = file->def->inactive_regions;
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_CclsFileInfo);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_CclsFileInfo);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,12 +1,11 @@
 | 
				
			|||||||
#include "cache_manager.h"
 | 
					 | 
				
			||||||
#include "match.h"
 | 
					#include "match.h"
 | 
				
			||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "pipeline.hh"
 | 
					 | 
				
			||||||
#include "platform.h"
 | 
					#include "platform.h"
 | 
				
			||||||
#include "project.h"
 | 
					#include "project.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "timer.h"
 | 
					#include "timer.h"
 | 
				
			||||||
#include "working_files.h"
 | 
					#include "working_files.h"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <queue>
 | 
					#include <queue>
 | 
				
			||||||
#include <unordered_set>
 | 
					#include <unordered_set>
 | 
				
			||||||
@ -79,7 +78,7 @@ struct Handler_CclsFreshenIndex : BaseMessageHandler<In_CclsFreshenIndex> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Send index requests for every file.
 | 
					    // Send index requests for every file.
 | 
				
			||||||
    project->Index(QueueManager::instance(), working_files, lsRequestId());
 | 
					    project->Index(working_files, lsRequestId());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_CclsFreshenIndex);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_CclsFreshenIndex);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <unordered_set>
 | 
					#include <unordered_set>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -95,7 +96,7 @@ bool ExpandHelper(MessageHandler* m,
 | 
				
			|||||||
  if (derived) {
 | 
					  if (derived) {
 | 
				
			||||||
    if (levels > 0) {
 | 
					    if (levels > 0) {
 | 
				
			||||||
      for (auto usr : entity.derived) {
 | 
					      for (auto usr : entity.derived) {
 | 
				
			||||||
        if (seen.insert(usr).second)
 | 
					        if (!seen.insert(usr).second)
 | 
				
			||||||
          continue;
 | 
					          continue;
 | 
				
			||||||
        Out_CclsInheritanceHierarchy::Entry entry1;
 | 
					        Out_CclsInheritanceHierarchy::Entry entry1;
 | 
				
			||||||
        entry1.id = std::to_string(usr);
 | 
					        entry1.id = std::to_string(usr);
 | 
				
			||||||
@ -110,7 +111,7 @@ bool ExpandHelper(MessageHandler* m,
 | 
				
			|||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    if (levels > 0) {
 | 
					    if (levels > 0) {
 | 
				
			||||||
      for (auto usr : def->bases) {
 | 
					      for (auto usr : def->bases) {
 | 
				
			||||||
        if (seen.insert(usr).second)
 | 
					        if (!seen.insert(usr).second)
 | 
				
			||||||
          continue;
 | 
					          continue;
 | 
				
			||||||
        Out_CclsInheritanceHierarchy::Entry entry1;
 | 
					        Out_CclsInheritanceHierarchy::Entry entry1;
 | 
				
			||||||
        entry1.id = std::to_string(usr);
 | 
					        entry1.id = std::to_string(usr);
 | 
				
			||||||
@ -180,17 +181,15 @@ struct Handler_CclsInheritanceHierarchy
 | 
				
			|||||||
      WorkingFile* wfile =
 | 
					      WorkingFile* wfile =
 | 
				
			||||||
          working_files->GetFileByFilename(file->def->path);
 | 
					          working_files->GetFileByFilename(file->def->path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      for (SymbolRef sym :
 | 
					      for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, params.position))
 | 
				
			||||||
           FindSymbolsAtLocation(wfile, file, params.position)) {
 | 
					 | 
				
			||||||
        if (sym.kind == SymbolKind::Func || sym.kind == SymbolKind::Type) {
 | 
					        if (sym.kind == SymbolKind::Func || sym.kind == SymbolKind::Type) {
 | 
				
			||||||
          out.result = BuildInitial(sym, params.derived, params.qualified,
 | 
					          out.result = BuildInitial(sym, params.derived, params.qualified,
 | 
				
			||||||
                                    params.levels);
 | 
					                                    params.levels);
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_CclsInheritanceHierarchy);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_CclsInheritanceHierarchy);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <unordered_set>
 | 
					#include <unordered_set>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -264,7 +265,7 @@ struct Handler_CclsMemberHierarchy
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_CclsMemberHierarchy);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_CclsMemberHierarchy);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <math.h>
 | 
					#include <math.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
@ -126,7 +127,7 @@ struct Handler_CclsRandom : BaseMessageHandler<In_CclsRandom> {
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_CclsRandom);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_CclsRandom);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
MethodType kMethodType = "$ccls/vars";
 | 
					MethodType kMethodType = "$ccls/vars";
 | 
				
			||||||
@ -48,7 +49,7 @@ struct Handler_CclsVars : BaseMessageHandler<In_CclsVars> {
 | 
				
			|||||||
          break;
 | 
					          break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_CclsVars);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_CclsVars);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,3 @@
 | 
				
			|||||||
#include "cache_manager.h"
 | 
					 | 
				
			||||||
#include "diagnostics_engine.h"
 | 
					#include "diagnostics_engine.h"
 | 
				
			||||||
#include "filesystem.hh"
 | 
					#include "filesystem.hh"
 | 
				
			||||||
#include "include_complete.h"
 | 
					#include "include_complete.h"
 | 
				
			||||||
@ -7,10 +6,10 @@
 | 
				
			|||||||
#include "pipeline.hh"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "platform.h"
 | 
					#include "platform.h"
 | 
				
			||||||
#include "project.h"
 | 
					#include "project.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					 | 
				
			||||||
#include "serializers/json.h"
 | 
					#include "serializers/json.h"
 | 
				
			||||||
#include "timer.h"
 | 
					#include "timer.h"
 | 
				
			||||||
#include "working_files.h"
 | 
					#include "working_files.h"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <llvm/ADT/Twine.h>
 | 
					#include <llvm/ADT/Twine.h>
 | 
				
			||||||
#include <llvm/Support/Threading.h>
 | 
					#include <llvm/Support/Threading.h>
 | 
				
			||||||
@ -482,7 +481,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
 | 
				
			|||||||
    Out_InitializeResponse out;
 | 
					    Out_InitializeResponse out;
 | 
				
			||||||
    out.id = request->id;
 | 
					    out.id = request->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Set project root.
 | 
					    // Set project root.
 | 
				
			||||||
    EnsureEndsInSlash(project_path);
 | 
					    EnsureEndsInSlash(project_path);
 | 
				
			||||||
@ -515,7 +514,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
 | 
				
			|||||||
        g_thread_id = i + 1;
 | 
					        g_thread_id = i + 1;
 | 
				
			||||||
        std::string name = "indexer" + std::to_string(i);
 | 
					        std::string name = "indexer" + std::to_string(i);
 | 
				
			||||||
        set_thread_name(name.c_str());
 | 
					        set_thread_name(name.c_str());
 | 
				
			||||||
        Indexer_Main(diag_engine, vfs, project, working_files, waiter);
 | 
					        pipeline::Indexer_Main(diag_engine, vfs, project, working_files);
 | 
				
			||||||
      }).detach();
 | 
					      }).detach();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -524,7 +523,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
 | 
				
			|||||||
    include_complete->Rescan();
 | 
					    include_complete->Rescan();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    time.Reset();
 | 
					    time.Reset();
 | 
				
			||||||
    project->Index(QueueManager::instance(), working_files, request->id);
 | 
					    project->Index(working_files, request->id);
 | 
				
			||||||
    // We need to support multiple concurrent index processes.
 | 
					    // We need to support multiple concurrent index processes.
 | 
				
			||||||
    time.ResetAndPrint("[perf] Dispatched initial index requests");
 | 
					    time.ResetAndPrint("[perf] Dispatched initial index requests");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
MethodType kMethodType = "shutdown";
 | 
					MethodType kMethodType = "shutdown";
 | 
				
			||||||
@ -21,7 +22,7 @@ struct Handler_Shutdown : BaseMessageHandler<In_Shutdown> {
 | 
				
			|||||||
  void Run(In_Shutdown* request) override {
 | 
					  void Run(In_Shutdown* request) override {
 | 
				
			||||||
    Out_Shutdown out;
 | 
					    Out_Shutdown out;
 | 
				
			||||||
    out.id = request->id;
 | 
					    out.id = request->id;
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_Shutdown);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_Shutdown);
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,8 @@
 | 
				
			|||||||
#include "lsp_code_action.h"
 | 
					#include "lsp_code_action.h"
 | 
				
			||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
MethodType kMethodType = "textDocument/codeLens";
 | 
					MethodType kMethodType = "textDocument/codeLens";
 | 
				
			||||||
@ -225,7 +226,7 @@ struct Handler_TextDocumentCodeLens
 | 
				
			|||||||
      };
 | 
					      };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeLens);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeLens);
 | 
				
			||||||
 | 
				
			|||||||
@ -2,9 +2,10 @@
 | 
				
			|||||||
#include "fuzzy_match.h"
 | 
					#include "fuzzy_match.h"
 | 
				
			||||||
#include "include_complete.h"
 | 
					#include "include_complete.h"
 | 
				
			||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "timer.h"
 | 
					#include "timer.h"
 | 
				
			||||||
#include "working_files.h"
 | 
					#include "working_files.h"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "lex_utils.h"
 | 
					#include "lex_utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -270,7 +271,7 @@ struct Handler_TextDocumentCompletion : MessageHandler {
 | 
				
			|||||||
    auto write_empty_result = [request]() {
 | 
					    auto write_empty_result = [request]() {
 | 
				
			||||||
      Out_TextDocumentComplete out;
 | 
					      Out_TextDocumentComplete out;
 | 
				
			||||||
      out.id = request->id;
 | 
					      out.id = request->id;
 | 
				
			||||||
      QueueManager::WriteStdout(kMethodType, out);
 | 
					      pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string path = request->params.textDocument.uri.GetPath();
 | 
					    std::string path = request->params.textDocument.uri.GetPath();
 | 
				
			||||||
@ -377,7 +378,7 @@ struct Handler_TextDocumentCompletion : MessageHandler {
 | 
				
			|||||||
        item.textEdit->range.end.character = (int)buffer_line.size();
 | 
					        item.textEdit->range.end.character = (int)buffer_line.size();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      QueueManager::WriteStdout(kMethodType, out);
 | 
					      pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      ClangCompleteManager::OnComplete callback = std::bind(
 | 
					      ClangCompleteManager::OnComplete callback = std::bind(
 | 
				
			||||||
          [this, request, is_global_completion, existing_completion,
 | 
					          [this, request, is_global_completion, existing_completion,
 | 
				
			||||||
@ -389,7 +390,7 @@ struct Handler_TextDocumentCompletion : MessageHandler {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            // Emit completion results.
 | 
					            // Emit completion results.
 | 
				
			||||||
            FilterAndSortCompletionResponse(&out, existing_completion, has_open_paren);
 | 
					            FilterAndSortCompletionResponse(&out, existing_completion, has_open_paren);
 | 
				
			||||||
            QueueManager::WriteStdout(kMethodType, out);
 | 
					            pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Cache completion results.
 | 
					            // Cache completion results.
 | 
				
			||||||
            if (!is_cached_result) {
 | 
					            if (!is_cached_result) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,8 @@
 | 
				
			|||||||
#include "lex_utils.h"
 | 
					#include "lex_utils.h"
 | 
				
			||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ctype.h>
 | 
					#include <ctype.h>
 | 
				
			||||||
#include <limits.h>
 | 
					#include <limits.h>
 | 
				
			||||||
@ -173,7 +174,7 @@ struct Handler_TextDocumentDefinition
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDefinition);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDefinition);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
#include "cache_manager.h"
 | 
					 | 
				
			||||||
#include "clang_complete.h"
 | 
					#include "clang_complete.h"
 | 
				
			||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "project.h"
 | 
					#include "project.h"
 | 
				
			||||||
#include "working_files.h"
 | 
					#include "working_files.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
MethodType kMethodType = "textDocument/didChange";
 | 
					MethodType kMethodType = "textDocument/didChange";
 | 
				
			||||||
@ -25,9 +25,7 @@ struct Handler_TextDocumentDidChange
 | 
				
			|||||||
    working_files->OnChange(request->params);
 | 
					    working_files->OnChange(request->params);
 | 
				
			||||||
    if (g_config->index.onDidChange) {
 | 
					    if (g_config->index.onDidChange) {
 | 
				
			||||||
      Project::Entry entry = project->FindCompilationEntryForFile(path);
 | 
					      Project::Entry entry = project->FindCompilationEntryForFile(path);
 | 
				
			||||||
      QueueManager::instance()->index_request.PushBack(
 | 
					      pipeline::Index(entry.filename, entry.args, true);
 | 
				
			||||||
          Index_Request(entry.filename, entry.args, true /*is_interactive*/),
 | 
					 | 
				
			||||||
          true);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    clang_complete->NotifyEdit(path);
 | 
					    clang_complete->NotifyEdit(path);
 | 
				
			||||||
    clang_complete->DiagnosticsUpdate(
 | 
					    clang_complete->DiagnosticsUpdate(
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,8 @@
 | 
				
			|||||||
#include "clang_complete.h"
 | 
					#include "clang_complete.h"
 | 
				
			||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "working_files.h"
 | 
					#include "working_files.h"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
MethodType kMethodType = "textDocument/didClose";
 | 
					MethodType kMethodType = "textDocument/didClose";
 | 
				
			||||||
@ -27,7 +28,7 @@ struct Handler_TextDocumentDidClose
 | 
				
			|||||||
    // Clear any diagnostics for the file.
 | 
					    // Clear any diagnostics for the file.
 | 
				
			||||||
    Out_TextDocumentPublishDiagnostics out;
 | 
					    Out_TextDocumentPublishDiagnostics out;
 | 
				
			||||||
    out.params.uri = request->params.textDocument.uri;
 | 
					    out.params.uri = request->params.textDocument.uri;
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Remove internal state.
 | 
					    // Remove internal state.
 | 
				
			||||||
    working_files->OnClose(request->params.textDocument);
 | 
					    working_files->OnClose(request->params.textDocument);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
#include "cache_manager.h"
 | 
					 | 
				
			||||||
#include "clang_complete.h"
 | 
					#include "clang_complete.h"
 | 
				
			||||||
#include "include_complete.h"
 | 
					#include "include_complete.h"
 | 
				
			||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "project.h"
 | 
					#include "project.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
#include "timer.h"
 | 
					#include "timer.h"
 | 
				
			||||||
#include "working_files.h"
 | 
					#include "working_files.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -38,11 +38,9 @@ struct Handler_TextDocumentDidOpen
 | 
				
			|||||||
    const auto& params = request->params;
 | 
					    const auto& params = request->params;
 | 
				
			||||||
    std::string path = params.textDocument.uri.GetPath();
 | 
					    std::string path = params.textDocument.uri.GetPath();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ICacheManager cache;
 | 
					 | 
				
			||||||
    WorkingFile* working_file = working_files->OnOpen(params.textDocument);
 | 
					    WorkingFile* working_file = working_files->OnOpen(params.textDocument);
 | 
				
			||||||
    std::optional<std::string> cached_file_contents =
 | 
					    if (std::optional<std::string> cached_file_contents =
 | 
				
			||||||
        cache.LoadCachedFileContents(path);
 | 
					            pipeline::LoadCachedFileContents(path))
 | 
				
			||||||
    if (cached_file_contents)
 | 
					 | 
				
			||||||
      working_file->SetIndexContent(*cached_file_contents);
 | 
					      working_file->SetIndexContent(*cached_file_contents);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QueryFile* file = nullptr;
 | 
					    QueryFile* file = nullptr;
 | 
				
			||||||
@ -60,11 +58,8 @@ struct Handler_TextDocumentDidOpen
 | 
				
			|||||||
    // Submit new index request if it is not a header file.
 | 
					    // Submit new index request if it is not a header file.
 | 
				
			||||||
    if (SourceFileLanguage(path) != LanguageId::Unknown) {
 | 
					    if (SourceFileLanguage(path) != LanguageId::Unknown) {
 | 
				
			||||||
      Project::Entry entry = project->FindCompilationEntryForFile(path);
 | 
					      Project::Entry entry = project->FindCompilationEntryForFile(path);
 | 
				
			||||||
      QueueManager::instance()->index_request.PushBack(
 | 
					      pipeline::Index(entry.filename,
 | 
				
			||||||
          Index_Request(entry.filename,
 | 
					                      params.args.size() ? params.args : entry.args, true);
 | 
				
			||||||
                        params.args.size() ? params.args : entry.args,
 | 
					 | 
				
			||||||
                        true /*is_interactive*/),
 | 
					 | 
				
			||||||
          true /* priority */);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      clang_complete->FlushSession(entry.filename);
 | 
					      clang_complete->FlushSession(entry.filename);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
#include "cache_manager.h"
 | 
					 | 
				
			||||||
#include "clang_complete.h"
 | 
					#include "clang_complete.h"
 | 
				
			||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "project.h"
 | 
					#include "project.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
MethodType kMethodType = "textDocument/didSave";
 | 
					MethodType kMethodType = "textDocument/didSave";
 | 
				
			||||||
@ -29,7 +29,8 @@ struct Handler_TextDocumentDidSave
 | 
				
			|||||||
  MethodType GetMethodType() const override { return kMethodType; }
 | 
					  MethodType GetMethodType() const override { return kMethodType; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void Run(In_TextDocumentDidSave* request) override {
 | 
					  void Run(In_TextDocumentDidSave* request) override {
 | 
				
			||||||
    std::string path = request->params.textDocument.uri.GetPath();
 | 
					    const auto& params = request->params;
 | 
				
			||||||
 | 
					    std::string path = params.textDocument.uri.GetPath();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Send out an index request, and copy the current buffer state so we
 | 
					    // Send out an index request, and copy the current buffer state so we
 | 
				
			||||||
    // can update the cached index contents when the index is done.
 | 
					    // can update the cached index contents when the index is done.
 | 
				
			||||||
@ -47,9 +48,7 @@ struct Handler_TextDocumentDidSave
 | 
				
			|||||||
    // TODO: send as priority request
 | 
					    // TODO: send as priority request
 | 
				
			||||||
    if (!g_config->index.onDidChange) {
 | 
					    if (!g_config->index.onDidChange) {
 | 
				
			||||||
      Project::Entry entry = project->FindCompilationEntryForFile(path);
 | 
					      Project::Entry entry = project->FindCompilationEntryForFile(path);
 | 
				
			||||||
      QueueManager::instance()->index_request.PushBack(
 | 
					      pipeline::Index(entry.filename, entry.args, true);
 | 
				
			||||||
          Index_Request(entry.filename, entry.args, true /*is_interactive*/),
 | 
					 | 
				
			||||||
          true);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    clang_complete->NotifySave(path);
 | 
					    clang_complete->NotifySave(path);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,8 @@
 | 
				
			|||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					 | 
				
			||||||
#include "symbol.h"
 | 
					#include "symbol.h"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
MethodType kMethodType = "textDocument/documentHighlight";
 | 
					MethodType kMethodType = "textDocument/documentHighlight";
 | 
				
			||||||
@ -61,7 +62,7 @@ struct Handler_TextDocumentDocumentHighlight
 | 
				
			|||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentHighlight);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentHighlight);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
MethodType kMethodType = "textDocument/documentSymbol";
 | 
					MethodType kMethodType = "textDocument/documentSymbol";
 | 
				
			||||||
@ -64,7 +65,7 @@ struct Handler_TextDocumentDocumentSymbol
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentSymbol);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentSymbol);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
MethodType kMethodType = "textDocument/hover";
 | 
					MethodType kMethodType = "textDocument/hover";
 | 
				
			||||||
@ -99,7 +100,7 @@ struct Handler_TextDocumentHover : BaseMessageHandler<In_TextDocumentHover> {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentHover);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_TextDocumentHover);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
MethodType kMethodType = "textDocument/implementation";
 | 
					MethodType kMethodType = "textDocument/implementation";
 | 
				
			||||||
@ -41,7 +42,7 @@ struct Handler_TextDocumentImplementation
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentImplementation);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_TextDocumentImplementation);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,8 @@
 | 
				
			|||||||
#include "clang_format.h"
 | 
					#include "clang_format.h"
 | 
				
			||||||
#include "lex_utils.h"
 | 
					#include "lex_utils.h"
 | 
				
			||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
#include "working_files.h"
 | 
					#include "working_files.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <loguru.hpp>
 | 
					#include <loguru.hpp>
 | 
				
			||||||
@ -64,7 +65,7 @@ struct Handler_TextDocumentRangeFormatting
 | 
				
			|||||||
    response.result = {};
 | 
					    response.result = {};
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, response);
 | 
					    pipeline::WriteStdout(kMethodType, response);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentRangeFormatting);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_TextDocumentRangeFormatting);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <unordered_set>
 | 
					#include <unordered_set>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -135,7 +136,7 @@ struct Handler_TextDocumentReferences
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if ((int)out.result.size() >= g_config->xref.maxNum)
 | 
					    if ((int)out.result.size() >= g_config->xref.maxNum)
 | 
				
			||||||
      out.result.resize(g_config->xref.maxNum);
 | 
					      out.result.resize(g_config->xref.maxNum);
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentReferences);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_TextDocumentReferences);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
MethodType kMethodType = "textDocument/rename";
 | 
					MethodType kMethodType = "textDocument/rename";
 | 
				
			||||||
@ -102,7 +103,7 @@ struct Handler_TextDocumentRename : BaseMessageHandler<In_TextDocumentRename> {
 | 
				
			|||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentRename);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_TextDocumentRename);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "clang_complete.h"
 | 
					#include "clang_complete.h"
 | 
				
			||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
#include "timer.h"
 | 
					#include "timer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
@ -142,7 +143,7 @@ struct Handler_TextDocumentSignatureHelp : MessageHandler {
 | 
				
			|||||||
          out.result.activeParameter = active_param;
 | 
					          out.result.activeParameter = active_param;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          Timer timer;
 | 
					          Timer timer;
 | 
				
			||||||
          QueueManager::WriteStdout(kMethodType, out);
 | 
					          pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (!is_cached_result) {
 | 
					          if (!is_cached_result) {
 | 
				
			||||||
            signature_cache->WithLock([&]() {
 | 
					            signature_cache->WithLock([&]() {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
MethodType kMethodType = "textDocument/typeDefinition";
 | 
					MethodType kMethodType = "textDocument/typeDefinition";
 | 
				
			||||||
@ -60,7 +61,7 @@ struct Handler_TextDocumentTypeDefinition
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentTypeDefinition);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_TextDocumentTypeDefinition);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
#include "cache_manager.h"
 | 
					 | 
				
			||||||
#include "clang_complete.h"
 | 
					#include "clang_complete.h"
 | 
				
			||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "project.h"
 | 
					#include "project.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
#include "timer.h"
 | 
					#include "timer.h"
 | 
				
			||||||
#include "working_files.h"
 | 
					#include "working_files.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -31,7 +31,7 @@ struct Handler_WorkspaceDidChangeConfiguration
 | 
				
			|||||||
                       std::to_string(project->entries.size()) + " files)");
 | 
					                       std::to_string(project->entries.size()) + " files)");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    time.Reset();
 | 
					    time.Reset();
 | 
				
			||||||
    project->Index(QueueManager::instance(), working_files, lsRequestId());
 | 
					    project->Index(working_files, lsRequestId());
 | 
				
			||||||
    time.ResetAndPrint(
 | 
					    time.ResetAndPrint(
 | 
				
			||||||
        "[perf] Dispatched workspace/didChangeConfiguration index requests");
 | 
					        "[perf] Dispatched workspace/didChangeConfiguration index requests");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
#include "cache_manager.h"
 | 
					 | 
				
			||||||
#include "clang_complete.h"
 | 
					#include "clang_complete.h"
 | 
				
			||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "project.h"
 | 
					#include "project.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "working_files.h"
 | 
					#include "working_files.h"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
MethodType kMethodType = "workspace/didChangeWatchedFiles";
 | 
					MethodType kMethodType = "workspace/didChangeWatchedFiles";
 | 
				
			||||||
@ -52,15 +52,13 @@ struct Handler_WorkspaceDidChangeWatchedFiles
 | 
				
			|||||||
      switch (event.type) {
 | 
					      switch (event.type) {
 | 
				
			||||||
        case lsFileChangeType::Created:
 | 
					        case lsFileChangeType::Created:
 | 
				
			||||||
        case lsFileChangeType::Changed: {
 | 
					        case lsFileChangeType::Changed: {
 | 
				
			||||||
          QueueManager::instance()->index_request.PushBack(
 | 
					          pipeline::Index(path, entry.args, is_interactive);
 | 
				
			||||||
              Index_Request(path, entry.args, is_interactive));
 | 
					 | 
				
			||||||
          if (is_interactive)
 | 
					          if (is_interactive)
 | 
				
			||||||
            clang_complete->NotifySave(path);
 | 
					            clang_complete->NotifySave(path);
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        case lsFileChangeType::Deleted:
 | 
					        case lsFileChangeType::Deleted:
 | 
				
			||||||
          QueueManager::instance()->index_request.PushBack(
 | 
					          pipeline::Index(path, entry.args, is_interactive);
 | 
				
			||||||
              Index_Request(path, entry.args, is_interactive));
 | 
					 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,8 @@
 | 
				
			|||||||
#include "lsp_code_action.h"
 | 
					#include "lsp_code_action.h"
 | 
				
			||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
MethodType kMethodType = "workspace/executeCommand";
 | 
					MethodType kMethodType = "workspace/executeCommand";
 | 
				
			||||||
@ -34,7 +35,7 @@ struct Handler_WorkspaceExecuteCommand
 | 
				
			|||||||
      out.result = params.arguments.locations;
 | 
					      out.result = params.arguments.locations;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceExecuteCommand);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_WorkspaceExecuteCommand);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,9 @@
 | 
				
			|||||||
#include "fuzzy_match.h"
 | 
					#include "fuzzy_match.h"
 | 
				
			||||||
#include "lex_utils.h"
 | 
					#include "lex_utils.h"
 | 
				
			||||||
#include "message_handler.h"
 | 
					#include "message_handler.h"
 | 
				
			||||||
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ctype.h>
 | 
					#include <ctype.h>
 | 
				
			||||||
#include <limits.h>
 | 
					#include <limits.h>
 | 
				
			||||||
@ -124,7 +125,7 @@ struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
 | 
				
			|||||||
        out.result.push_back(std::get<0>(entry));
 | 
					        out.result.push_back(std::get<0>(entry));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, out);
 | 
					    pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceSymbol);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_WorkspaceSymbol);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										189
									
								
								src/pipeline.cc
									
									
									
									
									
								
							
							
						
						
									
										189
									
								
								src/pipeline.cc
									
									
									
									
									
								
							@ -1,6 +1,5 @@
 | 
				
			|||||||
#include "pipeline.hh"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "cache_manager.h"
 | 
					 | 
				
			||||||
#include "clang_complete.h"
 | 
					#include "clang_complete.h"
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
#include "diagnostics_engine.h"
 | 
					#include "diagnostics_engine.h"
 | 
				
			||||||
@ -11,18 +10,43 @@
 | 
				
			|||||||
#include "platform.h"
 | 
					#include "platform.h"
 | 
				
			||||||
#include "project.h"
 | 
					#include "project.h"
 | 
				
			||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "timer.h"
 | 
					#include "timer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <llvm/ADT/Twine.h>
 | 
					#include <llvm/ADT/Twine.h>
 | 
				
			||||||
#include <llvm/Support/Threading.h>
 | 
					#include <llvm/Support/Threading.h>
 | 
				
			||||||
using namespace llvm;
 | 
					using namespace llvm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <chrono>
 | 
					 | 
				
			||||||
#include <thread>
 | 
					#include <thread>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Index_Request {
 | 
				
			||||||
 | 
					  std::string path;
 | 
				
			||||||
 | 
					  std::vector<std::string> args;
 | 
				
			||||||
 | 
					  bool is_interactive;
 | 
				
			||||||
 | 
					  lsRequestId id;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Index_OnIndexed {
 | 
				
			||||||
 | 
					  IndexUpdate update;
 | 
				
			||||||
 | 
					  PerformanceImportFile perf;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Stdout_Request {
 | 
				
			||||||
 | 
					  MethodType method;
 | 
				
			||||||
 | 
					  std::string content;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ccls::pipeline {
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MultiQueueWaiter* main_waiter;
 | 
				
			||||||
 | 
					MultiQueueWaiter* indexer_waiter;
 | 
				
			||||||
 | 
					MultiQueueWaiter* stdout_waiter;
 | 
				
			||||||
 | 
					ThreadedQueue<std::unique_ptr<InMessage>>* on_request;
 | 
				
			||||||
 | 
					ThreadedQueue<Index_Request>* index_request;
 | 
				
			||||||
 | 
					ThreadedQueue<Index_OnIndexed>* on_indexed;
 | 
				
			||||||
 | 
					ThreadedQueue<Stdout_Request>* for_stdout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Checks if |path| needs to be reparsed. This will modify cached state
 | 
					// Checks if |path| needs to be reparsed. This will modify cached state
 | 
				
			||||||
// such that calling this function twice with the same path may return true
 | 
					// such that calling this function twice with the same path may return true
 | 
				
			||||||
// the first time but will return false the second.
 | 
					// the first time but will return false the second.
 | 
				
			||||||
@ -64,24 +88,57 @@ bool FileNeedsParse(int64_t write_time,
 | 
				
			|||||||
  return false;
 | 
					  return false;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string AppendSerializationFormat(const std::string& base) {
 | 
				
			||||||
 | 
					  switch (g_config->cacheFormat) {
 | 
				
			||||||
 | 
					    case SerializeFormat::Binary:
 | 
				
			||||||
 | 
					      return base + ".blob";
 | 
				
			||||||
 | 
					    case SerializeFormat::Json:
 | 
				
			||||||
 | 
					      return base + ".json";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string GetCachePath(const std::string& source_file) {
 | 
				
			||||||
 | 
					  std::string cache_file;
 | 
				
			||||||
 | 
					  size_t len = g_config->projectRoot.size();
 | 
				
			||||||
 | 
					  if (StartsWith(source_file, g_config->projectRoot)) {
 | 
				
			||||||
 | 
					    cache_file = EscapeFileName(g_config->projectRoot) +
 | 
				
			||||||
 | 
					                 EscapeFileName(source_file.substr(len));
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    cache_file = '@' + EscapeFileName(g_config->projectRoot) +
 | 
				
			||||||
 | 
					                 EscapeFileName(source_file);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return g_config->cacheDirectory + cache_file;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 =
 | 
				
			||||||
 | 
					      ReadContent(AppendSerializationFormat(cache_path));
 | 
				
			||||||
 | 
					  if (!file_content || !serialized_indexed_content)
 | 
				
			||||||
 | 
					    return nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return Deserialize(g_config->cacheFormat, path, *serialized_indexed_content,
 | 
				
			||||||
 | 
					                     *file_content, IndexFile::kMajorVersion);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Indexer_Parse(DiagnosticsEngine* diag_engine,
 | 
					bool Indexer_Parse(DiagnosticsEngine* diag_engine,
 | 
				
			||||||
                   WorkingFiles* working_files,
 | 
					                   WorkingFiles* working_files,
 | 
				
			||||||
                   Project* project,
 | 
					                   Project* project,
 | 
				
			||||||
                   VFS* vfs,
 | 
					                   VFS* vfs,
 | 
				
			||||||
                   ClangIndexer* indexer) {
 | 
					                   ClangIndexer* indexer) {
 | 
				
			||||||
  auto* queue = QueueManager::instance();
 | 
					  std::optional<Index_Request> opt_request = index_request->TryPopFront();
 | 
				
			||||||
  std::optional<Index_Request> opt_request = queue->index_request.TryPopFront();
 | 
					 | 
				
			||||||
  if (!opt_request)
 | 
					  if (!opt_request)
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  auto& request = *opt_request;
 | 
					  auto& request = *opt_request;
 | 
				
			||||||
  ICacheManager cache;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Dummy one to trigger refresh semantic highlight.
 | 
					  // Dummy one to trigger refresh semantic highlight.
 | 
				
			||||||
  if (request.path.empty()) {
 | 
					  if (request.path.empty()) {
 | 
				
			||||||
    IndexUpdate dummy;
 | 
					    IndexUpdate dummy;
 | 
				
			||||||
    dummy.refresh = true;
 | 
					    dummy.refresh = true;
 | 
				
			||||||
    queue->on_indexed.PushBack(
 | 
					    on_indexed->PushBack({std::move(dummy), PerformanceImportFile()}, false);
 | 
				
			||||||
        Index_OnIndexed(std::move(dummy), PerformanceImportFile()), false);
 | 
					 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -108,7 +165,7 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
 | 
				
			|||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int reparse; // request.is_interactive;
 | 
					  int reparse; // request.is_interactive;
 | 
				
			||||||
  prev = cache.RawCacheLoad(path_to_index);
 | 
					  prev = RawCacheLoad(path_to_index);
 | 
				
			||||||
  if (!prev)
 | 
					  if (!prev)
 | 
				
			||||||
    reparse = 2;
 | 
					    reparse = 2;
 | 
				
			||||||
  else {
 | 
					  else {
 | 
				
			||||||
@ -132,15 +189,13 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
 | 
				
			|||||||
    auto dependencies = prev->dependencies;
 | 
					    auto dependencies = prev->dependencies;
 | 
				
			||||||
    if (reparse) {
 | 
					    if (reparse) {
 | 
				
			||||||
      IndexUpdate update = IndexUpdate::CreateDelta(nullptr, prev.get());
 | 
					      IndexUpdate update = IndexUpdate::CreateDelta(nullptr, prev.get());
 | 
				
			||||||
      queue->on_indexed.PushBack(Index_OnIndexed(std::move(update), perf),
 | 
					      on_indexed->PushBack({std::move(update), perf}, request.is_interactive);
 | 
				
			||||||
        request.is_interactive);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    for (const auto& dep : dependencies)
 | 
					    for (const auto& dep : dependencies)
 | 
				
			||||||
      if (vfs->Mark(dep.first().str(), 0, 2)) {
 | 
					      if (vfs->Mark(dep.first().str(), 0, 2)) {
 | 
				
			||||||
        prev = cache.RawCacheLoad(dep.first().str());
 | 
					        prev = RawCacheLoad(dep.first().str());
 | 
				
			||||||
        IndexUpdate update = IndexUpdate::CreateDelta(nullptr, prev.get());
 | 
					        IndexUpdate update = IndexUpdate::CreateDelta(nullptr, prev.get());
 | 
				
			||||||
        queue->on_indexed.PushBack(Index_OnIndexed(std::move(update), perf),
 | 
					        on_indexed->PushBack({std::move(update), perf}, request.is_interactive);
 | 
				
			||||||
          request.is_interactive);
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::lock_guard<std::mutex> lock(vfs->mutex);
 | 
					    std::lock_guard<std::mutex> lock(vfs->mutex);
 | 
				
			||||||
@ -152,7 +207,6 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  LOG_S(INFO) << "parse " << path_to_index;
 | 
					  LOG_S(INFO) << "parse " << path_to_index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::vector<Index_OnIdMapped> result;
 | 
					 | 
				
			||||||
  PerformanceImportFile perf;
 | 
					  PerformanceImportFile perf;
 | 
				
			||||||
  auto indexes = indexer->Index(vfs, path_to_index, entry.args, {}, &perf);
 | 
					  auto indexes = indexer->Index(vfs, path_to_index, entry.args, {}, &perf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -162,7 +216,7 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
 | 
				
			|||||||
      out.id = request.id;
 | 
					      out.id = request.id;
 | 
				
			||||||
      out.error.code = lsErrorCodes::InternalError;
 | 
					      out.error.code = lsErrorCodes::InternalError;
 | 
				
			||||||
      out.error.message = "Failed to index " + path_to_index;
 | 
					      out.error.message = "Failed to index " + path_to_index;
 | 
				
			||||||
      QueueManager::WriteStdout(kMethodType_Unknown, out);
 | 
					      pipeline::WriteStdout(kMethodType_Unknown, out);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    vfs->Reset(path_to_index);
 | 
					    vfs->Reset(path_to_index);
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
@ -179,12 +233,17 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
 | 
				
			|||||||
    if (!(vfs->Stamp(path, curr->last_write_time) || path == path_to_index))
 | 
					    if (!(vfs->Stamp(path, curr->last_write_time) || path == path_to_index))
 | 
				
			||||||
      continue;
 | 
					      continue;
 | 
				
			||||||
    LOG_S(INFO) << "emit index for " << path;
 | 
					    LOG_S(INFO) << "emit index for " << path;
 | 
				
			||||||
    prev = cache.RawCacheLoad(path);
 | 
					    prev = RawCacheLoad(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Write current index to disk if requested.
 | 
					    // Write current index to disk if requested.
 | 
				
			||||||
    LOG_S(INFO) << "store index for " << path;
 | 
					    LOG_S(INFO) << "store index for " << path;
 | 
				
			||||||
    Timer time;
 | 
					    Timer time;
 | 
				
			||||||
    cache.WriteToCache(*curr);
 | 
					    {
 | 
				
			||||||
 | 
					      std::string cache_path = GetCachePath(path);
 | 
				
			||||||
 | 
					      WriteToFile(cache_path, curr->file_contents);
 | 
				
			||||||
 | 
					      WriteToFile(AppendSerializationFormat(cache_path),
 | 
				
			||||||
 | 
					                  Serialize(g_config->cacheFormat, *curr));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    perf.index_save_to_disk = time.ElapsedMicrosecondsAndReset();
 | 
					    perf.index_save_to_disk = time.ElapsedMicrosecondsAndReset();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vfs->Reset(path_to_index);
 | 
					    vfs->Reset(path_to_index);
 | 
				
			||||||
@ -199,8 +258,7 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
 | 
				
			|||||||
    perf.index_make_delta = time.ElapsedMicrosecondsAndReset();
 | 
					    perf.index_make_delta = time.ElapsedMicrosecondsAndReset();
 | 
				
			||||||
    LOG_S(INFO) << "built index for " << path << " (is_delta=" << !!prev << ")";
 | 
					    LOG_S(INFO) << "built index for " << path << " (is_delta=" << !!prev << ")";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Index_OnIndexed reply(std::move(update), perf);
 | 
					    on_indexed->PushBack({std::move(update), perf}, request.is_interactive);
 | 
				
			||||||
    queue->on_indexed.PushBack(std::move(reply), request.is_interactive);
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
@ -217,26 +275,34 @@ bool ShouldDisplayMethodTiming(MethodType type) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}  // namespace
 | 
					}  // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Init() {
 | 
				
			||||||
 | 
					  main_waiter = new MultiQueueWaiter;
 | 
				
			||||||
 | 
					  on_request = new ThreadedQueue<std::unique_ptr<InMessage>>(main_waiter);
 | 
				
			||||||
 | 
					  on_indexed = new ThreadedQueue<Index_OnIndexed>(main_waiter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  indexer_waiter = new MultiQueueWaiter;
 | 
				
			||||||
 | 
					  index_request = new ThreadedQueue<Index_Request>(indexer_waiter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  stdout_waiter = new MultiQueueWaiter;
 | 
				
			||||||
 | 
					  for_stdout = new ThreadedQueue<Stdout_Request>(stdout_waiter);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Indexer_Main(DiagnosticsEngine* diag_engine,
 | 
					void Indexer_Main(DiagnosticsEngine* diag_engine,
 | 
				
			||||||
                  VFS* vfs,
 | 
					                  VFS* vfs,
 | 
				
			||||||
                  Project* project,
 | 
					                  Project* project,
 | 
				
			||||||
                  WorkingFiles* working_files,
 | 
					                  WorkingFiles* working_files) {
 | 
				
			||||||
                  MultiQueueWaiter* waiter) {
 | 
					 | 
				
			||||||
  auto* queue = QueueManager::instance();
 | 
					 | 
				
			||||||
  // Build one index per-indexer, as building the index acquires a global lock.
 | 
					  // Build one index per-indexer, as building the index acquires a global lock.
 | 
				
			||||||
  ClangIndexer indexer;
 | 
					  ClangIndexer indexer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  while (true)
 | 
					  while (true)
 | 
				
			||||||
    if (!Indexer_Parse(diag_engine, working_files, project, vfs, &indexer))
 | 
					    if (!Indexer_Parse(diag_engine, working_files, project, vfs, &indexer))
 | 
				
			||||||
      waiter->Wait(&queue->index_request);
 | 
					      indexer_waiter->Wait(index_request);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void QueryDb_OnIndexed(QueueManager* queue,
 | 
					void Main_OnIndexed(QueryDatabase* db,
 | 
				
			||||||
                       QueryDatabase* db,
 | 
					                    SemanticHighlightSymbolCache* semantic_cache,
 | 
				
			||||||
                       SemanticHighlightSymbolCache* semantic_cache,
 | 
					                    WorkingFiles* working_files,
 | 
				
			||||||
                       WorkingFiles* working_files,
 | 
					                    Index_OnIndexed* response) {
 | 
				
			||||||
                       Index_OnIndexed* response) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (response->update.refresh) {
 | 
					  if (response->update.refresh) {
 | 
				
			||||||
    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);
 | 
					    std::lock_guard<std::mutex> lock(working_files->files_mutex);
 | 
				
			||||||
@ -257,9 +323,8 @@ void QueryDb_OnIndexed(QueueManager* queue,
 | 
				
			|||||||
  if (response->update.files_def_update) {
 | 
					  if (response->update.files_def_update) {
 | 
				
			||||||
    auto& update = *response->update.files_def_update;
 | 
					    auto& update = *response->update.files_def_update;
 | 
				
			||||||
    time.ResetAndPrint("apply index for " + update.value.path);
 | 
					    time.ResetAndPrint("apply index for " + update.value.path);
 | 
				
			||||||
    WorkingFile* working_file =
 | 
					    if (WorkingFile* working_file =
 | 
				
			||||||
        working_files->GetFileByFilename(update.value.path);
 | 
					            working_files->GetFileByFilename(update.value.path)) {
 | 
				
			||||||
    if (working_file) {
 | 
					 | 
				
			||||||
      // Update indexed content.
 | 
					      // Update indexed content.
 | 
				
			||||||
      working_file->SetIndexContent(update.file_content);
 | 
					      working_file->SetIndexContent(update.file_content);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -275,10 +340,9 @@ void QueryDb_OnIndexed(QueueManager* queue,
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) {
 | 
					void LaunchStdin(std::unordered_map<MethodType, Timer>* request_times) {
 | 
				
			||||||
  std::thread([request_times]() {
 | 
					  std::thread([request_times]() {
 | 
				
			||||||
    set_thread_name("stdin");
 | 
					    set_thread_name("stdin");
 | 
				
			||||||
    auto* queue = QueueManager::instance();
 | 
					 | 
				
			||||||
    while (true) {
 | 
					    while (true) {
 | 
				
			||||||
      std::unique_ptr<InMessage> message;
 | 
					      std::unique_ptr<InMessage> message;
 | 
				
			||||||
      std::optional<std::string> err =
 | 
					      std::optional<std::string> err =
 | 
				
			||||||
@ -295,7 +359,7 @@ void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) {
 | 
				
			|||||||
            out.id = id;
 | 
					            out.id = id;
 | 
				
			||||||
            out.error.code = lsErrorCodes::InvalidParams;
 | 
					            out.error.code = lsErrorCodes::InvalidParams;
 | 
				
			||||||
            out.error.message = std::move(*err);
 | 
					            out.error.message = std::move(*err);
 | 
				
			||||||
            queue->WriteStdout(kMethodType_Unknown, out);
 | 
					            WriteStdout(kMethodType_Unknown, out);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
@ -305,7 +369,7 @@ void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) {
 | 
				
			|||||||
      MethodType method_type = message->GetMethodType();
 | 
					      MethodType method_type = message->GetMethodType();
 | 
				
			||||||
      (*request_times)[method_type] = Timer();
 | 
					      (*request_times)[method_type] = Timer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      queue->for_querydb.PushBack(std::move(message));
 | 
					      on_request->PushBack(std::move(message));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // If the message was to exit then querydb will take care of the actual
 | 
					      // If the message was to exit then querydb will take care of the actual
 | 
				
			||||||
      // exit. Stop reading from stdin since it might be detached.
 | 
					      // exit. Stop reading from stdin since it might be detached.
 | 
				
			||||||
@ -315,16 +379,14 @@ void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) {
 | 
				
			|||||||
  }).detach();
 | 
					  }).detach();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void LaunchStdoutThread(std::unordered_map<MethodType, Timer>* request_times,
 | 
					void LaunchStdout(std::unordered_map<MethodType, Timer>* request_times) {
 | 
				
			||||||
                        MultiQueueWaiter* waiter) {
 | 
					 | 
				
			||||||
  std::thread([=]() {
 | 
					  std::thread([=]() {
 | 
				
			||||||
    set_thread_name("stdout");
 | 
					    set_thread_name("stdout");
 | 
				
			||||||
    auto* queue = QueueManager::instance();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (true) {
 | 
					    while (true) {
 | 
				
			||||||
      std::vector<Stdout_Request> messages = queue->for_stdout.DequeueAll();
 | 
					      std::vector<Stdout_Request> messages = for_stdout->DequeueAll();
 | 
				
			||||||
      if (messages.empty()) {
 | 
					      if (messages.empty()) {
 | 
				
			||||||
        waiter->Wait(&queue->for_stdout);
 | 
					        stdout_waiter->Wait(for_stdout);
 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -341,8 +403,7 @@ void LaunchStdoutThread(std::unordered_map<MethodType, Timer>* request_times,
 | 
				
			|||||||
  }).detach();
 | 
					  }).detach();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MainLoop(MultiQueueWaiter* querydb_waiter,
 | 
					void MainLoop() {
 | 
				
			||||||
              MultiQueueWaiter* indexer_waiter) {
 | 
					 | 
				
			||||||
  Project project;
 | 
					  Project project;
 | 
				
			||||||
  SemanticHighlightSymbolCache semantic_cache;
 | 
					  SemanticHighlightSymbolCache semantic_cache;
 | 
				
			||||||
  WorkingFiles working_files;
 | 
					  WorkingFiles working_files;
 | 
				
			||||||
@ -362,7 +423,7 @@ void MainLoop(MultiQueueWaiter* querydb_waiter,
 | 
				
			|||||||
          out.error.message =
 | 
					          out.error.message =
 | 
				
			||||||
              "Dropping completion request; a newer request "
 | 
					              "Dropping completion request; a newer request "
 | 
				
			||||||
              "has come in that will be serviced instead.";
 | 
					              "has come in that will be serviced instead.";
 | 
				
			||||||
          QueueManager::WriteStdout(kMethodType_Unknown, out);
 | 
					          pipeline::WriteStdout(kMethodType_Unknown, out);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -389,11 +450,8 @@ void MainLoop(MultiQueueWaiter* querydb_waiter,
 | 
				
			|||||||
    handler->signature_cache = signature_cache.get();
 | 
					    handler->signature_cache = signature_cache.get();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Run query db main loop.
 | 
					 | 
				
			||||||
  auto* queue = QueueManager::instance();
 | 
					 | 
				
			||||||
  while (true) {
 | 
					  while (true) {
 | 
				
			||||||
    std::vector<std::unique_ptr<InMessage>> messages =
 | 
					    std::vector<std::unique_ptr<InMessage>> messages = on_request->DequeueAll();
 | 
				
			||||||
        queue->for_querydb.DequeueAll();
 | 
					 | 
				
			||||||
    bool did_work = messages.size();
 | 
					    bool did_work = messages.size();
 | 
				
			||||||
    for (auto& message : messages) {
 | 
					    for (auto& message : messages) {
 | 
				
			||||||
      // TODO: Consider using std::unordered_map to lookup the handler
 | 
					      // TODO: Consider using std::unordered_map to lookup the handler
 | 
				
			||||||
@ -409,19 +467,40 @@ void MainLoop(MultiQueueWaiter* querydb_waiter,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (int i = 80; i--;) {
 | 
					    for (int i = 80; i--;) {
 | 
				
			||||||
      std::optional<Index_OnIndexed> response = queue->on_indexed.TryPopFront();
 | 
					      std::optional<Index_OnIndexed> response = on_indexed->TryPopFront();
 | 
				
			||||||
      if (!response)
 | 
					      if (!response)
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      did_work = true;
 | 
					      did_work = true;
 | 
				
			||||||
      QueryDb_OnIndexed(queue, &db, &semantic_cache, &working_files, &*response);
 | 
					      Main_OnIndexed(&db, &semantic_cache, &working_files, &*response);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Cleanup and free any unused memory.
 | 
					    // Cleanup and free any unused memory.
 | 
				
			||||||
    FreeUnusedMemory();
 | 
					    FreeUnusedMemory();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!did_work) {
 | 
					    if (!did_work)
 | 
				
			||||||
      auto* queue = QueueManager::instance();
 | 
					      main_waiter->Wait(on_indexed, on_request);
 | 
				
			||||||
      querydb_waiter->Wait(&queue->on_indexed, &queue->for_querydb);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Index(const std::string& path,
 | 
				
			||||||
 | 
					           const std::vector<std::string>& args,
 | 
				
			||||||
 | 
					           bool interactive,
 | 
				
			||||||
 | 
					           lsRequestId id) {
 | 
				
			||||||
 | 
					  index_request->PushBack({path, args, interactive, id}, interactive);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::optional<std::string> LoadCachedFileContents(const std::string& path) {
 | 
				
			||||||
 | 
					  return ReadContent(GetCachePath(path));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void WriteStdout(MethodType method, lsBaseOutMessage& response) {
 | 
				
			||||||
 | 
					  std::ostringstream sstream;
 | 
				
			||||||
 | 
					  response.Write(sstream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Stdout_Request out;
 | 
				
			||||||
 | 
					  out.content = sstream.str();
 | 
				
			||||||
 | 
					  out.method = method;
 | 
				
			||||||
 | 
					  for_stdout->PushBack(std::move(out));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,28 +1,35 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "method.h"
 | 
				
			||||||
 | 
					#include "query.h"
 | 
				
			||||||
#include "timer.h"
 | 
					#include "timer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <atomic>
 | 
					#include <string>
 | 
				
			||||||
#include <unordered_map>
 | 
					#include <unordered_map>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ClangTranslationUnit;
 | 
					 | 
				
			||||||
class DiagnosticsEngine;
 | 
					class DiagnosticsEngine;
 | 
				
			||||||
struct VFS;
 | 
					struct VFS;
 | 
				
			||||||
struct ICacheManager;
 | 
					 | 
				
			||||||
struct Project;
 | 
					struct Project;
 | 
				
			||||||
struct QueryDatabase;
 | 
					 | 
				
			||||||
struct SemanticHighlightSymbolCache;
 | 
					 | 
				
			||||||
struct WorkingFiles;
 | 
					struct WorkingFiles;
 | 
				
			||||||
 | 
					struct lsBaseOutMessage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ccls::pipeline {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Init();
 | 
				
			||||||
 | 
					void LaunchStdin(std::unordered_map<MethodType, Timer>* request_times);
 | 
				
			||||||
 | 
					void LaunchStdout(std::unordered_map<MethodType, Timer>* request_times);
 | 
				
			||||||
void Indexer_Main(DiagnosticsEngine* diag_engine,
 | 
					void Indexer_Main(DiagnosticsEngine* diag_engine,
 | 
				
			||||||
                  VFS* vfs,
 | 
					                  VFS* vfs,
 | 
				
			||||||
                  Project* project,
 | 
					                  Project* project,
 | 
				
			||||||
                  WorkingFiles* working_files,
 | 
					                  WorkingFiles* working_files);
 | 
				
			||||||
                  MultiQueueWaiter* waiter);
 | 
					void MainLoop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times);
 | 
					void Index(const std::string& path,
 | 
				
			||||||
void LaunchStdoutThread(std::unordered_map<MethodType, Timer>* request_times,
 | 
					           const std::vector<std::string>& args,
 | 
				
			||||||
                        MultiQueueWaiter* waiter);
 | 
					           bool is_interactive,
 | 
				
			||||||
void MainLoop(MultiQueueWaiter* querydb_waiter,
 | 
					           lsRequestId id = {});
 | 
				
			||||||
              MultiQueueWaiter* indexer_waiter);
 | 
					
 | 
				
			||||||
 | 
					std::optional<std::string> LoadCachedFileContents(const std::string& path);
 | 
				
			||||||
 | 
					void WriteStdout(MethodType method, lsBaseOutMessage& response);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										10
									
								
								src/port.cc
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/port.cc
									
									
									
									
									
								
							@ -1,10 +0,0 @@
 | 
				
			|||||||
#include "port.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ccls_unreachable_internal(const char* msg, const char* file, int line) {
 | 
					 | 
				
			||||||
  fprintf(stderr, "unreachable %s:%d %s\n", file, line, msg);
 | 
					 | 
				
			||||||
  CCLS_BUILTIN_UNREACHABLE;
 | 
					 | 
				
			||||||
  abort();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										34
									
								
								src/port.h
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								src/port.h
									
									
									
									
									
								
							@ -1,34 +0,0 @@
 | 
				
			|||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef __has_builtin
 | 
					 | 
				
			||||||
#define __has_builtin(x) 0
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(__GNUC__)
 | 
					 | 
				
			||||||
#define ATTRIBUTE_UNUSED __attribute__((unused))
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
#define ATTRIBUTE_UNUSED
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __clang__
 | 
					 | 
				
			||||||
#define GUARDED_BY(x)  __attribute__((guarded_by(x)))
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
#define GUARDED_BY(x)
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TODO GCC
 | 
					 | 
				
			||||||
#if __has_builtin(__builtin_unreachable)
 | 
					 | 
				
			||||||
#define CCLS_BUILTIN_UNREACHABLE __builtin_unreachable()
 | 
					 | 
				
			||||||
#elif defined(_MSC_VER)
 | 
					 | 
				
			||||||
#define CCLS_BUILTIN_UNREACHABLE __assume(false)
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
#define CCLS_BUILTIN_UNREACHABLE
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ccls_unreachable_internal(const char* msg, const char* file, int line);
 | 
					 | 
				
			||||||
#ifndef NDEBUG
 | 
					 | 
				
			||||||
#define CCLS_UNREACHABLE(msg) \
 | 
					 | 
				
			||||||
  ccls_unreachable_internal(msg, __FILE__, __LINE__)
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
#define CCLS_UNREACHABLE(msg)
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
@ -1,17 +1,17 @@
 | 
				
			|||||||
#include "project.h"
 | 
					#include "project.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "cache_manager.h"
 | 
					 | 
				
			||||||
#include "clang_utils.h"
 | 
					#include "clang_utils.h"
 | 
				
			||||||
#include "filesystem.hh"
 | 
					#include "filesystem.hh"
 | 
				
			||||||
#include "language.h"
 | 
					#include "language.h"
 | 
				
			||||||
#include "log.hh"
 | 
					#include "log.hh"
 | 
				
			||||||
#include "match.h"
 | 
					#include "match.h"
 | 
				
			||||||
#include "platform.h"
 | 
					#include "platform.h"
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "serializers/json.h"
 | 
					#include "serializers/json.h"
 | 
				
			||||||
#include "timer.h"
 | 
					#include "timer.h"
 | 
				
			||||||
#include "utils.h"
 | 
					#include "utils.h"
 | 
				
			||||||
#include "working_files.h"
 | 
					#include "working_files.h"
 | 
				
			||||||
 | 
					using namespace ccls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <clang/Driver/Options.h>
 | 
					#include <clang/Driver/Options.h>
 | 
				
			||||||
#include <llvm/ADT/ArrayRef.h>
 | 
					#include <llvm/ADT/ArrayRef.h>
 | 
				
			||||||
@ -454,17 +454,15 @@ void Project::ForAllFilteredFiles(
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Project::Index(QueueManager* queue,
 | 
					void Project::Index(WorkingFiles* wfiles,
 | 
				
			||||||
                    WorkingFiles* wfiles,
 | 
					 | 
				
			||||||
                    lsRequestId id) {
 | 
					                    lsRequestId id) {
 | 
				
			||||||
  ForAllFilteredFiles([&](int i, const Project::Entry& entry) {
 | 
					  ForAllFilteredFiles([&](int i, const Project::Entry& entry) {
 | 
				
			||||||
    bool is_interactive = wfiles->GetFileByFilename(entry.filename) != nullptr;
 | 
					    bool is_interactive = wfiles->GetFileByFilename(entry.filename) != nullptr;
 | 
				
			||||||
    queue->index_request.PushBack(
 | 
					    pipeline::Index(entry.filename, entry.args, is_interactive, id);
 | 
				
			||||||
        Index_Request(entry.filename, entry.args, is_interactive, id));
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  // Dummy request to indicate that project is loaded and
 | 
					  // Dummy request to indicate that project is loaded and
 | 
				
			||||||
  // trigger refreshing semantic highlight for all working files.
 | 
					  // trigger refreshing semantic highlight for all working files.
 | 
				
			||||||
  queue->index_request.PushBack(Index_Request("", {}, false));
 | 
					  pipeline::Index("", {}, false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST_SUITE("Project") {
 | 
					TEST_SUITE("Project") {
 | 
				
			||||||
 | 
				
			|||||||
@ -5,12 +5,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
#include <mutex>
 | 
					#include <mutex>
 | 
				
			||||||
#include <optional>
 | 
					 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <unordered_map>
 | 
					#include <unordered_map>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class QueueManager;
 | 
					 | 
				
			||||||
struct WorkingFiles;
 | 
					struct WorkingFiles;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Project {
 | 
					struct Project {
 | 
				
			||||||
@ -29,7 +27,7 @@ struct Project {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  std::vector<Entry> entries;
 | 
					  std::vector<Entry> entries;
 | 
				
			||||||
  std::mutex mutex_;
 | 
					  std::mutex mutex_;
 | 
				
			||||||
  std::unordered_map<std::string, int> absolute_path_to_entry_index_ GUARDED_BY(mutex_);
 | 
					  std::unordered_map<std::string, int> absolute_path_to_entry_index_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Loads a project for the given |directory|.
 | 
					  // Loads a project for the given |directory|.
 | 
				
			||||||
  //
 | 
					  //
 | 
				
			||||||
@ -58,5 +56,5 @@ struct Project {
 | 
				
			|||||||
  void ForAllFilteredFiles(
 | 
					  void ForAllFilteredFiles(
 | 
				
			||||||
      std::function<void(int i, const Entry& entry)> action);
 | 
					      std::function<void(int i, const Entry& entry)> action);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void Index(QueueManager* queue, WorkingFiles* wfiles, lsRequestId id);
 | 
					  void Index(WorkingFiles* wfiles, lsRequestId id);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
#include "query_utils.h"
 | 
					#include "query_utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "queue_manager.h"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <limits.h>
 | 
					#include <limits.h>
 | 
				
			||||||
#include <unordered_set>
 | 
					#include <unordered_set>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,46 +0,0 @@
 | 
				
			|||||||
#include "queue_manager.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "cache_manager.h"
 | 
					 | 
				
			||||||
#include "lsp.h"
 | 
					 | 
				
			||||||
#include "query.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <sstream>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Index_Request::Index_Request(const std::string& path,
 | 
					 | 
				
			||||||
                             const std::vector<std::string>& args,
 | 
					 | 
				
			||||||
                             bool is_interactive,
 | 
					 | 
				
			||||||
                             lsRequestId id)
 | 
					 | 
				
			||||||
    : path(path), args(args), is_interactive(is_interactive), id(id) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Index_OnIndexed::Index_OnIndexed(IndexUpdate&& update,
 | 
					 | 
				
			||||||
                                 PerformanceImportFile perf)
 | 
					 | 
				
			||||||
    : update(std::move(update)), perf(perf) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::unique_ptr<QueueManager> QueueManager::instance_;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// static
 | 
					 | 
				
			||||||
void QueueManager::Init(MultiQueueWaiter* querydb_waiter,
 | 
					 | 
				
			||||||
                        MultiQueueWaiter* indexer_waiter,
 | 
					 | 
				
			||||||
                        MultiQueueWaiter* stdout_waiter) {
 | 
					 | 
				
			||||||
  instance_ = std::unique_ptr<QueueManager>(
 | 
					 | 
				
			||||||
      new QueueManager(querydb_waiter, indexer_waiter, stdout_waiter));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// static
 | 
					 | 
				
			||||||
void QueueManager::WriteStdout(MethodType method, lsBaseOutMessage& response) {
 | 
					 | 
				
			||||||
  std::ostringstream sstream;
 | 
					 | 
				
			||||||
  response.Write(sstream);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Stdout_Request out;
 | 
					 | 
				
			||||||
  out.content = sstream.str();
 | 
					 | 
				
			||||||
  out.method = method;
 | 
					 | 
				
			||||||
  instance()->for_stdout.PushBack(std::move(out));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
QueueManager::QueueManager(MultiQueueWaiter* querydb_waiter,
 | 
					 | 
				
			||||||
                           MultiQueueWaiter* indexer_waiter,
 | 
					 | 
				
			||||||
                           MultiQueueWaiter* stdout_waiter)
 | 
					 | 
				
			||||||
    : for_stdout(stdout_waiter),
 | 
					 | 
				
			||||||
      for_querydb(querydb_waiter),
 | 
					 | 
				
			||||||
      on_indexed(querydb_waiter),
 | 
					 | 
				
			||||||
      index_request(indexer_waiter) {}
 | 
					 | 
				
			||||||
@ -1,84 +0,0 @@
 | 
				
			|||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "method.h"
 | 
					 | 
				
			||||||
#include "query.h"
 | 
					 | 
				
			||||||
#include "threaded_queue.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct ICacheManager;
 | 
					 | 
				
			||||||
struct lsBaseOutMessage;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct Stdout_Request {
 | 
					 | 
				
			||||||
  MethodType method;
 | 
					 | 
				
			||||||
  std::string content;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct Index_Request {
 | 
					 | 
				
			||||||
  std::string path;
 | 
					 | 
				
			||||||
  // TODO: make |args| a string that is parsed lazily.
 | 
					 | 
				
			||||||
  std::vector<std::string> args;
 | 
					 | 
				
			||||||
  bool is_interactive;
 | 
					 | 
				
			||||||
  lsRequestId id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Index_Request(const std::string& path,
 | 
					 | 
				
			||||||
                const std::vector<std::string>& args,
 | 
					 | 
				
			||||||
                bool is_interactive,
 | 
					 | 
				
			||||||
                lsRequestId id = {});
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct Index_OnIdMapped {
 | 
					 | 
				
			||||||
  std::shared_ptr<ICacheManager> cache_manager;
 | 
					 | 
				
			||||||
  std::unique_ptr<IndexFile> previous;
 | 
					 | 
				
			||||||
  std::unique_ptr<IndexFile> current;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  PerformanceImportFile perf;
 | 
					 | 
				
			||||||
  bool is_interactive;
 | 
					 | 
				
			||||||
  bool write_to_disk;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Index_OnIdMapped(const std::shared_ptr<ICacheManager>& cache_manager,
 | 
					 | 
				
			||||||
                   std::unique_ptr<IndexFile> previous,
 | 
					 | 
				
			||||||
                   std::unique_ptr<IndexFile> current,
 | 
					 | 
				
			||||||
                   PerformanceImportFile perf,
 | 
					 | 
				
			||||||
                   bool is_interactive,
 | 
					 | 
				
			||||||
                   bool write_to_disk)
 | 
					 | 
				
			||||||
      : cache_manager(cache_manager),
 | 
					 | 
				
			||||||
        previous(std::move(previous)),
 | 
					 | 
				
			||||||
        current(std::move(current)),
 | 
					 | 
				
			||||||
        perf(perf),
 | 
					 | 
				
			||||||
        is_interactive(is_interactive),
 | 
					 | 
				
			||||||
        write_to_disk(write_to_disk) {}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct Index_OnIndexed {
 | 
					 | 
				
			||||||
  IndexUpdate update;
 | 
					 | 
				
			||||||
  PerformanceImportFile perf;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Index_OnIndexed(IndexUpdate&& update, PerformanceImportFile perf);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class QueueManager {
 | 
					 | 
				
			||||||
  static std::unique_ptr<QueueManager> instance_;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 public:
 | 
					 | 
				
			||||||
  static QueueManager* instance() { return instance_.get(); }
 | 
					 | 
				
			||||||
  static void Init(MultiQueueWaiter* querydb_waiter,
 | 
					 | 
				
			||||||
                   MultiQueueWaiter* indexer_waiter,
 | 
					 | 
				
			||||||
                   MultiQueueWaiter* stdout_waiter);
 | 
					 | 
				
			||||||
  static void WriteStdout(MethodType method, lsBaseOutMessage& response);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Messages received by "stdout" thread.
 | 
					 | 
				
			||||||
  ThreadedQueue<Stdout_Request> for_stdout;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Runs on querydb thread.
 | 
					 | 
				
			||||||
  ThreadedQueue<std::unique_ptr<InMessage>> for_querydb;
 | 
					 | 
				
			||||||
  ThreadedQueue<Index_OnIndexed> on_indexed;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Runs on indexer threads.
 | 
					 | 
				
			||||||
  ThreadedQueue<Index_Request> index_request;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 private:
 | 
					 | 
				
			||||||
  explicit QueueManager(MultiQueueWaiter* querydb_waiter,
 | 
					 | 
				
			||||||
                        MultiQueueWaiter* indexer_waiter,
 | 
					 | 
				
			||||||
                        MultiQueueWaiter* stdout_waiter);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@ -2,7 +2,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "maybe.h"
 | 
					#include "maybe.h"
 | 
				
			||||||
#include "nt_string.h"
 | 
					#include "nt_string.h"
 | 
				
			||||||
#include "port.h"
 | 
					
 | 
				
			||||||
 | 
					#include <llvm/Support/Compiler.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <macro_map.h>
 | 
					#include <macro_map.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -83,15 +84,15 @@ struct IndexFile;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define MAKE_REFLECT_TYPE_PROXY(type_name) \
 | 
					#define MAKE_REFLECT_TYPE_PROXY(type_name) \
 | 
				
			||||||
  MAKE_REFLECT_TYPE_PROXY2(type_name, std::underlying_type_t<type_name>)
 | 
					  MAKE_REFLECT_TYPE_PROXY2(type_name, std::underlying_type_t<type_name>)
 | 
				
			||||||
#define MAKE_REFLECT_TYPE_PROXY2(type, as_type)                        \
 | 
					#define MAKE_REFLECT_TYPE_PROXY2(type, as_type)                             \
 | 
				
			||||||
  ATTRIBUTE_UNUSED inline void Reflect(Reader& visitor, type& value) { \
 | 
					  LLVM_ATTRIBUTE_UNUSED inline void Reflect(Reader& visitor, type& value) { \
 | 
				
			||||||
    as_type value0;                                                    \
 | 
					    as_type value0;                                                         \
 | 
				
			||||||
    ::Reflect(visitor, value0);                                        \
 | 
					    ::Reflect(visitor, value0);                                             \
 | 
				
			||||||
    value = static_cast<type>(value0);                                 \
 | 
					    value = static_cast<type>(value0);                                      \
 | 
				
			||||||
  }                                                                    \
 | 
					  }                                                                         \
 | 
				
			||||||
  ATTRIBUTE_UNUSED inline void Reflect(Writer& visitor, type& value) { \
 | 
					  LLVM_ATTRIBUTE_UNUSED inline void Reflect(Writer& visitor, type& value) { \
 | 
				
			||||||
    auto value0 = static_cast<as_type>(value);                         \
 | 
					    auto value0 = static_cast<as_type>(value);                              \
 | 
				
			||||||
    ::Reflect(visitor, value0);                                        \
 | 
					    ::Reflect(visitor, value0);                                             \
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define _MAPPABLE_REFLECT_MEMBER(name) REFLECT_MEMBER(name);
 | 
					#define _MAPPABLE_REFLECT_MEMBER(name) REFLECT_MEMBER(name);
 | 
				
			||||||
 | 
				
			|||||||
@ -284,8 +284,6 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
 | 
				
			|||||||
                             &all_expected_output);
 | 
					                             &all_expected_output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Build flags.
 | 
					        // Build flags.
 | 
				
			||||||
        if (!AnyStartsWith(flags, "-x"))
 | 
					 | 
				
			||||||
          flags.push_back("-xc++");
 | 
					 | 
				
			||||||
        flags.push_back("-resource-dir=" + GetDefaultResourceDirectory());
 | 
					        flags.push_back("-resource-dir=" + GetDefaultResourceDirectory());
 | 
				
			||||||
        flags.push_back(path);
 | 
					        flags.push_back(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -94,26 +94,6 @@ struct ThreadedQueue : public BaseThreadQueue {
 | 
				
			|||||||
    Push<&std::deque<T>::push_back>(std::move(t), priority);
 | 
					    Push<&std::deque<T>::push_back>(std::move(t), priority);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Add a set of elements to the queue.
 | 
					 | 
				
			||||||
  void EnqueueAll(std::vector<T>&& elements, bool priority = false) {
 | 
					 | 
				
			||||||
    if (elements.empty())
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::lock_guard<std::mutex> lock(mutex_);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    total_count_ += elements.size();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (T& element : elements) {
 | 
					 | 
				
			||||||
      if (priority)
 | 
					 | 
				
			||||||
        priority_.push_back(std::move(element));
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        queue_.push_back(std::move(element));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    elements.clear();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    waiter_->cv.notify_all();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Return all elements in the queue.
 | 
					  // Return all elements in the queue.
 | 
				
			||||||
  std::vector<T> DequeueAll() {
 | 
					  std::vector<T> DequeueAll() {
 | 
				
			||||||
    std::lock_guard<std::mutex> lock(mutex_);
 | 
					    std::lock_guard<std::mutex> lock(mutex_);
 | 
				
			||||||
 | 
				
			|||||||
@ -48,15 +48,6 @@ bool StartsWith(std::string_view s, std::string_view prefix) {
 | 
				
			|||||||
         std::equal(prefix.begin(), prefix.end(), s.begin());
 | 
					         std::equal(prefix.begin(), prefix.end(), s.begin());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool AnyStartsWith(const std::vector<std::string>& xs,
 | 
					 | 
				
			||||||
                   std::string_view prefix) {
 | 
					 | 
				
			||||||
  return std::any_of(xs.begin(), xs.end(), std::bind(StartsWith, _1, prefix));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool StartsWithAny(std::string_view s, const std::vector<std::string>& ps) {
 | 
					 | 
				
			||||||
  return std::any_of(ps.begin(), ps.end(), std::bind(StartsWith, s, _1));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool EndsWithAny(std::string_view s, const std::vector<std::string>& ss) {
 | 
					bool EndsWithAny(std::string_view s, const std::vector<std::string>& ss) {
 | 
				
			||||||
  return std::any_of(ss.begin(), ss.end(), std::bind(EndsWith, s, _1));
 | 
					  return std::any_of(ss.begin(), ss.end(), std::bind(EndsWith, s, _1));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -17,8 +17,6 @@ uint64_t HashUsr(std::string_view s);
 | 
				
			|||||||
// Returns true if |value| starts/ends with |start| or |ending|.
 | 
					// Returns true if |value| starts/ends with |start| or |ending|.
 | 
				
			||||||
bool StartsWith(std::string_view value, std::string_view start);
 | 
					bool StartsWith(std::string_view value, std::string_view start);
 | 
				
			||||||
bool EndsWith(std::string_view value, std::string_view ending);
 | 
					bool EndsWith(std::string_view value, std::string_view ending);
 | 
				
			||||||
bool AnyStartsWith(const std::vector<std::string>& xs, std::string_view prefix);
 | 
					 | 
				
			||||||
bool StartsWithAny(std::string_view s, const std::vector<std::string>& ps);
 | 
					 | 
				
			||||||
bool EndsWithAny(std::string_view s, const std::vector<std::string>& ss);
 | 
					bool EndsWithAny(std::string_view s, const std::vector<std::string>& ss);
 | 
				
			||||||
bool FindAnyPartial(const std::string& value,
 | 
					bool FindAnyPartial(const std::string& value,
 | 
				
			||||||
                    const std::vector<std::string>& values);
 | 
					                    const std::vector<std::string>& values);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user