From 2d255da07b49879b0da2879449c3193e01f85a5d Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Thu, 8 Feb 2018 10:38:27 -0800 Subject: [PATCH] {Index,Query}Type::uses: Range/QueryLocation -> Reference And add serialization for Reference --- src/indexer.cc | 63 +++++++++++++++++++++++-- src/indexer.h | 25 +++++++--- src/messages/text_document_code_lens.cc | 7 ++- src/query.cc | 62 +++++++++++------------- src/query.h | 17 +++---- src/query_utils.cc | 37 ++++++++++++++- src/query_utils.h | 2 + src/serializer.cc | 2 +- src/test.cc | 7 +-- 9 files changed, 159 insertions(+), 63 deletions(-) diff --git a/src/indexer.cc b/src/indexer.cc index 35a2e445..3ed03e0b 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -603,7 +603,7 @@ void OnIndexReference_Function(IndexFile* db, // static const int IndexFile::kMajorVersion = 11; -const int IndexFile::kMinorVersion = 2; +const int IndexFile::kMinorVersion = 3; IndexFile::IndexFile(const std::string& path, const std::string& contents) @@ -693,6 +693,20 @@ void UniqueAdd(std::vector& values, T value) { values.push_back(value); } +// FIXME Reference: set lex_parent_id in call sites and remove this +void AddUse(std::vector& values, Range value) { + values.push_back(Reference{value, Id(), SymbolKind::Invalid, + SymbolRole::Reference}); +} + +// FIXME Reference: set lex_parent_id in call sites and remove this +void UniqueAdd(std::vector& values, Range value) { + if (std::find_if(values.begin(), values.end(), [&](const Reference& ref) { + return ref.range == value; + }) == values.end()) + AddUse(values, value); +} + IdCache::IdCache(const std::string& primary_file) : primary_file(primary_file) {} @@ -1238,7 +1252,7 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor, // seems no way to extract the spelling range of `type` and we do // not want to do subtraction here. // See https://github.com/jacobdufault/cquery/issues/252 - ref_type_index->uses.push_back(ref_cursor.get_extent()); + UniqueAdd(ref_type_index->uses, ref_cursor.get_extent()); } } UniqueAdd(ref_index->uses, cursor.get_spelling_range()); @@ -1439,7 +1453,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { ns->def.parents.push_back(parent_id); } } - ns->uses.push_back(decl_spell); + AddUse(ns->uses, decl_spell); break; } @@ -1745,7 +1759,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { if (!enum_type.is_fundamental()) { IndexType* int_type = db->Resolve(db->ToTypeId(enum_type.get_usr_hash())); - int_type->uses.push_back(decl_spell); + AddUse(int_type->uses, decl_spell); // type is invalidated. type = db->Resolve(type_id); } @@ -1899,7 +1913,7 @@ void OnIndexReference(CXClientData client_data, const CXIdxEntityRefInfo* ref) { case CXIdxEntity_CXXNamespace: { ClangCursor referenced = ref->referencedEntity->cursor; IndexType* ns = db->Resolve(db->ToTypeId(referenced.get_usr_hash())); - ns->uses.push_back(cursor.get_spelling_range()); + AddUse(ns->uses, cursor.get_spelling_range()); break; } @@ -2352,3 +2366,42 @@ void Reflect(Writer& visitor, IndexFuncRef& value) { Reflect(visitor, value.role); } } + +void Reflect(Reader& visitor, Reference& value) { + if (visitor.Format() == SerializeFormat::Json) { + std::string s = visitor.GetString(); + value = Reference{}; + value.range = Range(s.c_str()); + auto sep = s.find('|'); + if (sep == std::string::npos) + value.role = SymbolRole::Reference; + else { + char* p = const_cast(s.c_str()) + sep; + value.role = SymbolRole(strtol(p + 1, &p, 10)); + value.lex_parent_kind = SymbolKind(strtol(p + 1, &p, 10)); + value.lex_parent_id = Id(strtol(p + 1, &p, 10)); + } + } else { + Reflect(visitor, value.range); + Reflect(visitor, value.lex_parent_id); + Reflect(visitor, value.lex_parent_kind); + Reflect(visitor, value.role); + } +} +void Reflect(Writer& visitor, Reference& value) { + if (visitor.Format() == SerializeFormat::Json) { + std::string s = value.range.ToString(); + if (value.role != SymbolRole::Reference || + value.lex_parent_kind != SymbolKind::Invalid) { + s += '|' + std::to_string(uint8_t(value.role)); + s += '|' + std::to_string(uint8_t(value.lex_parent_kind)); + s += '|' + std::to_string(RawId(value.lex_parent_id)); + } + visitor.String(s.c_str()); + } else { + Reflect(visitor, value.range); + Reflect(visitor, value.lex_parent_id); + Reflect(visitor, value.lex_parent_kind); + Reflect(visitor, value.role); + } +} diff --git a/src/indexer.h b/src/indexer.h index 306ba4fe..73cfb91c 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -78,13 +78,22 @@ using IndexVarId = Id; struct IdCache; -struct IndexLocation { - Range loc; - Id parent_id; - SymbolKind parent_kind = SymbolKind::Invalid; - SymbolRole role = SymbolRole::None; +struct Reference { + Range range; + Id lex_parent_id; + SymbolKind lex_parent_kind; + SymbolRole role; + + std::tuple, SymbolKind, SymbolRole> ToTuple() const { + return std::make_tuple(range, lex_parent_id, lex_parent_kind, role); + } + bool operator==(const Reference& o) const { + return ToTuple() == o.ToTuple(); + } + bool operator<(const Reference& o) const { + return ToTuple() < o.ToTuple(); + } }; -MAKE_REFLECT_STRUCT(IndexLocation, loc, parent_id, parent_kind, role); struct IndexFuncRef { // NOTE: id can be -1 if the function call is not coming from a function. @@ -104,6 +113,8 @@ struct IndexFuncRef { void Reflect(Reader& visitor, IndexFuncRef& value); void Reflect(Writer& visitor, IndexFuncRef& value); +void Reflect(Reader& visitor, Reference& value); +void Reflect(Writer& visitor, Reference& value); template uses; + std::vector uses; IndexType() {} // For serialization. IndexType(IndexTypeId id, Usr usr); diff --git a/src/messages/text_document_code_lens.cc b/src/messages/text_document_code_lens.cc index 3ce850b5..4a72514d 100644 --- a/src/messages/text_document_code_lens.cc +++ b/src/messages/text_document_code_lens.cc @@ -154,8 +154,13 @@ struct TextDocumentCodeLensHandler continue; if (type.def->kind == ClangSymbolKind::Namespace) continue; + // FIXME QueryRef + std::vector uses; + uses.reserve(type.uses.size()); + for (auto& x : type.uses) + uses.push_back(ToQueryLocation(db, x)); AddCodeLens("ref", "refs", &common, ref.loc.OffsetStartColumn(0), - type.uses, type.def->definition_spelling, + uses, type.def->definition_spelling, true /*force_display*/); AddCodeLens("derived", "derived", &common, ref.loc.OffsetStartColumn(1), diff --git a/src/query.cc b/src/query.cc index db026295..bea56521 100644 --- a/src/query.cc +++ b/src/query.cc @@ -254,8 +254,8 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IdMap& id_map, const IndexFile& in *type.def.definition_spelling); if (type.def.definition_extent.has_value()) add_outline(id_map.ToSymbol(type.id), *type.def.definition_extent); - for (const Range& use : type.uses) - add_all_symbols(id_map.ToSymbol(type.id), SymbolRole::Reference, use); + for (const Reference& use : type.uses) + add_all_symbols(id_map.ToSymbol(type.id), use.role, use.range); } for (const IndexFunc& func : indexed.funcs) { if (func.def.definition_spelling.has_value()) @@ -372,34 +372,6 @@ Maybe GetQueryVarIdFromUsr(QueryDatabase* query_db, } // namespace -QueryFileId QueryRef::FileId(QueryDatabase* db) const { - switch (lex_parent_kind) { - case SymbolKind::Invalid: - break; - case SymbolKind::File: - return QueryFileId(lex_parent_id); - case SymbolKind::Func: { - QueryFunc& file = db->funcs[lex_parent_id.id]; - if (file.def) - return file.def->file; - break; - } - case SymbolKind::Type: { - QueryType& type = db->types[lex_parent_id.id]; - if (type.def) - return type.def->file; - break; - } - case SymbolKind::Var: { - QueryVar& var = db->vars[lex_parent_id.id]; - if (var.def) - return var.def->file; - break; - } - } - return QueryFileId(); -} - Maybe QueryDatabase::GetQueryFileIdFromPath( const std::string& path) { return ::GetQueryFileIdFromPath(this, path, false); @@ -442,6 +414,28 @@ IdMap::IdMap(QueryDatabase* query_db, const IdCache& local_ids) QueryLocation IdMap::ToQuery(Range range, SymbolRole role) const { return QueryLocation{range, primary_file, role}; } +Reference IdMap::ToQuery(Reference ref) const { + switch (ref.lex_parent_kind) { + case SymbolKind::Invalid: + case SymbolKind::File: + ref.lex_parent_kind = SymbolKind::File; + ref.lex_parent_id = Id(primary_file); + break; + case SymbolKind::Func: + ref.lex_parent_id = Id( + cached_func_ids_.find(IndexFuncId(ref.lex_parent_id))->second); + break; + case SymbolKind::Type: + ref.lex_parent_id = Id( + cached_type_ids_.find(IndexTypeId(ref.lex_parent_id))->second); + break; + case SymbolKind::Var: + ref.lex_parent_id = + Id(cached_var_ids_.find(IndexVarId(ref.lex_parent_id))->second); + break; + } + return ref; +} QueryTypeId IdMap::ToQuery(IndexTypeId id) const { assert(cached_type_ids_.find(id) != cached_type_ids_.end()); return QueryTypeId(cached_type_ids_.find(id)->second); @@ -591,7 +585,7 @@ IndexUpdate::IndexUpdate(const IdMap& previous_id_map, PROCESS_UPDATE_DIFF(QueryTypeId, types_derived, derived, QueryTypeId); PROCESS_UPDATE_DIFF(QueryTypeId, types_instances, instances, QueryVarId); - PROCESS_UPDATE_DIFF(QueryTypeId, types_uses, uses, QueryLocation); + PROCESS_UPDATE_DIFF(QueryTypeId, types_uses, uses, Reference); }); // Functions @@ -1032,7 +1026,7 @@ TEST_SUITE("query") { IndexFile current("foo.cc", ""); previous.Resolve(previous.ToTypeId(HashUsr("usr1"))) - ->uses.push_back(Range(Position(1, 0))); + ->uses.push_back(Reference{Range(Position(1, 0))}); previous.Resolve(previous.ToFuncId(HashUsr("usr2"))) ->callers.push_back(IndexFuncRef{Range(Position(2, 0)), IndexFuncId(0), SymbolRole::None}); @@ -1078,8 +1072,8 @@ TEST_SUITE("query") { IndexType* pt = previous.Resolve(previous.ToTypeId(HashUsr("usr"))); IndexType* ct = current.Resolve(current.ToTypeId(HashUsr("usr"))); - pt->uses.push_back(Range(Position(1, 0))); - ct->uses.push_back(Range(Position(2, 0))); + pt->uses.push_back(Reference{Range(Position(1, 0))}); + ct->uses.push_back(Reference{Range(Position(2, 0))}); IndexUpdate update = GetDelta(previous, current); diff --git a/src/query.h b/src/query.h index 1cb8e278..727a181f 100644 --- a/src/query.h +++ b/src/query.h @@ -57,15 +57,6 @@ struct hash<::SymbolKind> { }; } // namespace std -struct QueryRef { - Range range; - Id lex_parent_id; - SymbolKind lex_parent_kind; - SymbolRole role; - QueryFileId FileId(QueryDatabase*) const; -}; -//MAKE_REFLECT_STRUCT(QueryRef, range, lex_parent_id, lex_parent_kind, role); - struct SymbolIdx { SymbolKind kind; RawId idx; @@ -235,14 +226,14 @@ struct QueryType { using DefUpdate = WithUsr; using DerivedUpdate = MergeableUpdate; using InstancesUpdate = MergeableUpdate; - using UsesUpdate = MergeableUpdate; + using UsesUpdate = MergeableUpdate; Usr usr; Maybe> symbol_idx; optional def; std::vector derived; std::vector instances; - std::vector uses; + std::vector uses; explicit QueryType(const Usr& usr) : usr(usr) {} }; @@ -410,6 +401,7 @@ template <> struct IndexToQuery { using type = QueryTypeId; }; template <> struct IndexToQuery { using type = QueryVarId; }; template <> struct IndexToQuery { using type = QueryFuncRef; }; template <> struct IndexToQuery { using type = QueryLocation; }; +template <> struct IndexToQuery { using type = Reference; }; template <> struct IndexToQuery { using type = QueryLocation; }; template struct IndexToQuery> { using type = optional::type>; @@ -428,6 +420,7 @@ struct IdMap { // FIXME Too verbose // clang-format off QueryLocation ToQuery(Range range, SymbolRole role) const; + Reference ToQuery(Reference ref) const; QueryTypeId ToQuery(IndexTypeId id) const; QueryFuncId ToQuery(IndexFuncId id) const; QueryVarId ToQuery(IndexVarId id) const; @@ -459,3 +452,5 @@ struct IdMap { spp::sparse_hash_map cached_func_ids_; spp::sparse_hash_map cached_var_ids_; }; + +QueryFileId GetFileId(const Reference& ref, QueryDatabase* db); diff --git a/src/query_utils.cc b/src/query_utils.cc index 236e27b9..0fe25733 100644 --- a/src/query_utils.cc +++ b/src/query_utils.cc @@ -28,6 +28,34 @@ std::vector ToQueryLocationHelper( return locs; } +QueryFileId GetFileId(QueryDatabase* db, Reference ref) { + switch (ref.lex_parent_kind) { + case SymbolKind::Invalid: + break; + case SymbolKind::File: + return QueryFileId(ref.lex_parent_id); + case SymbolKind::Func: { + QueryFunc& file = db->funcs[ref.lex_parent_id.id]; + if (file.def) + return file.def->file; + break; + } + case SymbolKind::Type: { + QueryType& type = db->types[ref.lex_parent_id.id]; + if (type.def) + return type.def->file; + break; + } + case SymbolKind::Var: { + QueryVar& var = db->vars[ref.lex_parent_id.id]; + if (var.def) + return var.def->file; + break; + } + } + return QueryFileId(); +} + } // namespace optional GetDefinitionSpellingOfSymbol(QueryDatabase* db, @@ -151,6 +179,10 @@ optional GetDeclarationFileForSymbol(QueryDatabase* db, return nullopt; } +QueryLocation ToQueryLocation(QueryDatabase* db, Reference ref) { + return QueryLocation{ref.range, GetFileId(db, ref), ref.role}; +} + std::vector ToQueryLocation( QueryDatabase* db, const std::vector& refs) { @@ -182,7 +214,10 @@ std::vector GetUsesOfSymbol(QueryDatabase* db, switch (symbol.kind) { case SymbolKind::Type: { QueryType& type = db->types[symbol.idx]; - std::vector ret = type.uses; + std::vector ret; + ret.reserve(type.uses.size()); + for (auto& x : type.uses) + ret.push_back(ToQueryLocation(db, x)); if (include_decl && type.def && type.def->definition_spelling) ret.push_back(*type.def->definition_spelling); return ret; diff --git a/src/query_utils.h b/src/query_utils.h index 7a06fd14..6c2d4ad8 100644 --- a/src/query_utils.h +++ b/src/query_utils.h @@ -19,6 +19,8 @@ optional GetDefinitionExtentOfSymbol(QueryDatabase* db, const SymbolIdx& symbol); optional GetDeclarationFileForSymbol(QueryDatabase* db, const SymbolIdx& symbol); + +QueryLocation ToQueryLocation(QueryDatabase* db, Reference ref); std::vector ToQueryLocation( QueryDatabase* db, const std::vector& refs); diff --git a/src/serializer.cc b/src/serializer.cc index 8b6c7dbc..74bfb948 100644 --- a/src/serializer.cc +++ b/src/serializer.cc @@ -44,7 +44,7 @@ void Reflect(Writer& visitor, int& value) { } void Reflect(Reader& visitor, unsigned& value) { - if (!visitor.IsInt()) + if (!visitor.IsUint64()) throw std::invalid_argument("unsigned"); value = visitor.GetUint32(); } diff --git a/src/test.cc b/src/test.cc index 3ddd8183..ce516de7 100644 --- a/src/test.cc +++ b/src/test.cc @@ -109,9 +109,10 @@ void DiffDocuments(std::string path, void VerifySerializeToFrom(IndexFile* file) { std::string expected = file->ToString(); - std::unique_ptr result = Deserialize( - SerializeFormat::Json, "--.cc", Serialize(SerializeFormat::Json, *file), "", - nullopt /*expected_version*/); + std::string serialized = Serialize(SerializeFormat::Json, *file); + std::unique_ptr result = + Deserialize(SerializeFormat::Json, "--.cc", serialized, "", + nullopt /*expected_version*/); std::string actual = result->ToString(); if (expected != actual) { std::cerr << "Serialization failure" << std::endl;