mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-04 06:15:20 +00:00 
			
		
		
		
	.
This commit is contained in:
		
							parent
							
								
									a58a38c32d
								
							
						
					
					
						commit
						c96631d1ee
					
				@ -179,6 +179,7 @@ target_sources(ccls PRIVATE
 | 
				
			|||||||
               src/clang_translation_unit.cc
 | 
					               src/clang_translation_unit.cc
 | 
				
			||||||
               src/clang_utils.cc
 | 
					               src/clang_utils.cc
 | 
				
			||||||
               src/command_line.cc
 | 
					               src/command_line.cc
 | 
				
			||||||
 | 
					               src/config.cc
 | 
				
			||||||
               src/diagnostics_engine.cc
 | 
					               src/diagnostics_engine.cc
 | 
				
			||||||
               src/file_consumer.cc
 | 
					               src/file_consumer.cc
 | 
				
			||||||
               src/file_contents.cc
 | 
					               src/file_contents.cc
 | 
				
			||||||
@ -209,7 +210,6 @@ target_sources(ccls PRIVATE
 | 
				
			|||||||
               src/timestamp_manager.cc
 | 
					               src/timestamp_manager.cc
 | 
				
			||||||
               src/type_printer.cc
 | 
					               src/type_printer.cc
 | 
				
			||||||
               src/utils.cc
 | 
					               src/utils.cc
 | 
				
			||||||
               src/work_thread.cc
 | 
					 | 
				
			||||||
               src/working_files.cc)
 | 
					               src/working_files.cc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
target_sources(ccls PRIVATE
 | 
					target_sources(ccls PRIVATE
 | 
				
			||||||
@ -217,7 +217,6 @@ target_sources(ccls PRIVATE
 | 
				
			|||||||
               src/messages/ccls_call_hierarchy.cc
 | 
					               src/messages/ccls_call_hierarchy.cc
 | 
				
			||||||
               src/messages/ccls_callers.cc
 | 
					               src/messages/ccls_callers.cc
 | 
				
			||||||
               src/messages/ccls_derived.cc
 | 
					               src/messages/ccls_derived.cc
 | 
				
			||||||
               src/messages/ccls_did_view.cc
 | 
					 | 
				
			||||||
               src/messages/ccls_file_info.cc
 | 
					               src/messages/ccls_file_info.cc
 | 
				
			||||||
               src/messages/ccls_freshen_index.cc
 | 
					               src/messages/ccls_freshen_index.cc
 | 
				
			||||||
               src/messages/ccls_index_file.cc
 | 
					               src/messages/ccls_index_file.cc
 | 
				
			||||||
@ -225,7 +224,6 @@ target_sources(ccls PRIVATE
 | 
				
			|||||||
               src/messages/ccls_member_hierarchy.cc
 | 
					               src/messages/ccls_member_hierarchy.cc
 | 
				
			||||||
               src/messages/ccls_random.cc
 | 
					               src/messages/ccls_random.cc
 | 
				
			||||||
               src/messages/ccls_vars.cc
 | 
					               src/messages/ccls_vars.cc
 | 
				
			||||||
               src/messages/ccls_wait.cc
 | 
					 | 
				
			||||||
               src/messages/exit.cc
 | 
					               src/messages/exit.cc
 | 
				
			||||||
               src/messages/initialize.cc
 | 
					               src/messages/initialize.cc
 | 
				
			||||||
               src/messages/shutdown.cc
 | 
					               src/messages/shutdown.cc
 | 
				
			||||||
 | 
				
			|||||||
@ -9,10 +9,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <loguru.hpp>
 | 
					#include <loguru.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <cassert>
 | 
					#include <cassert>
 | 
				
			||||||
#include <chrono>
 | 
					#include <chrono>
 | 
				
			||||||
#include <climits>
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: See if we can use clang_indexLoc_getFileLocation to get a type ref on
 | 
					// TODO: See if we can use clang_indexLoc_getFileLocation to get a type ref on
 | 
				
			||||||
@ -861,7 +861,7 @@ CXIdxClientFile OnIndexIncludedFile(CXClientData client_data,
 | 
				
			|||||||
  IndexInclude include;
 | 
					  IndexInclude include;
 | 
				
			||||||
  include.line = line;
 | 
					  include.line = line;
 | 
				
			||||||
  include.resolved_path = FileName(file->file);
 | 
					  include.resolved_path = FileName(file->file);
 | 
				
			||||||
  if (!include.resolved_path.empty())
 | 
					  if (include.resolved_path.size())
 | 
				
			||||||
    db->includes.push_back(include);
 | 
					    db->includes.push_back(include);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return nullptr;
 | 
					  return nullptr;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
#include "clang_utils.h"
 | 
					#include "clang_utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "filesystem.hh"
 | 
				
			||||||
#include "platform.h"
 | 
					#include "platform.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
@ -106,8 +107,11 @@ std::optional<lsDiagnostic> BuildAndDisposeDiagnostic(CXDiagnostic diagnostic,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
std::string FileName(CXFile file) {
 | 
					std::string FileName(CXFile file) {
 | 
				
			||||||
  CXString cx_name = clang_getFileName(file);
 | 
					  CXString cx_name = clang_getFileName(file);
 | 
				
			||||||
  std::string name = ToString(cx_name);
 | 
					  std::string ret = NormalizePath(ToString(cx_name));
 | 
				
			||||||
  return NormalizePath(name);
 | 
					  // Resolve /usr/include/c++/7.3.0 symlink.
 | 
				
			||||||
 | 
					  if (!StartsWith(ret, g_config.projectRoot))
 | 
				
			||||||
 | 
					    ret = fs::canonical(ret);
 | 
				
			||||||
 | 
					  return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string ToString(CXString cx_string) {
 | 
					std::string ToString(CXString cx_string) {
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,6 @@
 | 
				
			|||||||
#include "test.h"
 | 
					#include "test.h"
 | 
				
			||||||
#include "timer.h"
 | 
					#include "timer.h"
 | 
				
			||||||
#include "timestamp_manager.h"
 | 
					#include "timestamp_manager.h"
 | 
				
			||||||
#include "work_thread.h"
 | 
					 | 
				
			||||||
#include "working_files.h"
 | 
					#include "working_files.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <doctest/doctest.h>
 | 
					#include <doctest/doctest.h>
 | 
				
			||||||
@ -35,7 +34,6 @@
 | 
				
			|||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
#include <iterator>
 | 
					#include <iterator>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <thread>
 | 
					 | 
				
			||||||
#include <unordered_map>
 | 
					#include <unordered_map>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -255,7 +253,7 @@ void LaunchStdinLoop(Config* config,
 | 
				
			|||||||
  // clients.
 | 
					  // clients.
 | 
				
			||||||
  std::cin.tie(nullptr);
 | 
					  std::cin.tie(nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  WorkThread::StartThread("stdin", [request_times]() {
 | 
					  StartThread("stdin", [request_times]() {
 | 
				
			||||||
    auto* queue = QueueManager::instance();
 | 
					    auto* queue = QueueManager::instance();
 | 
				
			||||||
    while (true) {
 | 
					    while (true) {
 | 
				
			||||||
      std::unique_ptr<InMessage> message;
 | 
					      std::unique_ptr<InMessage> message;
 | 
				
			||||||
@ -295,7 +293,7 @@ void LaunchStdinLoop(Config* config,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void LaunchStdoutThread(std::unordered_map<MethodType, Timer>* request_times,
 | 
					void LaunchStdoutThread(std::unordered_map<MethodType, Timer>* request_times,
 | 
				
			||||||
                        MultiQueueWaiter* waiter) {
 | 
					                        MultiQueueWaiter* waiter) {
 | 
				
			||||||
  WorkThread::StartThread("stdout", [=]() {
 | 
					  StartThread("stdout", [=]() {
 | 
				
			||||||
    auto* queue = QueueManager::instance();
 | 
					    auto* queue = QueueManager::instance();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (true) {
 | 
					    while (true) {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										3
									
								
								src/config.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/config.cc
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Config g_config;
 | 
				
			||||||
@ -281,5 +281,4 @@ MAKE_REFLECT_STRUCT(Config,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                    dumpAST);
 | 
					                    dumpAST);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Expected client version. We show an error if this doesn't match.
 | 
					extern Config g_config;
 | 
				
			||||||
constexpr const int kExpectedClientVersion = 3;
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -104,4 +104,4 @@ void FileConsumer::EmitError(CXFile file) const {
 | 
				
			|||||||
    LOG_S(ERROR) << "Could not get unique file id for " << file_name
 | 
					    LOG_S(ERROR) << "Could not get unique file id for " << file_name
 | 
				
			||||||
                 << " when parsing " << parse_file_;
 | 
					                 << " when parsing " << parse_file_;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -5,9 +5,6 @@
 | 
				
			|||||||
#include "project.h"
 | 
					#include "project.h"
 | 
				
			||||||
#include "standard_includes.h"
 | 
					#include "standard_includes.h"
 | 
				
			||||||
#include "timer.h"
 | 
					#include "timer.h"
 | 
				
			||||||
#include "work_thread.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <thread>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -116,7 +113,7 @@ void IncludeComplete::Rescan() {
 | 
				
			|||||||
                                          config_->completion.includeBlacklist);
 | 
					                                          config_->completion.includeBlacklist);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  is_scanning = true;
 | 
					  is_scanning = true;
 | 
				
			||||||
  WorkThread::StartThread("scan_includes", [this]() {
 | 
					  StartThread("scan_includes", [this]() {
 | 
				
			||||||
    Timer timer;
 | 
					    Timer timer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    InsertStlIncludes();
 | 
					    InsertStlIncludes();
 | 
				
			||||||
 | 
				
			|||||||
@ -1,40 +0,0 @@
 | 
				
			|||||||
#include "clang_complete.h"
 | 
					 | 
				
			||||||
#include "message_handler.h"
 | 
					 | 
				
			||||||
#include "working_files.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace {
 | 
					 | 
				
			||||||
MethodType kMethodType = "$ccls/textDocumentDidView";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct In_CclsTextDocumentDidView : public NotificationInMessage {
 | 
					 | 
				
			||||||
  MethodType GetMethodType() const override { return kMethodType; }
 | 
					 | 
				
			||||||
  struct Params {
 | 
					 | 
				
			||||||
    lsDocumentUri textDocumentUri;
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  Params params;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
MAKE_REFLECT_STRUCT(In_CclsTextDocumentDidView::Params, textDocumentUri);
 | 
					 | 
				
			||||||
MAKE_REFLECT_STRUCT(In_CclsTextDocumentDidView, params);
 | 
					 | 
				
			||||||
REGISTER_IN_MESSAGE(In_CclsTextDocumentDidView);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct Handler_CclsDidView
 | 
					 | 
				
			||||||
    : BaseMessageHandler<In_CclsTextDocumentDidView> {
 | 
					 | 
				
			||||||
  MethodType GetMethodType() const override { return kMethodType; }
 | 
					 | 
				
			||||||
  void Run(In_CclsTextDocumentDidView* request) override {
 | 
					 | 
				
			||||||
    std::string path = request->params.textDocumentUri.GetPath();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    WorkingFile* working_file = working_files->GetFileByFilename(path);
 | 
					 | 
				
			||||||
    if (!working_file)
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    QueryFile* file = nullptr;
 | 
					 | 
				
			||||||
    if (!FindFileOrFail(db, project, std::nullopt, path, &file))
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    clang_complete->NotifyView(path);
 | 
					 | 
				
			||||||
    if (file->def) {
 | 
					 | 
				
			||||||
      EmitInactiveLines(working_file, file->def->inactive_regions);
 | 
					 | 
				
			||||||
      EmitSemanticHighlighting(db, semantic_cache, working_file, file);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_CclsDidView);
 | 
					 | 
				
			||||||
}  // namespace
 | 
					 | 
				
			||||||
@ -1,47 +0,0 @@
 | 
				
			|||||||
#include "import_manager.h"
 | 
					 | 
				
			||||||
#include "import_pipeline.h"
 | 
					 | 
				
			||||||
#include "message_handler.h"
 | 
					 | 
				
			||||||
#include "queue_manager.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <loguru.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace {
 | 
					 | 
				
			||||||
MethodType kMethodType = "$ccls/wait";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct In_CclsWait : public NotificationInMessage {
 | 
					 | 
				
			||||||
  MethodType GetMethodType() const override { return kMethodType; }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
MAKE_REFLECT_EMPTY_STRUCT(In_CclsWait);
 | 
					 | 
				
			||||||
REGISTER_IN_MESSAGE(In_CclsWait);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct Handler_CclsWait : MessageHandler {
 | 
					 | 
				
			||||||
  MethodType GetMethodType() const override { return kMethodType; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void Run(std::unique_ptr<InMessage> request) override {
 | 
					 | 
				
			||||||
    // TODO: use status message system here, then run querydb as normal? Maybe
 | 
					 | 
				
			||||||
    // this cannot be a normal message, ie, it needs to be re-entrant.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    LOG_S(INFO) << "Waiting for idle";
 | 
					 | 
				
			||||||
    int idle_count = 0;
 | 
					 | 
				
			||||||
    while (true) {
 | 
					 | 
				
			||||||
      bool has_work = false;
 | 
					 | 
				
			||||||
      has_work |= import_pipeline_status->num_active_threads != 0;
 | 
					 | 
				
			||||||
      has_work |= QueueManager::instance()->HasWork();
 | 
					 | 
				
			||||||
      has_work |=
 | 
					 | 
				
			||||||
          QueryDb_ImportMain(config, db, import_manager, import_pipeline_status,
 | 
					 | 
				
			||||||
                             semantic_cache, working_files);
 | 
					 | 
				
			||||||
      if (!has_work)
 | 
					 | 
				
			||||||
        ++idle_count;
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        idle_count = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // There are race conditions between each of the three checks above,
 | 
					 | 
				
			||||||
      // so we retry a bunch of times to try to avoid any.
 | 
					 | 
				
			||||||
      if (idle_count > 10)
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    LOG_S(INFO) << "Done waiting for idle";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_CclsWait);
 | 
					 | 
				
			||||||
}  // namespace
 | 
					 | 
				
			||||||
@ -8,7 +8,6 @@
 | 
				
			|||||||
#include "queue_manager.h"
 | 
					#include "queue_manager.h"
 | 
				
			||||||
#include "serializers/json.h"
 | 
					#include "serializers/json.h"
 | 
				
			||||||
#include "timer.h"
 | 
					#include "timer.h"
 | 
				
			||||||
#include "work_thread.h"
 | 
					 | 
				
			||||||
#include "working_files.h"
 | 
					#include "working_files.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <loguru.hpp>
 | 
					#include <loguru.hpp>
 | 
				
			||||||
@ -270,45 +269,13 @@ struct lsTextDocumentClientCapabilities {
 | 
				
			|||||||
    // The client supports the following `CompletionItem` specific
 | 
					    // The client supports the following `CompletionItem` specific
 | 
				
			||||||
    // capabilities.
 | 
					    // capabilities.
 | 
				
			||||||
    std::optional<lsCompletionItem> completionItem;
 | 
					    std::optional<lsCompletionItem> completionItem;
 | 
				
			||||||
  };
 | 
					  } completion;
 | 
				
			||||||
  // Capabilities specific to the `textDocument/completion`
 | 
					 | 
				
			||||||
  std::optional<lsCompletion> completion;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct lsGenericDynamicReg {
 | 
					  struct lsGenericDynamicReg {
 | 
				
			||||||
    // Whether foo supports dynamic registration.
 | 
					    // Whether foo supports dynamic registration.
 | 
				
			||||||
    std::optional<bool> dynamicRegistration;
 | 
					    std::optional<bool> dynamicRegistration;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Capabilities specific to the `textDocument/hover`
 | 
					 | 
				
			||||||
  std::optional<lsGenericDynamicReg> hover;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Capabilities specific to the `textDocument/signatureHelp`
 | 
					 | 
				
			||||||
  std::optional<lsGenericDynamicReg> signatureHelp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Capabilities specific to the `textDocument/references`
 | 
					 | 
				
			||||||
  std::optional<lsGenericDynamicReg> references;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Capabilities specific to the `textDocument/documentHighlight`
 | 
					 | 
				
			||||||
  std::optional<lsGenericDynamicReg> documentHighlight;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Capabilities specific to the `textDocument/documentSymbol`
 | 
					 | 
				
			||||||
  std::optional<lsGenericDynamicReg> documentSymbol;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Capabilities specific to the `textDocument/formatting`
 | 
					 | 
				
			||||||
  std::optional<lsGenericDynamicReg> formatting;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Capabilities specific to the `textDocument/rangeFormatting`
 | 
					 | 
				
			||||||
  std::optional<lsGenericDynamicReg> rangeFormatting;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Capabilities specific to the `textDocument/onTypeFormatting`
 | 
					 | 
				
			||||||
  std::optional<lsGenericDynamicReg> onTypeFormatting;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Capabilities specific to the `textDocument/definition`
 | 
					 | 
				
			||||||
  std::optional<lsGenericDynamicReg> definition;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Capabilities specific to the `textDocument/codeAction`
 | 
					 | 
				
			||||||
  std::optional<lsGenericDynamicReg> codeAction;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  struct CodeLensRegistrationOptions : public lsGenericDynamicReg {
 | 
					  struct CodeLensRegistrationOptions : public lsGenericDynamicReg {
 | 
				
			||||||
    // Code lens has a resolve provider as well.
 | 
					    // Code lens has a resolve provider as well.
 | 
				
			||||||
    bool resolveProvider;
 | 
					    bool resolveProvider;
 | 
				
			||||||
@ -317,9 +284,6 @@ struct lsTextDocumentClientCapabilities {
 | 
				
			|||||||
  // Capabilities specific to the `textDocument/codeLens`
 | 
					  // Capabilities specific to the `textDocument/codeLens`
 | 
				
			||||||
  std::optional<CodeLensRegistrationOptions> codeLens;
 | 
					  std::optional<CodeLensRegistrationOptions> codeLens;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Capabilities specific to the `textDocument/documentLink`
 | 
					 | 
				
			||||||
  std::optional<lsGenericDynamicReg> documentLink;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Capabilities specific to the `textDocument/rename`
 | 
					  // Capabilities specific to the `textDocument/rename`
 | 
				
			||||||
  std::optional<lsGenericDynamicReg> rename;
 | 
					  std::optional<lsGenericDynamicReg> rename;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -344,18 +308,6 @@ MAKE_REFLECT_STRUCT(
 | 
				
			|||||||
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities,
 | 
					MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities,
 | 
				
			||||||
                    synchronization,
 | 
					                    synchronization,
 | 
				
			||||||
                    completion,
 | 
					                    completion,
 | 
				
			||||||
                    hover,
 | 
					 | 
				
			||||||
                    signatureHelp,
 | 
					 | 
				
			||||||
                    references,
 | 
					 | 
				
			||||||
                    documentHighlight,
 | 
					 | 
				
			||||||
                    documentSymbol,
 | 
					 | 
				
			||||||
                    formatting,
 | 
					 | 
				
			||||||
                    rangeFormatting,
 | 
					 | 
				
			||||||
                    onTypeFormatting,
 | 
					 | 
				
			||||||
                    definition,
 | 
					 | 
				
			||||||
                    codeAction,
 | 
					 | 
				
			||||||
                    codeLens,
 | 
					 | 
				
			||||||
                    documentLink,
 | 
					 | 
				
			||||||
                    rename);
 | 
					                    rename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct lsClientCapabilities {
 | 
					struct lsClientCapabilities {
 | 
				
			||||||
@ -512,29 +464,9 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
 | 
				
			|||||||
      // Client capabilities
 | 
					      // Client capabilities
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        const auto& cap = request->params.capabilities.textDocument;
 | 
					        const auto& cap = request->params.capabilities.textDocument;
 | 
				
			||||||
        if (cap.completion && cap.completion->completionItem)
 | 
					        if (cap.completion.completionItem)
 | 
				
			||||||
          config->client.snippetSupport =
 | 
					          config->client.snippetSupport =
 | 
				
			||||||
              cap.completion->completionItem->snippetSupport.value_or(false);
 | 
					              cap.completion.completionItem->snippetSupport.value_or(false);
 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Check client version.
 | 
					 | 
				
			||||||
      if (config->clientVersion.has_value() &&
 | 
					 | 
				
			||||||
          *config->clientVersion != kExpectedClientVersion) {
 | 
					 | 
				
			||||||
        Out_ShowLogMessage out;
 | 
					 | 
				
			||||||
        out.display_type = Out_ShowLogMessage::DisplayType::Show;
 | 
					 | 
				
			||||||
        out.params.type = lsMessageType::Error;
 | 
					 | 
				
			||||||
        out.params.message =
 | 
					 | 
				
			||||||
            "ccls client (v" + std::to_string(*config->clientVersion) +
 | 
					 | 
				
			||||||
            ") and server (v" + std::to_string(kExpectedClientVersion) +
 | 
					 | 
				
			||||||
            ") version mismatch. Please update ";
 | 
					 | 
				
			||||||
        if (config->clientVersion > kExpectedClientVersion)
 | 
					 | 
				
			||||||
          out.params.message += "the ccls binary.";
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
          out.params.message +=
 | 
					 | 
				
			||||||
              "your extension client (VSIX file). Make sure to uninstall "
 | 
					 | 
				
			||||||
              "the ccls extension and restart vscode before "
 | 
					 | 
				
			||||||
              "reinstalling.";
 | 
					 | 
				
			||||||
        out.Write(std::cout);
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Ensure there is a resource directory.
 | 
					      // Ensure there is a resource directory.
 | 
				
			||||||
@ -576,6 +508,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
 | 
				
			|||||||
      MakeDirectoryRecursive(config->cacheDirectory + '@' +
 | 
					      MakeDirectoryRecursive(config->cacheDirectory + '@' +
 | 
				
			||||||
                             EscapeFileName(config->projectRoot));
 | 
					                             EscapeFileName(config->projectRoot));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      g_config = *config;
 | 
				
			||||||
      Timer time;
 | 
					      Timer time;
 | 
				
			||||||
      diag_engine->Init(config);
 | 
					      diag_engine->Init(config);
 | 
				
			||||||
      semantic_cache->Init(config);
 | 
					      semantic_cache->Init(config);
 | 
				
			||||||
@ -599,7 +532,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      LOG_S(INFO) << "Starting " << config->index.threads << " indexers";
 | 
					      LOG_S(INFO) << "Starting " << config->index.threads << " indexers";
 | 
				
			||||||
      for (int i = 0; i < config->index.threads; ++i) {
 | 
					      for (int i = 0; i < config->index.threads; ++i) {
 | 
				
			||||||
        WorkThread::StartThread("indexer" + std::to_string(i), [=]() {
 | 
					        StartThread("indexer" + std::to_string(i), [=]() {
 | 
				
			||||||
          Indexer_Main(config, diag_engine, file_consumer_shared,
 | 
					          Indexer_Main(config, diag_engine, file_consumer_shared,
 | 
				
			||||||
                       timestamp_manager, import_manager,
 | 
					                       timestamp_manager, import_manager,
 | 
				
			||||||
                       import_pipeline_status, project, working_files, waiter);
 | 
					                       import_pipeline_status, project, working_files, waiter);
 | 
				
			||||||
 | 
				
			|||||||
@ -72,9 +72,8 @@ struct Handler_TextDocumentDidOpen
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    clang_complete->FlushSession(entry.filename);
 | 
					    clang_complete->FlushSession(entry.filename);
 | 
				
			||||||
    LOG_S(INFO) << "Flushed clang complete sessions for " << entry.filename;
 | 
					    LOG_S(INFO) << "Flushed clang complete sessions for " << entry.filename;
 | 
				
			||||||
    if (params.args.size()) {
 | 
					    if (params.args.size())
 | 
				
			||||||
      project->SetFlagsForFile(params.args, path);
 | 
					        project->SetFlagsForFile(params.args, path);
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidOpen);
 | 
					REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidOpen);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,62 +0,0 @@
 | 
				
			|||||||
#include "clang_format.h"
 | 
					 | 
				
			||||||
#include "message_handler.h"
 | 
					 | 
				
			||||||
#include "queue_manager.h"
 | 
					 | 
				
			||||||
#include "working_files.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <loguru.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace {
 | 
					 | 
				
			||||||
MethodType kMethodType = "textDocument/formatting";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct In_TextDocumentFormatting : public RequestInMessage {
 | 
					 | 
				
			||||||
  MethodType GetMethodType() const override { return kMethodType; }
 | 
					 | 
				
			||||||
  struct Params {
 | 
					 | 
				
			||||||
    lsTextDocumentIdentifier textDocument;
 | 
					 | 
				
			||||||
    lsFormattingOptions options;
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  Params params;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
MAKE_REFLECT_STRUCT(In_TextDocumentFormatting::Params, textDocument, options);
 | 
					 | 
				
			||||||
MAKE_REFLECT_STRUCT(In_TextDocumentFormatting, id, params);
 | 
					 | 
				
			||||||
REGISTER_IN_MESSAGE(In_TextDocumentFormatting);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct Out_TextDocumentFormatting
 | 
					 | 
				
			||||||
    : public lsOutMessage<Out_TextDocumentFormatting> {
 | 
					 | 
				
			||||||
  lsRequestId id;
 | 
					 | 
				
			||||||
  std::vector<lsTextEdit> result;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentFormatting, jsonrpc, id, result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct Handler_TextDocumentFormatting
 | 
					 | 
				
			||||||
    : BaseMessageHandler<In_TextDocumentFormatting> {
 | 
					 | 
				
			||||||
  MethodType GetMethodType() const override { return kMethodType; }
 | 
					 | 
				
			||||||
  void Run(In_TextDocumentFormatting* request) override {
 | 
					 | 
				
			||||||
    Out_TextDocumentFormatting response;
 | 
					 | 
				
			||||||
    response.id = request->id;
 | 
					 | 
				
			||||||
#if USE_CLANG_CXX
 | 
					 | 
				
			||||||
    QueryFile* file;
 | 
					 | 
				
			||||||
    if (!FindFileOrFail(db, project, request->id,
 | 
					 | 
				
			||||||
                        request->params.textDocument.uri.GetPath(), &file)) {
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    WorkingFile* working_file =
 | 
					 | 
				
			||||||
        working_files->GetFileByFilename(file->def->path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    response.result = ConvertClangReplacementsIntoTextEdits(
 | 
					 | 
				
			||||||
        working_file->buffer_content,
 | 
					 | 
				
			||||||
        ClangFormatDocument(working_file, 0,
 | 
					 | 
				
			||||||
                            working_file->buffer_content.size(),
 | 
					 | 
				
			||||||
                            request->params.options));
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
    LOG_S(WARNING) << "You must compile ccls with --use-clang-cxx to use "
 | 
					 | 
				
			||||||
                      "textDocument/formatting.";
 | 
					 | 
				
			||||||
    // TODO: Fallback to execute the clang-format binary?
 | 
					 | 
				
			||||||
    response.result = {};
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QueueManager::WriteStdout(kMethodType, response);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentFormatting);
 | 
					 | 
				
			||||||
}  // namespace
 | 
					 | 
				
			||||||
@ -277,7 +277,7 @@ void TraceMe() {
 | 
				
			|||||||
  // If the environment variable is defined, wait for a debugger.
 | 
					  // If the environment variable is defined, wait for a debugger.
 | 
				
			||||||
  // In gdb, you need to invoke `signal SIGCONT` if you want ccls to continue
 | 
					  // In gdb, you need to invoke `signal SIGCONT` if you want ccls to continue
 | 
				
			||||||
  // after detaching.
 | 
					  // after detaching.
 | 
				
			||||||
  if (getenv("CQUERY_TRACEME"))
 | 
					  if (getenv("CCLS_TRACEME"))
 | 
				
			||||||
    raise(SIGTSTP);
 | 
					    raise(SIGTSTP);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void ccls_unreachable_internal(const char* msg, const char* file, int line) {
 | 
					void ccls_unreachable_internal(const char* msg, const char* file, int line) {
 | 
				
			||||||
  fprintf(stderr, "unreachable %s:%d %s\n", file, line, msg);
 | 
					  fprintf(stderr, "unreachable %s:%d %s\n", file, line, msg);
 | 
				
			||||||
  CQUERY_BUILTIN_UNREACHABLE;
 | 
					  CCLS_BUILTIN_UNREACHABLE;
 | 
				
			||||||
  abort();
 | 
					  abort();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										10
									
								
								src/port.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/port.h
									
									
									
									
									
								
							@ -12,17 +12,17 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// TODO GCC
 | 
					// TODO GCC
 | 
				
			||||||
#if __has_builtin(__builtin_unreachable)
 | 
					#if __has_builtin(__builtin_unreachable)
 | 
				
			||||||
#define CQUERY_BUILTIN_UNREACHABLE __builtin_unreachable()
 | 
					#define CCLS_BUILTIN_UNREACHABLE __builtin_unreachable()
 | 
				
			||||||
#elif defined(_MSC_VER)
 | 
					#elif defined(_MSC_VER)
 | 
				
			||||||
#define CQUERY_BUILTIN_UNREACHABLE __assume(false)
 | 
					#define CCLS_BUILTIN_UNREACHABLE __assume(false)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define CQUERY_BUILTIN_UNREACHABLE
 | 
					#define CCLS_BUILTIN_UNREACHABLE
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ccls_unreachable_internal(const char* msg, const char* file, int line);
 | 
					void ccls_unreachable_internal(const char* msg, const char* file, int line);
 | 
				
			||||||
#ifndef NDEBUG
 | 
					#ifndef NDEBUG
 | 
				
			||||||
#define CQUERY_UNREACHABLE(msg) \
 | 
					#define CCLS_UNREACHABLE(msg) \
 | 
				
			||||||
  ccls_unreachable_internal(msg, __FILE__, __LINE__)
 | 
					  ccls_unreachable_internal(msg, __FILE__, __LINE__)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define CQUERY_UNREACHABLE(msg)
 | 
					#define CCLS_UNREACHABLE(msg)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										121
									
								
								src/project.cc
									
									
									
									
									
								
							
							
						
						
									
										121
									
								
								src/project.cc
									
									
									
									
									
								
							@ -2,6 +2,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "cache_manager.h"
 | 
					#include "cache_manager.h"
 | 
				
			||||||
#include "clang_utils.h"
 | 
					#include "clang_utils.h"
 | 
				
			||||||
 | 
					#include "filesystem.hh"
 | 
				
			||||||
#include "language.h"
 | 
					#include "language.h"
 | 
				
			||||||
#include "match.h"
 | 
					#include "match.h"
 | 
				
			||||||
#include "platform.h"
 | 
					#include "platform.h"
 | 
				
			||||||
@ -27,41 +28,22 @@
 | 
				
			|||||||
#include <unordered_set>
 | 
					#include <unordered_set>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern bool gTestOutputMode;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct CompileCommandsEntry {
 | 
					struct CompileCommandsEntry {
 | 
				
			||||||
  std::string directory;
 | 
					  fs::path directory;
 | 
				
			||||||
  std::string file;
 | 
					  std::string file;
 | 
				
			||||||
  std::string command;
 | 
					  std::string command;
 | 
				
			||||||
  std::vector<std::string> args;
 | 
					  std::vector<std::string> args;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fs::path ResolveIfRelative(fs::path path) const {
 | 
				
			||||||
 | 
					    if (path.is_absolute())
 | 
				
			||||||
 | 
					      return path;
 | 
				
			||||||
 | 
					    return directory / path;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
MAKE_REFLECT_STRUCT(CompileCommandsEntry, directory, file, command, args);
 | 
					MAKE_REFLECT_STRUCT(CompileCommandsEntry, directory, file, command, args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool g_disable_normalize_path_for_test = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::string NormalizePathWithTestOptOut(const std::string& path) {
 | 
					 | 
				
			||||||
  if (g_disable_normalize_path_for_test) {
 | 
					 | 
				
			||||||
    // Add a & so we can test to verify a path is normalized.
 | 
					 | 
				
			||||||
    return "&" + path;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return NormalizePath(path);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool IsUnixAbsolutePath(const std::string& path) {
 | 
					 | 
				
			||||||
  return !path.empty() && path[0] == '/';
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool IsWindowsAbsolutePath(const std::string& path) {
 | 
					 | 
				
			||||||
  auto is_drive_letter = [](char c) {
 | 
					 | 
				
			||||||
    return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return path.size() > 3 && path[1] == ':' &&
 | 
					 | 
				
			||||||
         (path[2] == '/' || path[2] == '\\') && is_drive_letter(path[0]);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum class ProjectMode { CompileCommandsJson, DotCcls, ExternalCommand };
 | 
					enum class ProjectMode { CompileCommandsJson, DotCcls, ExternalCommand };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ProjectConfig {
 | 
					struct ProjectConfig {
 | 
				
			||||||
@ -127,22 +109,8 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
 | 
				
			|||||||
    Config* init_opts,
 | 
					    Config* init_opts,
 | 
				
			||||||
    ProjectConfig* config,
 | 
					    ProjectConfig* config,
 | 
				
			||||||
    const CompileCommandsEntry& entry) {
 | 
					    const CompileCommandsEntry& entry) {
 | 
				
			||||||
  auto cleanup_maybe_relative_path = [&](const std::string& path) {
 | 
					 | 
				
			||||||
    // TODO/FIXME: Normalization will fail for paths that do not exist. Should
 | 
					 | 
				
			||||||
    // it return an std::optional<std::string>?
 | 
					 | 
				
			||||||
    assert(!path.empty());
 | 
					 | 
				
			||||||
    if (entry.directory.empty() || IsUnixAbsolutePath(path) ||
 | 
					 | 
				
			||||||
        IsWindowsAbsolutePath(path)) {
 | 
					 | 
				
			||||||
      // We still want to normalize, as the path may contain .. characters.
 | 
					 | 
				
			||||||
      return NormalizePathWithTestOptOut(path);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (EndsWith(entry.directory, "/"))
 | 
					 | 
				
			||||||
      return NormalizePathWithTestOptOut(entry.directory + path);
 | 
					 | 
				
			||||||
    return NormalizePathWithTestOptOut(entry.directory + "/" + path);
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Project::Entry result;
 | 
					  Project::Entry result;
 | 
				
			||||||
  result.filename = NormalizePathWithTestOptOut(entry.file);
 | 
					  result.filename = entry.file;
 | 
				
			||||||
  const std::string base_name = GetBaseName(entry.file);
 | 
					  const std::string base_name = GetBaseName(entry.file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Expand %c %cpp %clang
 | 
					  // Expand %c %cpp %clang
 | 
				
			||||||
@ -185,7 +153,7 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // Add -working-directory if not provided.
 | 
					  // Add -working-directory if not provided.
 | 
				
			||||||
  if (!AnyStartsWith(args, "-working-directory"))
 | 
					  if (!AnyStartsWith(args, "-working-directory"))
 | 
				
			||||||
    result.args.emplace_back("-working-directory=" + entry.directory);
 | 
					    result.args.emplace_back("-working-directory=" + entry.directory.string());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool next_flag_is_path = false;
 | 
					  bool next_flag_is_path = false;
 | 
				
			||||||
  bool add_next_flag_to_quote_dirs = false;
 | 
					  bool add_next_flag_to_quote_dirs = false;
 | 
				
			||||||
@ -212,7 +180,7 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
 | 
				
			|||||||
    // Finish processing path for the previous argument, which was a switch.
 | 
					    // Finish processing path for the previous argument, which was a switch.
 | 
				
			||||||
    // {"-I", "foo"} style.
 | 
					    // {"-I", "foo"} style.
 | 
				
			||||||
    if (next_flag_is_path) {
 | 
					    if (next_flag_is_path) {
 | 
				
			||||||
      std::string normalized_arg = cleanup_maybe_relative_path(arg);
 | 
					      std::string normalized_arg = entry.ResolveIfRelative(arg);
 | 
				
			||||||
      if (add_next_flag_to_quote_dirs)
 | 
					      if (add_next_flag_to_quote_dirs)
 | 
				
			||||||
        config->quote_dirs.insert(normalized_arg);
 | 
					        config->quote_dirs.insert(normalized_arg);
 | 
				
			||||||
      if (add_next_flag_to_angle_dirs)
 | 
					      if (add_next_flag_to_angle_dirs)
 | 
				
			||||||
@ -238,7 +206,7 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
 | 
				
			|||||||
        if (StartsWith(arg, flag_type)) {
 | 
					        if (StartsWith(arg, flag_type)) {
 | 
				
			||||||
          std::string path = arg.substr(flag_type.size());
 | 
					          std::string path = arg.substr(flag_type.size());
 | 
				
			||||||
          assert(!path.empty());
 | 
					          assert(!path.empty());
 | 
				
			||||||
          path = cleanup_maybe_relative_path(path);
 | 
					          path = entry.ResolveIfRelative(path);
 | 
				
			||||||
          if (clang_cl || StartsWithAny(arg, kNormalizePathArgs))
 | 
					          if (clang_cl || StartsWithAny(arg, kNormalizePathArgs))
 | 
				
			||||||
            arg = flag_type + path;
 | 
					            arg = flag_type + path;
 | 
				
			||||||
          if (ShouldAddToQuoteIncludes(flag_type))
 | 
					          if (ShouldAddToQuoteIncludes(flag_type))
 | 
				
			||||||
@ -254,7 +222,7 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
 | 
				
			|||||||
      // slow. See
 | 
					      // slow. See
 | 
				
			||||||
      // https://github.com/cquery-project/cquery/commit/af63df09d57d765ce12d40007bf56302a0446678.
 | 
					      // https://github.com/cquery-project/cquery/commit/af63df09d57d765ce12d40007bf56302a0446678.
 | 
				
			||||||
      if (EndsWith(arg, base_name))
 | 
					      if (EndsWith(arg, base_name))
 | 
				
			||||||
        arg = cleanup_maybe_relative_path(arg);
 | 
					        arg = entry.ResolveIfRelative(arg);
 | 
				
			||||||
      // TODO Exclude .a .o to make link command in compile_commands.json work.
 | 
					      // TODO Exclude .a .o to make link command in compile_commands.json work.
 | 
				
			||||||
      // Also, clang_parseTranslationUnit2FullArgv does not seem to accept
 | 
					      // Also, clang_parseTranslationUnit2FullArgv does not seem to accept
 | 
				
			||||||
      // multiple source filenames.
 | 
					      // multiple source filenames.
 | 
				
			||||||
@ -450,13 +418,7 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    our_time.Resume();
 | 
					    our_time.Resume();
 | 
				
			||||||
    entry.directory = directory;
 | 
					    entry.directory = directory;
 | 
				
			||||||
    std::string absolute_filename;
 | 
					    entry.file = entry.ResolveIfRelative(relative_filename);
 | 
				
			||||||
    if (IsUnixAbsolutePath(relative_filename) ||
 | 
					 | 
				
			||||||
        IsWindowsAbsolutePath(relative_filename))
 | 
					 | 
				
			||||||
      absolute_filename = relative_filename;
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      absolute_filename = directory + "/" + relative_filename;
 | 
					 | 
				
			||||||
    entry.file = NormalizePathWithTestOptOut(absolute_filename);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    result.push_back(
 | 
					    result.push_back(
 | 
				
			||||||
        GetCompilationEntryFromCompileCommandEntry(config, project, entry));
 | 
					        GetCompilationEntryFromCompileCommandEntry(config, project, entry));
 | 
				
			||||||
@ -513,8 +475,8 @@ void Project::Load(Config* config, const std::string& root_directory) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Setup project entries.
 | 
					  // Setup project entries.
 | 
				
			||||||
  absolute_path_to_entry_index_.resize(entries.size());
 | 
					  absolute_path_to_entry_index_.reserve(entries.size());
 | 
				
			||||||
  for (int i = 0; i < entries.size(); ++i)
 | 
					  for (size_t i = 0; i < entries.size(); ++i)
 | 
				
			||||||
    absolute_path_to_entry_index_[entries[i].filename] = i;
 | 
					    absolute_path_to_entry_index_[entries[i].filename] = i;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -616,9 +578,6 @@ TEST_SUITE("Project") {
 | 
				
			|||||||
  void CheckFlags(const std::string& directory, const std::string& file,
 | 
					  void CheckFlags(const std::string& directory, const std::string& file,
 | 
				
			||||||
                  std::vector<std::string> raw,
 | 
					                  std::vector<std::string> raw,
 | 
				
			||||||
                  std::vector<std::string> expected) {
 | 
					                  std::vector<std::string> expected) {
 | 
				
			||||||
    g_disable_normalize_path_for_test = true;
 | 
					 | 
				
			||||||
    gTestOutputMode = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Config config;
 | 
					    Config config;
 | 
				
			||||||
    ProjectConfig project;
 | 
					    ProjectConfig project;
 | 
				
			||||||
    project.project_dir = "/w/c/s/";
 | 
					    project.project_dir = "/w/c/s/";
 | 
				
			||||||
@ -656,7 +615,7 @@ TEST_SUITE("Project") {
 | 
				
			|||||||
    CheckFlags(
 | 
					    CheckFlags(
 | 
				
			||||||
        /* raw */ {"clang", "-lstdc++", "myfile.cc"},
 | 
					        /* raw */ {"clang", "-lstdc++", "myfile.cc"},
 | 
				
			||||||
        /* expected */
 | 
					        /* expected */
 | 
				
			||||||
        {"clang", "-working-directory=/dir/", "-lstdc++", "&/dir/myfile.cc",
 | 
					        {"clang", "-working-directory=/dir/", "-lstdc++", "/dir/myfile.cc",
 | 
				
			||||||
         "-resource-dir=/w/resource_dir/", "-Wno-unknown-warning-option",
 | 
					         "-resource-dir=/w/resource_dir/", "-Wno-unknown-warning-option",
 | 
				
			||||||
         "-fparse-all-comments"});
 | 
					         "-fparse-all-comments"});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -668,17 +627,18 @@ TEST_SUITE("Project") {
 | 
				
			|||||||
         "-fparse-all-comments"});
 | 
					         "-fparse-all-comments"});
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _WIN32
 | 
				
			||||||
  TEST_CASE("Windows path normalization") {
 | 
					  TEST_CASE("Windows path normalization") {
 | 
				
			||||||
    CheckFlags("E:/workdir", "E:/workdir/bar.cc", /* raw */ {"clang", "bar.cc"},
 | 
					    CheckFlags("E:/workdir", "E:/workdir/bar.cc", /* raw */ {"clang", "bar.cc"},
 | 
				
			||||||
               /* expected */
 | 
					               /* expected */
 | 
				
			||||||
               {"clang", "-working-directory=E:/workdir", "&E:/workdir/bar.cc",
 | 
					               {"clang", "-working-directory=E:/workdir", "E:/workdir/bar.cc",
 | 
				
			||||||
                "-resource-dir=/w/resource_dir/", "-Wno-unknown-warning-option",
 | 
					                "-resource-dir=/w/resource_dir/", "-Wno-unknown-warning-option",
 | 
				
			||||||
                "-fparse-all-comments"});
 | 
					                "-fparse-all-comments"});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CheckFlags("E:/workdir", "E:/workdir/bar.cc",
 | 
					    CheckFlags("E:/workdir", "E:/workdir/bar.cc",
 | 
				
			||||||
               /* raw */ {"clang", "E:/workdir/bar.cc"},
 | 
					               /* raw */ {"clang", "E:/workdir/bar.cc"},
 | 
				
			||||||
               /* expected */
 | 
					               /* expected */
 | 
				
			||||||
               {"clang", "-working-directory=E:/workdir", "&E:/workdir/bar.cc",
 | 
					               {"clang", "-working-directory=E:/workdir", "E:/workdir/bar.cc",
 | 
				
			||||||
                "-resource-dir=/w/resource_dir/", "-Wno-unknown-warning-option",
 | 
					                "-resource-dir=/w/resource_dir/", "-Wno-unknown-warning-option",
 | 
				
			||||||
                "-fparse-all-comments"});
 | 
					                "-fparse-all-comments"});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -686,7 +646,7 @@ TEST_SUITE("Project") {
 | 
				
			|||||||
               /* raw */ {"clang-cl.exe", "/I./test", "E:/workdir/bar.cc"},
 | 
					               /* raw */ {"clang-cl.exe", "/I./test", "E:/workdir/bar.cc"},
 | 
				
			||||||
               /* expected */
 | 
					               /* expected */
 | 
				
			||||||
               {"clang-cl.exe", "-working-directory=E:/workdir",
 | 
					               {"clang-cl.exe", "-working-directory=E:/workdir",
 | 
				
			||||||
                "/I&E:/workdir/./test", "&E:/workdir/bar.cc",
 | 
					                "/I&E:/workdir/./test", "E:/workdir/bar.cc",
 | 
				
			||||||
                "-resource-dir=/w/resource_dir/", "-Wno-unknown-warning-option",
 | 
					                "-resource-dir=/w/resource_dir/", "-Wno-unknown-warning-option",
 | 
				
			||||||
                "-fparse-all-comments"});
 | 
					                "-fparse-all-comments"});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -696,28 +656,20 @@ TEST_SUITE("Project") {
 | 
				
			|||||||
               /* expected */
 | 
					               /* expected */
 | 
				
			||||||
               {"cl.exe", "-working-directory=E:/workdir",
 | 
					               {"cl.exe", "-working-directory=E:/workdir",
 | 
				
			||||||
                "/I&E:/workdir/../third_party/test/include",
 | 
					                "/I&E:/workdir/../third_party/test/include",
 | 
				
			||||||
                "&E:/workdir/bar.cc", "-resource-dir=/w/resource_dir/",
 | 
					                "E:/workdir/bar.cc", "-resource-dir=/w/resource_dir/",
 | 
				
			||||||
                "-Wno-unknown-warning-option", "-fparse-all-comments"});
 | 
					                "-Wno-unknown-warning-option", "-fparse-all-comments"});
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  TEST_CASE("Path in args") {
 | 
					  TEST_CASE("Path in args") {
 | 
				
			||||||
    CheckFlags("/home/user", "/home/user/foo/bar.c",
 | 
					    CheckFlags("/home/user", "/home/user/foo/bar.c",
 | 
				
			||||||
               /* raw */ {"cc", "-O0", "foo/bar.c"},
 | 
					               /* raw */ {"cc", "-O0", "foo/bar.c"},
 | 
				
			||||||
               /* expected */
 | 
					               /* expected */
 | 
				
			||||||
               {"cc", "-working-directory=/home/user", "-O0",
 | 
					               {"cc", "-working-directory=/home/user", "-O0",
 | 
				
			||||||
                "&/home/user/foo/bar.c", "-resource-dir=/w/resource_dir/",
 | 
					                "/home/user/foo/bar.c", "-resource-dir=/w/resource_dir/",
 | 
				
			||||||
                "-Wno-unknown-warning-option", "-fparse-all-comments"});
 | 
					                "-Wno-unknown-warning-option", "-fparse-all-comments"});
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  TEST_CASE("Implied binary") {
 | 
					 | 
				
			||||||
    CheckFlags("/home/user", "/home/user/foo/bar.cc",
 | 
					 | 
				
			||||||
               /* raw */ {"clang", "-DDONT_IGNORE_ME"},
 | 
					 | 
				
			||||||
               /* expected */
 | 
					 | 
				
			||||||
               {"clang", "-working-directory=/home/user", "-DDONT_IGNORE_ME",
 | 
					 | 
				
			||||||
                "-resource-dir=/w/resource_dir/", "-Wno-unknown-warning-option",
 | 
					 | 
				
			||||||
                "-fparse-all-comments"});
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  TEST_CASE("Directory extraction") {
 | 
					  TEST_CASE("Directory extraction") {
 | 
				
			||||||
    Config init_opts;
 | 
					    Config init_opts;
 | 
				
			||||||
    ProjectConfig config;
 | 
					    ProjectConfig config;
 | 
				
			||||||
@ -752,11 +704,11 @@ TEST_SUITE("Project") {
 | 
				
			|||||||
        GetCompilationEntryFromCompileCommandEntry(&init_opts, &config, entry);
 | 
					        GetCompilationEntryFromCompileCommandEntry(&init_opts, &config, entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::unordered_set<std::string> angle_expected{
 | 
					    std::unordered_set<std::string> angle_expected{
 | 
				
			||||||
        "&/a_absolute1", "&/a_absolute2", "&/base/a_relative1",
 | 
					        "/a_absolute1", "/a_absolute2", "/base/a_relative1",
 | 
				
			||||||
        "&/base/a_relative2"};
 | 
					        "/base/a_relative2"};
 | 
				
			||||||
    std::unordered_set<std::string> quote_expected{
 | 
					    std::unordered_set<std::string> quote_expected{
 | 
				
			||||||
        "&/q_absolute1", "&/q_absolute2", "&/base/q_relative1",
 | 
					        "/q_absolute1", "/q_absolute2", "/base/q_relative1",
 | 
				
			||||||
        "&/base/q_relative2"};
 | 
					        "/base/q_relative2"};
 | 
				
			||||||
    REQUIRE(config.angle_dirs == angle_expected);
 | 
					    REQUIRE(config.angle_dirs == angle_expected);
 | 
				
			||||||
    REQUIRE(config.quote_dirs == quote_expected);
 | 
					    REQUIRE(config.quote_dirs == quote_expected);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -817,23 +769,6 @@ TEST_SUITE("Project") {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  TEST_CASE("IsWindowsAbsolutePath works correctly") {
 | 
					 | 
				
			||||||
    REQUIRE(IsWindowsAbsolutePath("C:/Users/projects/"));
 | 
					 | 
				
			||||||
    REQUIRE(IsWindowsAbsolutePath("C:/Users/projects"));
 | 
					 | 
				
			||||||
    REQUIRE(IsWindowsAbsolutePath("C:/Users/projects"));
 | 
					 | 
				
			||||||
    REQUIRE(IsWindowsAbsolutePath("C:\\Users\\projects"));
 | 
					 | 
				
			||||||
    REQUIRE(IsWindowsAbsolutePath("C:\\\\Users\\\\projects"));
 | 
					 | 
				
			||||||
    REQUIRE(IsWindowsAbsolutePath("c:\\\\Users\\\\projects"));
 | 
					 | 
				
			||||||
    REQUIRE(IsWindowsAbsolutePath("A:\\\\Users\\\\projects"));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    REQUIRE(!IsWindowsAbsolutePath("C:/"));
 | 
					 | 
				
			||||||
    REQUIRE(!IsWindowsAbsolutePath("../abc/test"));
 | 
					 | 
				
			||||||
    REQUIRE(!IsWindowsAbsolutePath("5:/test"));
 | 
					 | 
				
			||||||
    REQUIRE(!IsWindowsAbsolutePath("ccls/project/file.cc"));
 | 
					 | 
				
			||||||
    REQUIRE(!IsWindowsAbsolutePath(""));
 | 
					 | 
				
			||||||
    REQUIRE(!IsWindowsAbsolutePath("/etc/linux/path"));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  TEST_CASE("Entry inference prefers same file endings") {
 | 
					  TEST_CASE("Entry inference prefers same file endings") {
 | 
				
			||||||
    Project p;
 | 
					    Project p;
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
				
			|||||||
@ -3,13 +3,12 @@
 | 
				
			|||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
#include "method.h"
 | 
					#include "method.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <optional>
 | 
					 | 
				
			||||||
#include <sparsepp/spp.h>
 | 
					 | 
				
			||||||
#include <variant>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
#include <mutex>
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					#include <optional>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <unordered_map>
 | 
				
			||||||
 | 
					#include <variant>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class QueueManager;
 | 
					class QueueManager;
 | 
				
			||||||
@ -29,7 +28,7 @@ struct Project {
 | 
				
			|||||||
  std::vector<std::string> angle_include_directories;
 | 
					  std::vector<std::string> angle_include_directories;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::vector<Entry> entries;
 | 
					  std::vector<Entry> entries;
 | 
				
			||||||
  spp::sparse_hash_map<std::string, int> absolute_path_to_entry_index_;
 | 
					  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|.
 | 
				
			||||||
  //
 | 
					  //
 | 
				
			||||||
 | 
				
			|||||||
@ -270,7 +270,7 @@ struct QueryDatabase {
 | 
				
			|||||||
  std::vector<QueryVar> vars;
 | 
					  std::vector<QueryVar> vars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Lookup symbol based on a usr.
 | 
					  // Lookup symbol based on a usr.
 | 
				
			||||||
  spp::sparse_hash_map<std::string, QueryFileId> usr_to_file;
 | 
					  std::unordered_map<std::string, QueryFileId> usr_to_file;
 | 
				
			||||||
  spp::sparse_hash_map<Usr, QueryTypeId> usr_to_type;
 | 
					  spp::sparse_hash_map<Usr, QueryTypeId> usr_to_type;
 | 
				
			||||||
  spp::sparse_hash_map<Usr, QueryFuncId> usr_to_func;
 | 
					  spp::sparse_hash_map<Usr, QueryFuncId> usr_to_func;
 | 
				
			||||||
  spp::sparse_hash_map<Usr, QueryVarId> usr_to_var;
 | 
					  spp::sparse_hash_map<Usr, QueryVarId> usr_to_var;
 | 
				
			||||||
 | 
				
			|||||||
@ -16,6 +16,7 @@
 | 
				
			|||||||
#include <queue>
 | 
					#include <queue>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <thread>
 | 
				
			||||||
#include <unordered_map>
 | 
					#include <unordered_map>
 | 
				
			||||||
using namespace std::placeholders;
 | 
					using namespace std::placeholders;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -277,6 +278,13 @@ std::string GetDefaultResourceDirectory() {
 | 
				
			|||||||
  return NormalizePath(result);
 | 
					  return NormalizePath(result);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void StartThread(const std::string& thread_name, std::function<void()> entry) {
 | 
				
			||||||
 | 
					  new std::thread([thread_name, entry]() {
 | 
				
			||||||
 | 
					    SetCurrentThreadName(thread_name);
 | 
				
			||||||
 | 
					    entry();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST_SUITE("StripFileType") {
 | 
					TEST_SUITE("StripFileType") {
 | 
				
			||||||
  TEST_CASE("all") {
 | 
					  TEST_CASE("all") {
 | 
				
			||||||
    REQUIRE(StripFileType("") == "");
 | 
					    REQUIRE(StripFileType("") == "");
 | 
				
			||||||
 | 
				
			|||||||
@ -149,3 +149,5 @@ inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string GetDefaultResourceDirectory();
 | 
					std::string GetDefaultResourceDirectory();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void StartThread(const std::string& thread_name, std::function<void()> entry);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,12 +0,0 @@
 | 
				
			|||||||
#include "work_thread.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "platform.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// static
 | 
					 | 
				
			||||||
void WorkThread::StartThread(const std::string& thread_name,
 | 
					 | 
				
			||||||
                             std::function<void()> entry_point) {
 | 
					 | 
				
			||||||
  new std::thread([thread_name, entry_point]() {
 | 
					 | 
				
			||||||
    SetCurrentThreadName(thread_name);
 | 
					 | 
				
			||||||
    entry_point();
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,19 +0,0 @@
 | 
				
			|||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <atomic>
 | 
					 | 
				
			||||||
#include <functional>
 | 
					 | 
				
			||||||
#include <mutex>
 | 
					 | 
				
			||||||
#include <thread>
 | 
					 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Helper methods for starting threads that do some work. Enables test code to
 | 
					 | 
				
			||||||
// wait for all work to complete.
 | 
					 | 
				
			||||||
struct WorkThread {
 | 
					 | 
				
			||||||
  // Launch a new thread. |entry_point| will be called continously. It should
 | 
					 | 
				
			||||||
  // return true if it there is still known work to be done.
 | 
					 | 
				
			||||||
  static void StartThread(const std::string& thread_name,
 | 
					 | 
				
			||||||
                          std::function<void()> entry_point);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Static-only class.
 | 
					 | 
				
			||||||
  WorkThread() = delete;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user