Backport and cleanup

This commit is contained in:
Fangrui Song 2018-05-08 22:01:58 -07:00
parent 4797401d55
commit a385bffcbd
11 changed files with 61 additions and 151 deletions

View File

@ -252,7 +252,6 @@ target_sources(ccls PRIVATE
src/messages/ccls_base.cc src/messages/ccls_base.cc
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_file_info.cc src/messages/ccls_file_info.cc
src/messages/ccls_freshen_index.cc src/messages/ccls_freshen_index.cc
src/messages/ccls_inheritance_hierarchy.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_highlight.cc
src/messages/text_document_document_symbol.cc src/messages/text_document_document_symbol.cc
src/messages/text_document_hover.cc src/messages/text_document_hover.cc
src/messages/text_document_implementation.cc
src/messages/text_document_references.cc src/messages/text_document_references.cc
src/messages/text_document_rename.cc src/messages/text_document_rename.cc
src/messages/text_document_signature_help.cc src/messages/text_document_signature_help.cc

View File

@ -275,7 +275,7 @@ void BuildDetailString(CXCompletionString completion_string,
int num_chunks = clang_getNumCompletionChunks(completion_string); int num_chunks = clang_getNumCompletionChunks(completion_string);
auto append = [&](const char* text) { auto append = [&](const char* text) {
detail += text; detail += text;
if (do_insert) if (do_insert && include_snippets)
insert += text; insert += text;
}; };
for (int i = 0; i < num_chunks; ++i) { 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. // Fetching the completion request blocks until we have a request.
ClangCompleteManager::DiagnosticRequest request = ClangCompleteManager::DiagnosticRequest request =
completion_manager->diagnostic_request_.Dequeue(); completion_manager->diagnostic_request_.Dequeue();
if (!g_config->diagnostics.onType)
continue;
std::string path = request.document.uri.GetPath(); std::string path = request.document.uri.GetPath();
std::shared_ptr<CompletionSession> session = std::shared_ptr<CompletionSession> session =

View File

@ -131,6 +131,18 @@ Usr ClangCursor::get_usr_hash() const {
return ret; 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 { bool ClangCursor::is_definition() const {
return clang_isCursorDefinition(cx_cursor); return clang_isCursorDefinition(cx_cursor);
} }

View File

@ -67,6 +67,7 @@ class ClangCursor {
std::string get_display_name() const; std::string get_display_name() const;
std::string get_usr() const; std::string get_usr() const;
Usr get_usr_hash() const; Usr get_usr_hash() const;
std::optional<Usr> get_opt_usr_hash() const;
bool is_definition() const; bool is_definition() const;
@ -108,15 +109,6 @@ class ClangCursor {
CXCursor cx_cursor; 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. // Simple RAII wrapper about CXIndex.
// Note: building a ClangIndex instance acquires a global lock, since libclang // Note: building a ClangIndex instance acquires a global lock, since libclang
// API does not appear to be thread-safe here. // API does not appear to be thread-safe here.

View File

@ -557,15 +557,10 @@ IndexType* ResolveToDeclarationType(IndexFile* db,
ClangCursor declaration = ClangCursor declaration =
type.get_declaration().template_specialization_to_template_definition(); type.get_declaration().template_specialization_to_template_definition();
CXString cx_usr = clang_getCursorUSR(declaration.cx_cursor); std::optional<Usr> usr = declaration.get_opt_usr_hash();
const char* str_usr = clang_getCString(cx_usr); if (!usr)
if (!str_usr || str_usr[0] == '\0') {
clang_disposeString(cx_usr);
return nullptr; return nullptr;
} IndexType& typ = db->ToType(*usr);
Usr usr = HashUsr(str_usr);
clang_disposeString(cx_usr);
IndexType& typ = db->ToType(usr);
if (typ.def.detailed_name.empty()) { if (typ.def.detailed_name.empty()) {
std::string name = declaration.get_spell_name(); std::string name = declaration.get_spell_name();
SetTypeName(typ, declaration, nullptr, name.c_str(), param); SetTypeName(typ, declaration, nullptr, name.c_str(), param);
@ -602,11 +597,12 @@ void SetVarDetail(IndexVar& var,
param->ns.QualifiedName(semanticContainer, short_name); param->ns.QualifiedName(semanticContainer, short_name);
if (cursor.get_kind() == CXCursor_EnumConstantDecl && semanticContainer) { if (cursor.get_kind() == CXCursor_EnumConstantDecl && semanticContainer) {
CXType enum_type = clang_getCanonicalType( CXTypeKind k = clang_getCanonicalType(
clang_getEnumDeclIntegerType(semanticContainer->cursor)); clang_getEnumDeclIntegerType(semanticContainer->cursor))
.kind;
std::string hover = qualified_name + " = "; std::string hover = qualified_name + " = ";
if (enum_type.kind == CXType_UInt || enum_type.kind == CXType_ULong || if (k == CXType_Char_U || k == CXType_UChar || k == CXType_UShort ||
enum_type.kind == CXType_ULongLong) k == CXType_UInt || k == CXType_ULong || k == CXType_ULongLong)
hover += std::to_string( hover += std::to_string(
clang_getEnumConstantDeclUnsignedValue(cursor.cx_cursor)); clang_getEnumConstantDeclUnsignedValue(cursor.cx_cursor));
else else
@ -896,15 +892,15 @@ void VisitDeclForTypeUsageVisitorHandler(ClangCursor cursor,
} }
} }
std::string referenced_usr = std::optional<Usr> referenced_usr =
cursor.get_referenced() cursor.get_referenced()
.template_specialization_to_template_definition() .template_specialization_to_template_definition()
.get_usr(); .get_opt_usr_hash();
// TODO: things in STL cause this to be empty. Figure out why and document it. // In STL this may be empty.
if (referenced_usr == "") if (!referenced_usr)
return; return;
IndexType& ref_type = db->ToType(HashUsr(referenced_usr)); IndexType& ref_type = db->ToType(*referenced_usr);
if (!param->initial_type) if (!param->initial_type)
param->initial_type = &ref_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(); // cursor.get_referenced().template_specialization_to_template_definition().get_type().strip_qualifiers().get_usr_hash();
auto ref_usr = cursor.get_referenced() auto ref_usr = cursor.get_referenced()
.template_specialization_to_template_definition() .template_specialization_to_template_definition()
.get_usr(); .get_opt_usr_hash();
// std::string ref_usr = ref.get_usr_hash(); if (!ref_usr)
if (ref_usr.empty())
break; break;
IndexVar& ref_var = db->ToVar(*ref_usr);
IndexVar& ref_var = db->ToVar(HashUsr(ref_usr));
AddUseSpell(db, ref_var.uses, cursor); AddUseSpell(db, ref_var.uses, cursor);
break; break;
} }
@ -1347,8 +1341,8 @@ std::tuple<std::string, int16_t, int16_t> NamespaceHelper::QualifiedName(
std::string qualifier; std::string qualifier;
while (cursor.get_kind() != CXCursor_TranslationUnit && while (cursor.get_kind() != CXCursor_TranslationUnit &&
GetSymbolKind(cursor.get_kind()) == SymbolKind::Type) { GetSymbolKind(cursor.get_kind()) == SymbolKind::Type) {
auto it = container_cursor_to_qualified_name.find(cursor); auto it = usr2qualified_name.find(cursor.get_usr_hash());
if (it != container_cursor_to_qualified_name.end()) { if (it != usr2qualified_name.end()) {
qualifier = it->second; qualifier = it->second;
break; break;
} }
@ -1365,7 +1359,7 @@ std::tuple<std::string, int16_t, int16_t> NamespaceHelper::QualifiedName(
else else
qualifier += GetAnonName(namespaces[i].get_kind()); qualifier += GetAnonName(namespaces[i].get_kind());
qualifier += "::"; qualifier += "::";
container_cursor_to_qualified_name[namespaces[i]] = qualifier; usr2qualified_name[namespaces[i].get_usr_hash()] = qualifier;
} }
int16_t pos = qualifier.size(); int16_t pos = qualifier.size();
qualifier.append(unqualified_name); 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, VFS* vfs,
std::string file, std::string file,
const std::vector<std::string>& args, const std::vector<std::string>& args,
const std::vector<FileContents>& file_contents, const std::vector<FileContents>& file_contents,
PerformanceImportFile* perf, PerformanceImportFile* perf) {
ClangIndex* index) {
if (!g_config->index.enabled) if (!g_config->index.enabled)
return {}; return {};
@ -2037,7 +2030,7 @@ std::vector<std::unique_ptr<IndexFile>> Parse(
} }
std::unique_ptr<ClangTranslationUnit> tu = ClangTranslationUnit::Create( std::unique_ptr<ClangTranslationUnit> tu = ClangTranslationUnit::Create(
index, file, args, unsaved_files, &index, file, args, unsaved_files,
CXTranslationUnit_KeepGoing | CXTranslationUnit_KeepGoing |
CXTranslationUnit_DetailedPreprocessingRecord); CXTranslationUnit_DetailedPreprocessingRecord);
if (!tu) if (!tu)
@ -2045,7 +2038,7 @@ std::vector<std::unique_ptr<IndexFile>> Parse(
perf->index_parse = timer.ElapsedMicrosecondsAndReset(); 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( std::vector<std::unique_ptr<IndexFile>> ParseWithTu(
@ -2206,58 +2199,3 @@ void Reflect(Writer& visitor, Reference& value) {
Reflect(visitor, value.role); 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);
}

View File

@ -137,6 +137,9 @@ struct Config {
// If true, diagnostics from a full document parse will be reported. // If true, diagnostics from a full document parse will be reported.
bool onParse = true; bool onParse = true;
// If true, diagnostics from typing will be reported.
bool onType = true;
std::vector<std::string> whitelist; std::vector<std::string> whitelist;
} diagnostics; } diagnostics;
@ -211,6 +214,7 @@ MAKE_REFLECT_STRUCT(Config::ClientCapability, snippetSupport);
MAKE_REFLECT_STRUCT(Config::CodeLens, localVariables); MAKE_REFLECT_STRUCT(Config::CodeLens, localVariables);
MAKE_REFLECT_STRUCT(Config::Completion, MAKE_REFLECT_STRUCT(Config::Completion,
caseSensitivity, caseSensitivity,
dropOldRequests,
detailedLabel, detailedLabel,
filterAndSort, filterAndSort,
includeBlacklist, includeBlacklist,
@ -221,6 +225,7 @@ MAKE_REFLECT_STRUCT(Config::Diagnostics,
blacklist, blacklist,
frequencyMs, frequencyMs,
onParse, onParse,
onType,
whitelist) whitelist)
MAKE_REFLECT_STRUCT(Config::Highlight, blacklist, whitelist) MAKE_REFLECT_STRUCT(Config::Highlight, blacklist, whitelist)
MAKE_REFLECT_STRUCT(Config::Index, MAKE_REFLECT_STRUCT(Config::Index,

View File

@ -63,7 +63,7 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
WorkingFiles* working_files, WorkingFiles* working_files,
Project* project, Project* project,
VFS* vfs, VFS* vfs,
IIndexer* indexer) { ClangIndexer* indexer) {
auto* queue = QueueManager::instance(); auto* queue = QueueManager::instance();
std::optional<Index_Request> opt_request = queue->index_request.TryPopFront(); std::optional<Index_Request> opt_request = queue->index_request.TryPopFront();
if (!opt_request) if (!opt_request)
@ -211,10 +211,10 @@ void Indexer_Main(DiagnosticsEngine* diag_engine,
MultiQueueWaiter* waiter) { MultiQueueWaiter* waiter) {
auto* queue = QueueManager::instance(); auto* queue = QueueManager::instance();
// Build one index per-indexer, as building the index acquires a global lock. // Build one index per-indexer, as building the index acquires a global lock.
auto indexer = std::make_unique<ClangIndexer>(); ClangIndexer indexer;
while (true) 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); waiter->Wait(&queue->index_request);
} }

View File

@ -321,25 +321,13 @@ struct IndexFile {
}; };
struct NamespaceHelper { struct NamespaceHelper {
std::unordered_map<ClangCursor, std::string> std::unordered_map<Usr, std::string> usr2qualified_name;
container_cursor_to_qualified_name;
std::tuple<std::string, int16_t, int16_t> QualifiedName( std::tuple<std::string, int16_t, int16_t> QualifiedName(
const CXIdxContainerInfo* container, const CXIdxContainerInfo* container,
std::string_view unqualified_name); 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( std::vector<std::unique_ptr<IndexFile>> ParseWithTu(
VFS* vfs, VFS* vfs,
PerformanceImportFile* perf, PerformanceImportFile* perf,
@ -353,36 +341,13 @@ bool ConcatTypeAndName(std::string& type, const std::string& name);
void IndexInit(); void IndexInit();
// Abstracts away the actual indexing process. Each IIndexer instance is struct ClangIndexer {
// 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 {
std::vector<std::unique_ptr<IndexFile>> Index( std::vector<std::unique_ptr<IndexFile>> Index(
VFS* vfs, VFS* vfs,
std::string file, std::string file,
const std::vector<std::string>& args, const std::vector<std::string>& args,
const std::vector<FileContents>& file_contents, const std::vector<FileContents>& file_contents,
PerformanceImportFile* perf) override { PerformanceImportFile* perf);
return Parse(vfs, file, args, file_contents, perf, &index);
}
// Note: constructing this acquires a global lock // Note: constructing this acquires a global lock
ClangIndex index; ClangIndex index;

View File

@ -3,18 +3,19 @@
#include "queue_manager.h" #include "queue_manager.h"
namespace { 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; } MethodType GetMethodType() const override { return kMethodType; }
lsTextDocumentPositionParams params; lsTextDocumentPositionParams params;
}; };
MAKE_REFLECT_STRUCT(In_CclsDerived, id, params); MAKE_REFLECT_STRUCT(In_TextDocumentImplementation, id, params);
REGISTER_IN_MESSAGE(In_CclsDerived); REGISTER_IN_MESSAGE(In_TextDocumentImplementation);
struct Handler_CclsDerived : BaseMessageHandler<In_CclsDerived> { struct Handler_TextDocumentImplementation
: BaseMessageHandler<In_TextDocumentImplementation> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_CclsDerived* request) override { void Run(In_TextDocumentImplementation* request) override {
QueryFile* file; QueryFile* file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
request->params.textDocument.uri.GetPath(), &file)) { request->params.textDocument.uri.GetPath(), &file)) {
@ -43,5 +44,5 @@ struct Handler_CclsDerived : BaseMessageHandler<In_CclsDerived> {
QueueManager::WriteStdout(kMethodType, out); QueueManager::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsDerived); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentImplementation);
} // namespace } // namespace

View File

@ -247,7 +247,7 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
bool update_all = false; bool update_all = false;
// FIXME: show diagnostics in STL/headers when running tests. At the moment // FIXME: show diagnostics in STL/headers when running tests. At the moment
// this can be done by constructing ClangIndex index(1, 1); // this can be done by constructing ClangIndex index(1, 1);
ClangIndex index; ClangIndexer index;
GetFilesInFolder( GetFilesInFolder(
"index_tests", true /*recursive*/, true /*add_folder_to_path*/, "index_tests", true /*recursive*/, true /*add_folder_to_path*/,
[&](const std::string& 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>(); g_config = std::make_unique<Config>();
VFS vfs; VFS vfs;
PerformanceImportFile perf; 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) { for (const auto& entry : all_expected_output) {
const std::string& expected_path = entry.first; const std::string& expected_path = entry.first;

View File

@ -49,11 +49,6 @@ std::string StringJoin(const TValues& values, const std::string& sep = ", ") {
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. // Ensures that |path| ends in a slash.
void EnsureEndsInSlash(std::string& path); void EnsureEndsInSlash(std::string& path);