mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-03 22:04:24 +00:00 
			
		
		
		
	Simplify; improve $ccls/inheritanceHierarchy
This commit is contained in:
		
							parent
							
								
									32bde07df6
								
							
						
					
					
						commit
						07f0cdbf38
					
				@ -2,6 +2,8 @@
 | 
			
		||||
#include "query_utils.h"
 | 
			
		||||
#include "queue_manager.h"
 | 
			
		||||
 | 
			
		||||
#include <unordered_set>
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
MethodType kMethodType = "$ccls/inheritanceHierarchy";
 | 
			
		||||
 | 
			
		||||
@ -79,19 +81,22 @@ bool ExpandHelper(MessageHandler* m,
 | 
			
		||||
                  int levels,
 | 
			
		||||
                  Q& entity) {
 | 
			
		||||
  const auto* def = entity.AnyDef();
 | 
			
		||||
  if (!def) {
 | 
			
		||||
  if (def) {
 | 
			
		||||
    entry->name = def->Name(qualified);
 | 
			
		||||
    if (def->spell) {
 | 
			
		||||
      if (auto loc = GetLsLocation(m->db, m->working_files, *def->spell))
 | 
			
		||||
        entry->location = *loc;
 | 
			
		||||
    }
 | 
			
		||||
  } else if (!derived) {
 | 
			
		||||
    entry->numChildren = 0;
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  entry->name = def->Name(qualified);
 | 
			
		||||
  if (def->spell) {
 | 
			
		||||
    if (std::optional<lsLocation> loc =
 | 
			
		||||
            GetLsLocation(m->db, m->working_files, *def->spell))
 | 
			
		||||
      entry->location = *loc;
 | 
			
		||||
  }
 | 
			
		||||
  std::unordered_set<Usr> seen;
 | 
			
		||||
  if (derived) {
 | 
			
		||||
    if (levels > 0) {
 | 
			
		||||
      for (auto usr : entity.derived) {
 | 
			
		||||
        if (seen.insert(usr).second)
 | 
			
		||||
          continue;
 | 
			
		||||
        Out_CclsInheritanceHierarchy::Entry entry1;
 | 
			
		||||
        entry1.id = std::to_string(usr);
 | 
			
		||||
        entry1.usr = usr;
 | 
			
		||||
@ -105,6 +110,8 @@ bool ExpandHelper(MessageHandler* m,
 | 
			
		||||
  } else {
 | 
			
		||||
    if (levels > 0) {
 | 
			
		||||
      for (auto usr : def->bases) {
 | 
			
		||||
        if (seen.insert(usr).second)
 | 
			
		||||
          continue;
 | 
			
		||||
        Out_CclsInheritanceHierarchy::Entry entry1;
 | 
			
		||||
        entry1.id = std::to_string(usr);
 | 
			
		||||
        entry1.usr = usr;
 | 
			
		||||
 | 
			
		||||
@ -267,12 +267,8 @@ struct lsTextDocumentClientCapabilities {
 | 
			
		||||
      // and `${3:foo}`. `$0` defines the final tab stop, it defaults to
 | 
			
		||||
      // the end of the snippet. Placeholders with equal identifiers are linked,
 | 
			
		||||
      // that is typing in one will update others too.
 | 
			
		||||
      std::optional<bool> snippetSupport;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // The client supports the following `CompletionItem` specific
 | 
			
		||||
    // capabilities.
 | 
			
		||||
    std::optional<lsCompletionItem> completionItem;
 | 
			
		||||
      bool snippetSupport = false;
 | 
			
		||||
    } completionItem;
 | 
			
		||||
  } completion;
 | 
			
		||||
 | 
			
		||||
  struct lsGenericDynamicReg {
 | 
			
		||||
@ -426,58 +422,56 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
 | 
			
		||||
  MethodType GetMethodType() const override { return kMethodType; }
 | 
			
		||||
 | 
			
		||||
  void Run(In_InitializeRequest* request) override {
 | 
			
		||||
    // Log initialization parameters.
 | 
			
		||||
    auto& params = request->params;
 | 
			
		||||
    if (!params.rootUri)
 | 
			
		||||
      return;
 | 
			
		||||
    {
 | 
			
		||||
      rapidjson::StringBuffer output;
 | 
			
		||||
      rapidjson::Writer<rapidjson::StringBuffer> writer(output);
 | 
			
		||||
      JsonWriter json_writer(&writer);
 | 
			
		||||
    Reflect(json_writer, request->params.initializationOptions);
 | 
			
		||||
    LOG_S(INFO) << "Init parameters: " << output.GetString();
 | 
			
		||||
    std::unique_ptr<Config> config;
 | 
			
		||||
      Reflect(json_writer, params.initializationOptions);
 | 
			
		||||
      LOG_S(INFO) << "initializationOptions: " << output.GetString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (request->params.rootUri) {
 | 
			
		||||
      std::string project_path =
 | 
			
		||||
          NormalizePath(request->params.rootUri->GetPath());
 | 
			
		||||
      LOG_S(INFO) << "[querydb] Initialize in directory " << project_path
 | 
			
		||||
                  << " with uri " << request->params.rootUri->raw_uri;
 | 
			
		||||
    std::string project_path = NormalizePath(params.rootUri->GetPath());
 | 
			
		||||
    LOG_S(INFO) << "initialize in directory " << project_path << " with uri "
 | 
			
		||||
                << params.rootUri->raw_uri;
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        if (request->params.initializationOptions)
 | 
			
		||||
          config = std::make_unique<Config>(*request->params.initializationOptions);
 | 
			
		||||
      if (params.initializationOptions)
 | 
			
		||||
        g_config = std::make_unique<Config>(*params.initializationOptions);
 | 
			
		||||
      else
 | 
			
		||||
          config = std::make_unique<Config>();
 | 
			
		||||
        g_config = std::make_unique<Config>();
 | 
			
		||||
      rapidjson::Document reader;
 | 
			
		||||
      reader.Parse(g_init_options.c_str());
 | 
			
		||||
      if (!reader.HasParseError()) {
 | 
			
		||||
        JsonReader json_reader{&reader};
 | 
			
		||||
        try {
 | 
			
		||||
            Reflect(json_reader, *config);
 | 
			
		||||
          Reflect(json_reader, *g_config);
 | 
			
		||||
        } catch (std::invalid_argument&) {
 | 
			
		||||
          // This will not trigger because parse error is handled in
 | 
			
		||||
          // MessageRegistry::Parse in lsp.cc
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
        if (config->cacheDirectory.empty()) {
 | 
			
		||||
      if (g_config->cacheDirectory.empty()) {
 | 
			
		||||
        LOG_S(ERROR) << "cacheDirectory cannot be empty.";
 | 
			
		||||
        exit(1);
 | 
			
		||||
      } else {
 | 
			
		||||
          config->cacheDirectory = NormalizePath(config->cacheDirectory);
 | 
			
		||||
          EnsureEndsInSlash(config->cacheDirectory);
 | 
			
		||||
        g_config->cacheDirectory = NormalizePath(g_config->cacheDirectory);
 | 
			
		||||
        EnsureEndsInSlash(g_config->cacheDirectory);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Client capabilities
 | 
			
		||||
      {
 | 
			
		||||
        const auto& cap = request->params.capabilities.textDocument;
 | 
			
		||||
        if (cap.completion.completionItem)
 | 
			
		||||
          config->client.snippetSupport =
 | 
			
		||||
              cap.completion.completionItem->snippetSupport.value_or(false);
 | 
			
		||||
      }
 | 
			
		||||
    const auto& capabilities = params.capabilities;
 | 
			
		||||
    g_config->client.snippetSupport =
 | 
			
		||||
        capabilities.textDocument.completion.completionItem.snippetSupport;
 | 
			
		||||
 | 
			
		||||
    // Ensure there is a resource directory.
 | 
			
		||||
      if (config->clang.resourceDir.empty())
 | 
			
		||||
        config->clang.resourceDir = GetDefaultResourceDirectory();
 | 
			
		||||
      LOG_S(INFO) << "Using -resource-dir=" << config->clang.resourceDir;
 | 
			
		||||
    if (g_config->clang.resourceDir.empty())
 | 
			
		||||
      g_config->clang.resourceDir = GetDefaultResourceDirectory();
 | 
			
		||||
    LOG_S(INFO) << "Using -resource-dir=" << g_config->clang.resourceDir;
 | 
			
		||||
 | 
			
		||||
    // Send initialization before starting indexers, so we don't send a
 | 
			
		||||
    // status update too early.
 | 
			
		||||
@ -491,15 +485,14 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
 | 
			
		||||
 | 
			
		||||
    // Set project root.
 | 
			
		||||
    EnsureEndsInSlash(project_path);
 | 
			
		||||
      config->projectRoot = project_path;
 | 
			
		||||
    g_config->projectRoot = project_path;
 | 
			
		||||
    // Create two cache directories for files inside and outside of the
 | 
			
		||||
    // project.
 | 
			
		||||
      sys::fs::create_directories(config->cacheDirectory +
 | 
			
		||||
                                  EscapeFileName(config->projectRoot));
 | 
			
		||||
      sys::fs::create_directories(config->cacheDirectory + '@' +
 | 
			
		||||
                                  EscapeFileName(config->projectRoot));
 | 
			
		||||
    sys::fs::create_directories(g_config->cacheDirectory +
 | 
			
		||||
                                EscapeFileName(g_config->projectRoot));
 | 
			
		||||
    sys::fs::create_directories(g_config->cacheDirectory + '@' +
 | 
			
		||||
                                EscapeFileName(g_config->projectRoot));
 | 
			
		||||
 | 
			
		||||
      g_config = std::move(config);
 | 
			
		||||
    Timer time;
 | 
			
		||||
    diag_engine->Init();
 | 
			
		||||
    semantic_cache->Init();
 | 
			
		||||
@ -534,7 +527,6 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
 | 
			
		||||
    // We need to support multiple concurrent index processes.
 | 
			
		||||
    time.ResetAndPrint("[perf] Dispatched initial index requests");
 | 
			
		||||
  }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
REGISTER_MESSAGE_HANDLER(Handler_Initialize);
 | 
			
		||||
}  // namespace
 | 
			
		||||
 | 
			
		||||
@ -26,17 +26,11 @@ struct Handler_TextDocumentDidChange
 | 
			
		||||
    std::string path = request->params.textDocument.uri.GetPath();
 | 
			
		||||
    working_files->OnChange(request->params);
 | 
			
		||||
    if (g_config->index.onDidChange) {
 | 
			
		||||
      std::optional<std::string> content = ReadContent(path);
 | 
			
		||||
      if (!content) {
 | 
			
		||||
        LOG_S(ERROR) << "Unable to read file content after saving " << path;
 | 
			
		||||
      } else {
 | 
			
		||||
      Project::Entry entry = project->FindCompilationEntryForFile(path);
 | 
			
		||||
      QueueManager::instance()->index_request.PushBack(
 | 
			
		||||
            Index_Request(entry.filename, entry.args, true /*is_interactive*/,
 | 
			
		||||
                          *content),
 | 
			
		||||
          Index_Request(entry.filename, entry.args, true /*is_interactive*/),
 | 
			
		||||
          true);
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
    clang_complete->NotifyEdit(path);
 | 
			
		||||
    clang_complete->DiagnosticsUpdate(
 | 
			
		||||
        request->params.textDocument.AsTextDocumentIdentifier());
 | 
			
		||||
 | 
			
		||||
@ -65,7 +65,7 @@ struct Handler_TextDocumentDidOpen
 | 
			
		||||
      QueueManager::instance()->index_request.PushBack(
 | 
			
		||||
          Index_Request(entry.filename,
 | 
			
		||||
                        params.args.size() ? params.args : entry.args,
 | 
			
		||||
                        true /*is_interactive*/, params.textDocument.text),
 | 
			
		||||
                        true /*is_interactive*/),
 | 
			
		||||
          true /* priority */);
 | 
			
		||||
 | 
			
		||||
      clang_complete->FlushSession(entry.filename);
 | 
			
		||||
 | 
			
		||||
@ -48,17 +48,11 @@ struct Handler_TextDocumentDidSave
 | 
			
		||||
    //      if so, ignore that index response.
 | 
			
		||||
    // TODO: send as priority request
 | 
			
		||||
    if (!g_config->index.onDidChange) {
 | 
			
		||||
      std::optional<std::string> content = ReadContent(path);
 | 
			
		||||
      if (!content) {
 | 
			
		||||
        LOG_S(ERROR) << "Unable to read file content after saving " << path;
 | 
			
		||||
      } else {
 | 
			
		||||
      Project::Entry entry = project->FindCompilationEntryForFile(path);
 | 
			
		||||
      QueueManager::instance()->index_request.PushBack(
 | 
			
		||||
            Index_Request(entry.filename, entry.args, true /*is_interactive*/,
 | 
			
		||||
                          *content),
 | 
			
		||||
          Index_Request(entry.filename, entry.args, true /*is_interactive*/),
 | 
			
		||||
          true);
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    clang_complete->NotifySave(path);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -54,20 +54,15 @@ struct Handler_WorkspaceDidChangeWatchedFiles
 | 
			
		||||
      switch (event.type) {
 | 
			
		||||
        case lsFileChangeType::Created:
 | 
			
		||||
        case lsFileChangeType::Changed: {
 | 
			
		||||
          std::optional<std::string> content = ReadContent(path);
 | 
			
		||||
          if (!content)
 | 
			
		||||
            LOG_S(ERROR) << "Unable to read file content after saving " << path;
 | 
			
		||||
          else {
 | 
			
		||||
          QueueManager::instance()->index_request.PushBack(
 | 
			
		||||
                Index_Request(path, entry.args, is_interactive, *content));
 | 
			
		||||
              Index_Request(path, entry.args, is_interactive));
 | 
			
		||||
          if (is_interactive)
 | 
			
		||||
            clang_complete->NotifySave(path);
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        case lsFileChangeType::Deleted:
 | 
			
		||||
          QueueManager::instance()->index_request.PushBack(
 | 
			
		||||
              Index_Request(path, entry.args, is_interactive, std::string()));
 | 
			
		||||
              Index_Request(path, entry.args, is_interactive));
 | 
			
		||||
          break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -458,19 +458,13 @@ void Project::Index(QueueManager* queue,
 | 
			
		||||
                    WorkingFiles* wfiles,
 | 
			
		||||
                    lsRequestId id) {
 | 
			
		||||
  ForAllFilteredFiles([&](int i, const Project::Entry& entry) {
 | 
			
		||||
    std::optional<std::string> content = ReadContent(entry.filename);
 | 
			
		||||
    if (!content) {
 | 
			
		||||
      LOG_S(ERROR) << "When loading project, canont read file "
 | 
			
		||||
                   << entry.filename;
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    bool is_interactive = wfiles->GetFileByFilename(entry.filename) != nullptr;
 | 
			
		||||
    queue->index_request.PushBack(Index_Request(entry.filename, entry.args,
 | 
			
		||||
                                                is_interactive, *content, id));
 | 
			
		||||
    queue->index_request.PushBack(
 | 
			
		||||
        Index_Request(entry.filename, entry.args, is_interactive, id));
 | 
			
		||||
  });
 | 
			
		||||
  // Dummy request to indicate that project is loaded and
 | 
			
		||||
  // trigger refreshing semantic highlight for all working files.
 | 
			
		||||
  queue->index_request.PushBack(Index_Request("", {}, false, ""));
 | 
			
		||||
  queue->index_request.PushBack(Index_Request("", {}, false));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_SUITE("Project") {
 | 
			
		||||
 | 
			
		||||
@ -6,17 +6,11 @@
 | 
			
		||||
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 | 
			
		||||
Index_Request::Index_Request(
 | 
			
		||||
    const std::string& path,
 | 
			
		||||
Index_Request::Index_Request(const std::string& path,
 | 
			
		||||
                             const std::vector<std::string>& args,
 | 
			
		||||
                             bool is_interactive,
 | 
			
		||||
    const std::string& contents,
 | 
			
		||||
                             lsRequestId id)
 | 
			
		||||
    : path(path),
 | 
			
		||||
      args(args),
 | 
			
		||||
      is_interactive(is_interactive),
 | 
			
		||||
      contents(contents),
 | 
			
		||||
      id(id) {}
 | 
			
		||||
    : path(path), args(args), is_interactive(is_interactive), id(id) {}
 | 
			
		||||
 | 
			
		||||
Index_OnIndexed::Index_OnIndexed(IndexUpdate&& update,
 | 
			
		||||
                                 PerformanceImportFile perf)
 | 
			
		||||
 | 
			
		||||
@ -19,13 +19,11 @@ struct Index_Request {
 | 
			
		||||
  // TODO: make |args| a string that is parsed lazily.
 | 
			
		||||
  std::vector<std::string> args;
 | 
			
		||||
  bool is_interactive;
 | 
			
		||||
  std::string contents;  // Preloaded contents.
 | 
			
		||||
  lsRequestId id;
 | 
			
		||||
 | 
			
		||||
  Index_Request(const std::string& path,
 | 
			
		||||
                const std::vector<std::string>& args,
 | 
			
		||||
                bool is_interactive,
 | 
			
		||||
                const std::string& contents,
 | 
			
		||||
                lsRequestId id = {});
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user