From cbe308c0f900239f0725487a5409e292d6face35 Mon Sep 17 00:00:00 2001 From: Jacob Dufault Date: Tue, 18 Apr 2017 23:56:37 -0700 Subject: [PATCH] Try to have better behavior when types are defined across multiple files. --- foo/a.h | 6 +- foo/b.cc | 19 +- src/command_line.cc | 23 +- src/indexer.h | 44 +++- src/query.cc | 464 +++++++++++++++++---------------- src/query.h | 5 +- src/test.cc | 2 +- tests/multi_file/funky_enum.cc | 62 +++++ tests/multi_file/funky_enum.h | 6 + 9 files changed, 374 insertions(+), 257 deletions(-) create mode 100644 tests/multi_file/funky_enum.cc create mode 100644 tests/multi_file/funky_enum.h diff --git a/foo/a.h b/foo/a.h index 3aac844e..cd6e7b7f 100644 --- a/foo/a.h +++ b/foo/a.h @@ -1,5 +1 @@ -#if false -struct Parent { - virtual void foo() {} -}; -#endif +a,b,c \ No newline at end of file diff --git a/foo/b.cc b/foo/b.cc index d13c8851..2c226e7f 100644 --- a/foo/b.cc +++ b/foo/b.cc @@ -1,17 +1,4 @@ -struct Parent { - virtual void Method() = 0; -}; -struct Derived : public Parent { - void Method() override {} -}; - - -void Caller() { - Derived d; - Parent* p = &d; - - p->Method(); - d->Method(); -} - +enum Foo { + #include "a.h" +}; \ No newline at end of file diff --git a/src/command_line.cc b/src/command_line.cc index f8358256..ff9e291d 100644 --- a/src/command_line.cc +++ b/src/command_line.cc @@ -563,7 +563,7 @@ optional GetLsLocation(QueryDatabase* db, WorkingFiles* working_file } // Returns a symbol. The symbol will have *NOT* have a location assigned. -lsSymbolInformation GetSymbolInfo(QueryDatabase* db, WorkingFiles* working_files, SymbolIdx symbol) { +optional GetSymbolInfo(QueryDatabase* db, WorkingFiles* working_files, SymbolIdx symbol) { lsSymbolInformation info; switch (symbol.kind) { @@ -599,8 +599,7 @@ lsSymbolInformation GetSymbolInfo(QueryDatabase* db, WorkingFiles* working_files break; } case SymbolKind::Invalid: { - assert(false && "unexpected"); - break; + return nullopt; } }; @@ -1397,12 +1396,15 @@ void QueryDbMainLoop( std::cerr << "File outline size is " << file->def.outline.size() << std::endl; for (SymbolRef ref : file->def.outline) { - lsSymbolInformation info = GetSymbolInfo(db, working_files, ref.idx); + optional info = GetSymbolInfo(db, working_files, ref.idx); + if (!info) + continue; + optional location = GetLsLocation(db, working_files, ref.loc); if (!location) continue; - info.location = *location; - response.result.push_back(info); + info->location = *location; + response.result.push_back(*info); } ipc->SendOutMessageToClient(response); @@ -1520,7 +1522,10 @@ void QueryDbMainLoop( } if (db->detailed_names[i].find(query) != std::string::npos) { - lsSymbolInformation info = GetSymbolInfo(db, working_files, db->symbols[i]); + optional info = GetSymbolInfo(db, working_files, db->symbols[i]); + if (!info) + continue; + optional location = GetDefinitionExtentOfSymbol(db, db->symbols[i]); if (!location) { auto decls = GetDeclarationsOfSymbolForGotoDefinition(db, db->symbols[i]); @@ -1532,8 +1537,8 @@ void QueryDbMainLoop( optional ls_location = GetLsLocation(db, working_files, *location); if (!ls_location) continue; - info.location = *ls_location; - response.result.push_back(info); + info->location = *ls_location; + response.result.push_back(*info); } } diff --git a/src/indexer.h b/src/indexer.h index 90343ac5..241e5396 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -146,6 +146,19 @@ struct TypeDefDefinitionData { TypeDefDefinitionData() {} // For reflection. TypeDefDefinitionData(const std::string& usr) : usr(usr) {} + bool HasInterestingState() const { + return + !short_name.empty() || + !detailed_name.empty() || + definition_spelling || + definition_extent || + alias_of || + !parents.empty() || + !types.empty() || + !funcs.empty() || + !vars.empty(); + } + bool operator==(const TypeDefDefinitionData& other) const { return usr == other.usr && short_name == other.short_name && @@ -206,8 +219,7 @@ struct IndexedTypeDef { bool HasInterestingState() const { return - def.definition_spelling || - def.definition_extent || + def.HasInterestingState() || !derived.empty() || !instantiations.empty() || !uses.empty(); @@ -250,6 +262,18 @@ struct FuncDefDefinitionData { // assert(usr.size() > 0); } + bool HasInterestingState() const { + return + !short_name.empty() || + !detailed_name.empty() || + definition_spelling || + definition_extent || + declaring_type || + base || + !locals.empty() || + !callees.empty(); + } + bool operator==( const FuncDefDefinitionData& other) const { @@ -314,8 +338,7 @@ struct IndexedFuncDef { bool HasInterestingState() const { return - def.definition_spelling || - def.definition_extent || + def.HasInterestingState() || !def.callees.empty() || !declarations.empty() || !derived.empty() || @@ -352,6 +375,16 @@ struct VarDefDefinitionData { VarDefDefinitionData() {} // For reflection. VarDefDefinitionData(const std::string& usr) : usr(usr) {} + bool HasInterestingState() const { + return + !short_name.empty() || + !detailed_name.empty() || + declaration || + definition_spelling || + definition_extent || + variable_type || + declaring_type; + } bool operator==(const VarDefDefinitionData& other) const { return usr == other.usr && short_name == other.short_name && @@ -403,8 +436,7 @@ struct IndexedVarDef { bool HasInterestingState() const { return - def.definition_spelling || - def.definition_extent || + def.HasInterestingState() || !uses.empty(); } diff --git a/src/query.cc b/src/query.cc index 6f6b7aba..9c732e7c 100644 --- a/src/query.cc +++ b/src/query.cc @@ -18,7 +18,6 @@ namespace { QueryType::DefUpdate ToQuery(const IdMap& id_map, const IndexedTypeDef::Def& type) { - assert(!type.short_name.empty()); QueryType::DefUpdate result(type.usr); result.short_name = type.short_name; result.detailed_name = type.detailed_name; @@ -33,7 +32,6 @@ QueryType::DefUpdate ToQuery(const IdMap& id_map, const IndexedTypeDef::Def& typ } QueryFunc::DefUpdate ToQuery(const IdMap& id_map, const IndexedFuncDef::Def& func) { - assert(!func.short_name.empty()); QueryFunc::DefUpdate result(func.usr); result.short_name = func.short_name; result.detailed_name = func.detailed_name; @@ -47,7 +45,6 @@ QueryFunc::DefUpdate ToQuery(const IdMap& id_map, const IndexedFuncDef::Def& fun } QueryVar::DefUpdate ToQuery(const IdMap& id_map, const IndexedVarDef::Def& var) { - assert(!var.short_name.empty()); QueryVar::DefUpdate result(var.usr); result.short_name = var.short_name; result.detailed_name = var.detailed_name; @@ -65,8 +62,8 @@ QueryVar::DefUpdate ToQuery(const IdMap& id_map, const IndexedVarDef::Def& var) // updates take longer but reduces import time on the querydb thread. template void AddMergeableRange( - std::vector>* dest, - const std::vector>& source) { + std::vector>* dest, + const std::vector>& source) { // TODO: Consider caching the lookup table. It can probably save even more // time at the cost of some additional memory. @@ -91,131 +88,6 @@ void AddMergeableRange( } } } - -} // namespace - - - - - - - - - - - - -QueryFile::Def BuildFileDef(const IdMap& id_map, const IndexedFile& indexed) { - QueryFile::Def def; - def.path = indexed.path; - - auto add_outline = [&def, &id_map](SymbolIdx idx, Range range) { - def.outline.push_back(SymbolRef(idx, id_map.ToQuery(range))); - }; - auto add_all_symbols = [&def, &id_map](SymbolIdx idx, Range range) { - def.all_symbols.push_back(SymbolRef(idx, id_map.ToQuery(range))); - }; - - for (const IndexedTypeDef& def : indexed.types) { - if (def.def.definition_spelling.has_value()) - add_all_symbols(id_map.ToSymbol(def.id), def.def.definition_spelling.value()); - if (def.def.definition_extent.has_value()) - add_outline(id_map.ToSymbol(def.id), def.def.definition_extent.value()); - for (const Range& use : def.uses) - 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(id_map.ToSymbol(def.id), def.def.definition_spelling.value()); - if (def.def.definition_extent.has_value()) - add_outline(id_map.ToSymbol(def.id), def.def.definition_extent.value()); - for (Range decl : def.declarations) { - add_all_symbols(id_map.ToSymbol(def.id), decl); - add_outline(id_map.ToSymbol(def.id), decl); - } - for (const IndexFuncRef& caller : def.callers) - add_all_symbols(id_map.ToSymbol(def.id), caller.loc); - } - for (const IndexedVarDef& def : indexed.vars) { - if (def.def.definition_spelling.has_value()) - add_all_symbols(id_map.ToSymbol(def.id), def.def.definition_spelling.value()); - if (def.def.definition_extent.has_value()) - add_outline(id_map.ToSymbol(def.id), def.def.definition_extent.value()); - for (const Range& use : def.uses) - add_all_symbols(id_map.ToSymbol(def.id), use); - } - - 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 SymbolRef& a, const SymbolRef& b) { - return a.loc.range.start < b.loc.range.start; - }); - - return def; -} - - - - - - - - - - - - - - -QueryFile* SymbolIdx::ResolveFile(QueryDatabase* db) const { - assert(kind == SymbolKind::File); - return &db->files[idx]; -} -QueryType* SymbolIdx::ResolveType(QueryDatabase* db) const { - assert(kind == SymbolKind::Type); - return &db->types[idx]; -} -QueryFunc* SymbolIdx::ResolveFunc(QueryDatabase* db) const { - assert(kind == SymbolKind::Func); - return &db->funcs[idx]; -} -QueryVar* SymbolIdx::ResolveVar(QueryDatabase* db) const { - assert(kind == SymbolKind::Var); - return &db->vars[idx]; -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Compares |previous| and |current|, adding all elements that are // in |previous| but not |current| to |removed|, and all elements @@ -288,6 +160,127 @@ void CompareGroups( ++curr_it; } } + +QueryFile::Def BuildFileDef(const IdMap& id_map, const IndexedFile& indexed) { + QueryFile::Def def; + def.path = indexed.path; + + auto add_outline = [&def, &id_map](SymbolIdx idx, Range range) { + def.outline.push_back(SymbolRef(idx, id_map.ToQuery(range))); + }; + auto add_all_symbols = [&def, &id_map](SymbolIdx idx, Range range) { + def.all_symbols.push_back(SymbolRef(idx, id_map.ToQuery(range))); + }; + + for (const IndexedTypeDef& def : indexed.types) { + if (def.def.definition_spelling.has_value()) + add_all_symbols(id_map.ToSymbol(def.id), def.def.definition_spelling.value()); + if (def.def.definition_extent.has_value()) + add_outline(id_map.ToSymbol(def.id), def.def.definition_extent.value()); + for (const Range& use : def.uses) + 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(id_map.ToSymbol(def.id), def.def.definition_spelling.value()); + if (def.def.definition_extent.has_value()) + add_outline(id_map.ToSymbol(def.id), def.def.definition_extent.value()); + for (Range decl : def.declarations) { + add_all_symbols(id_map.ToSymbol(def.id), decl); + add_outline(id_map.ToSymbol(def.id), decl); + } + for (const IndexFuncRef& caller : def.callers) + add_all_symbols(id_map.ToSymbol(def.id), caller.loc); + } + for (const IndexedVarDef& def : indexed.vars) { + if (def.def.definition_spelling.has_value()) + add_all_symbols(id_map.ToSymbol(def.id), def.def.definition_spelling.value()); + if (def.def.definition_extent.has_value()) + add_outline(id_map.ToSymbol(def.id), def.def.definition_extent.value()); + for (const Range& use : def.uses) + add_all_symbols(id_map.ToSymbol(def.id), use); + } + + 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 SymbolRef& a, const SymbolRef& b) { + return a.loc.range.start < b.loc.range.start; + }); + + return def; +} + +} // namespace + + + + + + + + + + + + + + + + + + + + + + + + + + + +QueryFile* SymbolIdx::ResolveFile(QueryDatabase* db) const { + assert(kind == SymbolKind::File); + return &db->files[idx]; +} +QueryType* SymbolIdx::ResolveType(QueryDatabase* db) const { + assert(kind == SymbolKind::Type); + return &db->types[idx]; +} +QueryFunc* SymbolIdx::ResolveFunc(QueryDatabase* db) const { + assert(kind == SymbolKind::Func); + return &db->funcs[idx]; +} +QueryVar* SymbolIdx::ResolveVar(QueryDatabase* db) const { + assert(kind == SymbolKind::Var); + return &db->vars[idx]; +} + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -296,7 +289,6 @@ void CompareGroups( // TODO: consider having separate lookup maps so they are smaller (maybe // lookups will go faster). -// TODO: Figure out where the invalid SymbolKinds are coming from. QueryFileId GetQueryFileIdFromPath(QueryDatabase* query_db, const std::string& path) { auto it = query_db->usr_to_symbol.find(path); if (it != query_db->usr_to_symbol.end() && it->second.kind != SymbolKind::Invalid) { @@ -470,8 +462,18 @@ SymbolIdx IdMap::ToSymbol(IndexVarId id) const { + + + + +// ---------------------- +// INDEX THREAD FUNCTIONS +// ---------------------- + // static IndexUpdate IndexUpdate::CreateDelta(const IdMap* previous_id_map, const IdMap* current_id_map, IndexedFile* previous, IndexedFile* current) { + // This function runs on an indexer thread. + if (!previous_id_map) { assert(!previous); IndexedFile previous(current->path); @@ -481,6 +483,8 @@ IndexUpdate IndexUpdate::CreateDelta(const IdMap* previous_id_map, const IdMap* } IndexUpdate::IndexUpdate(const IdMap& previous_id_map, const IdMap& current_id_map, IndexedFile& previous_file, IndexedFile& current_file) { + // This function runs on an indexer thread. + // |query_name| is the name of the variable on the query type. // |index_name| is the name of the variable on the index type. // |type| is the type of the variable. @@ -507,7 +511,7 @@ IndexUpdate::IndexUpdate(const IdMap& previous_id_map, const IdMap& current_id_m types_removed.push_back(def->def.usr); }, /*onAdded:*/[this, ¤t_id_map](IndexedTypeDef* type) { - if (!type->def.short_name.empty()) + if (!type->def.detailed_name.empty()) types_def_update.push_back(ToQuery(current_id_map, type->def)); if (!type->derived.empty()) types_derived.push_back(QueryType::DerivedUpdate(current_id_map.ToQuery(type->id), current_id_map.ToQuery(type->derived))); @@ -533,7 +537,7 @@ IndexUpdate::IndexUpdate(const IdMap& previous_id_map, const IdMap& current_id_m funcs_removed.push_back(def->def.usr); }, /*onAdded:*/[this, ¤t_id_map](IndexedFuncDef* func) { - if (!func->def.short_name.empty()) + if (!func->def.detailed_name.empty()) funcs_def_update.push_back(ToQuery(current_id_map, func->def)); if (!func->declarations.empty()) funcs_declarations.push_back(QueryFunc::DeclarationsUpdate(current_id_map.ToQuery(func->id), current_id_map.ToQuery(func->declarations))); @@ -559,7 +563,7 @@ IndexUpdate::IndexUpdate(const IdMap& previous_id_map, const IdMap& current_id_m vars_removed.push_back(def->def.usr); }, /*onAdded:*/[this, ¤t_id_map](IndexedVarDef* var) { - if (!var->def.short_name.empty()) + if (!var->def.detailed_name.empty()) vars_def_update.push_back(ToQuery(current_id_map, var->def)); if (!var->uses.empty()) vars_uses.push_back(QueryVar::UsesUpdate(current_id_map.ToQuery(var->id), current_id_map.ToQuery(var->uses))); @@ -577,6 +581,8 @@ IndexUpdate::IndexUpdate(const IdMap& previous_id_map, const IdMap& current_id_m } void IndexUpdate::Merge(const IndexUpdate& update) { + // This function runs on an indexer thread. + #define INDEX_UPDATE_APPEND(name) \ AddRange(&name, update.name); #define INDEX_UPDATE_MERGE(name) \ @@ -623,92 +629,38 @@ void IndexUpdate::Merge(const IndexUpdate& update) { -void SetDetailedNameForWorkspaceSearch(QueryDatabase* db, size_t* qualified_name_index, SymbolKind kind, size_t symbol_index, const std::string& name) { - if (*qualified_name_index == -1) { - db->detailed_names.push_back(name); - db->symbols.push_back(SymbolIdx(kind, symbol_index)); - *qualified_name_index = db->detailed_names.size() - 1; - } - else { - db->detailed_names[*qualified_name_index] = name; - } -} + + + + + + + +// ------------------------ +// QUERYDB THREAD FUNCTIONS +// ------------------------ void QueryDatabase::RemoveUsrs(const std::vector& to_remove) { - // TODO: Removing usrs is tricky because it means we will have to rebuild idx locations. I'm thinking we just nullify - // the entry instead of actually removing the data. The index could be massive. + // This function runs on the querydb thread. + + // Actually removing data is extremely slow because every offset/index would + // have to be updated. Instead, we just accept the memory overhead and mark + // the symbol as invalid. + // + // If the user wants to reduce memory usage, they will have to restart the + // indexer and load it from cache. Luckily, this doesn't take too long even + // on large projects (1-2 minutes). + for (Usr usr : to_remove) usr_to_symbol[usr].kind = SymbolKind::Invalid; - // TODO: also remove from qualified_names? -} - -void QueryDatabase::ImportOrUpdate(const std::vector& updates) { - for (auto& def : updates) { - auto it = usr_to_symbol.find(def.path); - assert(it != usr_to_symbol.end()); - - QueryFile& existing = files[it->second.idx]; - existing.def = def; - //SetQualifiedNameForWorkspaceSearch(this, &existing.qualified_name_idx, SymbolKind::File, it->second.idx, def.qualified_name); - } -} - -void QueryDatabase::ImportOrUpdate(const std::vector& updates) { - for (auto& def : updates) { - if (def.detailed_name.empty()) - continue; - - auto it = usr_to_symbol.find(def.usr); - assert(it != usr_to_symbol.end()); - - QueryType& existing = types[it->second.idx]; - if (existing.def.definition_spelling && !def.definition_spelling) - continue; - - existing.def = def; - SetDetailedNameForWorkspaceSearch(this, &existing.detailed_name_idx, SymbolKind::Type, it->second.idx, def.detailed_name); - } -} - -void QueryDatabase::ImportOrUpdate(const std::vector& updates) { - for (auto& def : updates) { - if (def.detailed_name.empty()) - continue; - - auto it = usr_to_symbol.find(def.usr); - assert(it != usr_to_symbol.end()); - - QueryFunc& existing = funcs[it->second.idx]; - if (existing.def.definition_spelling && !def.definition_spelling) - continue; - - existing.def = def; - SetDetailedNameForWorkspaceSearch(this, &existing.detailed_name_idx, SymbolKind::Func, it->second.idx, def.detailed_name); - } -} - -void QueryDatabase::ImportOrUpdate(const std::vector& updates) { - for (auto& def : updates) { - if (def.detailed_name.empty()) - continue; - - auto it = usr_to_symbol.find(def.usr); - assert(it != usr_to_symbol.end()); - - QueryVar& existing = vars[it->second.idx]; - if (existing.def.definition_spelling && !def.definition_spelling) - continue; - - existing.def = def; - if (def.declaring_type) - SetDetailedNameForWorkspaceSearch(this, &existing.detailed_name_idx, SymbolKind::Var, it->second.idx, def.detailed_name); - } } void QueryDatabase::ApplyIndexUpdate(IndexUpdate* update) { + // This function runs on the querydb thread. + #define HANDLE_MERGEABLE(update_var_name, def_var_name, storage_name) \ for (auto merge_update : update->update_var_name) { \ auto* def = &storage_name[merge_update.id.id]; \ @@ -737,6 +689,90 @@ void QueryDatabase::ApplyIndexUpdate(IndexUpdate* update) { #undef HANDLE_MERGEABLE } +void QueryDatabase::ImportOrUpdate(const std::vector& updates) { + // This function runs on the querydb thread. + + for (auto& def : updates) { + auto it = usr_to_symbol.find(def.path); + assert(it != usr_to_symbol.end()); + + QueryFile& existing = files[it->second.idx]; + existing.def = def; + UpdateDetailedNames(&existing.detailed_name_idx, SymbolKind::File, it->second.idx, def.path); + } +} + +void QueryDatabase::ImportOrUpdate(const std::vector& updates) { + // This function runs on the querydb thread. + + for (auto& def : updates) { + assert(!def.detailed_name.empty()); + + auto it = usr_to_symbol.find(def.usr); + assert(it != usr_to_symbol.end()); + + QueryType& existing = types[it->second.idx]; + + // Keep the existing definition if it is higher quality. + if (existing.def.definition_spelling && !def.definition_spelling) + continue; + + existing.def = def; + UpdateDetailedNames(&existing.detailed_name_idx, SymbolKind::Type, it->second.idx, def.detailed_name); + } +} + +void QueryDatabase::ImportOrUpdate(const std::vector& updates) { + // This function runs on the querydb thread. + + for (auto& def : updates) { + assert(!def.detailed_name.empty()); + + auto it = usr_to_symbol.find(def.usr); + assert(it != usr_to_symbol.end()); + + QueryFunc& existing = funcs[it->second.idx]; + + // Keep the existing definition if it is higher quality. + if (existing.def.definition_spelling && !def.definition_spelling) + continue; + + existing.def = def; + UpdateDetailedNames(&existing.detailed_name_idx, SymbolKind::Func, it->second.idx, def.detailed_name); + } +} + +void QueryDatabase::ImportOrUpdate(const std::vector& updates) { + // This function runs on the querydb thread. + + for (auto& def : updates) { + assert(!def.detailed_name.empty()); + + auto it = usr_to_symbol.find(def.usr); + assert(it != usr_to_symbol.end()); + + QueryVar& existing = vars[it->second.idx]; + + // Keep the existing definition if it is higher quality. + if (existing.def.definition_spelling && !def.definition_spelling) + continue; + + existing.def = def; + if (def.declaring_type) + UpdateDetailedNames(&existing.detailed_name_idx, SymbolKind::Var, it->second.idx, def.detailed_name); + } +} + +void QueryDatabase::UpdateDetailedNames(size_t* qualified_name_index, SymbolKind kind, size_t symbol_index, const std::string& name) { + if (*qualified_name_index == -1) { + detailed_names.push_back(name); + symbols.push_back(SymbolIdx(kind, symbol_index)); + *qualified_name_index = detailed_names.size() - 1; + } + else { + detailed_names[*qualified_name_index] = name; + } +} @@ -744,12 +780,4 @@ void QueryDatabase::ApplyIndexUpdate(IndexUpdate* update) { - -// TODO: Idea: when indexing and joining to the main db, allow many dbs that -// are joined to. So that way even if the main db is busy we can -// still be joining. Joining the partially joined db to the main -// db should be faster since we will have larger data lanes to use. -// TODO: allow user to store configuration as json? file in home dir; also -// allow local overrides (scan up dirs) -// TODO: add opt to dump config when starting (--dump-config) // TODO: allow user to decide some indexer choices, ie, do we mark prototype parameters as usages? diff --git a/src/query.h b/src/query.h index 23e3e618..42589918 100644 --- a/src/query.h +++ b/src/query.h @@ -265,14 +265,15 @@ struct QueryDatabase { } //std::unordered_map usr_to_symbol; + // Marks the given Usrs as invalid. + void RemoveUsrs(const std::vector& to_remove); // Insert the contents of |update| into |db|. void ApplyIndexUpdate(IndexUpdate* update); - - void RemoveUsrs(const std::vector& to_remove); void ImportOrUpdate(const std::vector& updates); void ImportOrUpdate(const std::vector& updates); void ImportOrUpdate(const std::vector& updates); void ImportOrUpdate(const std::vector& updates); + void UpdateDetailedNames(size_t* qualified_name_index, SymbolKind kind, size_t symbol_index, const std::string& name); }; diff --git a/src/test.cc b/src/test.cc index a2f9eaa6..6a4e8dc4 100644 --- a/src/test.cc +++ b/src/test.cc @@ -118,7 +118,7 @@ void RunTests() { for (std::string path : GetFilesInFolder("tests", true /*recursive*/, true /*add_folder_to_path*/)) { //if (path != "tests/templates/specialized_func_definition.cc") continue; //if (path != "tests/templates/namespace_template_class_template_func_usage_folded_into_one.cc") continue; - //if (path != "tests/multi_file/header.h") continue; + //if (path != "tests/multi_file/funky_enum.cc") continue; //if (path != "tests/multi_file/simple_impl.cc") continue; //if (path != "tests/usage/func_called_implicit_ctor.cc") continue; //if (path != "tests/templates/implicit_variable_instantiation.cc") continue; diff --git a/tests/multi_file/funky_enum.cc b/tests/multi_file/funky_enum.cc new file mode 100644 index 00000000..e10c8318 --- /dev/null +++ b/tests/multi_file/funky_enum.cc @@ -0,0 +1,62 @@ +enum Foo { +#include "funky_enum.h" +}; + +/* +// TODO: In the future try to have better support for types defined across +// multiple files. + +OUTPUT: funky_enum.h +{ + "types": [{ + "id": 0, + "usr": "c:@E@Foo", + "vars": [0, 1, 2] + }], + "vars": [{ + "id": 0, + "usr": "c:@E@Foo@A", + "short_name": "A", + "detailed_name": "Foo Foo::A", + "definition_spelling": "4:1-4:2", + "definition_extent": "4:1-4:2", + "variable_type": 0, + "declaring_type": 0, + "uses": ["4:1-4:2"] + }, { + "id": 1, + "usr": "c:@E@Foo@B", + "short_name": "B", + "detailed_name": "Foo Foo::B", + "definition_spelling": "5:1-5:2", + "definition_extent": "5:1-5:2", + "variable_type": 0, + "declaring_type": 0, + "uses": ["5:1-5:2"] + }, { + "id": 2, + "usr": "c:@E@Foo@C", + "short_name": "C", + "detailed_name": "Foo Foo::C", + "definition_spelling": "6:1-6:2", + "definition_extent": "6:1-6:2", + "variable_type": 0, + "declaring_type": 0, + "uses": ["6:1-6:2"] + }] +} + +OUTPUT: funky_enum.cc +{ + "dependencies": ["C:/Users/jacob/Desktop/superindex/indexer/tests/multi_file/funky_enum.h"], + "types": [{ + "id": 0, + "usr": "c:@E@Foo", + "short_name": "Foo", + "detailed_name": "Foo", + "definition_spelling": "1:6-1:9", + "definition_extent": "1:1-3:2", + "uses": ["1:6-1:9"] + }] +} +*/ \ No newline at end of file diff --git a/tests/multi_file/funky_enum.h b/tests/multi_file/funky_enum.h new file mode 100644 index 00000000..b11cc441 --- /dev/null +++ b/tests/multi_file/funky_enum.h @@ -0,0 +1,6 @@ +// This file cannot be built directory. It is included in an enum definition of +// another file. + +A, +B, +C \ No newline at end of file