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_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

View File

@ -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 =

View File

@ -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);
}

View File

@ -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.

View File

@ -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);
}

View File

@ -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,

View File

@ -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);
}

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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);