2017-02-23 09:23:23 +00:00
|
|
|
#include "query.h"
|
|
|
|
|
2017-03-25 20:32:44 +00:00
|
|
|
#include "indexer.h"
|
2018-02-12 01:15:56 +00:00
|
|
|
#include "serializer.h"
|
2018-01-06 21:46:41 +00:00
|
|
|
#include "serializers/json.h"
|
2017-03-25 20:32:44 +00:00
|
|
|
|
2017-05-15 03:51:53 +00:00
|
|
|
#include <doctest/doctest.h>
|
2018-03-31 03:16:33 +00:00
|
|
|
#include <optional>
|
2017-07-30 04:24:02 +00:00
|
|
|
#include <loguru.hpp>
|
2017-03-25 20:32:44 +00:00
|
|
|
|
2017-04-19 00:05:14 +00:00
|
|
|
#include <cassert>
|
2017-02-20 19:08:27 +00:00
|
|
|
#include <cstdint>
|
2017-02-25 23:59:09 +00:00
|
|
|
#include <functional>
|
2018-04-08 06:32:35 +00:00
|
|
|
#include <iterator>
|
2017-09-22 01:14:57 +00:00
|
|
|
#include <string>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <unordered_set>
|
2017-02-21 09:08:52 +00:00
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
// TODO: Make all copy constructors explicit.
|
2017-02-26 19:45:59 +00:00
|
|
|
|
2018-04-08 06:32:35 +00:00
|
|
|
// Used by |HANDLE_MERGEABLE| so only |range| is needed.
|
|
|
|
MAKE_HASHABLE(Range, t.start, t.end);
|
|
|
|
MAKE_HASHABLE(Use, t.range);
|
|
|
|
|
2018-04-09 07:52:04 +00:00
|
|
|
template <typename TVisitor, typename TId, typename TValue>
|
|
|
|
void Reflect(TVisitor& visitor, MergeableUpdate<TId, TValue>& value) {
|
|
|
|
REFLECT_MEMBER_START();
|
|
|
|
REFLECT_MEMBER(id);
|
|
|
|
REFLECT_MEMBER(to_add);
|
|
|
|
REFLECT_MEMBER(to_remove);
|
|
|
|
REFLECT_MEMBER_END();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename TVisitor, typename T>
|
|
|
|
void Reflect(TVisitor& visitor, WithUsr<T>& value) {
|
|
|
|
REFLECT_MEMBER_START();
|
|
|
|
REFLECT_MEMBER(usr);
|
|
|
|
REFLECT_MEMBER(value);
|
|
|
|
REFLECT_MEMBER_END();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename TVisitor, typename T>
|
|
|
|
void Reflect(TVisitor& visitor, WithFileContent<T>& value) {
|
|
|
|
REFLECT_MEMBER_START();
|
|
|
|
REFLECT_MEMBER(value);
|
|
|
|
REFLECT_MEMBER(file_content);
|
|
|
|
REFLECT_MEMBER_END();
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTICE: We're not reflecting on files_removed or files_def_update, it is too
|
|
|
|
// much output when logging
|
|
|
|
MAKE_REFLECT_STRUCT(IndexUpdate,
|
|
|
|
types_removed,
|
|
|
|
types_def_update,
|
|
|
|
types_derived,
|
|
|
|
types_instances,
|
|
|
|
types_uses,
|
|
|
|
funcs_removed,
|
|
|
|
funcs_def_update,
|
|
|
|
funcs_declarations,
|
|
|
|
funcs_derived,
|
|
|
|
funcs_uses,
|
|
|
|
vars_removed,
|
|
|
|
vars_def_update,
|
|
|
|
vars_declarations,
|
|
|
|
vars_uses);
|
|
|
|
|
2017-04-08 08:17:29 +00:00
|
|
|
namespace {
|
2017-04-07 06:57:26 +00:00
|
|
|
|
2018-04-08 06:32:35 +00:00
|
|
|
template <typename T>
|
|
|
|
void AddRange(std::vector<T>* dest, const std::vector<T>& to_add) {
|
|
|
|
dest->insert(dest->end(), to_add.begin(), to_add.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void AddRange(std::vector<T>* dest, std::vector<T>&& to_add) {
|
|
|
|
dest->insert(dest->end(), std::make_move_iterator(to_add.begin()),
|
|
|
|
std::make_move_iterator(to_add.end()));
|
|
|
|
}
|
|
|
|
|
2018-02-24 02:24:54 +00:00
|
|
|
template <typename T>
|
|
|
|
void RemoveRange(std::vector<T>* dest, const std::vector<T>& to_remove) {
|
|
|
|
std::unordered_set<T> to_remove_set(to_remove.begin(), to_remove.end());
|
|
|
|
dest->erase(
|
|
|
|
std::remove_if(dest->begin(), dest->end(),
|
|
|
|
[&](const T& t) { return to_remove_set.count(t) > 0; }),
|
|
|
|
dest->end());
|
|
|
|
}
|
|
|
|
|
2018-03-31 03:16:33 +00:00
|
|
|
std::optional<QueryType::Def> ToQuery(const IdMap& id_map,
|
2017-12-12 07:56:50 +00:00
|
|
|
const IndexType::Def& type) {
|
2017-05-22 06:09:09 +00:00
|
|
|
if (type.detailed_name.empty())
|
2018-03-31 03:16:33 +00:00
|
|
|
return std::nullopt;
|
2017-05-22 06:09:09 +00:00
|
|
|
|
2017-12-12 07:56:50 +00:00
|
|
|
QueryType::Def result;
|
2017-04-15 04:58:07 +00:00
|
|
|
result.detailed_name = type.detailed_name;
|
2018-04-06 00:00:07 +00:00
|
|
|
result.qual_name_offset = type.qual_name_offset;
|
2018-01-31 07:01:45 +00:00
|
|
|
result.short_name_offset = type.short_name_offset;
|
|
|
|
result.short_name_size = type.short_name_size;
|
2018-01-15 23:51:20 +00:00
|
|
|
result.kind = type.kind;
|
2018-02-11 17:12:22 +00:00
|
|
|
if (!type.hover.empty())
|
|
|
|
result.hover = type.hover;
|
|
|
|
if (!type.comments.empty())
|
|
|
|
result.comments = type.comments;
|
2018-02-08 08:06:04 +00:00
|
|
|
result.file = id_map.primary_file;
|
2018-02-11 04:01:10 +00:00
|
|
|
result.spell = id_map.ToQuery(type.spell);
|
|
|
|
result.extent = id_map.ToQuery(type.extent);
|
2018-02-05 18:12:28 +00:00
|
|
|
result.alias_of = id_map.ToQuery(type.alias_of);
|
2018-02-26 02:45:46 +00:00
|
|
|
result.bases = id_map.ToQuery(type.bases);
|
2018-02-05 18:12:28 +00:00
|
|
|
result.types = id_map.ToQuery(type.types);
|
|
|
|
result.funcs = id_map.ToQuery(type.funcs);
|
|
|
|
result.vars = id_map.ToQuery(type.vars);
|
2017-02-26 19:45:59 +00:00
|
|
|
return result;
|
|
|
|
}
|
2017-04-08 08:17:29 +00:00
|
|
|
|
2018-03-31 03:16:33 +00:00
|
|
|
std::optional<QueryFunc::Def> ToQuery(const IdMap& id_map,
|
2017-12-12 07:56:50 +00:00
|
|
|
const IndexFunc::Def& func) {
|
2017-05-22 06:09:09 +00:00
|
|
|
if (func.detailed_name.empty())
|
2018-03-31 03:16:33 +00:00
|
|
|
return std::nullopt;
|
2017-05-22 06:09:09 +00:00
|
|
|
|
2017-12-12 07:56:50 +00:00
|
|
|
QueryFunc::Def result;
|
2017-04-15 04:58:07 +00:00
|
|
|
result.detailed_name = func.detailed_name;
|
2018-04-06 00:00:07 +00:00
|
|
|
result.qual_name_offset = func.qual_name_offset;
|
2018-01-31 06:39:39 +00:00
|
|
|
result.short_name_offset = func.short_name_offset;
|
|
|
|
result.short_name_size = func.short_name_size;
|
2018-01-15 23:51:20 +00:00
|
|
|
result.kind = func.kind;
|
2018-01-26 17:28:29 +00:00
|
|
|
result.storage = func.storage;
|
2018-02-11 17:12:22 +00:00
|
|
|
if (!func.hover.empty())
|
|
|
|
result.hover = func.hover;
|
|
|
|
if (!func.comments.empty())
|
|
|
|
result.comments = func.comments;
|
2018-02-08 08:06:04 +00:00
|
|
|
result.file = id_map.primary_file;
|
2018-02-11 04:30:27 +00:00
|
|
|
result.spell = id_map.ToQuery(func.spell);
|
|
|
|
result.extent = id_map.ToQuery(func.extent);
|
2018-02-05 18:12:28 +00:00
|
|
|
result.declaring_type = id_map.ToQuery(func.declaring_type);
|
2018-02-26 02:45:46 +00:00
|
|
|
result.bases = id_map.ToQuery(func.bases);
|
2018-02-27 01:23:45 +00:00
|
|
|
result.vars = id_map.ToQuery(func.vars);
|
2017-04-14 02:17:15 +00:00
|
|
|
result.callees = id_map.ToQuery(func.callees);
|
2017-02-26 19:45:59 +00:00
|
|
|
return result;
|
|
|
|
}
|
2017-04-08 08:17:29 +00:00
|
|
|
|
2018-03-31 03:16:33 +00:00
|
|
|
std::optional<QueryVar::Def> ToQuery(const IdMap& id_map, const IndexVar::Def& var) {
|
2017-05-22 06:09:09 +00:00
|
|
|
if (var.detailed_name.empty())
|
2018-03-31 03:16:33 +00:00
|
|
|
return std::nullopt;
|
2017-05-22 06:09:09 +00:00
|
|
|
|
2017-12-12 07:56:50 +00:00
|
|
|
QueryVar::Def result;
|
2017-04-15 04:58:07 +00:00
|
|
|
result.detailed_name = var.detailed_name;
|
2018-04-06 00:00:07 +00:00
|
|
|
result.qual_name_offset = var.qual_name_offset;
|
2018-01-31 04:59:31 +00:00
|
|
|
result.short_name_offset = var.short_name_offset;
|
|
|
|
result.short_name_size = var.short_name_size;
|
2018-02-11 17:12:22 +00:00
|
|
|
if (!var.hover.empty())
|
|
|
|
result.hover = var.hover;
|
|
|
|
if (!var.comments.empty())
|
|
|
|
result.comments = var.comments;
|
2018-02-08 08:06:04 +00:00
|
|
|
result.file = id_map.primary_file;
|
2018-02-11 17:12:22 +00:00
|
|
|
result.spell = id_map.ToQuery(var.spell);
|
|
|
|
result.extent = id_map.ToQuery(var.extent);
|
2018-02-11 18:25:37 +00:00
|
|
|
result.type = id_map.ToQuery(var.type);
|
2018-01-28 04:25:14 +00:00
|
|
|
result.kind = var.kind;
|
|
|
|
result.storage = var.storage;
|
2017-02-26 19:45:59 +00:00
|
|
|
return result;
|
2017-02-26 08:11:47 +00:00
|
|
|
}
|
2017-02-25 23:59:09 +00:00
|
|
|
|
2017-04-16 08:31:28 +00:00
|
|
|
// Adds the mergeable updates in |source| to |dest|. If a mergeable update for
|
|
|
|
// the destination type already exists, it will be combined. This makes merging
|
|
|
|
// updates take longer but reduces import time on the querydb thread.
|
|
|
|
template <typename TId, typename TValue>
|
2018-02-22 07:34:32 +00:00
|
|
|
void AddMergeableRange(std::vector<MergeableUpdate<TId, TValue>>* dest,
|
|
|
|
std::vector<MergeableUpdate<TId, TValue>>&& source) {
|
2017-04-16 08:31:28 +00:00
|
|
|
// TODO: Consider caching the lookup table. It can probably save even more
|
|
|
|
// time at the cost of some additional memory.
|
|
|
|
|
|
|
|
// Build lookup table.
|
2017-04-19 05:45:37 +00:00
|
|
|
spp::sparse_hash_map<TId, size_t> id_to_index;
|
2017-04-16 08:31:28 +00:00
|
|
|
id_to_index.resize(dest->size());
|
|
|
|
for (size_t i = 0; i < dest->size(); ++i)
|
|
|
|
id_to_index[(*dest)[i].id] = i;
|
|
|
|
|
|
|
|
// Add entries. Try to add them to an existing entry.
|
2018-02-07 05:45:58 +00:00
|
|
|
for (auto& entry : source) {
|
2017-04-16 08:31:28 +00:00
|
|
|
auto it = id_to_index.find(entry.id);
|
|
|
|
if (it != id_to_index.end()) {
|
2018-02-07 05:45:58 +00:00
|
|
|
AddRange(&(*dest)[it->second].to_add, std::move(entry.to_add));
|
|
|
|
AddRange(&(*dest)[it->second].to_remove, std::move(entry.to_remove));
|
2017-09-22 01:14:57 +00:00
|
|
|
} else {
|
2018-02-07 05:45:58 +00:00
|
|
|
dest->push_back(std::move(entry));
|
2017-04-16 08:31:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-11 21:42:48 +00:00
|
|
|
// Compares |previous| and |current|, adding all elements that are in |previous|
|
|
|
|
// but not |current| to |removed|, and all elements that are in |current| but
|
|
|
|
// not |previous| to |added|.
|
2017-04-19 06:56:37 +00:00
|
|
|
//
|
|
|
|
// Returns true iff |removed| or |added| are non-empty.
|
2017-09-22 01:14:57 +00:00
|
|
|
template <typename T>
|
2018-02-07 06:46:05 +00:00
|
|
|
bool ComputeDifferenceForUpdate(std::vector<T>&& previous,
|
|
|
|
std::vector<T>&& current,
|
2017-09-22 01:14:57 +00:00
|
|
|
std::vector<T>* removed,
|
|
|
|
std::vector<T>* added) {
|
2017-04-19 06:56:37 +00:00
|
|
|
// We need to sort to use std::set_difference.
|
|
|
|
std::sort(previous.begin(), previous.end());
|
|
|
|
std::sort(current.begin(), current.end());
|
2017-04-07 07:12:53 +00:00
|
|
|
|
2018-01-01 20:36:08 +00:00
|
|
|
auto it0 = previous.begin(), it1 = current.begin();
|
|
|
|
while (it0 != previous.end() && it1 != current.end()) {
|
|
|
|
// Elements in |previous| that are not in |current|.
|
|
|
|
if (*it0 < *it1)
|
2018-02-07 06:46:05 +00:00
|
|
|
removed->push_back(std::move(*it0++));
|
2018-01-01 20:36:08 +00:00
|
|
|
// Elements in |current| that are not in |previous|.
|
|
|
|
else if (*it1 < *it0)
|
2018-02-07 06:46:05 +00:00
|
|
|
added->push_back(std::move(*it1++));
|
2018-01-01 20:36:08 +00:00
|
|
|
else
|
|
|
|
++it0, ++it1;
|
|
|
|
}
|
|
|
|
while (it0 != previous.end())
|
2018-02-07 06:46:05 +00:00
|
|
|
removed->push_back(std::move(*it0++));
|
2018-01-01 20:36:08 +00:00
|
|
|
while (it1 != current.end())
|
2018-02-07 06:46:05 +00:00
|
|
|
added->push_back(std::move(*it1++));
|
2017-04-07 07:12:53 +00:00
|
|
|
|
2017-04-19 06:56:37 +00:00
|
|
|
return !removed->empty() || !added->empty();
|
|
|
|
}
|
2017-04-07 07:12:53 +00:00
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
template <typename T>
|
|
|
|
void CompareGroups(std::vector<T>& previous_data,
|
|
|
|
std::vector<T>& current_data,
|
|
|
|
std::function<void(T*)> on_removed,
|
|
|
|
std::function<void(T*)> on_added,
|
|
|
|
std::function<void(T*, T*)> on_found) {
|
2017-04-19 06:56:37 +00:00
|
|
|
std::sort(previous_data.begin(), previous_data.end());
|
|
|
|
std::sort(current_data.begin(), current_data.end());
|
2017-04-07 07:12:53 +00:00
|
|
|
|
2017-04-19 06:56:37 +00:00
|
|
|
auto prev_it = previous_data.begin();
|
|
|
|
auto curr_it = current_data.begin();
|
|
|
|
while (prev_it != previous_data.end() && curr_it != current_data.end()) {
|
|
|
|
// same id
|
2017-12-12 07:56:50 +00:00
|
|
|
if (prev_it->usr == curr_it->usr) {
|
2017-04-19 06:56:37 +00:00
|
|
|
on_found(&*prev_it, &*curr_it);
|
|
|
|
++prev_it;
|
|
|
|
++curr_it;
|
|
|
|
}
|
2017-04-07 07:12:53 +00:00
|
|
|
|
2017-04-19 06:56:37 +00:00
|
|
|
// prev_id is smaller - prev_it has data curr_it does not have.
|
2017-12-12 07:56:50 +00:00
|
|
|
else if (prev_it->usr < curr_it->usr) {
|
2017-04-19 06:56:37 +00:00
|
|
|
on_removed(&*prev_it);
|
|
|
|
++prev_it;
|
|
|
|
}
|
2017-04-07 07:12:53 +00:00
|
|
|
|
2017-04-19 06:56:37 +00:00
|
|
|
// prev_id is bigger - curr_it has data prev_it does not have.
|
|
|
|
else {
|
|
|
|
on_added(&*curr_it);
|
|
|
|
++curr_it;
|
|
|
|
}
|
|
|
|
}
|
2017-04-07 07:12:53 +00:00
|
|
|
|
2017-04-19 06:56:37 +00:00
|
|
|
// if prev_it still has data, that means it is not in curr_it and was removed.
|
|
|
|
while (prev_it != previous_data.end()) {
|
|
|
|
on_removed(&*prev_it);
|
|
|
|
++prev_it;
|
|
|
|
}
|
2017-04-07 07:12:53 +00:00
|
|
|
|
2017-04-19 06:56:37 +00:00
|
|
|
// if curr_it still has data, that means it is not in prev_it and was added.
|
|
|
|
while (curr_it != current_data.end()) {
|
|
|
|
on_added(&*curr_it);
|
|
|
|
++curr_it;
|
|
|
|
}
|
|
|
|
}
|
2017-04-07 07:12:53 +00:00
|
|
|
|
2018-02-22 07:34:32 +00:00
|
|
|
QueryFile::DefUpdate BuildFileDefUpdate(const IdMap& id_map,
|
|
|
|
const IndexFile& indexed) {
|
2017-04-15 05:41:35 +00:00
|
|
|
QueryFile::Def def;
|
2018-02-18 18:07:13 +00:00
|
|
|
def.file = id_map.primary_file;
|
2017-04-15 05:41:35 +00:00
|
|
|
def.path = indexed.path;
|
2018-02-15 06:41:07 +00:00
|
|
|
def.args = indexed.args;
|
2017-05-21 03:46:15 +00:00
|
|
|
def.includes = indexed.includes;
|
2017-10-28 22:09:14 +00:00
|
|
|
def.inactive_regions = indexed.skipped_by_preprocessor;
|
2018-01-27 17:29:28 +00:00
|
|
|
def.dependencies = indexed.dependencies;
|
2017-04-07 05:42:57 +00:00
|
|
|
|
2017-11-30 21:56:55 +00:00
|
|
|
// Convert enum to markdown compatible strings
|
2018-02-08 02:29:34 +00:00
|
|
|
def.language = [&indexed]() {
|
2017-12-01 17:50:39 +00:00
|
|
|
switch (indexed.language) {
|
2017-11-30 21:56:55 +00:00
|
|
|
case LanguageId::C:
|
|
|
|
return "c";
|
|
|
|
case LanguageId::Cpp:
|
|
|
|
return "cpp";
|
|
|
|
case LanguageId::ObjC:
|
2018-02-15 04:58:42 +00:00
|
|
|
return "objective-c";
|
|
|
|
case LanguageId::ObjCpp:
|
|
|
|
return "objective-cpp";
|
2017-11-30 21:56:55 +00:00
|
|
|
default:
|
|
|
|
return "";
|
2017-12-01 17:50:39 +00:00
|
|
|
}
|
|
|
|
}();
|
2017-11-30 21:56:55 +00:00
|
|
|
|
2018-02-18 18:07:13 +00:00
|
|
|
auto add_all_symbols = [&](Use use, Id<void> id, SymbolKind kind) {
|
2018-02-22 07:34:32 +00:00
|
|
|
def.all_symbols.push_back(SymbolRef(use.range, id, kind, use.role));
|
2018-02-11 04:01:10 +00:00
|
|
|
};
|
2018-02-18 18:07:13 +00:00
|
|
|
auto add_outline = [&](Use use, Id<void> id, SymbolKind kind) {
|
2018-02-11 04:01:10 +00:00
|
|
|
def.outline.push_back(SymbolRef(use.range, id, kind, use.role));
|
2017-04-03 02:21:21 +00:00
|
|
|
};
|
2017-02-27 07:23:43 +00:00
|
|
|
|
2017-05-12 06:08:15 +00:00
|
|
|
for (const IndexType& type : indexed.types) {
|
2018-02-11 04:01:10 +00:00
|
|
|
QueryTypeId id = id_map.ToQuery(type.id);
|
|
|
|
if (type.def.spell)
|
2018-02-18 18:07:13 +00:00
|
|
|
add_all_symbols(*type.def.spell, id, SymbolKind::Type);
|
2018-02-11 04:01:10 +00:00
|
|
|
if (type.def.extent)
|
2018-02-18 18:07:13 +00:00
|
|
|
add_outline(*type.def.extent, id, SymbolKind::Type);
|
2018-02-20 21:56:56 +00:00
|
|
|
for (Use decl : type.declarations) {
|
|
|
|
add_all_symbols(decl, id, SymbolKind::Type);
|
2018-02-25 01:24:20 +00:00
|
|
|
// Constructor positions have references to the class,
|
|
|
|
// which we do not want to show in textDocument/documentSymbol
|
|
|
|
if (!(decl.role & Role::Reference))
|
|
|
|
add_outline(decl, id, SymbolKind::Type);
|
2018-02-20 21:56:56 +00:00
|
|
|
}
|
2018-02-11 04:01:10 +00:00
|
|
|
for (Use use : type.uses)
|
2018-02-18 18:07:13 +00:00
|
|
|
add_all_symbols(use, id, SymbolKind::Type);
|
2017-02-27 07:23:43 +00:00
|
|
|
}
|
2017-05-12 06:08:15 +00:00
|
|
|
for (const IndexFunc& func : indexed.funcs) {
|
2018-02-11 04:01:10 +00:00
|
|
|
QueryFuncId id = id_map.ToQuery(func.id);
|
2018-02-11 21:56:34 +00:00
|
|
|
if (func.def.spell)
|
2018-02-18 18:07:13 +00:00
|
|
|
add_all_symbols(*func.def.spell, id, SymbolKind::Func);
|
2018-02-11 21:56:34 +00:00
|
|
|
if (func.def.extent)
|
2018-02-18 18:07:13 +00:00
|
|
|
add_outline(*func.def.extent, id, SymbolKind::Func);
|
2017-05-27 21:09:20 +00:00
|
|
|
for (const IndexFunc::Declaration& decl : func.declarations) {
|
2018-02-18 18:07:13 +00:00
|
|
|
add_all_symbols(decl.spell, id, SymbolKind::Func);
|
|
|
|
add_outline(decl.spell, id, SymbolKind::Func);
|
2017-04-03 02:21:21 +00:00
|
|
|
}
|
2018-02-12 04:22:47 +00:00
|
|
|
for (Use use : func.uses) {
|
2018-01-03 00:30:03 +00:00
|
|
|
// Make ranges of implicit function calls larger (spanning one more column
|
|
|
|
// to the left/right). This is hacky but useful. e.g.
|
2018-01-11 02:43:01 +00:00
|
|
|
// textDocument/definition on the space/semicolon in `A a;` or `return
|
|
|
|
// 42;` will take you to the constructor.
|
2018-02-12 04:22:47 +00:00
|
|
|
if (use.role & Role::Implicit) {
|
|
|
|
if (use.range.start.column > 0)
|
|
|
|
use.range.start.column--;
|
|
|
|
use.range.end.column++;
|
2018-01-03 00:30:03 +00:00
|
|
|
}
|
2018-02-18 18:07:13 +00:00
|
|
|
add_all_symbols(use, id, SymbolKind::Func);
|
2017-05-23 06:57:46 +00:00
|
|
|
}
|
2017-02-27 07:23:43 +00:00
|
|
|
}
|
2017-05-12 06:08:15 +00:00
|
|
|
for (const IndexVar& var : indexed.vars) {
|
2018-02-11 04:01:10 +00:00
|
|
|
QueryVarId id = id_map.ToQuery(var.id);
|
2018-02-22 07:23:39 +00:00
|
|
|
if (var.def.spell)
|
2018-02-18 18:07:13 +00:00
|
|
|
add_all_symbols(*var.def.spell, id, SymbolKind::Var);
|
2018-02-22 07:23:39 +00:00
|
|
|
if (var.def.extent)
|
|
|
|
add_outline(*var.def.extent, id, SymbolKind::Var);
|
2018-02-12 04:22:47 +00:00
|
|
|
for (Use decl : var.declarations) {
|
2018-02-18 18:07:13 +00:00
|
|
|
add_all_symbols(decl, id, SymbolKind::Var);
|
2018-02-22 07:23:39 +00:00
|
|
|
add_outline(decl, id, SymbolKind::Var);
|
2018-01-27 05:50:17 +00:00
|
|
|
}
|
2018-02-11 04:01:10 +00:00
|
|
|
for (Use use : var.uses)
|
2018-02-18 18:07:13 +00:00
|
|
|
add_all_symbols(use, id, SymbolKind::Var);
|
2017-02-27 07:23:43 +00:00
|
|
|
}
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
std::sort(def.outline.begin(), def.outline.end(),
|
|
|
|
[](const SymbolRef& a, const SymbolRef& b) {
|
2018-02-09 17:42:10 +00:00
|
|
|
return a.range.start < b.range.start;
|
2017-09-22 01:14:57 +00:00
|
|
|
});
|
|
|
|
std::sort(def.all_symbols.begin(), def.all_symbols.end(),
|
|
|
|
[](const SymbolRef& a, const SymbolRef& b) {
|
2018-02-09 17:42:10 +00:00
|
|
|
return a.range.start < b.range.start;
|
2017-09-22 01:14:57 +00:00
|
|
|
});
|
2017-04-07 05:42:57 +00:00
|
|
|
|
2018-01-30 05:34:28 +00:00
|
|
|
return QueryFile::DefUpdate(def, indexed.file_contents);
|
2017-02-27 07:23:43 +00:00
|
|
|
}
|
|
|
|
|
2018-02-02 07:10:37 +00:00
|
|
|
Maybe<QueryFileId> GetQueryFileIdFromPath(QueryDatabase* query_db,
|
|
|
|
const std::string& path,
|
|
|
|
bool create_if_missing) {
|
2018-03-31 18:32:28 +00:00
|
|
|
std::string normalized_path = LowerPathIfInsensitive(path);
|
2018-01-30 00:55:51 +00:00
|
|
|
auto it = query_db->usr_to_file.find(normalized_path);
|
2017-05-09 04:20:28 +00:00
|
|
|
if (it != query_db->usr_to_file.end())
|
|
|
|
return QueryFileId(it->second.id);
|
2018-01-20 16:57:41 +00:00
|
|
|
if (!create_if_missing)
|
2018-01-20 18:32:39 +00:00
|
|
|
return {};
|
2017-04-07 08:01:58 +00:00
|
|
|
|
2018-02-03 18:33:22 +00:00
|
|
|
RawId idx = query_db->files.size();
|
2018-01-30 00:55:51 +00:00
|
|
|
query_db->usr_to_file[normalized_path] = QueryFileId(idx);
|
2017-04-15 05:41:35 +00:00
|
|
|
query_db->files.push_back(QueryFile(path));
|
2017-04-08 07:11:57 +00:00
|
|
|
return QueryFileId(idx);
|
2017-04-07 08:01:58 +00:00
|
|
|
}
|
|
|
|
|
2018-02-02 07:10:37 +00:00
|
|
|
Maybe<QueryTypeId> GetQueryTypeIdFromUsr(QueryDatabase* query_db,
|
|
|
|
Usr usr,
|
|
|
|
bool create_if_missing) {
|
2017-05-09 04:20:28 +00:00
|
|
|
auto it = query_db->usr_to_type.find(usr);
|
|
|
|
if (it != query_db->usr_to_type.end())
|
|
|
|
return QueryTypeId(it->second.id);
|
2018-01-20 16:57:41 +00:00
|
|
|
if (!create_if_missing)
|
2018-01-20 18:32:39 +00:00
|
|
|
return {};
|
2017-04-07 08:01:58 +00:00
|
|
|
|
2018-02-03 18:33:22 +00:00
|
|
|
RawId idx = query_db->types.size();
|
2017-05-09 04:20:28 +00:00
|
|
|
query_db->usr_to_type[usr] = QueryTypeId(idx);
|
2017-04-15 05:41:35 +00:00
|
|
|
query_db->types.push_back(QueryType(usr));
|
2017-04-08 07:11:57 +00:00
|
|
|
return QueryTypeId(idx);
|
2017-04-07 08:01:58 +00:00
|
|
|
}
|
|
|
|
|
2018-02-02 07:10:37 +00:00
|
|
|
Maybe<QueryFuncId> GetQueryFuncIdFromUsr(QueryDatabase* query_db,
|
|
|
|
Usr usr,
|
|
|
|
bool create_if_missing) {
|
2017-05-09 04:20:28 +00:00
|
|
|
auto it = query_db->usr_to_func.find(usr);
|
|
|
|
if (it != query_db->usr_to_func.end())
|
|
|
|
return QueryFuncId(it->second.id);
|
2018-01-20 16:57:41 +00:00
|
|
|
if (!create_if_missing)
|
2018-01-20 18:32:39 +00:00
|
|
|
return {};
|
|
|
|
|
2018-02-03 18:33:22 +00:00
|
|
|
RawId idx = query_db->funcs.size();
|
2017-05-09 04:20:28 +00:00
|
|
|
query_db->usr_to_func[usr] = QueryFuncId(idx);
|
2017-04-15 05:41:35 +00:00
|
|
|
query_db->funcs.push_back(QueryFunc(usr));
|
2017-04-08 07:11:57 +00:00
|
|
|
return QueryFuncId(idx);
|
2017-04-07 08:01:58 +00:00
|
|
|
}
|
|
|
|
|
2018-02-02 07:10:37 +00:00
|
|
|
Maybe<QueryVarId> GetQueryVarIdFromUsr(QueryDatabase* query_db,
|
|
|
|
Usr usr,
|
|
|
|
bool create_if_missing) {
|
2017-05-09 04:20:28 +00:00
|
|
|
auto it = query_db->usr_to_var.find(usr);
|
|
|
|
if (it != query_db->usr_to_var.end())
|
|
|
|
return QueryVarId(it->second.id);
|
2018-01-20 16:57:41 +00:00
|
|
|
if (!create_if_missing)
|
2018-01-20 18:32:39 +00:00
|
|
|
return {};
|
2017-04-07 08:01:58 +00:00
|
|
|
|
2018-02-03 18:33:22 +00:00
|
|
|
RawId idx = query_db->vars.size();
|
2017-05-09 04:20:28 +00:00
|
|
|
query_db->usr_to_var[usr] = QueryVarId(idx);
|
2017-04-15 05:41:35 +00:00
|
|
|
query_db->vars.push_back(QueryVar(usr));
|
2017-04-08 07:11:57 +00:00
|
|
|
return QueryVarId(idx);
|
2017-04-07 08:01:58 +00:00
|
|
|
}
|
|
|
|
|
2018-02-18 08:02:19 +00:00
|
|
|
// Returns true if an element with the same file is found.
|
|
|
|
template <typename Q>
|
|
|
|
bool TryReplaceDef(std::forward_list<Q>& def_list, Q&& def) {
|
|
|
|
for (auto& def1 : def_list)
|
|
|
|
if (def1.file == def.file) {
|
|
|
|
if (!def1.spell || def.spell)
|
|
|
|
def1 = std::move(def);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-01-20 18:32:39 +00:00
|
|
|
} // namespace
|
|
|
|
|
2018-02-02 07:10:37 +00:00
|
|
|
Maybe<QueryFileId> QueryDatabase::GetQueryFileIdFromPath(
|
2018-01-20 16:57:41 +00:00
|
|
|
const std::string& path) {
|
|
|
|
return ::GetQueryFileIdFromPath(this, path, false);
|
|
|
|
}
|
|
|
|
|
2018-02-02 07:10:37 +00:00
|
|
|
Maybe<QueryTypeId> QueryDatabase::GetQueryTypeIdFromUsr(Usr usr) {
|
2018-01-20 16:57:41 +00:00
|
|
|
return ::GetQueryTypeIdFromUsr(this, usr, false);
|
|
|
|
}
|
|
|
|
|
2018-02-02 07:10:37 +00:00
|
|
|
Maybe<QueryFuncId> QueryDatabase::GetQueryFuncIdFromUsr(Usr usr) {
|
2018-01-20 16:57:41 +00:00
|
|
|
return ::GetQueryFuncIdFromUsr(this, usr, false);
|
|
|
|
}
|
|
|
|
|
2018-02-02 07:10:37 +00:00
|
|
|
Maybe<QueryVarId> QueryDatabase::GetQueryVarIdFromUsr(Usr usr) {
|
2018-01-20 16:57:41 +00:00
|
|
|
return ::GetQueryVarIdFromUsr(this, usr, false);
|
|
|
|
}
|
|
|
|
|
2017-04-15 05:41:35 +00:00
|
|
|
IdMap::IdMap(QueryDatabase* query_db, const IdCache& local_ids)
|
2018-04-09 07:52:04 +00:00
|
|
|
: local_ids{local_ids} {
|
2017-09-22 01:14:57 +00:00
|
|
|
// LOG_S(INFO) << "Creating IdMap for " << local_ids.primary_file;
|
2018-01-20 18:32:39 +00:00
|
|
|
primary_file =
|
2018-02-02 07:10:37 +00:00
|
|
|
*GetQueryFileIdFromPath(query_db, local_ids.primary_file, true);
|
2017-04-08 06:45:28 +00:00
|
|
|
|
2017-04-08 07:11:57 +00:00
|
|
|
cached_type_ids_.resize(local_ids.type_id_to_usr.size());
|
2017-04-07 08:01:58 +00:00
|
|
|
for (const auto& entry : local_ids.type_id_to_usr)
|
2017-09-22 01:14:57 +00:00
|
|
|
cached_type_ids_[entry.first] =
|
2018-02-02 07:10:37 +00:00
|
|
|
*GetQueryTypeIdFromUsr(query_db, entry.second, true);
|
2017-04-07 08:01:58 +00:00
|
|
|
|
2017-04-08 07:11:57 +00:00
|
|
|
cached_func_ids_.resize(local_ids.func_id_to_usr.size());
|
2017-04-07 08:01:58 +00:00
|
|
|
for (const auto& entry : local_ids.func_id_to_usr)
|
2017-09-22 01:14:57 +00:00
|
|
|
cached_func_ids_[entry.first] =
|
2018-02-02 07:10:37 +00:00
|
|
|
*GetQueryFuncIdFromUsr(query_db, entry.second, true);
|
2017-04-07 08:01:58 +00:00
|
|
|
|
2017-04-08 07:11:57 +00:00
|
|
|
cached_var_ids_.resize(local_ids.var_id_to_usr.size());
|
2017-04-07 08:01:58 +00:00
|
|
|
for (const auto& entry : local_ids.var_id_to_usr)
|
2018-01-20 16:57:41 +00:00
|
|
|
cached_var_ids_[entry.first] =
|
2018-02-02 07:10:37 +00:00
|
|
|
*GetQueryVarIdFromUsr(query_db, entry.second, true);
|
2017-04-08 07:11:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QueryTypeId IdMap::ToQuery(IndexTypeId id) const {
|
2017-04-15 05:55:01 +00:00
|
|
|
assert(cached_type_ids_.find(id) != cached_type_ids_.end());
|
|
|
|
return QueryTypeId(cached_type_ids_.find(id)->second);
|
2017-04-07 08:01:58 +00:00
|
|
|
}
|
2017-04-08 07:11:57 +00:00
|
|
|
QueryFuncId IdMap::ToQuery(IndexFuncId id) const {
|
2017-04-15 05:55:01 +00:00
|
|
|
assert(cached_func_ids_.find(id) != cached_func_ids_.end());
|
|
|
|
return QueryFuncId(cached_func_ids_.find(id)->second);
|
2017-04-08 07:11:57 +00:00
|
|
|
}
|
|
|
|
QueryVarId IdMap::ToQuery(IndexVarId id) const {
|
2017-04-15 05:55:01 +00:00
|
|
|
assert(cached_var_ids_.find(id) != cached_var_ids_.end());
|
|
|
|
return QueryVarId(cached_var_ids_.find(id)->second);
|
2017-04-08 07:11:57 +00:00
|
|
|
}
|
2018-02-10 20:53:18 +00:00
|
|
|
|
|
|
|
Use IdMap::ToQuery(Reference ref) const {
|
2018-02-18 18:07:13 +00:00
|
|
|
Use ret(ref.range, ref.id, ref.kind, ref.role, primary_file);
|
2018-02-09 17:42:10 +00:00
|
|
|
switch (ref.kind) {
|
2018-02-22 07:34:32 +00:00
|
|
|
case SymbolKind::Invalid:
|
|
|
|
break;
|
|
|
|
case SymbolKind::File:
|
|
|
|
ret.id = primary_file;
|
|
|
|
break;
|
|
|
|
case SymbolKind::Func:
|
|
|
|
ret.id = ToQuery(IndexFuncId(ref.id));
|
|
|
|
break;
|
|
|
|
case SymbolKind::Type:
|
|
|
|
ret.id = ToQuery(IndexTypeId(ref.id));
|
|
|
|
break;
|
|
|
|
case SymbolKind::Var:
|
|
|
|
ret.id = ToQuery(IndexVarId(ref.id));
|
|
|
|
break;
|
2018-02-09 07:10:54 +00:00
|
|
|
}
|
2018-02-12 04:22:47 +00:00
|
|
|
return ret;
|
2017-04-08 08:04:38 +00:00
|
|
|
}
|
2018-02-10 20:53:18 +00:00
|
|
|
SymbolRef IdMap::ToQuery(SymbolRef ref) const {
|
|
|
|
ref.Reference::operator=(ToQuery(static_cast<Reference>(ref)));
|
|
|
|
return ref;
|
|
|
|
}
|
|
|
|
Use IdMap::ToQuery(Use use) const {
|
2018-02-12 04:22:47 +00:00
|
|
|
return ToQuery(static_cast<Reference>(use));
|
2018-02-10 20:53:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Use IdMap::ToQuery(IndexFunc::Declaration decl) const {
|
2018-02-18 18:07:13 +00:00
|
|
|
return ToQuery(static_cast<Reference>(decl.spell));
|
2017-05-27 21:09:20 +00:00
|
|
|
}
|
2017-04-07 08:01:58 +00:00
|
|
|
|
2017-04-19 06:56:37 +00:00
|
|
|
// ----------------------
|
|
|
|
// INDEX THREAD FUNCTIONS
|
|
|
|
// ----------------------
|
|
|
|
|
2017-04-07 05:42:57 +00:00
|
|
|
// static
|
2017-09-22 01:14:57 +00:00
|
|
|
IndexUpdate IndexUpdate::CreateDelta(const IdMap* previous_id_map,
|
|
|
|
const IdMap* current_id_map,
|
|
|
|
IndexFile* previous,
|
|
|
|
IndexFile* current) {
|
2017-04-19 06:56:37 +00:00
|
|
|
// This function runs on an indexer thread.
|
|
|
|
|
2017-04-08 06:45:28 +00:00
|
|
|
if (!previous_id_map) {
|
|
|
|
assert(!previous);
|
2018-01-30 05:34:28 +00:00
|
|
|
IndexFile empty(current->path, "<empty>");
|
2017-05-22 06:09:09 +00:00
|
|
|
return IndexUpdate(*current_id_map, *current_id_map, empty, *current);
|
2017-04-08 06:45:28 +00:00
|
|
|
}
|
|
|
|
return IndexUpdate(*previous_id_map, *current_id_map, *previous, *current);
|
2017-04-07 05:42:57 +00:00
|
|
|
}
|
2017-02-27 07:23:43 +00:00
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
IndexUpdate::IndexUpdate(const IdMap& previous_id_map,
|
|
|
|
const IdMap& current_id_map,
|
|
|
|
IndexFile& previous_file,
|
|
|
|
IndexFile& 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.
|
2018-02-07 06:46:05 +00:00
|
|
|
#define PROCESS_UPDATE_DIFF(type_id, query_name, index_name, type) \
|
|
|
|
{ \
|
|
|
|
/* Check for changes. */ \
|
|
|
|
std::vector<type> removed, added; \
|
|
|
|
auto query_previous = previous_id_map.ToQuery(previous->index_name); \
|
|
|
|
auto query_current = current_id_map.ToQuery(current->index_name); \
|
|
|
|
bool did_add = ComputeDifferenceForUpdate(std::move(query_previous), \
|
|
|
|
std::move(query_current), \
|
|
|
|
&removed, &added); \
|
|
|
|
if (did_add) { \
|
|
|
|
query_name.push_back(MergeableUpdate<type_id, type>( \
|
|
|
|
current_id_map.ToQuery(current->id), std::move(added), \
|
|
|
|
std::move(removed))); \
|
|
|
|
} \
|
2017-04-08 07:52:57 +00:00
|
|
|
}
|
2017-02-27 07:23:43 +00:00
|
|
|
// File
|
2018-01-30 05:34:28 +00:00
|
|
|
files_def_update.push_back(BuildFileDefUpdate(current_id_map, current_file));
|
2017-02-25 23:59:09 +00:00
|
|
|
|
2017-05-25 00:18:04 +00:00
|
|
|
// **NOTE** We only remove entries if they were defined in the previous index.
|
|
|
|
// For example, if a type is included from another file it will be defined
|
|
|
|
// simply so we can attribute the usage/reference to it. If the reference goes
|
|
|
|
// away we don't want to remove the type/func/var usage.
|
|
|
|
|
2017-02-25 23:59:09 +00:00
|
|
|
// Types
|
2017-09-22 01:14:57 +00:00
|
|
|
CompareGroups<IndexType>(
|
|
|
|
previous_file.types, current_file.types,
|
|
|
|
/*onRemoved:*/
|
|
|
|
[this, &previous_id_map](IndexType* type) {
|
2018-02-11 04:01:10 +00:00
|
|
|
if (type->def.spell)
|
2017-12-12 07:56:50 +00:00
|
|
|
types_removed.push_back(type->usr);
|
2018-02-20 21:56:56 +00:00
|
|
|
if (!type->declarations.empty())
|
|
|
|
types_declarations.push_back(QueryType::DeclarationsUpdate(
|
|
|
|
previous_id_map.ToQuery(type->id), {},
|
|
|
|
previous_id_map.ToQuery(type->declarations)));
|
2018-02-14 05:13:54 +00:00
|
|
|
if (!type->derived.empty())
|
2018-02-22 07:34:32 +00:00
|
|
|
types_derived.push_back(
|
|
|
|
QueryType::DerivedUpdate(previous_id_map.ToQuery(type->id), {},
|
|
|
|
previous_id_map.ToQuery(type->derived)));
|
2018-02-14 05:13:54 +00:00
|
|
|
if (!type->instances.empty())
|
|
|
|
types_instances.push_back(QueryType::InstancesUpdate(
|
|
|
|
previous_id_map.ToQuery(type->id), {},
|
|
|
|
previous_id_map.ToQuery(type->instances)));
|
|
|
|
if (!type->uses.empty())
|
|
|
|
types_uses.push_back(
|
|
|
|
QueryType::UsesUpdate(previous_id_map.ToQuery(type->id), {},
|
|
|
|
previous_id_map.ToQuery(type->uses)));
|
2017-09-22 01:14:57 +00:00
|
|
|
},
|
|
|
|
/*onAdded:*/
|
|
|
|
[this, ¤t_id_map](IndexType* type) {
|
2018-03-31 03:16:33 +00:00
|
|
|
std::optional<QueryType::Def> def_update =
|
2017-09-22 01:14:57 +00:00
|
|
|
ToQuery(current_id_map, type->def);
|
|
|
|
if (def_update)
|
2017-12-12 07:56:50 +00:00
|
|
|
types_def_update.push_back(
|
2018-02-07 06:46:05 +00:00
|
|
|
QueryType::DefUpdate(type->usr, std::move(*def_update)));
|
2018-02-20 21:56:56 +00:00
|
|
|
if (!type->declarations.empty())
|
|
|
|
types_declarations.push_back(QueryType::DeclarationsUpdate(
|
|
|
|
current_id_map.ToQuery(type->id),
|
|
|
|
current_id_map.ToQuery(type->declarations)));
|
2017-09-22 01:14:57 +00:00
|
|
|
if (!type->derived.empty())
|
|
|
|
types_derived.push_back(
|
|
|
|
QueryType::DerivedUpdate(current_id_map.ToQuery(type->id),
|
|
|
|
current_id_map.ToQuery(type->derived)));
|
|
|
|
if (!type->instances.empty())
|
|
|
|
types_instances.push_back(QueryType::InstancesUpdate(
|
|
|
|
current_id_map.ToQuery(type->id),
|
|
|
|
current_id_map.ToQuery(type->instances)));
|
|
|
|
if (!type->uses.empty())
|
|
|
|
types_uses.push_back(
|
|
|
|
QueryType::UsesUpdate(current_id_map.ToQuery(type->id),
|
|
|
|
current_id_map.ToQuery(type->uses)));
|
|
|
|
},
|
|
|
|
/*onFound:*/
|
2017-12-12 07:56:50 +00:00
|
|
|
[this, &previous_id_map, ¤t_id_map](IndexType* previous,
|
|
|
|
IndexType* current) {
|
2018-03-31 03:16:33 +00:00
|
|
|
std::optional<QueryType::Def> previous_remapped_def =
|
2017-12-12 07:56:50 +00:00
|
|
|
ToQuery(previous_id_map, previous->def);
|
2018-03-31 03:16:33 +00:00
|
|
|
std::optional<QueryType::Def> current_remapped_def =
|
2017-12-12 07:56:50 +00:00
|
|
|
ToQuery(current_id_map, current->def);
|
2017-09-22 01:14:57 +00:00
|
|
|
if (current_remapped_def &&
|
|
|
|
previous_remapped_def != current_remapped_def &&
|
2017-12-12 07:56:50 +00:00
|
|
|
!current_remapped_def->detailed_name.empty()) {
|
2018-02-07 06:46:05 +00:00
|
|
|
types_def_update.push_back(QueryType::DefUpdate(
|
|
|
|
current->usr, std::move(*current_remapped_def)));
|
2017-12-12 07:56:50 +00:00
|
|
|
}
|
2017-09-22 01:14:57 +00:00
|
|
|
|
2018-02-20 21:56:56 +00:00
|
|
|
PROCESS_UPDATE_DIFF(QueryTypeId, types_declarations, declarations, Use);
|
2017-09-22 01:14:57 +00:00
|
|
|
PROCESS_UPDATE_DIFF(QueryTypeId, types_derived, derived, QueryTypeId);
|
|
|
|
PROCESS_UPDATE_DIFF(QueryTypeId, types_instances, instances,
|
|
|
|
QueryVarId);
|
2018-02-10 20:53:18 +00:00
|
|
|
PROCESS_UPDATE_DIFF(QueryTypeId, types_uses, uses, Use);
|
2017-09-22 01:14:57 +00:00
|
|
|
});
|
2017-02-25 23:59:09 +00:00
|
|
|
|
|
|
|
// Functions
|
2017-09-22 01:14:57 +00:00
|
|
|
CompareGroups<IndexFunc>(
|
|
|
|
previous_file.funcs, current_file.funcs,
|
|
|
|
/*onRemoved:*/
|
|
|
|
[this, &previous_id_map](IndexFunc* func) {
|
2018-02-14 05:13:54 +00:00
|
|
|
if (func->def.spell)
|
2018-02-18 08:02:19 +00:00
|
|
|
funcs_removed.emplace_back(func->usr, previous_id_map.primary_file);
|
2018-02-14 05:13:54 +00:00
|
|
|
if (!func->declarations.empty())
|
|
|
|
funcs_declarations.push_back(QueryFunc::DeclarationsUpdate(
|
|
|
|
previous_id_map.ToQuery(func->id), {},
|
|
|
|
previous_id_map.ToQuery(func->declarations)));
|
|
|
|
if (!func->derived.empty())
|
2018-02-22 07:34:32 +00:00
|
|
|
funcs_derived.push_back(
|
|
|
|
QueryFunc::DerivedUpdate(previous_id_map.ToQuery(func->id), {},
|
|
|
|
previous_id_map.ToQuery(func->derived)));
|
2018-02-14 05:13:54 +00:00
|
|
|
if (!func->uses.empty())
|
2018-02-22 07:34:32 +00:00
|
|
|
funcs_uses.push_back(
|
|
|
|
QueryFunc::UsesUpdate(previous_id_map.ToQuery(func->id), {},
|
|
|
|
previous_id_map.ToQuery(func->uses)));
|
2017-09-22 01:14:57 +00:00
|
|
|
},
|
|
|
|
/*onAdded:*/
|
|
|
|
[this, ¤t_id_map](IndexFunc* func) {
|
2018-03-31 03:16:33 +00:00
|
|
|
std::optional<QueryFunc::Def> def_update =
|
2017-09-22 01:14:57 +00:00
|
|
|
ToQuery(current_id_map, func->def);
|
|
|
|
if (def_update)
|
2017-12-12 07:56:50 +00:00
|
|
|
funcs_def_update.push_back(
|
2018-02-07 06:46:05 +00:00
|
|
|
QueryFunc::DefUpdate(func->usr, std::move(*def_update)));
|
2017-09-22 01:14:57 +00:00
|
|
|
if (!func->declarations.empty())
|
|
|
|
funcs_declarations.push_back(QueryFunc::DeclarationsUpdate(
|
|
|
|
current_id_map.ToQuery(func->id),
|
|
|
|
current_id_map.ToQuery(func->declarations)));
|
|
|
|
if (!func->derived.empty())
|
|
|
|
funcs_derived.push_back(
|
|
|
|
QueryFunc::DerivedUpdate(current_id_map.ToQuery(func->id),
|
|
|
|
current_id_map.ToQuery(func->derived)));
|
2018-02-10 20:53:18 +00:00
|
|
|
if (!func->uses.empty())
|
|
|
|
funcs_uses.push_back(
|
|
|
|
QueryFunc::UsesUpdate(current_id_map.ToQuery(func->id),
|
|
|
|
current_id_map.ToQuery(func->uses)));
|
2017-09-22 01:14:57 +00:00
|
|
|
},
|
|
|
|
/*onFound:*/
|
2017-12-12 07:56:50 +00:00
|
|
|
[this, &previous_id_map, ¤t_id_map](IndexFunc* previous,
|
|
|
|
IndexFunc* current) {
|
2018-03-31 03:16:33 +00:00
|
|
|
std::optional<QueryFunc::Def> previous_remapped_def =
|
2017-12-12 07:56:50 +00:00
|
|
|
ToQuery(previous_id_map, previous->def);
|
2018-03-31 03:16:33 +00:00
|
|
|
std::optional<QueryFunc::Def> current_remapped_def =
|
2017-12-12 07:56:50 +00:00
|
|
|
ToQuery(current_id_map, current->def);
|
2017-09-22 01:14:57 +00:00
|
|
|
if (current_remapped_def &&
|
|
|
|
previous_remapped_def != current_remapped_def &&
|
2017-12-12 07:56:50 +00:00
|
|
|
!current_remapped_def->detailed_name.empty()) {
|
2018-02-07 06:46:05 +00:00
|
|
|
funcs_def_update.push_back(QueryFunc::DefUpdate(
|
|
|
|
current->usr, std::move(*current_remapped_def)));
|
2017-12-12 07:56:50 +00:00
|
|
|
}
|
2017-09-22 01:14:57 +00:00
|
|
|
|
2018-02-22 07:34:32 +00:00
|
|
|
PROCESS_UPDATE_DIFF(QueryFuncId, funcs_declarations, declarations, Use);
|
2017-09-22 01:14:57 +00:00
|
|
|
PROCESS_UPDATE_DIFF(QueryFuncId, funcs_derived, derived, QueryFuncId);
|
2018-02-10 20:53:18 +00:00
|
|
|
PROCESS_UPDATE_DIFF(QueryFuncId, funcs_uses, uses, Use);
|
2017-09-22 01:14:57 +00:00
|
|
|
});
|
2017-02-25 23:59:09 +00:00
|
|
|
|
|
|
|
// Variables
|
2017-09-22 01:14:57 +00:00
|
|
|
CompareGroups<IndexVar>(
|
|
|
|
previous_file.vars, current_file.vars,
|
|
|
|
/*onRemoved:*/
|
|
|
|
[this, &previous_id_map](IndexVar* var) {
|
2018-02-14 05:13:54 +00:00
|
|
|
if (var->def.spell)
|
2018-02-18 08:02:19 +00:00
|
|
|
vars_removed.emplace_back(var->usr, previous_id_map.primary_file);
|
2018-02-14 05:13:54 +00:00
|
|
|
if (!var->declarations.empty())
|
|
|
|
vars_declarations.push_back(QueryVar::DeclarationsUpdate(
|
|
|
|
previous_id_map.ToQuery(var->id), {},
|
|
|
|
previous_id_map.ToQuery(var->declarations)));
|
|
|
|
if (!var->uses.empty())
|
|
|
|
vars_uses.push_back(
|
|
|
|
QueryVar::UsesUpdate(previous_id_map.ToQuery(var->id), {},
|
2018-02-22 07:34:32 +00:00
|
|
|
previous_id_map.ToQuery(var->uses)));
|
2017-09-22 01:14:57 +00:00
|
|
|
},
|
|
|
|
/*onAdded:*/
|
|
|
|
[this, ¤t_id_map](IndexVar* var) {
|
2018-03-31 03:16:33 +00:00
|
|
|
std::optional<QueryVar::Def> def_update = ToQuery(current_id_map, var->def);
|
2017-09-22 01:14:57 +00:00
|
|
|
if (def_update)
|
2018-02-07 06:46:05 +00:00
|
|
|
vars_def_update.push_back(
|
|
|
|
QueryVar::DefUpdate(var->usr, std::move(*def_update)));
|
2018-01-27 05:50:17 +00:00
|
|
|
if (!var->declarations.empty())
|
|
|
|
vars_declarations.push_back(QueryVar::DeclarationsUpdate(
|
|
|
|
current_id_map.ToQuery(var->id),
|
|
|
|
current_id_map.ToQuery(var->declarations)));
|
2017-09-22 01:14:57 +00:00
|
|
|
if (!var->uses.empty())
|
|
|
|
vars_uses.push_back(
|
|
|
|
QueryVar::UsesUpdate(current_id_map.ToQuery(var->id),
|
|
|
|
current_id_map.ToQuery(var->uses)));
|
|
|
|
},
|
|
|
|
/*onFound:*/
|
2017-12-12 07:56:50 +00:00
|
|
|
[this, &previous_id_map, ¤t_id_map](IndexVar* previous,
|
|
|
|
IndexVar* current) {
|
2018-03-31 03:16:33 +00:00
|
|
|
std::optional<QueryVar::Def> previous_remapped_def =
|
2017-12-12 07:56:50 +00:00
|
|
|
ToQuery(previous_id_map, previous->def);
|
2018-03-31 03:16:33 +00:00
|
|
|
std::optional<QueryVar::Def> current_remapped_def =
|
2017-12-12 07:56:50 +00:00
|
|
|
ToQuery(current_id_map, current->def);
|
2017-09-22 01:14:57 +00:00
|
|
|
if (current_remapped_def &&
|
|
|
|
previous_remapped_def != current_remapped_def &&
|
|
|
|
!current_remapped_def->detailed_name.empty())
|
2018-02-07 06:46:05 +00:00
|
|
|
vars_def_update.push_back(QueryVar::DefUpdate(
|
|
|
|
current->usr, std::move(*current_remapped_def)));
|
2017-09-22 01:14:57 +00:00
|
|
|
|
2018-02-10 20:53:18 +00:00
|
|
|
PROCESS_UPDATE_DIFF(QueryVarId, vars_declarations, declarations, Use);
|
|
|
|
PROCESS_UPDATE_DIFF(QueryVarId, vars_uses, uses, Use);
|
2017-09-22 01:14:57 +00:00
|
|
|
});
|
2017-02-25 23:59:09 +00:00
|
|
|
|
|
|
|
#undef PROCESS_UPDATE_DIFF
|
|
|
|
}
|
2017-02-21 09:08:52 +00:00
|
|
|
|
2017-12-12 05:21:03 +00:00
|
|
|
// This function runs on an indexer thread.
|
2018-02-06 07:22:44 +00:00
|
|
|
void IndexUpdate::Merge(IndexUpdate&& update) {
|
2018-02-07 05:45:58 +00:00
|
|
|
#define INDEX_UPDATE_APPEND(name) AddRange(&name, std::move(update.name));
|
2018-02-22 07:34:32 +00:00
|
|
|
#define INDEX_UPDATE_MERGE(name) \
|
|
|
|
AddMergeableRange(&name, std::move(update.name));
|
2017-02-27 07:23:43 +00:00
|
|
|
|
2017-04-16 08:31:28 +00:00
|
|
|
INDEX_UPDATE_APPEND(files_removed);
|
|
|
|
INDEX_UPDATE_APPEND(files_def_update);
|
2017-02-27 07:23:43 +00:00
|
|
|
|
2017-04-16 08:31:28 +00:00
|
|
|
INDEX_UPDATE_APPEND(types_removed);
|
|
|
|
INDEX_UPDATE_APPEND(types_def_update);
|
2017-02-27 07:23:43 +00:00
|
|
|
INDEX_UPDATE_MERGE(types_derived);
|
2017-04-21 07:03:33 +00:00
|
|
|
INDEX_UPDATE_MERGE(types_instances);
|
2017-02-27 07:23:43 +00:00
|
|
|
INDEX_UPDATE_MERGE(types_uses);
|
|
|
|
|
2017-04-16 08:31:28 +00:00
|
|
|
INDEX_UPDATE_APPEND(funcs_removed);
|
|
|
|
INDEX_UPDATE_APPEND(funcs_def_update);
|
2017-02-27 07:23:43 +00:00
|
|
|
INDEX_UPDATE_MERGE(funcs_declarations);
|
|
|
|
INDEX_UPDATE_MERGE(funcs_derived);
|
2018-02-10 20:53:18 +00:00
|
|
|
INDEX_UPDATE_MERGE(funcs_uses);
|
2017-02-27 07:23:43 +00:00
|
|
|
|
2017-04-16 08:31:28 +00:00
|
|
|
INDEX_UPDATE_APPEND(vars_removed);
|
|
|
|
INDEX_UPDATE_APPEND(vars_def_update);
|
2018-01-27 05:50:17 +00:00
|
|
|
INDEX_UPDATE_MERGE(vars_declarations);
|
2017-02-27 07:23:43 +00:00
|
|
|
INDEX_UPDATE_MERGE(vars_uses);
|
2017-02-26 19:45:59 +00:00
|
|
|
|
2017-04-16 08:31:28 +00:00
|
|
|
#undef INDEX_UPDATE_APPEND
|
2017-02-27 07:23:43 +00:00
|
|
|
#undef INDEX_UPDATE_MERGE
|
|
|
|
}
|
2017-02-26 19:45:59 +00:00
|
|
|
|
2017-05-19 07:02:01 +00:00
|
|
|
std::string IndexUpdate::ToString() {
|
|
|
|
rapidjson::StringBuffer output;
|
2018-02-12 01:15:08 +00:00
|
|
|
rapidjson::Writer<rapidjson::StringBuffer> writer(output);
|
2018-01-06 21:46:41 +00:00
|
|
|
JsonWriter json_writer(&writer);
|
2017-05-19 07:02:01 +00:00
|
|
|
IndexUpdate& update = *this;
|
2018-01-06 21:46:41 +00:00
|
|
|
Reflect(json_writer, update);
|
2017-05-19 07:02:01 +00:00
|
|
|
return output.GetString();
|
|
|
|
}
|
2017-02-26 19:45:59 +00:00
|
|
|
|
2017-04-19 06:56:37 +00:00
|
|
|
// ------------------------
|
|
|
|
// QUERYDB THREAD FUNCTIONS
|
|
|
|
// ------------------------
|
2017-02-26 08:11:47 +00:00
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
void QueryDatabase::RemoveUsrs(SymbolKind usr_kind,
|
|
|
|
const std::vector<Usr>& to_remove) {
|
2017-05-09 04:20:28 +00:00
|
|
|
switch (usr_kind) {
|
|
|
|
case SymbolKind::Type: {
|
2018-02-02 01:24:46 +00:00
|
|
|
for (const Usr& usr : to_remove) {
|
|
|
|
QueryType& type = types[usr_to_type[usr].id];
|
2018-02-02 06:47:22 +00:00
|
|
|
if (type.symbol_idx)
|
|
|
|
symbols[type.symbol_idx->id].kind = SymbolKind::Invalid;
|
2018-02-18 07:09:05 +00:00
|
|
|
type.def.clear();
|
2018-02-02 01:24:46 +00:00
|
|
|
}
|
2017-05-09 04:20:28 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-02-18 08:02:19 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QueryDatabase::RemoveUsrs(
|
|
|
|
SymbolKind usr_kind,
|
|
|
|
const std::vector<WithUsr<QueryFileId>>& to_remove) {
|
|
|
|
switch (usr_kind) {
|
2017-05-09 04:20:28 +00:00
|
|
|
case SymbolKind::Func: {
|
2018-02-18 08:02:19 +00:00
|
|
|
for (const auto& usr_file : to_remove) {
|
|
|
|
QueryFunc& func = funcs[usr_to_func[usr_file.usr].id];
|
|
|
|
func.def.remove_if([&](const QueryFunc::Def& def) {
|
|
|
|
return def.file == usr_file.value;
|
|
|
|
});
|
2018-02-02 01:24:46 +00:00
|
|
|
}
|
2017-05-09 04:20:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SymbolKind::Var: {
|
2018-02-18 08:02:19 +00:00
|
|
|
for (const auto& usr_file : to_remove) {
|
|
|
|
QueryVar& var = vars[usr_to_var[usr_file.usr].id];
|
|
|
|
var.def.remove_if([&](const QueryVar::Def& def) {
|
|
|
|
return def.file == usr_file.value;
|
|
|
|
});
|
2018-02-02 01:24:46 +00:00
|
|
|
}
|
2017-05-09 04:20:28 +00:00
|
|
|
break;
|
2017-04-22 07:32:29 +00:00
|
|
|
}
|
2018-02-18 08:02:19 +00:00
|
|
|
default:
|
|
|
|
assert(false);
|
2017-05-21 23:48:21 +00:00
|
|
|
break;
|
2017-04-22 07:32:29 +00:00
|
|
|
}
|
2017-04-19 06:56:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QueryDatabase::ApplyIndexUpdate(IndexUpdate* update) {
|
2017-09-22 01:14:57 +00:00
|
|
|
// This function runs on the querydb thread.
|
|
|
|
|
|
|
|
// Example types:
|
2018-03-31 03:16:33 +00:00
|
|
|
// storage_name => std::vector<std::optional<QueryType>>
|
2017-09-22 01:14:57 +00:00
|
|
|
// merge_update => QueryType::DerivedUpdate =>
|
|
|
|
// MergeableUpdate<QueryTypeId, QueryTypeId> def => QueryType
|
|
|
|
// def->def_var_name => std::vector<QueryTypeId>
|
2017-10-17 05:44:58 +00:00
|
|
|
#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]; \
|
|
|
|
AddRange(&def.def_var_name, merge_update.to_add); \
|
|
|
|
RemoveRange(&def.def_var_name, merge_update.to_remove); \
|
2017-04-19 06:56:37 +00:00
|
|
|
}
|
|
|
|
|
2018-01-26 06:42:58 +00:00
|
|
|
for (const std::string& filename : update->files_removed)
|
2018-03-31 18:32:28 +00:00
|
|
|
files[usr_to_file[LowerPathIfInsensitive(filename)].id].def = std::nullopt;
|
2017-04-19 06:56:37 +00:00
|
|
|
ImportOrUpdate(update->files_def_update);
|
|
|
|
|
2017-05-09 04:20:28 +00:00
|
|
|
RemoveUsrs(SymbolKind::Type, update->types_removed);
|
2018-02-07 05:26:38 +00:00
|
|
|
ImportOrUpdate(std::move(update->types_def_update));
|
2018-02-20 21:56:56 +00:00
|
|
|
HANDLE_MERGEABLE(types_declarations, declarations, types);
|
2018-02-05 18:12:28 +00:00
|
|
|
HANDLE_MERGEABLE(types_derived, derived, types);
|
|
|
|
HANDLE_MERGEABLE(types_instances, instances, types);
|
2017-04-19 06:56:37 +00:00
|
|
|
HANDLE_MERGEABLE(types_uses, uses, types);
|
|
|
|
|
2017-05-09 04:20:28 +00:00
|
|
|
RemoveUsrs(SymbolKind::Func, update->funcs_removed);
|
2018-02-07 05:26:38 +00:00
|
|
|
ImportOrUpdate(std::move(update->funcs_def_update));
|
2017-04-19 06:56:37 +00:00
|
|
|
HANDLE_MERGEABLE(funcs_declarations, declarations, funcs);
|
2018-02-05 18:12:28 +00:00
|
|
|
HANDLE_MERGEABLE(funcs_derived, derived, funcs);
|
2018-02-10 20:53:18 +00:00
|
|
|
HANDLE_MERGEABLE(funcs_uses, uses, funcs);
|
2017-04-19 06:56:37 +00:00
|
|
|
|
2017-05-09 04:20:28 +00:00
|
|
|
RemoveUsrs(SymbolKind::Var, update->vars_removed);
|
2018-02-07 05:26:38 +00:00
|
|
|
ImportOrUpdate(std::move(update->vars_def_update));
|
2018-01-27 05:50:17 +00:00
|
|
|
HANDLE_MERGEABLE(vars_declarations, declarations, vars);
|
2017-04-19 06:56:37 +00:00
|
|
|
HANDLE_MERGEABLE(vars_uses, uses, vars);
|
|
|
|
|
|
|
|
#undef HANDLE_MERGEABLE
|
2017-02-27 07:23:43 +00:00
|
|
|
}
|
2017-02-26 19:45:59 +00:00
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
void QueryDatabase::ImportOrUpdate(
|
|
|
|
const std::vector<QueryFile::DefUpdate>& updates) {
|
2017-04-19 06:56:37 +00:00
|
|
|
// This function runs on the querydb thread.
|
|
|
|
|
2017-04-07 05:42:57 +00:00
|
|
|
for (auto& def : updates) {
|
2018-03-31 18:32:28 +00:00
|
|
|
auto it = usr_to_file.find(LowerPathIfInsensitive(def.value.path));
|
2017-05-09 04:20:28 +00:00
|
|
|
assert(it != usr_to_file.end());
|
2017-04-08 06:45:28 +00:00
|
|
|
|
2017-10-17 05:44:58 +00:00
|
|
|
QueryFile& existing = files[it->second.id];
|
2017-04-22 07:32:29 +00:00
|
|
|
|
2018-01-30 05:34:28 +00:00
|
|
|
existing.def = def.value;
|
2018-02-11 18:25:37 +00:00
|
|
|
UpdateSymbols(&existing.symbol_idx, SymbolKind::File, it->second);
|
2017-02-26 19:45:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
void QueryDatabase::ImportOrUpdate(
|
2018-02-07 05:26:38 +00:00
|
|
|
std::vector<QueryType::DefUpdate>&& updates) {
|
2017-04-19 06:56:37 +00:00
|
|
|
// This function runs on the querydb thread.
|
|
|
|
|
2017-04-07 05:42:57 +00:00
|
|
|
for (auto& def : updates) {
|
2017-12-12 07:56:50 +00:00
|
|
|
assert(!def.value.detailed_name.empty());
|
2017-04-08 06:45:28 +00:00
|
|
|
|
2017-05-09 04:20:28 +00:00
|
|
|
auto it = usr_to_type.find(def.usr);
|
|
|
|
assert(it != usr_to_type.end());
|
2017-05-21 07:56:21 +00:00
|
|
|
|
2017-05-09 04:20:28 +00:00
|
|
|
assert(it->second.id >= 0 && it->second.id < types.size());
|
2017-10-17 05:44:58 +00:00
|
|
|
QueryType& existing = types[it->second.id];
|
2018-02-22 06:34:34 +00:00
|
|
|
if (!TryReplaceDef(existing.def, std::move(def.value))) {
|
2018-02-18 07:09:05 +00:00
|
|
|
existing.def.push_front(std::move(def.value));
|
2018-02-11 18:25:37 +00:00
|
|
|
UpdateSymbols(&existing.symbol_idx, SymbolKind::Type, it->second);
|
2018-02-04 02:34:07 +00:00
|
|
|
}
|
2017-02-26 19:45:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
void QueryDatabase::ImportOrUpdate(
|
2018-02-07 05:26:38 +00:00
|
|
|
std::vector<QueryFunc::DefUpdate>&& updates) {
|
2017-04-19 06:56:37 +00:00
|
|
|
// This function runs on the querydb thread.
|
|
|
|
|
2017-04-07 05:42:57 +00:00
|
|
|
for (auto& def : updates) {
|
2017-12-12 07:56:50 +00:00
|
|
|
assert(!def.value.detailed_name.empty());
|
2017-04-08 06:45:28 +00:00
|
|
|
|
2017-05-09 04:20:28 +00:00
|
|
|
auto it = usr_to_func.find(def.usr);
|
|
|
|
assert(it != usr_to_func.end());
|
2017-05-09 01:21:21 +00:00
|
|
|
|
2017-05-09 04:20:28 +00:00
|
|
|
assert(it->second.id >= 0 && it->second.id < funcs.size());
|
2017-10-17 05:44:58 +00:00
|
|
|
QueryFunc& existing = funcs[it->second.id];
|
2018-02-18 08:02:19 +00:00
|
|
|
if (!TryReplaceDef(existing.def, std::move(def.value))) {
|
2018-02-18 07:09:05 +00:00
|
|
|
existing.def.push_front(std::move(def.value));
|
2018-02-11 18:25:37 +00:00
|
|
|
UpdateSymbols(&existing.symbol_idx, SymbolKind::Func, it->second);
|
2018-02-04 02:34:07 +00:00
|
|
|
}
|
2017-02-26 19:45:59 +00:00
|
|
|
}
|
|
|
|
}
|
2017-02-26 08:11:47 +00:00
|
|
|
|
2018-02-07 05:26:38 +00:00
|
|
|
void QueryDatabase::ImportOrUpdate(std::vector<QueryVar::DefUpdate>&& updates) {
|
2017-04-19 06:56:37 +00:00
|
|
|
// This function runs on the querydb thread.
|
|
|
|
|
2017-04-07 05:42:57 +00:00
|
|
|
for (auto& def : updates) {
|
2017-12-12 07:56:50 +00:00
|
|
|
assert(!def.value.detailed_name.empty());
|
2017-04-08 06:45:28 +00:00
|
|
|
|
2017-05-09 04:20:28 +00:00
|
|
|
auto it = usr_to_var.find(def.usr);
|
|
|
|
assert(it != usr_to_var.end());
|
2017-05-09 01:21:21 +00:00
|
|
|
|
2017-05-09 04:20:28 +00:00
|
|
|
assert(it->second.id >= 0 && it->second.id < vars.size());
|
2017-10-17 05:44:58 +00:00
|
|
|
QueryVar& existing = vars[it->second.id];
|
2018-02-18 08:02:19 +00:00
|
|
|
if (!TryReplaceDef(existing.def, std::move(def.value))) {
|
2018-02-18 05:52:14 +00:00
|
|
|
existing.def.push_front(std::move(def.value));
|
|
|
|
if (!existing.def.front().is_local())
|
2018-02-11 18:25:37 +00:00
|
|
|
UpdateSymbols(&existing.symbol_idx, SymbolKind::Var, it->second);
|
2018-02-04 02:34:07 +00:00
|
|
|
}
|
2017-02-26 08:11:47 +00:00
|
|
|
}
|
2017-02-26 19:45:59 +00:00
|
|
|
}
|
2017-02-26 08:11:47 +00:00
|
|
|
|
2018-02-02 06:47:22 +00:00
|
|
|
void QueryDatabase::UpdateSymbols(Maybe<Id<void>>* symbol_idx,
|
2018-02-02 01:59:01 +00:00
|
|
|
SymbolKind kind,
|
2018-02-11 18:25:37 +00:00
|
|
|
Id<void> idx) {
|
2018-04-08 06:32:35 +00:00
|
|
|
if (!symbol_idx->Valid()) {
|
2018-02-02 06:47:22 +00:00
|
|
|
*symbol_idx = Id<void>(symbols.size());
|
2018-02-10 00:42:33 +00:00
|
|
|
symbols.push_back(SymbolIdx{idx, kind});
|
2017-02-26 08:11:47 +00:00
|
|
|
}
|
2017-05-09 01:21:21 +00:00
|
|
|
}
|
2017-05-12 06:08:15 +00:00
|
|
|
|
2018-04-06 00:00:07 +00:00
|
|
|
std::string_view QueryDatabase::GetSymbolName(RawId symbol_idx,
|
|
|
|
bool qualified) const {
|
2018-02-11 18:25:37 +00:00
|
|
|
RawId idx = symbols[symbol_idx].id.id;
|
2018-02-02 01:59:01 +00:00
|
|
|
switch (symbols[symbol_idx].kind) {
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
case SymbolKind::File:
|
|
|
|
if (files[idx].def)
|
|
|
|
return files[idx].def->path;
|
|
|
|
break;
|
|
|
|
case SymbolKind::Func:
|
2018-02-26 02:45:46 +00:00
|
|
|
if (const auto* def = funcs[idx].AnyDef())
|
2018-04-06 00:00:07 +00:00
|
|
|
return def->Name(qualified);
|
2018-02-02 01:59:01 +00:00
|
|
|
break;
|
|
|
|
case SymbolKind::Type:
|
2018-02-18 05:52:14 +00:00
|
|
|
if (const auto* def = types[idx].AnyDef())
|
2018-04-06 00:00:07 +00:00
|
|
|
return def->Name(qualified);
|
2018-02-02 01:59:01 +00:00
|
|
|
break;
|
|
|
|
case SymbolKind::Var:
|
2018-02-18 05:52:14 +00:00
|
|
|
if (const auto* def = vars[idx].AnyDef())
|
2018-04-06 00:00:07 +00:00
|
|
|
return def->Name(qualified);
|
2018-02-02 01:59:01 +00:00
|
|
|
break;
|
2018-02-02 01:24:46 +00:00
|
|
|
}
|
2018-02-02 01:59:01 +00:00
|
|
|
return "";
|
2018-02-02 01:24:46 +00:00
|
|
|
}
|