mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-10-31 04:32:33 +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