diff --git a/src/import_pipeline.cc b/src/import_pipeline.cc index ff1f549f..2c6c2091 100644 --- a/src/import_pipeline.cc +++ b/src/import_pipeline.cc @@ -634,8 +634,8 @@ bool QueryDb_ImportMain(Config* config, // it, load the previous state from disk and rerun IdMap logic later. Do not // do this if we have already attempted in the past. if (!request->load_previous && !request->previous && - db->usr_to_file.find(LowerPathIfCaseInsensitive( - request->current->path)) != db->usr_to_file.end()) { + db->usr_to_file.find(NormalizedPath(request->current->path)) != + db->usr_to_file.end()) { assert(!request->load_previous); request->load_previous = true; queue->load_previous_index.Enqueue(std::move(*request)); @@ -719,7 +719,7 @@ bool QueryDb_ImportMain(Config* config, working_files->GetFileByFilename(updated_file.path); if (working_file) { QueryFileId file_id = - db->usr_to_file[LowerPathIfCaseInsensitive(working_file->filename)]; + db->usr_to_file[NormalizedPath(working_file->filename)]; QueryFile* file = &db->files[file_id.id]; EmitSemanticHighlighting(db, semantic_cache, working_file, file); } diff --git a/src/message_handler.cc b/src/message_handler.cc index 17c26ed9..f93ddd4d 100644 --- a/src/message_handler.cc +++ b/src/message_handler.cc @@ -42,7 +42,7 @@ bool FindFileOrFail(QueryDatabase* db, QueryFileId* out_file_id) { *out_query_file = nullptr; - auto it = db->usr_to_file.find(LowerPathIfCaseInsensitive(absolute_path)); + auto it = db->usr_to_file.find(NormalizedPath(absolute_path)); if (it != db->usr_to_file.end()) { QueryFile& file = db->files[it->second.id]; if (file.def) { diff --git a/src/messages/text_document_code_action.cc b/src/messages/text_document_code_action.cc index 69b65b1f..32333552 100644 --- a/src/messages/text_document_code_action.cc +++ b/src/messages/text_document_code_action.cc @@ -95,8 +95,8 @@ optional GetImplementationFile(QueryDatabase* db, // No associated definition, scan the project for a file in the same // directory with the same base-name. - std::string original_path = LowerPathIfCaseInsensitive(file->def->path); - std::string target_path = original_path; + NormalizedPath original_path(file->def->path); + std::string target_path = original_path.path; size_t last = target_path.find_last_of('.'); if (last != std::string::npos) { target_path = target_path.substr(0, last); @@ -105,14 +105,14 @@ optional GetImplementationFile(QueryDatabase* db, LOG_S(INFO) << "!! Looking for impl file that starts with " << target_path; for (auto& entry : db->usr_to_file) { - const std::string& path = entry.first; + const NormalizedPath& path = entry.first; // Do not consider header files for implementation files. // TODO: make file extensions configurable. - if (EndsWith(path, ".h") || EndsWith(path, ".hpp")) + if (EndsWith(path.path, ".h") || EndsWith(path.path, ".hpp")) continue; - if (StartsWith(path, target_path) && path != original_path) { + if (StartsWith(path.path, target_path) && path != original_path) { return entry.second; } } diff --git a/src/query.cc b/src/query.cc index b20a3adf..8893b74b 100644 --- a/src/query.cc +++ b/src/query.cc @@ -294,14 +294,15 @@ QueryFile::Def BuildFileDef(const IdMap& id_map, const IndexFile& indexed) { inline optional GetQueryFileIdFromPath(QueryDatabase* query_db, const std::string& path, bool create_if_missing) { - auto it = query_db->usr_to_file.find(LowerPathIfCaseInsensitive(path)); + NormalizedPath normalized_path(path); + auto it = query_db->usr_to_file.find(normalized_path); if (it != query_db->usr_to_file.end()) return QueryFileId(it->second.id); if (!create_if_missing) return {}; size_t idx = query_db->files.size(); - query_db->usr_to_file[LowerPathIfCaseInsensitive(path)] = QueryFileId(idx); + query_db->usr_to_file[normalized_path] = QueryFileId(idx); query_db->files.push_back(QueryFile(path)); return QueryFileId(idx); } @@ -752,6 +753,17 @@ std::string IndexUpdate::ToString() { return output.GetString(); } +NormalizedPath::NormalizedPath(const std::string& path) + : path(LowerPathIfCaseInsensitive(path)) {} + +bool NormalizedPath::operator==(const NormalizedPath& rhs) const { + return path == rhs.path; +} + +bool NormalizedPath::operator!=(const NormalizedPath& rhs) const { + return path != rhs.path; +} + // ------------------------ // QUERYDB THREAD FUNCTIONS // ------------------------ @@ -810,7 +822,7 @@ void QueryDatabase::ApplyIndexUpdate(IndexUpdate* update) { } for (const std::string& filename : update->files_removed) - files[usr_to_file[filename].id].def = nullopt; + files[usr_to_file[NormalizedPath(filename)].id].def = nullopt; ImportOrUpdate(update->files_def_update); RemoveUsrs(SymbolKind::Type, update->types_removed); @@ -838,7 +850,7 @@ void QueryDatabase::ImportOrUpdate( // This function runs on the querydb thread. for (auto& def : updates) { - auto it = usr_to_file.find(LowerPathIfCaseInsensitive(def.path)); + auto it = usr_to_file.find(NormalizedPath(def.path)); assert(it != usr_to_file.end()); QueryFile& existing = files[it->second.id]; diff --git a/src/query.h b/src/query.h index 6c29892a..ea92733a 100644 --- a/src/query.h +++ b/src/query.h @@ -334,6 +334,15 @@ MAKE_REFLECT_STRUCT(IndexUpdate, vars_declarations, vars_uses); +struct NormalizedPath { + explicit NormalizedPath(const std::string& path); + bool operator==(const NormalizedPath& rhs) const; + bool operator!=(const NormalizedPath& rhs) const; + + std::string path; +}; +MAKE_HASHABLE(NormalizedPath, t.path); + // The query database is heavily optimized for fast queries. It is stored // in-memory. struct QueryDatabase { @@ -350,9 +359,7 @@ struct QueryDatabase { std::vector vars; // Lookup symbol based on a usr. - // NOTE: For usr_to_file make sure to call LowerPathIfCaseInsensitive on key. - // TODO: add type wrapper to enforce we call it - spp::sparse_hash_map usr_to_file; + spp::sparse_hash_map usr_to_file; spp::sparse_hash_map usr_to_type; spp::sparse_hash_map usr_to_func; spp::sparse_hash_map usr_to_var;