diff --git a/src/indexer.cc b/src/indexer.cc index d87d7b77..5f6d9d49 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -460,6 +460,7 @@ optional ResolveToDeclarationType(IndexFile* db, } void SetVarDetail(IndexVar* var, + std::string_view short_name, const ClangCursor& cursor, const CXIdxContainerInfo* semanticContainer, bool is_first_seen, @@ -476,7 +477,7 @@ void SetVarDetail(IndexVar* var, def.storage = GetStorageClass(clang_Cursor_getStorageClass(cursor.cx_cursor)); std::string qualified_name = - param->ns.QualifiedName(semanticContainer, def.short_name); + param->ns.QualifiedName(semanticContainer, short_name); if (cursor.get_kind() == CXCursor_EnumConstantDecl && semanticContainer) { CXType enum_type = clang_getCanonicalType( @@ -515,6 +516,11 @@ void SetVarDetail(IndexVar* var, fc.content.substr(*spell_end, *extent_end - *spell_end); } } + // FIXME QualifiedName should return index + auto idx = def.detailed_name.find(short_name.begin(), 0, short_name.size()); + assert(idx != std::string::npos); + def.short_name_offset = idx; + def.short_name_size = short_name.size(); if (is_first_seen) { optional var_type = @@ -1139,8 +1145,9 @@ ClangCursor::VisitResult VisitMacroDefinitionAndExpansions(ClangCursor cursor, IndexVar* var_def = db->Resolve(db->ToVarId(decl_usr)); if (cursor.get_kind() == CXCursor_MacroDefinition) { CXSourceRange cx_extent = clang_getCursorExtent(cursor.cx_cursor); - var_def->def.short_name = cursor.get_display_name(); var_def->def.detailed_name = cursor.get_display_name(); + var_def->def.short_name_offset = 0; + var_def->def.short_name_size = int(var_def->def.detailed_name.size()); var_def->def.hover = "#define " + GetDocumentContentInRange(param->tu->cx_tu, cx_extent); var_def->def.kind = ClangSymbolKind::Macro; @@ -1181,11 +1188,11 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor, if (ref_cursor.get_kind() == CXCursor_NonTypeTemplateParameter) { IndexVar* ref_index = db->Resolve(db->ToVarId(ref_cursor.get_usr_hash())); - if (ref_index->def.short_name.empty()) { + if (ref_index->def.detailed_name.empty()) { ref_index->def.definition_spelling = ref_cursor.get_spelling_range(); ref_index->def.definition_extent = ref_cursor.get_extent(); - ref_index->def.short_name = ref_cursor.get_spelling(); - SetVarDetail(ref_index, ref_cursor, nullptr, true, db, data->param); + SetVarDetail(ref_index, ref_cursor.get_spelling(), ref_cursor, + nullptr, true, db, data->param); ClangType ref_type = clang_getCursorType(ref_cursor.cx_cursor); // TODO optimize @@ -1270,9 +1277,9 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor, } // namespace std::string NamespaceHelper::QualifiedName(const CXIdxContainerInfo* container, - std::string unqualified_name) { + std::string_view unqualified_name) { if (!container) - return unqualified_name; + return std::string(unqualified_name); // Anonymous namespaces are not processed by indexDeclaration. We trace // nested namespaces bottom-up through clang_getCursorSemanticParent until // one that we know its qualified name. Then do another trace top-down and @@ -1318,7 +1325,8 @@ std::string NamespaceHelper::QualifiedName(const CXIdxContainerInfo* container, qualifier += "::"; container_cursor_to_qualified_name[namespaces[i]] = qualifier; } - return qualifier + unqualified_name; + // C++17 string::append + return qualifier + std::string(unqualified_name); } void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { @@ -1409,10 +1417,8 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { // this may shadow. // TODO: Verify this gets called multiple times // if (!decl->isRedeclaration) { - var->def.short_name = decl->entityInfo->name; - - SetVarDetail(var, decl->cursor, decl->semanticContainer, - !decl->isRedeclaration, db, param); + SetVarDetail(var, std::string(decl->entityInfo->name), decl->cursor, + decl->semanticContainer, !decl->isRedeclaration, db, param); // FIXME https://github.com/jacobdufault/cquery/issues/239 var->def.kind = GetSymbolKind(decl->entityInfo->kind); @@ -1847,7 +1853,7 @@ void OnIndexReference(CXClientData client_data, const CXIdxEntityRefInfo* ref) { // may not have a short_name yet. Note that we only process the lambda // parameter as a definition if it is in the same file as the reference, // as lambdas cannot be split across files. - if (var->def.short_name.empty()) { + if (var->def.detailed_name.empty()) { CXFile referenced_file; Range spelling = referenced.get_spelling_range(&referenced_file); if (file == referenced_file) { @@ -1857,8 +1863,8 @@ void OnIndexReference(CXClientData client_data, const CXIdxEntityRefInfo* ref) { // TODO Some of the logic here duplicates CXIdxEntity_Variable branch // of OnIndexDeclaration. But there `decl` is of type CXIdxDeclInfo // and has more information, thus not easy to reuse the code. - var->def.short_name = referenced.get_spelling(); - SetVarDetail(var, referenced, nullptr, true, db, param); + SetVarDetail(var, referenced.get_spelling(), referenced, nullptr, + true, db, param); var->def.kind = ClangSymbolKind::Parameter; } } diff --git a/src/indexer.h b/src/indexer.h index 56eb1692..6d837e63 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -185,8 +186,7 @@ struct TypeDefDefinitionData { bool operator==( const TypeDefDefinitionData& other) const { - return short_name == other.short_name && - detailed_name == other.detailed_name && hover == other.hover && + return detailed_name == other.detailed_name && hover == other.hover && definition_spelling == other.definition_spelling && definition_extent == other.definition_extent && alias_of == other.alias_of && parents == other.parents && @@ -279,8 +279,7 @@ struct FuncDefDefinitionData { bool operator==( const FuncDefDefinitionData& other) const { - return short_name == other.short_name && - detailed_name == other.detailed_name && hover == other.hover && + return detailed_name == other.detailed_name && hover == other.hover && definition_spelling == other.definition_spelling && definition_extent == other.definition_extent && declaring_type == other.declaring_type && base == other.base && @@ -372,7 +371,6 @@ MAKE_REFLECT_STRUCT(IndexFunc::Declaration, template struct VarDefDefinitionData { // General metadata. - std::string short_name; std::string detailed_name; optional hover; optional comments; @@ -386,6 +384,8 @@ struct VarDefDefinitionData { // Function/type which declares this one. size_t parent_id = size_t(-1); + int16_t short_name_offset; + int16_t short_name_size; SymbolKind parent_kind = SymbolKind::Invalid; ClangSymbolKind kind = ClangSymbolKind::Unknown; @@ -401,8 +401,7 @@ struct VarDefDefinitionData { bool operator==( const VarDefDefinitionData& other) const { - return short_name == other.short_name && - detailed_name == other.detailed_name && hover == other.hover && + return detailed_name == other.detailed_name && hover == other.hover && definition_spelling == other.definition_spelling && definition_extent == other.definition_extent && variable_type == other.variable_type && comments == other.comments; @@ -411,6 +410,11 @@ struct VarDefDefinitionData { const VarDefDefinitionData& other) const { return !(*this == other); } + + std::string_view ShortName() const { + return std::string_view(detailed_name.c_str() + short_name_offset, + short_name_size); + } }; template & value) { REFLECT_MEMBER_START(); - REFLECT_MEMBER(short_name); REFLECT_MEMBER(detailed_name); + REFLECT_MEMBER(short_name_size); + REFLECT_MEMBER(short_name_offset); REFLECT_MEMBER(hover); REFLECT_MEMBER(comments); REFLECT_MEMBER(definition_spelling); @@ -538,7 +543,7 @@ struct NamespaceHelper { container_cursor_to_qualified_name; std::string QualifiedName(const CXIdxContainerInfo* container, - std::string unqualified_name); + std::string_view unqualified_name); }; // |import_file| is the cc file which is what gets passed to clang. diff --git a/src/message_handler.cc b/src/message_handler.cc index f93ddd4d..b543cdb8 100644 --- a/src/message_handler.cc +++ b/src/message_handler.cc @@ -110,7 +110,7 @@ void EmitSemanticHighlighting(QueryDatabase* db, std::unordered_map grouped_symbols; for (SymbolRef sym : file->def->all_symbols) { - std::string detailed_name; + std::string_view detailed_name; SymbolKind parent_kind = SymbolKind::Invalid; ClangSymbolKind kind = ClangSymbolKind::Unknown; StorageClass storage = StorageClass::Invalid; @@ -137,7 +137,7 @@ void EmitSemanticHighlighting(QueryDatabase* db, parent_kind = var->def->parent_kind; kind = var->def->kind; storage = var->def->storage; - detailed_name = var->def->short_name; + detailed_name = var->def->ShortName(); break; } case SymbolKind::Type: { @@ -159,8 +159,8 @@ void EmitSemanticHighlighting(QueryDatabase* db, it->second.ranges.push_back(*loc); } else { Out_CqueryPublishSemanticHighlighting::Symbol symbol; - symbol.stableId = - semantic_cache_for_file->GetStableId(sym.idx.kind, detailed_name); + symbol.stableId = semantic_cache_for_file->GetStableId( + sym.idx.kind, std::string(detailed_name)); symbol.parentKind = parent_kind; symbol.kind = kind; symbol.storage = storage; diff --git a/src/messages/cquery_member_hierarchy.cc b/src/messages/cquery_member_hierarchy.cc index 1fdbf631..59cb9fa2 100644 --- a/src/messages/cquery_member_hierarchy.cc +++ b/src/messages/cquery_member_hierarchy.cc @@ -63,7 +63,7 @@ ExpandNode(QueryDatabase* db, WorkingFiles* working_files, QueryTypeId root) { for (auto& var_id : root_type.def->vars) { QueryVar& var = db->vars[var_id.id]; Out_CqueryMemberHierarchy::Entry entry; - entry.name = var.def->short_name; + entry.name = std::string(var.def->ShortName()); entry.type_id = var.def->variable_type ? var.def->variable_type->id : size_t(-1); if (var.def->definition_spelling) { diff --git a/src/query.cc b/src/query.cc index dc52c034..b28a75d5 100644 --- a/src/query.cc +++ b/src/query.cc @@ -77,8 +77,9 @@ optional ToQuery(const IdMap& id_map, const IndexVar::Def& var) { return nullopt; QueryVar::Def result; - result.short_name = var.short_name; result.detailed_name = var.detailed_name; + result.short_name_offset = var.short_name_offset; + result.short_name_size = var.short_name_size; result.hover = var.hover; result.comments = var.comments; result.definition_spelling = id_map.ToQuery(var.definition_spelling); @@ -932,7 +933,7 @@ void QueryDatabase::ImportOrUpdate( existing.def = def.value; if (!def.value.is_local()) UpdateDetailedNames(&existing.detailed_name_idx, SymbolKind::Var, - it->second.id, def.value.short_name, + it->second.id, std::string(def.value.ShortName()), def.value.detailed_name); } } diff --git a/src/query_utils.cc b/src/query_utils.cc index c85197fc..0246e2ec 100644 --- a/src/query_utils.cc +++ b/src/query_utils.cc @@ -479,7 +479,7 @@ optional GetSymbolInfo(QueryDatabase* db, return nullopt; lsSymbolInformation info; - info.name = use_short_name ? var.def->short_name : var.def->detailed_name; + info.name = use_short_name ? std::string(var.def->ShortName()) : var.def->detailed_name; info.containerName = var.def->detailed_name; info.kind = lsSymbolKind::Variable; return info; diff --git a/src/serializer.cc b/src/serializer.cc index 1887758f..ebf26b02 100644 --- a/src/serializer.cc +++ b/src/serializer.cc @@ -106,7 +106,6 @@ void Reflect(Writer& visitor, bool& value) { visitor.Bool(value); } -// std::string void Reflect(Reader& visitor, std::string& value) { if (!visitor.IsString()) throw std::invalid_argument("std::string"); @@ -116,6 +115,14 @@ void Reflect(Writer& visitor, std::string& value) { visitor.String(value.c_str(), (rapidjson::SizeType)value.size()); } +void Reflect(Reader&, std::string_view&) { + assert(0); +} +void Reflect(Writer& visitor, std::string_view& data) { + visitor.String(&data[0], (rapidjson::SizeType)data.size()); +} + + // ReflectMember void ReflectMember(Writer& visitor, const char* name, std::string& value) { visitor.Key(name); @@ -194,8 +201,9 @@ void Reflect(TVisitor& visitor, IndexVar& value) { REFLECT_MEMBER_START(); REFLECT_MEMBER2("id", value.id); REFLECT_MEMBER2("usr", value.usr); - REFLECT_MEMBER2("short_name", value.def.short_name); REFLECT_MEMBER2("detailed_name", value.def.detailed_name); + REFLECT_MEMBER2("short_name_offset", value.def.short_name_offset); + REFLECT_MEMBER2("short_name_size", value.def.short_name_size); REFLECT_MEMBER2("hover", value.def.hover); REFLECT_MEMBER2("comments", value.def.comments); REFLECT_MEMBER2("declarations", value.declarations); diff --git a/src/serializer.h b/src/serializer.h index fee42c65..2784359c 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -181,6 +182,9 @@ void Reflect(Writer& visitor, bool& value); void Reflect(Reader& visitor, std::string& value); void Reflect(Writer& visitor, std::string& value); +void Reflect(Reader& visitor, std::string& view, const std::string& data); +void Reflect(Writer& visitor, std::string& view, const std::string& data); + // std::monostate is used to represent JSON null void Reflect(Reader& visitor, std::monostate&); void Reflect(Writer& visitor, std::monostate&); @@ -306,40 +310,44 @@ void Reflect(Writer& visitor, std::vector& values) { visitor.EndArray(); } -// Writer: +// ReflectMember inline void DefaultReflectMemberStart(Writer& visitor) { visitor.StartObject(); } +inline void DefaultReflectMemberStart(Reader& visitor) {} + +template +bool ReflectMemberStart(Reader& visitor, T& value) { + return true; +} template bool ReflectMemberStart(Writer& visitor, T& value) { visitor.StartObject(); return true; } + +template +void ReflectMemberEnd(Reader& visitor, T& value) {} template void ReflectMemberEnd(Writer& visitor, T& value) { visitor.EndObject(); } + +template +void ReflectMember(Reader& visitor, const char* name, T& value) { + visitor.DoMember(name, [&](Reader& child) { Reflect(child, value); }); +} template void ReflectMember(Writer& visitor, const char* name, T& value) { visitor.Key(name); Reflect(visitor, value); } + void ReflectMember(Writer& visitor, const char* name, std::string& value); -// Reader: - -inline void DefaultReflectMemberStart(Reader& visitor) {} -template -bool ReflectMemberStart(Reader& visitor, T& value) { - return true; -} -template -void ReflectMemberEnd(Reader& visitor, T& value) {} -template -void ReflectMember(Reader& visitor, const char* name, T& value) { - visitor.DoMember(name, [&](Reader& child) { Reflect(child, value); }); -} +void ReflectMember(Reader& visitor, const char* name, std::string_view& view); +void ReflectMember(Writer& visitor, const char* name, std::string_view& view); // API