diff --git a/src/command_line.cc b/src/command_line.cc index 97cfe55b..3ec9d2c1 100644 --- a/src/command_line.cc +++ b/src/command_line.cc @@ -124,8 +124,7 @@ std::string Join(const std::vector& elements, std::string sep) { } -optional GetDefinitionSpellingOfUsr(QueryableDatabase* db, const Usr& usr) { - SymbolIdx symbol = db->usr_to_symbol[usr]; +optional GetDefinitionSpellingOfSymbol(QueryableDatabase* db, const SymbolIdx& symbol) { switch (symbol.kind) { case SymbolKind::Type: { QueryableTypeDef* def = &db->types[symbol.idx]; @@ -148,6 +147,10 @@ optional GetDefinitionSpellingOfUsr(QueryableDatabase* db, co return nullopt; } +optional GetDefinitionSpellingOfUsr(QueryableDatabase* db, const Usr& usr) { + return GetDefinitionSpellingOfSymbol(db, db->usr_to_symbol[usr]); +} + optional GetDefinitionExtentOfUsr(QueryableDatabase* db, const Usr& usr) { SymbolIdx symbol = db->usr_to_symbol[usr]; switch (symbol.kind) { @@ -555,10 +558,10 @@ void QueryDbMainLoop( int target_line = msg->params.position.line + 1; int target_column = msg->params.position.character + 1; - for (const UsrRef& ref : file->def.all_symbols) { + for (const SymbolRef& ref : file->def.all_symbols) { if (ref.loc.range.start.line >= target_line && ref.loc.range.end.line <= target_line && ref.loc.range.start.column <= target_column && ref.loc.range.end.column >= target_column) { - optional location = GetDefinitionSpellingOfUsr(db, ref.usr); + optional location = GetDefinitionSpellingOfSymbol(db, ref.idx); if (location) response.result.push_back(GetLsLocation(location.value())); break; @@ -582,13 +585,12 @@ void QueryDbMainLoop( } std::cerr << "File outline size is " << file->def.outline.size() << std::endl; - for (UsrRef ref : file->def.outline) { - SymbolIdx symbol = db->usr_to_symbol[ref.usr]; + for (SymbolRef ref : file->def.outline) { + SymbolIdx symbol = ref.idx; lsSymbolInformation info; info.location = GetLsLocation(ref.loc); - // TODO: cleanup namespace/naming so there is only one SymbolKind. switch (symbol.kind) { case SymbolKind::Type: { QueryableTypeDef& def = db->types[symbol.idx]; @@ -645,11 +647,11 @@ void QueryDbMainLoop( break; } - for (UsrRef ref : file->def.outline) { + for (SymbolRef ref : file->def.outline) { // NOTE: We OffsetColumn so that the code lens always show up in a // predictable order. Otherwise, the client may randomize it. - SymbolIdx symbol = db->usr_to_symbol[ref.usr]; + SymbolIdx symbol = ref.idx; switch (symbol.kind) { case SymbolKind::Type: { QueryableTypeDef& def = db->types[symbol.idx]; diff --git a/src/indexer.h b/src/indexer.h index 6695a604..50777a5a 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -30,7 +30,7 @@ struct Id { uint64_t id; Id() : id(0) {} // Needed for containers. Do not use directly. - Id(uint64_t id) : id(id) {} + explicit Id(uint64_t id) : id(id) {} bool operator==(const Id& other) const { return id == other.id; } diff --git a/src/query.cc b/src/query.cc index 865701b8..f78771f7 100644 --- a/src/query.cc +++ b/src/query.cc @@ -135,46 +135,46 @@ QueryableFile::Def BuildFileDef(const IdMap& id_map, const IndexedFile& indexed) QueryableFile::Def def; def.usr = indexed.path; - auto add_outline = [&def, &id_map](Usr usr, Range range) { - def.outline.push_back(UsrRef(usr, MapIdToUsr(id_map, range))); + auto add_outline = [&def, &id_map](SymbolIdx idx, Range range) { + def.outline.push_back(SymbolRef(idx, MapIdToUsr(id_map, range))); }; - auto add_all_symbols = [&def, &id_map](Usr usr, Range range) { - def.all_symbols.push_back(UsrRef(usr, MapIdToUsr(id_map, range))); + auto add_all_symbols = [&def, &id_map](SymbolIdx idx, Range range) { + def.all_symbols.push_back(SymbolRef(idx, MapIdToUsr(id_map, range))); }; for (const IndexedTypeDef& def : indexed.types) { if (def.def.definition_spelling.has_value()) - add_all_symbols(def.def.usr, def.def.definition_spelling.value()); + add_all_symbols(id_map.ToSymbol(def.id), def.def.definition_spelling.value()); if (def.def.definition_extent.has_value()) - add_outline(def.def.usr, def.def.definition_extent.value()); + add_outline(id_map.ToSymbol(def.id), def.def.definition_extent.value()); for (const Range& use : def.uses) - add_all_symbols(def.def.usr, use); + add_all_symbols(id_map.ToSymbol(def.id), use); } for (const IndexedFuncDef& def : indexed.funcs) { if (def.def.definition_spelling.has_value()) - add_all_symbols(def.def.usr, def.def.definition_spelling.value()); + add_all_symbols(id_map.ToSymbol(def.id), def.def.definition_spelling.value()); if (def.def.definition_extent.has_value()) - add_outline(def.def.usr, def.def.definition_extent.value()); + add_outline(id_map.ToSymbol(def.id), def.def.definition_extent.value()); for (Range decl : def.declarations) { - add_outline(def.def.usr, decl); - add_all_symbols(def.def.usr, decl); + add_outline(id_map.ToSymbol(def.id), decl); + add_all_symbols(id_map.ToSymbol(def.id), decl); } for (const Range& use : def.uses) - add_all_symbols(def.def.usr, use); + add_all_symbols(id_map.ToSymbol(def.id), use); } for (const IndexedVarDef& def : indexed.vars) { if (def.def.definition_spelling.has_value()) - add_all_symbols(def.def.usr, def.def.definition_spelling.value()); + add_all_symbols(id_map.ToSymbol(def.id), def.def.definition_spelling.value()); if (def.def.definition_extent.has_value()) - add_outline(def.def.usr, def.def.definition_extent.value()); + add_outline(id_map.ToSymbol(def.id), def.def.definition_extent.value()); for (const Range& use : def.uses) - add_all_symbols(def.def.usr, use); + add_all_symbols(id_map.ToSymbol(def.id), use); } - std::sort(def.outline.begin(), def.outline.end(), [](const UsrRef& a, const UsrRef& b) { + std::sort(def.outline.begin(), def.outline.end(), [](const SymbolRef& a, const SymbolRef& b) { return a.loc.range.start < b.loc.range.start; }); - std::sort(def.all_symbols.begin(), def.all_symbols.end(), [](const UsrRef& a, const UsrRef& b) { + std::sort(def.all_symbols.begin(), def.all_symbols.end(), [](const SymbolRef& a, const SymbolRef& b) { return a.loc.range.start < b.loc.range.start; }); @@ -352,123 +352,101 @@ QueryFileId GetQueryFileIdFromUsr(QueryableDatabase* query_db, const Usr& usr) { auto it = query_db->usr_to_symbol.find(usr); if (it != query_db->usr_to_symbol.end()) { assert(it->second.kind == SymbolKind::File); - return it->second.idx; + return QueryFileId(it->second.idx); } - int idx = query_db->files.size(); + size_t idx = query_db->files.size(); query_db->usr_to_symbol[usr] = SymbolIdx(SymbolKind::File, idx); query_db->files.push_back(QueryableFile(usr)); - return idx; + return QueryFileId(idx); } QueryTypeId GetQueryTypeIdFromUsr(QueryableDatabase* query_db, const Usr& usr) { auto it = query_db->usr_to_symbol.find(usr); if (it != query_db->usr_to_symbol.end()) { assert(it->second.kind == SymbolKind::Type); - return it->second.idx; + return QueryTypeId(it->second.idx); } - int idx = query_db->types.size(); + size_t idx = query_db->types.size(); query_db->usr_to_symbol[usr] = SymbolIdx(SymbolKind::Type, idx); query_db->types.push_back(QueryableTypeDef(usr)); - return idx; + return QueryTypeId(idx); } QueryFuncId GetQueryFuncIdFromUsr(QueryableDatabase* query_db, const Usr& usr) { auto it = query_db->usr_to_symbol.find(usr); if (it != query_db->usr_to_symbol.end()) { assert(it->second.kind == SymbolKind::Func); - return it->second.idx; + return QueryFuncId(it->second.idx); } - int idx = query_db->funcs.size(); + size_t idx = query_db->funcs.size(); query_db->usr_to_symbol[usr] = SymbolIdx(SymbolKind::Func, idx); query_db->funcs.push_back(QueryableFuncDef(usr)); - return idx; + return QueryFuncId(idx); } QueryVarId GetQueryVarIdFromUsr(QueryableDatabase* query_db, const Usr& usr) { auto it = query_db->usr_to_symbol.find(usr); if (it != query_db->usr_to_symbol.end()) { assert(it->second.kind == SymbolKind::Var); - return it->second.idx; + return QueryVarId(it->second.idx); } - int idx = query_db->vars.size(); + size_t idx = query_db->vars.size(); query_db->usr_to_symbol[usr] = SymbolIdx(SymbolKind::Var, idx); query_db->vars.push_back(QueryableVarDef(usr)); - return idx; + return QueryVarId(idx); } -#if false -int GetOrAddSymbol(QueryableDatabase* query_db, SymbolKind kind, const Usr& usr) { - // TODO: consider having separate lookup maps so they are smaller (maybe - // lookups will go faster). - auto it = query_db->usr_to_symbol.find(usr); - - // Found; return existing symbol. - if (it != query_db->usr_to_symbol.end()) { - assert(it->second.kind == kind); - return it->second.idx; - } - - // Not found; add a new symbol. - switch (kind) { - case SymbolKind::File: { - int idx = query_db->files.size(); - query_db->usr_to_symbol[usr] = SymbolIdx(kind, idx); - query_db->files.push_back(QueryableFile(usr)); - return idx; - } - case SymbolKind::Type: { - int idx = query_db->types.size(); - query_db->usr_to_symbol[usr] = SymbolIdx(kind, idx); - query_db->types.push_back(QueryableTypeDef(usr)); - return idx; - } - case SymbolKind::Func: { - int idx = query_db->funcs.size(); - query_db->usr_to_symbol[usr] = SymbolIdx(kind, idx); - query_db->funcs.push_back(QueryableFuncDef(usr)); - return idx; - } - case SymbolKind::Var: { - int idx = query_db->vars.size(); - query_db->usr_to_symbol[usr] = SymbolIdx(kind, idx); - query_db->vars.push_back(QueryableVarDef(usr)); - return idx; - } - case SymbolKind::Invalid: { - assert(false); - return -1; - } - } - - assert(false); - return -1; -} -#endif - IdMap::IdMap(QueryableDatabase* query_db, const IdCache& local_ids) : local_ids(local_ids) { index_file_id = GetQueryFileIdFromUsr(query_db, local_ids.primary_file); - cached_type_ids_.reserve(local_ids.type_id_to_usr.size()); + cached_type_ids_.set_empty_key(-1); + cached_type_ids_.resize(local_ids.type_id_to_usr.size()); for (const auto& entry : local_ids.type_id_to_usr) - cached_type_ids_[entry.first] = GetQueryTypeIdFromUsr(query_db, entry.second); + cached_type_ids_[entry.first.id] = GetQueryTypeIdFromUsr(query_db, entry.second).id; - cached_func_ids_.reserve(local_ids.func_id_to_usr.size()); + cached_func_ids_.set_empty_key(-1); + cached_func_ids_.resize(local_ids.func_id_to_usr.size()); for (const auto& entry : local_ids.func_id_to_usr) - cached_func_ids_[entry.first] = GetQueryFuncIdFromUsr(query_db, entry.second); + cached_func_ids_[entry.first.id] = GetQueryFuncIdFromUsr(query_db, entry.second).id; - cached_var_ids_.reserve(local_ids.var_id_to_usr.size()); + cached_var_ids_.set_empty_key(-1); + cached_var_ids_.resize(local_ids.var_id_to_usr.size()); for (const auto& entry : local_ids.var_id_to_usr) - cached_var_ids_[entry.first] = GetQueryVarIdFromUsr(query_db, entry.second); + cached_var_ids_[entry.first.id] = GetQueryVarIdFromUsr(query_db, entry.second).id; +} + +QueryTypeId IdMap::ToQuery(IndexTypeId id) const { + assert(cached_type_ids_.find(id.id) != cached_type_ids_.end()); + return QueryTypeId(cached_type_ids_.find(id.id)->second); } +QueryFuncId IdMap::ToQuery(IndexFuncId id) const { + assert(cached_func_ids_.find(id.id) != cached_func_ids_.end()); + return QueryFuncId(cached_func_ids_.find(id.id)->second); +} +QueryVarId IdMap::ToQuery(IndexVarId id) const { + assert(cached_var_ids_.find(id.id) != cached_var_ids_.end()); + return QueryVarId(cached_var_ids_.find(id.id)->second); +} +SymbolIdx IdMap::ToSymbol(IndexTypeId id) const { + return SymbolIdx(SymbolKind::Type, ToQuery(id).id); +} + +SymbolIdx IdMap::ToSymbol(IndexFuncId id) const { + return SymbolIdx(SymbolKind::Func, ToQuery(id).id); +} + +SymbolIdx IdMap::ToSymbol(IndexVarId id) const { + return SymbolIdx(SymbolKind::Var, ToQuery(id).id); +} @@ -633,7 +611,7 @@ void IndexUpdate::Merge(const IndexUpdate& update) { -void UpdateQualifiedName(QueryableDatabase* db, int* qualified_name_index, SymbolKind kind, int symbol_index, const std::string& name) { +void UpdateQualifiedName(QueryableDatabase* db, size_t* qualified_name_index, SymbolKind kind, size_t symbol_index, const std::string& name) { if (*qualified_name_index == -1) { db->qualified_names.push_back(name); db->symbols.push_back(SymbolIdx(kind, symbol_index)); diff --git a/src/query.h b/src/query.h index b3c1acf0..ef8763ce 100644 --- a/src/query.h +++ b/src/query.h @@ -56,6 +56,38 @@ struct QueryableLocation { } }; +enum class SymbolKind { Invalid, File, Type, Func, Var }; +struct SymbolIdx { + SymbolKind kind; + size_t idx; + + SymbolIdx() : kind(SymbolKind::Invalid), idx(-1) {} // Default ctor needed by stdlib. Do not use. + SymbolIdx(SymbolKind kind, uint64_t idx) : kind(kind), idx(idx) {} + + bool operator==(const SymbolIdx& that) const { + return kind == that.kind && idx == that.idx; + } + bool operator!=(const SymbolIdx& that) const { return !(*this == that); } + bool operator<(const SymbolIdx& that) const { + return kind < that.kind || idx < that.idx; + } +}; + +struct SymbolRef { + SymbolIdx idx; + QueryableLocation loc; + + SymbolRef(SymbolIdx idx, QueryableLocation loc) : idx(idx), loc(loc) {} + + bool operator==(const SymbolRef& that) const { + return idx == that.idx && loc == that.loc; + } + bool operator!=(const SymbolRef& that) const { return !(*this == that); } + bool operator<(const SymbolRef& that) const { + return idx < that.idx && loc.range.start < that.loc.range.start; + } +}; + struct UsrRef { Usr usr; QueryableLocation loc; @@ -110,15 +142,15 @@ struct QueryableFile { struct Def { Usr usr; // Outline of the file (ie, for code lens). - std::vector outline; + std::vector outline; // Every symbol found in the file (ie, for goto definition) - std::vector all_symbols; + std::vector all_symbols; }; using DefUpdate = Def; DefUpdate def; - int qualified_name_idx = -1; + size_t qualified_name_idx = -1; QueryableFile(const Usr& usr) { def.usr = usr; } QueryableFile(const Def& def) : def(def) {} @@ -135,7 +167,7 @@ struct QueryableTypeDef { std::vector derived; std::vector instantiations; std::vector uses; - int qualified_name_idx = -1; + size_t qualified_name_idx = -1; QueryableTypeDef(const Usr& usr) : def(usr) {} QueryableTypeDef(const DefUpdate& def) : def(def) {} @@ -154,7 +186,7 @@ struct QueryableFuncDef { std::vector derived; std::vector callers; std::vector uses; - int qualified_name_idx = -1; + size_t qualified_name_idx = -1; QueryableFuncDef(const Usr& usr) : def(usr) {} QueryableFuncDef(const DefUpdate& def) : def(def) {} @@ -167,23 +199,13 @@ struct QueryableVarDef { DefUpdate def; std::vector uses; - int qualified_name_idx = -1; + size_t qualified_name_idx = -1; QueryableVarDef(const Usr& usr) : def(usr) {} QueryableVarDef(const DefUpdate& def) : def(def) {} QueryableVarDef(const IdMap& id_map, const IndexedVarDef& indexed); }; -enum class SymbolKind { Invalid, File, Type, Func, Var }; -struct SymbolIdx { - SymbolKind kind; - uint64_t idx; - - SymbolIdx() : kind(SymbolKind::Invalid), idx(-1) {} // Default ctor needed by stdlib. Do not use. - SymbolIdx(SymbolKind kind, uint64_t idx) : kind(kind), idx(idx) {} -}; - - struct IndexUpdate { // Creates a new IndexUpdate based on the delta from previous to current. If // no delta computation should be done just pass null for previous. @@ -272,10 +294,18 @@ struct IdMap { IdMap(QueryableDatabase* query_db, const IdCache& local_ids); + QueryTypeId ToQuery(IndexTypeId id) const; + QueryFuncId ToQuery(IndexFuncId id) const; + QueryVarId ToQuery(IndexVarId id) const; + SymbolIdx ToSymbol(IndexTypeId id) const; + SymbolIdx ToSymbol(IndexFuncId id) const; + SymbolIdx ToSymbol(IndexVarId id) const; + // TODO private: QueryFileId index_file_id; - std::unordered_map cached_type_ids_; - std::unordered_map cached_func_ids_; - std::unordered_map cached_var_ids_; + // TODO: make these type safe + google::dense_hash_map cached_type_ids_; // IndexTypeId -> QueryTypeId + google::dense_hash_map cached_func_ids_; // IndexFuncId -> QueryFuncId + google::dense_hash_map cached_var_ids_; // IndexVarId -> QueryVarId }; diff --git a/src/test.cc b/src/test.cc index 96c35d4f..02ba9586 100644 --- a/src/test.cc +++ b/src/test.cc @@ -56,7 +56,7 @@ void DiffDocuments(std::string path, rapidjson::Document& expected, rapidjson::D int max_diff = 5; - int len = std::min(actual_output.size(), expected_output.size()); + size_t len = std::min(actual_output.size(), expected_output.size()); for (int i = 0; i < len; ++i) { if (actual_output[i] != expected_output[i]) { if (--max_diff < 0) {