mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-21 23:25:07 +00:00
Backport and cleanup
This commit is contained in:
parent
4797401d55
commit
a385bffcbd
@ -252,7 +252,6 @@ target_sources(ccls PRIVATE
|
||||
src/messages/ccls_base.cc
|
||||
src/messages/ccls_call_hierarchy.cc
|
||||
src/messages/ccls_callers.cc
|
||||
src/messages/ccls_derived.cc
|
||||
src/messages/ccls_file_info.cc
|
||||
src/messages/ccls_freshen_index.cc
|
||||
src/messages/ccls_inheritance_hierarchy.cc
|
||||
@ -272,6 +271,7 @@ target_sources(ccls PRIVATE
|
||||
src/messages/text_document_document_highlight.cc
|
||||
src/messages/text_document_document_symbol.cc
|
||||
src/messages/text_document_hover.cc
|
||||
src/messages/text_document_implementation.cc
|
||||
src/messages/text_document_references.cc
|
||||
src/messages/text_document_rename.cc
|
||||
src/messages/text_document_signature_help.cc
|
||||
|
@ -275,7 +275,7 @@ void BuildDetailString(CXCompletionString completion_string,
|
||||
int num_chunks = clang_getNumCompletionChunks(completion_string);
|
||||
auto append = [&](const char* text) {
|
||||
detail += text;
|
||||
if (do_insert)
|
||||
if (do_insert && include_snippets)
|
||||
insert += text;
|
||||
};
|
||||
for (int i = 0; i < num_chunks; ++i) {
|
||||
@ -587,6 +587,8 @@ void DiagnosticQueryMain(ClangCompleteManager* completion_manager) {
|
||||
// Fetching the completion request blocks until we have a request.
|
||||
ClangCompleteManager::DiagnosticRequest request =
|
||||
completion_manager->diagnostic_request_.Dequeue();
|
||||
if (!g_config->diagnostics.onType)
|
||||
continue;
|
||||
std::string path = request.document.uri.GetPath();
|
||||
|
||||
std::shared_ptr<CompletionSession> session =
|
||||
|
@ -131,6 +131,18 @@ Usr ClangCursor::get_usr_hash() const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::optional<Usr> ClangCursor::get_opt_usr_hash() const {
|
||||
CXString usr = clang_getCursorUSR(cx_cursor);
|
||||
const char* str = clang_getCString(usr);
|
||||
if (!str || str[0] == '\0') {
|
||||
clang_disposeString(usr);
|
||||
return {};
|
||||
}
|
||||
Usr ret = HashUsr(str);
|
||||
clang_disposeString(usr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ClangCursor::is_definition() const {
|
||||
return clang_isCursorDefinition(cx_cursor);
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ class ClangCursor {
|
||||
std::string get_display_name() const;
|
||||
std::string get_usr() const;
|
||||
Usr get_usr_hash() const;
|
||||
std::optional<Usr> get_opt_usr_hash() const;
|
||||
|
||||
bool is_definition() const;
|
||||
|
||||
@ -108,15 +109,6 @@ class ClangCursor {
|
||||
CXCursor cx_cursor;
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<ClangCursor> {
|
||||
size_t operator()(const ClangCursor& x) const {
|
||||
return clang_hashCursor(x.cx_cursor);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
// Simple RAII wrapper about CXIndex.
|
||||
// Note: building a ClangIndex instance acquires a global lock, since libclang
|
||||
// API does not appear to be thread-safe here.
|
||||
|
@ -557,15 +557,10 @@ IndexType* ResolveToDeclarationType(IndexFile* db,
|
||||
|
||||
ClangCursor declaration =
|
||||
type.get_declaration().template_specialization_to_template_definition();
|
||||
CXString cx_usr = clang_getCursorUSR(declaration.cx_cursor);
|
||||
const char* str_usr = clang_getCString(cx_usr);
|
||||
if (!str_usr || str_usr[0] == '\0') {
|
||||
clang_disposeString(cx_usr);
|
||||
std::optional<Usr> usr = declaration.get_opt_usr_hash();
|
||||
if (!usr)
|
||||
return nullptr;
|
||||
}
|
||||
Usr usr = HashUsr(str_usr);
|
||||
clang_disposeString(cx_usr);
|
||||
IndexType& typ = db->ToType(usr);
|
||||
IndexType& typ = db->ToType(*usr);
|
||||
if (typ.def.detailed_name.empty()) {
|
||||
std::string name = declaration.get_spell_name();
|
||||
SetTypeName(typ, declaration, nullptr, name.c_str(), param);
|
||||
@ -602,11 +597,12 @@ void SetVarDetail(IndexVar& var,
|
||||
param->ns.QualifiedName(semanticContainer, short_name);
|
||||
|
||||
if (cursor.get_kind() == CXCursor_EnumConstantDecl && semanticContainer) {
|
||||
CXType enum_type = clang_getCanonicalType(
|
||||
clang_getEnumDeclIntegerType(semanticContainer->cursor));
|
||||
CXTypeKind k = clang_getCanonicalType(
|
||||
clang_getEnumDeclIntegerType(semanticContainer->cursor))
|
||||
.kind;
|
||||
std::string hover = qualified_name + " = ";
|
||||
if (enum_type.kind == CXType_UInt || enum_type.kind == CXType_ULong ||
|
||||
enum_type.kind == CXType_ULongLong)
|
||||
if (k == CXType_Char_U || k == CXType_UChar || k == CXType_UShort ||
|
||||
k == CXType_UInt || k == CXType_ULong || k == CXType_ULongLong)
|
||||
hover += std::to_string(
|
||||
clang_getEnumConstantDeclUnsignedValue(cursor.cx_cursor));
|
||||
else
|
||||
@ -896,15 +892,15 @@ void VisitDeclForTypeUsageVisitorHandler(ClangCursor cursor,
|
||||
}
|
||||
}
|
||||
|
||||
std::string referenced_usr =
|
||||
std::optional<Usr> referenced_usr =
|
||||
cursor.get_referenced()
|
||||
.template_specialization_to_template_definition()
|
||||
.get_usr();
|
||||
// TODO: things in STL cause this to be empty. Figure out why and document it.
|
||||
if (referenced_usr == "")
|
||||
.get_opt_usr_hash();
|
||||
// In STL this may be empty.
|
||||
if (!referenced_usr)
|
||||
return;
|
||||
|
||||
IndexType& ref_type = db->ToType(HashUsr(referenced_usr));
|
||||
IndexType& ref_type = db->ToType(*referenced_usr);
|
||||
|
||||
if (!param->initial_type)
|
||||
param->initial_type = &ref_type;
|
||||
@ -1129,12 +1125,10 @@ ClangCursor::VisitResult AddDeclInitializerUsagesVisitor(ClangCursor cursor,
|
||||
// cursor.get_referenced().template_specialization_to_template_definition().get_type().strip_qualifiers().get_usr_hash();
|
||||
auto ref_usr = cursor.get_referenced()
|
||||
.template_specialization_to_template_definition()
|
||||
.get_usr();
|
||||
// std::string ref_usr = ref.get_usr_hash();
|
||||
if (ref_usr.empty())
|
||||
.get_opt_usr_hash();
|
||||
if (!ref_usr)
|
||||
break;
|
||||
|
||||
IndexVar& ref_var = db->ToVar(HashUsr(ref_usr));
|
||||
IndexVar& ref_var = db->ToVar(*ref_usr);
|
||||
AddUseSpell(db, ref_var.uses, cursor);
|
||||
break;
|
||||
}
|
||||
@ -1347,8 +1341,8 @@ std::tuple<std::string, int16_t, int16_t> NamespaceHelper::QualifiedName(
|
||||
std::string qualifier;
|
||||
while (cursor.get_kind() != CXCursor_TranslationUnit &&
|
||||
GetSymbolKind(cursor.get_kind()) == SymbolKind::Type) {
|
||||
auto it = container_cursor_to_qualified_name.find(cursor);
|
||||
if (it != container_cursor_to_qualified_name.end()) {
|
||||
auto it = usr2qualified_name.find(cursor.get_usr_hash());
|
||||
if (it != usr2qualified_name.end()) {
|
||||
qualifier = it->second;
|
||||
break;
|
||||
}
|
||||
@ -1365,7 +1359,7 @@ std::tuple<std::string, int16_t, int16_t> NamespaceHelper::QualifiedName(
|
||||
else
|
||||
qualifier += GetAnonName(namespaces[i].get_kind());
|
||||
qualifier += "::";
|
||||
container_cursor_to_qualified_name[namespaces[i]] = qualifier;
|
||||
usr2qualified_name[namespaces[i].get_usr_hash()] = qualifier;
|
||||
}
|
||||
int16_t pos = qualifier.size();
|
||||
qualifier.append(unqualified_name);
|
||||
@ -2013,13 +2007,12 @@ void OnIndexReference(CXClientData client_data, const CXIdxEntityRefInfo* ref) {
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<IndexFile>> Parse(
|
||||
std::vector<std::unique_ptr<IndexFile>> ClangIndexer::Index(
|
||||
VFS* vfs,
|
||||
std::string file,
|
||||
const std::vector<std::string>& args,
|
||||
const std::vector<FileContents>& file_contents,
|
||||
PerformanceImportFile* perf,
|
||||
ClangIndex* index) {
|
||||
PerformanceImportFile* perf) {
|
||||
if (!g_config->index.enabled)
|
||||
return {};
|
||||
|
||||
@ -2037,7 +2030,7 @@ std::vector<std::unique_ptr<IndexFile>> Parse(
|
||||
}
|
||||
|
||||
std::unique_ptr<ClangTranslationUnit> tu = ClangTranslationUnit::Create(
|
||||
index, file, args, unsaved_files,
|
||||
&index, file, args, unsaved_files,
|
||||
CXTranslationUnit_KeepGoing |
|
||||
CXTranslationUnit_DetailedPreprocessingRecord);
|
||||
if (!tu)
|
||||
@ -2045,7 +2038,7 @@ std::vector<std::unique_ptr<IndexFile>> Parse(
|
||||
|
||||
perf->index_parse = timer.ElapsedMicrosecondsAndReset();
|
||||
|
||||
return ParseWithTu(vfs, perf, tu.get(), index, file, args, unsaved_files);
|
||||
return ParseWithTu(vfs, perf, tu.get(), &index, file, args, unsaved_files);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<IndexFile>> ParseWithTu(
|
||||
@ -2206,58 +2199,3 @@ void Reflect(Writer& visitor, Reference& value) {
|
||||
Reflect(visitor, value.role);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct TestIndexer : IIndexer {
|
||||
static std::unique_ptr<TestIndexer> FromEntries(
|
||||
const std::vector<TestEntry>& entries) {
|
||||
auto result = std::make_unique<TestIndexer>();
|
||||
|
||||
for (const TestEntry& entry : entries) {
|
||||
std::vector<std::unique_ptr<IndexFile>> indexes;
|
||||
|
||||
if (entry.num_indexes > 0)
|
||||
indexes.push_back(std::make_unique<IndexFile>(entry.path, "<empty>"));
|
||||
for (int i = 1; i < entry.num_indexes; ++i) {
|
||||
indexes.push_back(std::make_unique<IndexFile>(
|
||||
entry.path + "_extra_" + std::to_string(i) + ".h", "<empty>"));
|
||||
}
|
||||
|
||||
result->indexes.insert(std::make_pair(entry.path, std::move(indexes)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<IndexFile>> Index(
|
||||
VFS* vfs,
|
||||
std::string file,
|
||||
const std::vector<std::string>& args,
|
||||
const std::vector<FileContents>& file_contents,
|
||||
PerformanceImportFile* perf) override {
|
||||
auto it = indexes.find(file);
|
||||
if (it == indexes.end()) {
|
||||
// Don't return any indexes for unexpected data.
|
||||
assert(false && "no indexes");
|
||||
return {};
|
||||
}
|
||||
|
||||
// FIXME: allow user to control how many times we return the index for a
|
||||
// specific file (atm it is always 1)
|
||||
auto result = std::move(it->second);
|
||||
indexes.erase(it);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::vector<std::unique_ptr<IndexFile>>>
|
||||
indexes;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
std::unique_ptr<IIndexer> IIndexer::MakeTestIndexer(
|
||||
std::initializer_list<TestEntry> entries) {
|
||||
return TestIndexer::FromEntries(entries);
|
||||
}
|
||||
|
@ -137,6 +137,9 @@ struct Config {
|
||||
// If true, diagnostics from a full document parse will be reported.
|
||||
bool onParse = true;
|
||||
|
||||
// If true, diagnostics from typing will be reported.
|
||||
bool onType = true;
|
||||
|
||||
std::vector<std::string> whitelist;
|
||||
} diagnostics;
|
||||
|
||||
@ -211,6 +214,7 @@ MAKE_REFLECT_STRUCT(Config::ClientCapability, snippetSupport);
|
||||
MAKE_REFLECT_STRUCT(Config::CodeLens, localVariables);
|
||||
MAKE_REFLECT_STRUCT(Config::Completion,
|
||||
caseSensitivity,
|
||||
dropOldRequests,
|
||||
detailedLabel,
|
||||
filterAndSort,
|
||||
includeBlacklist,
|
||||
@ -221,6 +225,7 @@ MAKE_REFLECT_STRUCT(Config::Diagnostics,
|
||||
blacklist,
|
||||
frequencyMs,
|
||||
onParse,
|
||||
onType,
|
||||
whitelist)
|
||||
MAKE_REFLECT_STRUCT(Config::Highlight, blacklist, whitelist)
|
||||
MAKE_REFLECT_STRUCT(Config::Index,
|
||||
|
@ -63,7 +63,7 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
|
||||
WorkingFiles* working_files,
|
||||
Project* project,
|
||||
VFS* vfs,
|
||||
IIndexer* indexer) {
|
||||
ClangIndexer* indexer) {
|
||||
auto* queue = QueueManager::instance();
|
||||
std::optional<Index_Request> opt_request = queue->index_request.TryPopFront();
|
||||
if (!opt_request)
|
||||
@ -211,10 +211,10 @@ void Indexer_Main(DiagnosticsEngine* diag_engine,
|
||||
MultiQueueWaiter* waiter) {
|
||||
auto* queue = QueueManager::instance();
|
||||
// Build one index per-indexer, as building the index acquires a global lock.
|
||||
auto indexer = std::make_unique<ClangIndexer>();
|
||||
ClangIndexer indexer;
|
||||
|
||||
while (true)
|
||||
if (!Indexer_Parse(diag_engine, working_files, project, vfs, indexer.get()))
|
||||
if (!Indexer_Parse(diag_engine, working_files, project, vfs, &indexer))
|
||||
waiter->Wait(&queue->index_request);
|
||||
}
|
||||
|
||||
|
@ -321,25 +321,13 @@ struct IndexFile {
|
||||
};
|
||||
|
||||
struct NamespaceHelper {
|
||||
std::unordered_map<ClangCursor, std::string>
|
||||
container_cursor_to_qualified_name;
|
||||
std::unordered_map<Usr, std::string> usr2qualified_name;
|
||||
|
||||
std::tuple<std::string, int16_t, int16_t> QualifiedName(
|
||||
const CXIdxContainerInfo* container,
|
||||
std::string_view unqualified_name);
|
||||
};
|
||||
|
||||
// |import_file| is the cc file which is what gets passed to clang.
|
||||
// |desired_index_file| is the (h or cc) file which has actually changed.
|
||||
// |dependencies| are the existing dependencies of |import_file| if this is a
|
||||
// reparse.
|
||||
std::vector<std::unique_ptr<IndexFile>> Parse(
|
||||
VFS* vfs,
|
||||
std::string file,
|
||||
const std::vector<std::string>& args,
|
||||
const std::vector<FileContents>& file_contents,
|
||||
PerformanceImportFile* perf,
|
||||
ClangIndex* index);
|
||||
std::vector<std::unique_ptr<IndexFile>> ParseWithTu(
|
||||
VFS* vfs,
|
||||
PerformanceImportFile* perf,
|
||||
@ -353,36 +341,13 @@ bool ConcatTypeAndName(std::string& type, const std::string& name);
|
||||
|
||||
void IndexInit();
|
||||
|
||||
// Abstracts away the actual indexing process. Each IIndexer instance is
|
||||
// per-thread and constructing an instance may be extremely expensive (ie,
|
||||
// acquire a lock) and should be done as rarely as possible.
|
||||
struct IIndexer {
|
||||
struct TestEntry {
|
||||
std::string path;
|
||||
int num_indexes = 0;
|
||||
};
|
||||
|
||||
static std::unique_ptr<IIndexer> MakeTestIndexer(
|
||||
std::initializer_list<TestEntry> entries);
|
||||
|
||||
virtual ~IIndexer() = default;
|
||||
virtual std::vector<std::unique_ptr<IndexFile>> Index(
|
||||
VFS* vfs,
|
||||
std::string file,
|
||||
const std::vector<std::string>& args,
|
||||
const std::vector<FileContents>& file_contents,
|
||||
PerformanceImportFile* perf) = 0;
|
||||
};
|
||||
|
||||
struct ClangIndexer : IIndexer {
|
||||
struct ClangIndexer {
|
||||
std::vector<std::unique_ptr<IndexFile>> Index(
|
||||
VFS* vfs,
|
||||
std::string file,
|
||||
const std::vector<std::string>& args,
|
||||
const std::vector<FileContents>& file_contents,
|
||||
PerformanceImportFile* perf) override {
|
||||
return Parse(vfs, file, args, file_contents, perf, &index);
|
||||
}
|
||||
PerformanceImportFile* perf);
|
||||
|
||||
// Note: constructing this acquires a global lock
|
||||
ClangIndex index;
|
||||
|
@ -3,18 +3,19 @@
|
||||
#include "queue_manager.h"
|
||||
|
||||
namespace {
|
||||
MethodType kMethodType = "$ccls/derived";
|
||||
MethodType kMethodType = "textDocument/implementation";
|
||||
|
||||
struct In_CclsDerived : public RequestInMessage {
|
||||
struct In_TextDocumentImplementation : public RequestInMessage {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
lsTextDocumentPositionParams params;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(In_CclsDerived, id, params);
|
||||
REGISTER_IN_MESSAGE(In_CclsDerived);
|
||||
MAKE_REFLECT_STRUCT(In_TextDocumentImplementation, id, params);
|
||||
REGISTER_IN_MESSAGE(In_TextDocumentImplementation);
|
||||
|
||||
struct Handler_CclsDerived : BaseMessageHandler<In_CclsDerived> {
|
||||
struct Handler_TextDocumentImplementation
|
||||
: BaseMessageHandler<In_TextDocumentImplementation> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_CclsDerived* request) override {
|
||||
void Run(In_TextDocumentImplementation* request) override {
|
||||
QueryFile* file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
request->params.textDocument.uri.GetPath(), &file)) {
|
||||
@ -43,5 +44,5 @@ struct Handler_CclsDerived : BaseMessageHandler<In_CclsDerived> {
|
||||
QueueManager::WriteStdout(kMethodType, out);
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_CclsDerived);
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentImplementation);
|
||||
} // namespace
|
@ -247,7 +247,7 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
|
||||
bool update_all = false;
|
||||
// FIXME: show diagnostics in STL/headers when running tests. At the moment
|
||||
// this can be done by constructing ClangIndex index(1, 1);
|
||||
ClangIndex index;
|
||||
ClangIndexer index;
|
||||
GetFilesInFolder(
|
||||
"index_tests", true /*recursive*/, true /*add_folder_to_path*/,
|
||||
[&](const std::string& path) {
|
||||
@ -294,7 +294,7 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
|
||||
g_config = std::make_unique<Config>();
|
||||
VFS vfs;
|
||||
PerformanceImportFile perf;
|
||||
auto dbs = Parse(&vfs, path, flags, {}, &perf, &index);
|
||||
auto dbs = index.Index(&vfs, path, flags, {}, &perf);
|
||||
|
||||
for (const auto& entry : all_expected_output) {
|
||||
const std::string& expected_path = entry.first;
|
||||
|
@ -49,11 +49,6 @@ std::string StringJoin(const TValues& values, const std::string& sep = ", ") {
|
||||
sep);
|
||||
}
|
||||
|
||||
template <typename TCollection, typename TValue>
|
||||
bool ContainsValue(const TCollection& collection, const TValue& value) {
|
||||
return collection.find(value) != collection.end();
|
||||
}
|
||||
|
||||
// Ensures that |path| ends in a slash.
|
||||
void EnsureEndsInSlash(std::string& path);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user