mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-30 11:27:07 +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