mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-03 22:04:24 +00:00 
			
		
		
		
	Use non-inferred entries and build preamble for .h; index on didOpen if no pending requests; documentHighlight
This commit is contained in:
		
							parent
							
								
									79373ba486
								
							
						
					
					
						commit
						84984c6c27
					
				@ -231,16 +231,13 @@ void CompletionPreloadMain(CompletionManager *manager) {
 | 
			
		||||
    if (!session)
 | 
			
		||||
      continue;
 | 
			
		||||
 | 
			
		||||
    // For inferred session, don't build preamble because changes in a.h will
 | 
			
		||||
    // invalidate it.
 | 
			
		||||
    if (!session->inferred) {
 | 
			
		||||
    const auto &args = session->file.args;
 | 
			
		||||
      WorkingFiles::Snapshot snapshot = session->wfiles->AsSnapshot(
 | 
			
		||||
        {StripFileType(session->file.filename)});
 | 
			
		||||
    WorkingFiles::Snapshot snapshot =
 | 
			
		||||
        session->wfiles->AsSnapshot({StripFileType(session->file.filename)});
 | 
			
		||||
    if (std::unique_ptr<CompilerInvocation> CI =
 | 
			
		||||
            BuildCompilerInvocation(args, session->FS))
 | 
			
		||||
      session->BuildPreamble(*CI, request.path);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int debounce =
 | 
			
		||||
        is_open ? g_config->diagnostics.onOpen : g_config->diagnostics.onSave;
 | 
			
		||||
    if (debounce >= 0) {
 | 
			
		||||
@ -539,7 +536,7 @@ bool CompletionManager::EnsureCompletionOrCreatePreloadSession(
 | 
			
		||||
 | 
			
		||||
  // No CompletionSession, create new one.
 | 
			
		||||
  auto session = std::make_shared<ccls::CompletionSession>(
 | 
			
		||||
      project_->FindCompilationEntryForFile(path), working_files_, PCH);
 | 
			
		||||
      project_->FindEntry(path, false), working_files_, PCH);
 | 
			
		||||
  if (session->file.filename != path) {
 | 
			
		||||
    session->inferred = true;
 | 
			
		||||
    session->file.filename = path;
 | 
			
		||||
@ -568,7 +565,7 @@ CompletionManager::TryGetSession(const std::string &path, bool preload,
 | 
			
		||||
  session = sessions.TryGet(path);
 | 
			
		||||
  if (!session && !preload) {
 | 
			
		||||
    session = std::make_shared<ccls::CompletionSession>(
 | 
			
		||||
        project_->FindCompilationEntryForFile(path), working_files_, PCH);
 | 
			
		||||
        project_->FindEntry(path, false), working_files_, PCH);
 | 
			
		||||
    sessions.Insert(path, session);
 | 
			
		||||
    LOG_S(INFO) << "create session for " << path;
 | 
			
		||||
    if (is_open)
 | 
			
		||||
 | 
			
		||||
@ -29,7 +29,6 @@ limitations under the License.
 | 
			
		||||
#include <llvm/ADT/CachedHashString.h>
 | 
			
		||||
#include <llvm/ADT/DenseMap.h>
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string_view>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
@ -76,21 +76,11 @@ struct Handler_TextDocumentDefinition
 | 
			
		||||
    Out_TextDocumentDefinition out;
 | 
			
		||||
    out.id = request->id;
 | 
			
		||||
 | 
			
		||||
    Maybe<Range> range;
 | 
			
		||||
    SymbolKind kind;
 | 
			
		||||
    Maybe<Use> on_def;
 | 
			
		||||
    WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
 | 
			
		||||
    lsPosition &ls_pos = params.position;
 | 
			
		||||
 | 
			
		||||
    for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, ls_pos)) {
 | 
			
		||||
      if (!range) {
 | 
			
		||||
        range = sym.range;
 | 
			
		||||
        kind = sym.kind;
 | 
			
		||||
      } else if (!(sym.range == *range && sym.kind == kind)) {
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      // Found symbol. Return definition.
 | 
			
		||||
 | 
			
		||||
    for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, ls_pos, true)) {
 | 
			
		||||
      // Special cases which are handled:
 | 
			
		||||
      //  - symbol has declaration but no definition (ie, pure virtual)
 | 
			
		||||
      //  - goto declaration while in definition of recursive type
 | 
			
		||||
@ -129,6 +119,7 @@ struct Handler_TextDocumentDefinition
 | 
			
		||||
      out.result.erase(std::unique(out.result.begin(), out.result.end()),
 | 
			
		||||
                       out.result.end());
 | 
			
		||||
    } else {
 | 
			
		||||
      Maybe<Range> range;
 | 
			
		||||
      // Check #include
 | 
			
		||||
      for (const IndexInclude &include : file->def->includes) {
 | 
			
		||||
        if (include.line == ls_pos.line) {
 | 
			
		||||
 | 
			
		||||
@ -125,8 +125,10 @@ struct Handler_TextDocumentDidOpen
 | 
			
		||||
    if (args.size())
 | 
			
		||||
      project->SetArgsForFile(args, path);
 | 
			
		||||
 | 
			
		||||
    // Submit new index request if it is not a header file.
 | 
			
		||||
    if (SourceFileLanguage(path) != LanguageId::Unknown)
 | 
			
		||||
    // Submit new index request if it is not a header file or there is no
 | 
			
		||||
    // pending index request.
 | 
			
		||||
    if (SourceFileLanguage(path) != LanguageId::Unknown ||
 | 
			
		||||
        !pipeline::pending_index_requests)
 | 
			
		||||
      pipeline::Index(path, args, IndexMode::Normal);
 | 
			
		||||
 | 
			
		||||
    clang_complete->NotifyView(path);
 | 
			
		||||
 | 
			
		||||
@ -17,11 +17,28 @@ limitations under the License.
 | 
			
		||||
#include "pipeline.hh"
 | 
			
		||||
#include "query_utils.h"
 | 
			
		||||
#include "symbol.h"
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
using namespace ccls;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
MethodType kMethodType = "textDocument/documentHighlight";
 | 
			
		||||
 | 
			
		||||
struct lsDocumentHighlight {
 | 
			
		||||
  enum Kind { Text = 1, Read = 2, Write = 3 };
 | 
			
		||||
 | 
			
		||||
  lsRange range;
 | 
			
		||||
  int kind = 1;
 | 
			
		||||
 | 
			
		||||
  // ccls extension
 | 
			
		||||
  Role role = Role::None;
 | 
			
		||||
 | 
			
		||||
  bool operator<(const lsDocumentHighlight &o) const {
 | 
			
		||||
    return !(range == o.range) ? range < o.range : kind < o.kind;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsDocumentHighlight, range, kind, role);
 | 
			
		||||
 | 
			
		||||
struct In_TextDocumentDocumentHighlight : public RequestInMessage {
 | 
			
		||||
  MethodType GetMethodType() const override { return kMethodType; }
 | 
			
		||||
  lsTextDocumentPositionParams params;
 | 
			
		||||
@ -44,39 +61,41 @@ struct Handler_TextDocumentDocumentHighlight
 | 
			
		||||
    QueryFile *file;
 | 
			
		||||
    if (!FindFileOrFail(db, project, request->id,
 | 
			
		||||
                        request->params.textDocument.uri.GetPath(), &file,
 | 
			
		||||
                        &file_id)) {
 | 
			
		||||
                        &file_id))
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    WorkingFile *working_file =
 | 
			
		||||
        working_files->GetFileByFilename(file->def->path);
 | 
			
		||||
 | 
			
		||||
    Out_TextDocumentDocumentHighlight out;
 | 
			
		||||
    out.id = request->id;
 | 
			
		||||
 | 
			
		||||
    for (SymbolRef sym :
 | 
			
		||||
         FindSymbolsAtLocation(working_file, file, request->params.position)) {
 | 
			
		||||
      // Found symbol. Return references to highlight.
 | 
			
		||||
      EachOccurrence(db, sym, true, [&](Use use) {
 | 
			
		||||
        if (use.file_id != file_id)
 | 
			
		||||
          return;
 | 
			
		||||
        if (std::optional<lsLocation> ls_loc =
 | 
			
		||||
                GetLsLocation(db, working_files, use)) {
 | 
			
		||||
    std::vector<SymbolRef> syms = FindSymbolsAtLocation(
 | 
			
		||||
        working_file, file, request->params.position, true);
 | 
			
		||||
    for (auto [sym, refcnt] : file->symbol2refcnt) {
 | 
			
		||||
      if (refcnt <= 0)
 | 
			
		||||
        continue;
 | 
			
		||||
      Usr usr = sym.usr;
 | 
			
		||||
      SymbolKind kind = sym.kind;
 | 
			
		||||
      if (std::none_of(syms.begin(), syms.end(), [&](auto &sym1) {
 | 
			
		||||
            return usr == sym1.usr && kind == sym1.kind;
 | 
			
		||||
          }))
 | 
			
		||||
        continue;
 | 
			
		||||
      if (auto ls_loc =
 | 
			
		||||
              GetLsLocation(db, working_files,
 | 
			
		||||
                            Use{{sym.range, usr, kind, sym.role}, file_id})) {
 | 
			
		||||
        lsDocumentHighlight highlight;
 | 
			
		||||
        highlight.range = ls_loc->range;
 | 
			
		||||
          if (use.role & Role::Write)
 | 
			
		||||
            highlight.kind = lsDocumentHighlightKind::Write;
 | 
			
		||||
          else if (use.role & Role::Read)
 | 
			
		||||
            highlight.kind = lsDocumentHighlightKind::Read;
 | 
			
		||||
        if (sym.role & Role::Write)
 | 
			
		||||
          highlight.kind = lsDocumentHighlight::Write;
 | 
			
		||||
        else if (sym.role & Role::Read)
 | 
			
		||||
          highlight.kind = lsDocumentHighlight::Read;
 | 
			
		||||
        else
 | 
			
		||||
            highlight.kind = lsDocumentHighlightKind::Text;
 | 
			
		||||
          highlight.role = use.role;
 | 
			
		||||
          highlight.kind = lsDocumentHighlight::Text;
 | 
			
		||||
        highlight.role = sym.role;
 | 
			
		||||
        out.result.push_back(highlight);
 | 
			
		||||
      }
 | 
			
		||||
      });
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::sort(out.result.begin(), out.result.end());
 | 
			
		||||
    pipeline::WriteStdout(kMethodType, out);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -62,7 +62,8 @@ bool VFS::Stamp(const std::string &path, int64_t ts, int step) {
 | 
			
		||||
 | 
			
		||||
namespace ccls::pipeline {
 | 
			
		||||
 | 
			
		||||
std::atomic<int64_t> loaded_ts = ATOMIC_VAR_INIT(0);
 | 
			
		||||
std::atomic<int64_t> loaded_ts = ATOMIC_VAR_INIT(0),
 | 
			
		||||
                     pending_index_requests = ATOMIC_VAR_INIT(0);
 | 
			
		||||
int64_t tick = 0;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
@ -175,6 +176,9 @@ bool Indexer_Parse(CompletionManager *completion, WorkingFiles *wfiles,
 | 
			
		||||
    return false;
 | 
			
		||||
  auto &request = *opt_request;
 | 
			
		||||
  bool loud = request.mode != IndexMode::OnChange;
 | 
			
		||||
  struct RAII {
 | 
			
		||||
    ~RAII() { pending_index_requests--; }
 | 
			
		||||
  } raii;
 | 
			
		||||
 | 
			
		||||
  // Dummy one to trigger refresh semantic highlight.
 | 
			
		||||
  if (request.path.empty()) {
 | 
			
		||||
@ -189,7 +193,7 @@ bool Indexer_Parse(CompletionManager *completion, WorkingFiles *wfiles,
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Project::Entry entry = project->FindCompilationEntryForFile(request.path);
 | 
			
		||||
  Project::Entry entry = project->FindEntry(request.path, true);
 | 
			
		||||
  if (request.args.size())
 | 
			
		||||
    entry.args = request.args;
 | 
			
		||||
  std::string path_to_index = entry.filename;
 | 
			
		||||
@ -547,6 +551,7 @@ void MainLoop() {
 | 
			
		||||
 | 
			
		||||
void Index(const std::string &path, const std::vector<const char *> &args,
 | 
			
		||||
           IndexMode mode, lsRequestId id) {
 | 
			
		||||
  pending_index_requests++;
 | 
			
		||||
  index_request->PushBack({path, args, mode, id}, mode != IndexMode::NonInteractive);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -39,7 +39,7 @@ enum class IndexMode {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
namespace pipeline {
 | 
			
		||||
extern std::atomic<int64_t> loaded_ts;
 | 
			
		||||
extern std::atomic<int64_t> loaded_ts, pending_index_requests;
 | 
			
		||||
extern int64_t tick;
 | 
			
		||||
void Init();
 | 
			
		||||
void LaunchStdin();
 | 
			
		||||
 | 
			
		||||
@ -386,13 +386,16 @@ void Project::SetArgsForFile(const std::vector<const char *> &args,
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Project::Entry
 | 
			
		||||
Project::FindCompilationEntryForFile(const std::string &filename) {
 | 
			
		||||
Project::Entry Project::FindEntry(const std::string &path,
 | 
			
		||||
                                  bool can_be_inferred) {
 | 
			
		||||
  {
 | 
			
		||||
    std::lock_guard<std::mutex> lock(mutex_);
 | 
			
		||||
    auto it = path_to_entry_index.find(filename);
 | 
			
		||||
    if (it != path_to_entry_index.end())
 | 
			
		||||
      return entries[it->second];
 | 
			
		||||
    auto it = path_to_entry_index.find(path);
 | 
			
		||||
    if (it != path_to_entry_index.end()) {
 | 
			
		||||
      Project::Entry &entry = entries[it->second];
 | 
			
		||||
      if (can_be_inferred || entry.filename == path)
 | 
			
		||||
        return entry;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // We couldn't find the file. Try to infer it.
 | 
			
		||||
@ -400,7 +403,7 @@ Project::FindCompilationEntryForFile(const std::string &filename) {
 | 
			
		||||
  Entry *best_entry = nullptr;
 | 
			
		||||
  int best_score = INT_MIN;
 | 
			
		||||
  for (Entry &entry : entries) {
 | 
			
		||||
    int score = ComputeGuessScore(filename, entry.filename);
 | 
			
		||||
    int score = ComputeGuessScore(path, entry.filename);
 | 
			
		||||
    if (score > best_score) {
 | 
			
		||||
      best_score = score;
 | 
			
		||||
      best_entry = &entry;
 | 
			
		||||
@ -409,10 +412,10 @@ Project::FindCompilationEntryForFile(const std::string &filename) {
 | 
			
		||||
 | 
			
		||||
  Project::Entry result;
 | 
			
		||||
  result.is_inferred = true;
 | 
			
		||||
  result.filename = filename;
 | 
			
		||||
  result.filename = path;
 | 
			
		||||
  if (!best_entry) {
 | 
			
		||||
    result.args.push_back("%clang");
 | 
			
		||||
    result.args.push_back(Intern(filename));
 | 
			
		||||
    result.args.push_back(Intern(path));
 | 
			
		||||
  } else {
 | 
			
		||||
    result.args = best_entry->args;
 | 
			
		||||
 | 
			
		||||
@ -424,7 +427,7 @@ Project::FindCompilationEntryForFile(const std::string &filename) {
 | 
			
		||||
      try {
 | 
			
		||||
        if (arg == best_entry->filename ||
 | 
			
		||||
            sys::path::filename(arg) == best_entry_base_name)
 | 
			
		||||
          arg = Intern(filename);
 | 
			
		||||
          arg = Intern(path);
 | 
			
		||||
      } catch (...) {
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -59,7 +59,7 @@ struct Project {
 | 
			
		||||
 | 
			
		||||
  // Lookup the CompilationEntry for |filename|. If no entry was found this
 | 
			
		||||
  // will infer one based on existing project structure.
 | 
			
		||||
  Entry FindCompilationEntryForFile(const std::string &filename);
 | 
			
		||||
  Entry FindEntry(const std::string &path, bool can_be_inferred);
 | 
			
		||||
 | 
			
		||||
  // If the client has overridden the flags, or specified them for a file
 | 
			
		||||
  // that is not in the compilation_database.json make sure those changes
 | 
			
		||||
 | 
			
		||||
@ -308,7 +308,8 @@ std::optional<lsSymbolInformation> GetSymbolInfo(DB *db, SymbolIdx sym,
 | 
			
		||||
 | 
			
		||||
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *wfile,
 | 
			
		||||
                                             QueryFile *file,
 | 
			
		||||
                                             lsPosition &ls_pos) {
 | 
			
		||||
                                             lsPosition &ls_pos,
 | 
			
		||||
                                             bool smallest) {
 | 
			
		||||
  std::vector<SymbolRef> symbols;
 | 
			
		||||
  // If multiVersion > 0, index may not exist and thus index_lines is empty.
 | 
			
		||||
  if (wfile && wfile->index_lines.size()) {
 | 
			
		||||
@ -353,6 +354,14 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *wfile,
 | 
			
		||||
          return t > 0;
 | 
			
		||||
        return a.usr < b.usr;
 | 
			
		||||
      });
 | 
			
		||||
  if (symbols.size() && smallest) {
 | 
			
		||||
    SymbolRef sym = symbols[0];
 | 
			
		||||
    for (size_t i = 1; i < symbols.size(); i++)
 | 
			
		||||
      if (!(sym.range == symbols[i].range && sym.kind == symbols[i].kind)) {
 | 
			
		||||
        symbols.resize(i);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return symbols;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -51,7 +51,8 @@ std::optional<lsSymbolInformation> GetSymbolInfo(DB *db, SymbolIdx sym,
 | 
			
		||||
 | 
			
		||||
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *working_file,
 | 
			
		||||
                                             QueryFile *file,
 | 
			
		||||
                                             lsPosition &ls_pos);
 | 
			
		||||
                                             lsPosition &ls_pos,
 | 
			
		||||
                                             bool smallest = false);
 | 
			
		||||
 | 
			
		||||
template <typename Fn> void WithEntity(DB *db, SymbolIdx sym, Fn &&fn) {
 | 
			
		||||
  switch (sym.kind) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										26
									
								
								src/symbol.h
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								src/symbol.h
									
									
									
									
									
								
							@ -46,32 +46,6 @@ inline Role operator|(Role lhs, Role rhs) {
 | 
			
		||||
  return Role(uint16_t(lhs) | uint16_t(rhs));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A document highlight kind.
 | 
			
		||||
enum class lsDocumentHighlightKind {
 | 
			
		||||
  // A textual occurrence.
 | 
			
		||||
  Text = 1,
 | 
			
		||||
  // Read-access of a symbol, like reading a variable.
 | 
			
		||||
  Read = 2,
 | 
			
		||||
  // Write-access of a symbol, like writing to a variable.
 | 
			
		||||
  Write = 3
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_TYPE_PROXY(lsDocumentHighlightKind);
 | 
			
		||||
 | 
			
		||||
// A document highlight is a range inside a text document which deserves
 | 
			
		||||
// special attention. Usually a document highlight is visualized by changing
 | 
			
		||||
// the background color of its range.
 | 
			
		||||
struct lsDocumentHighlight {
 | 
			
		||||
  // The range this highlight applies to.
 | 
			
		||||
  lsRange range;
 | 
			
		||||
 | 
			
		||||
  // The highlight kind, default is DocumentHighlightKind.Text.
 | 
			
		||||
  lsDocumentHighlightKind kind = lsDocumentHighlightKind::Text;
 | 
			
		||||
 | 
			
		||||
  // ccls extension
 | 
			
		||||
  Role role = Role::None;
 | 
			
		||||
};
 | 
			
		||||
MAKE_REFLECT_STRUCT(lsDocumentHighlight, range, kind, role);
 | 
			
		||||
 | 
			
		||||
struct lsSymbolInformation {
 | 
			
		||||
  std::string_view name;
 | 
			
		||||
  lsSymbolKind kind;
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,6 @@ limitations under the License.
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <string_view>
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user