mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-25 17:11:59 +00:00
Try to have better behavior when types are defined across multiple files.
This commit is contained in:
parent
eb83ba26e1
commit
cbe308c0f9
19
foo/b.cc
19
foo/b.cc
@ -1,17 +1,4 @@
|
||||
struct Parent {
|
||||
virtual void Method() = 0;
|
||||
|
||||
enum Foo {
|
||||
#include "a.h"
|
||||
};
|
||||
struct Derived : public Parent {
|
||||
void Method() override {}
|
||||
};
|
||||
|
||||
|
||||
void Caller() {
|
||||
Derived d;
|
||||
Parent* p = &d;
|
||||
|
||||
p->Method();
|
||||
d->Method();
|
||||
}
|
||||
|
||||
|
||||
|
@ -563,7 +563,7 @@ optional<lsLocation> 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<lsSymbolInformation> 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<lsSymbolInformation> info = GetSymbolInfo(db, working_files, ref.idx);
|
||||
if (!info)
|
||||
continue;
|
||||
|
||||
optional<lsLocation> 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<lsSymbolInformation> info = GetSymbolInfo(db, working_files, db->symbols[i]);
|
||||
if (!info)
|
||||
continue;
|
||||
|
||||
optional<QueryLocation> location = GetDefinitionExtentOfSymbol(db, db->symbols[i]);
|
||||
if (!location) {
|
||||
auto decls = GetDeclarationsOfSymbolForGotoDefinition(db, db->symbols[i]);
|
||||
@ -1532,8 +1537,8 @@ void QueryDbMainLoop(
|
||||
optional<lsLocation> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<TypeId, FuncId, VarId, Range>&
|
||||
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<TypeId, FuncId, VarId, FuncRef, Range>&
|
||||
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<TypeId, FuncId, VarId, Range>&
|
||||
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();
|
||||
}
|
||||
|
||||
|
460
src/query.cc
460
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;
|
||||
@ -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<Usr>& 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<QueryFile::DefUpdate>& 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<QueryType::DefUpdate>& 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<QueryFunc::DefUpdate>& 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<QueryVar::DefUpdate>& 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<QueryFile::DefUpdate>& 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<QueryType::DefUpdate>& 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<QueryFunc::DefUpdate>& 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<QueryVar::DefUpdate>& 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?
|
||||
|
@ -265,14 +265,15 @@ struct QueryDatabase {
|
||||
}
|
||||
//std::unordered_map<Usr, SymbolIdx> usr_to_symbol;
|
||||
|
||||
// Marks the given Usrs as invalid.
|
||||
void RemoveUsrs(const std::vector<Usr>& to_remove);
|
||||
// Insert the contents of |update| into |db|.
|
||||
void ApplyIndexUpdate(IndexUpdate* update);
|
||||
|
||||
void RemoveUsrs(const std::vector<Usr>& to_remove);
|
||||
void ImportOrUpdate(const std::vector<QueryFile::DefUpdate>& updates);
|
||||
void ImportOrUpdate(const std::vector<QueryType::DefUpdate>& updates);
|
||||
void ImportOrUpdate(const std::vector<QueryFunc::DefUpdate>& updates);
|
||||
void ImportOrUpdate(const std::vector<QueryVar::DefUpdate>& updates);
|
||||
void UpdateDetailedNames(size_t* qualified_name_index, SymbolKind kind, size_t symbol_index, const std::string& name);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
62
tests/multi_file/funky_enum.cc
Normal file
62
tests/multi_file/funky_enum.cc
Normal file
@ -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"]
|
||||
}]
|
||||
}
|
||||
*/
|
6
tests/multi_file/funky_enum.h
Normal file
6
tests/multi_file/funky_enum.h
Normal file
@ -0,0 +1,6 @@
|
||||
// This file cannot be built directory. It is included in an enum definition of
|
||||
// another file.
|
||||
|
||||
A,
|
||||
B,
|
||||
C
|
Loading…
Reference in New Issue
Block a user