mirror of
https://github.com/MaskRay/ccls.git
synced 2025-01-18 19:45:49 +00:00
{Index,Query}Type::uses: Range/QueryLocation -> Reference
And add serialization for Reference
This commit is contained in:
parent
5f85867f88
commit
2d255da07b
@ -603,7 +603,7 @@ void OnIndexReference_Function(IndexFile* db,
|
||||
|
||||
// static
|
||||
const int IndexFile::kMajorVersion = 11;
|
||||
const int IndexFile::kMinorVersion = 2;
|
||||
const int IndexFile::kMinorVersion = 3;
|
||||
|
||||
IndexFile::IndexFile(const std::string& path,
|
||||
const std::string& contents)
|
||||
@ -693,6 +693,20 @@ void UniqueAdd(std::vector<T>& values, T value) {
|
||||
values.push_back(value);
|
||||
}
|
||||
|
||||
// FIXME Reference: set lex_parent_id in call sites and remove this
|
||||
void AddUse(std::vector<Reference>& values, Range value) {
|
||||
values.push_back(Reference{value, Id<void>(), SymbolKind::Invalid,
|
||||
SymbolRole::Reference});
|
||||
}
|
||||
|
||||
// FIXME Reference: set lex_parent_id in call sites and remove this
|
||||
void UniqueAdd(std::vector<Reference>& values, Range value) {
|
||||
if (std::find_if(values.begin(), values.end(), [&](const Reference& ref) {
|
||||
return ref.range == value;
|
||||
}) == values.end())
|
||||
AddUse(values, value);
|
||||
}
|
||||
|
||||
IdCache::IdCache(const std::string& primary_file)
|
||||
: primary_file(primary_file) {}
|
||||
|
||||
@ -1238,7 +1252,7 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor,
|
||||
// seems no way to extract the spelling range of `type` and we do
|
||||
// not want to do subtraction here.
|
||||
// See https://github.com/jacobdufault/cquery/issues/252
|
||||
ref_type_index->uses.push_back(ref_cursor.get_extent());
|
||||
UniqueAdd(ref_type_index->uses, ref_cursor.get_extent());
|
||||
}
|
||||
}
|
||||
UniqueAdd(ref_index->uses, cursor.get_spelling_range());
|
||||
@ -1439,7 +1453,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
ns->def.parents.push_back(parent_id);
|
||||
}
|
||||
}
|
||||
ns->uses.push_back(decl_spell);
|
||||
AddUse(ns->uses, decl_spell);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1745,7 +1759,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
if (!enum_type.is_fundamental()) {
|
||||
IndexType* int_type =
|
||||
db->Resolve(db->ToTypeId(enum_type.get_usr_hash()));
|
||||
int_type->uses.push_back(decl_spell);
|
||||
AddUse(int_type->uses, decl_spell);
|
||||
// type is invalidated.
|
||||
type = db->Resolve(type_id);
|
||||
}
|
||||
@ -1899,7 +1913,7 @@ void OnIndexReference(CXClientData client_data, const CXIdxEntityRefInfo* ref) {
|
||||
case CXIdxEntity_CXXNamespace: {
|
||||
ClangCursor referenced = ref->referencedEntity->cursor;
|
||||
IndexType* ns = db->Resolve(db->ToTypeId(referenced.get_usr_hash()));
|
||||
ns->uses.push_back(cursor.get_spelling_range());
|
||||
AddUse(ns->uses, cursor.get_spelling_range());
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2352,3 +2366,42 @@ void Reflect(Writer& visitor, IndexFuncRef& value) {
|
||||
Reflect(visitor, value.role);
|
||||
}
|
||||
}
|
||||
|
||||
void Reflect(Reader& visitor, Reference& value) {
|
||||
if (visitor.Format() == SerializeFormat::Json) {
|
||||
std::string s = visitor.GetString();
|
||||
value = Reference{};
|
||||
value.range = Range(s.c_str());
|
||||
auto sep = s.find('|');
|
||||
if (sep == std::string::npos)
|
||||
value.role = SymbolRole::Reference;
|
||||
else {
|
||||
char* p = const_cast<char*>(s.c_str()) + sep;
|
||||
value.role = SymbolRole(strtol(p + 1, &p, 10));
|
||||
value.lex_parent_kind = SymbolKind(strtol(p + 1, &p, 10));
|
||||
value.lex_parent_id = Id<void>(strtol(p + 1, &p, 10));
|
||||
}
|
||||
} else {
|
||||
Reflect(visitor, value.range);
|
||||
Reflect(visitor, value.lex_parent_id);
|
||||
Reflect(visitor, value.lex_parent_kind);
|
||||
Reflect(visitor, value.role);
|
||||
}
|
||||
}
|
||||
void Reflect(Writer& visitor, Reference& value) {
|
||||
if (visitor.Format() == SerializeFormat::Json) {
|
||||
std::string s = value.range.ToString();
|
||||
if (value.role != SymbolRole::Reference ||
|
||||
value.lex_parent_kind != SymbolKind::Invalid) {
|
||||
s += '|' + std::to_string(uint8_t(value.role));
|
||||
s += '|' + std::to_string(uint8_t(value.lex_parent_kind));
|
||||
s += '|' + std::to_string(RawId(value.lex_parent_id));
|
||||
}
|
||||
visitor.String(s.c_str());
|
||||
} else {
|
||||
Reflect(visitor, value.range);
|
||||
Reflect(visitor, value.lex_parent_id);
|
||||
Reflect(visitor, value.lex_parent_kind);
|
||||
Reflect(visitor, value.role);
|
||||
}
|
||||
}
|
||||
|
@ -78,13 +78,22 @@ using IndexVarId = Id<IndexVar>;
|
||||
|
||||
struct IdCache;
|
||||
|
||||
struct IndexLocation {
|
||||
Range loc;
|
||||
Id<void> parent_id;
|
||||
SymbolKind parent_kind = SymbolKind::Invalid;
|
||||
SymbolRole role = SymbolRole::None;
|
||||
struct Reference {
|
||||
Range range;
|
||||
Id<void> lex_parent_id;
|
||||
SymbolKind lex_parent_kind;
|
||||
SymbolRole role;
|
||||
|
||||
std::tuple<Range, Id<void>, SymbolKind, SymbolRole> ToTuple() const {
|
||||
return std::make_tuple(range, lex_parent_id, lex_parent_kind, role);
|
||||
}
|
||||
bool operator==(const Reference& o) const {
|
||||
return ToTuple() == o.ToTuple();
|
||||
}
|
||||
bool operator<(const Reference& o) const {
|
||||
return ToTuple() < o.ToTuple();
|
||||
}
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(IndexLocation, loc, parent_id, parent_kind, role);
|
||||
|
||||
struct IndexFuncRef {
|
||||
// NOTE: id can be -1 if the function call is not coming from a function.
|
||||
@ -104,6 +113,8 @@ struct IndexFuncRef {
|
||||
|
||||
void Reflect(Reader& visitor, IndexFuncRef& value);
|
||||
void Reflect(Writer& visitor, IndexFuncRef& value);
|
||||
void Reflect(Reader& visitor, Reference& value);
|
||||
void Reflect(Writer& visitor, Reference& value);
|
||||
|
||||
template <typename FileId,
|
||||
typename TypeId,
|
||||
@ -209,7 +220,7 @@ struct IndexType {
|
||||
|
||||
// Every usage, useful for things like renames.
|
||||
// NOTE: Do not insert directly! Use AddUsage instead.
|
||||
std::vector<Range> uses;
|
||||
std::vector<Reference> uses;
|
||||
|
||||
IndexType() {} // For serialization.
|
||||
IndexType(IndexTypeId id, Usr usr);
|
||||
|
@ -154,8 +154,13 @@ struct TextDocumentCodeLensHandler
|
||||
continue;
|
||||
if (type.def->kind == ClangSymbolKind::Namespace)
|
||||
continue;
|
||||
// FIXME QueryRef
|
||||
std::vector<QueryLocation> uses;
|
||||
uses.reserve(type.uses.size());
|
||||
for (auto& x : type.uses)
|
||||
uses.push_back(ToQueryLocation(db, x));
|
||||
AddCodeLens("ref", "refs", &common, ref.loc.OffsetStartColumn(0),
|
||||
type.uses, type.def->definition_spelling,
|
||||
uses, type.def->definition_spelling,
|
||||
true /*force_display*/);
|
||||
AddCodeLens("derived", "derived", &common,
|
||||
ref.loc.OffsetStartColumn(1),
|
||||
|
62
src/query.cc
62
src/query.cc
@ -254,8 +254,8 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IdMap& id_map, const IndexFile& in
|
||||
*type.def.definition_spelling);
|
||||
if (type.def.definition_extent.has_value())
|
||||
add_outline(id_map.ToSymbol(type.id), *type.def.definition_extent);
|
||||
for (const Range& use : type.uses)
|
||||
add_all_symbols(id_map.ToSymbol(type.id), SymbolRole::Reference, use);
|
||||
for (const Reference& use : type.uses)
|
||||
add_all_symbols(id_map.ToSymbol(type.id), use.role, use.range);
|
||||
}
|
||||
for (const IndexFunc& func : indexed.funcs) {
|
||||
if (func.def.definition_spelling.has_value())
|
||||
@ -372,34 +372,6 @@ Maybe<QueryVarId> GetQueryVarIdFromUsr(QueryDatabase* query_db,
|
||||
|
||||
} // namespace
|
||||
|
||||
QueryFileId QueryRef::FileId(QueryDatabase* db) const {
|
||||
switch (lex_parent_kind) {
|
||||
case SymbolKind::Invalid:
|
||||
break;
|
||||
case SymbolKind::File:
|
||||
return QueryFileId(lex_parent_id);
|
||||
case SymbolKind::Func: {
|
||||
QueryFunc& file = db->funcs[lex_parent_id.id];
|
||||
if (file.def)
|
||||
return file.def->file;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Type: {
|
||||
QueryType& type = db->types[lex_parent_id.id];
|
||||
if (type.def)
|
||||
return type.def->file;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
QueryVar& var = db->vars[lex_parent_id.id];
|
||||
if (var.def)
|
||||
return var.def->file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return QueryFileId();
|
||||
}
|
||||
|
||||
Maybe<QueryFileId> QueryDatabase::GetQueryFileIdFromPath(
|
||||
const std::string& path) {
|
||||
return ::GetQueryFileIdFromPath(this, path, false);
|
||||
@ -442,6 +414,28 @@ IdMap::IdMap(QueryDatabase* query_db, const IdCache& local_ids)
|
||||
QueryLocation IdMap::ToQuery(Range range, SymbolRole role) const {
|
||||
return QueryLocation{range, primary_file, role};
|
||||
}
|
||||
Reference IdMap::ToQuery(Reference ref) const {
|
||||
switch (ref.lex_parent_kind) {
|
||||
case SymbolKind::Invalid:
|
||||
case SymbolKind::File:
|
||||
ref.lex_parent_kind = SymbolKind::File;
|
||||
ref.lex_parent_id = Id<void>(primary_file);
|
||||
break;
|
||||
case SymbolKind::Func:
|
||||
ref.lex_parent_id = Id<void>(
|
||||
cached_func_ids_.find(IndexFuncId(ref.lex_parent_id))->second);
|
||||
break;
|
||||
case SymbolKind::Type:
|
||||
ref.lex_parent_id = Id<void>(
|
||||
cached_type_ids_.find(IndexTypeId(ref.lex_parent_id))->second);
|
||||
break;
|
||||
case SymbolKind::Var:
|
||||
ref.lex_parent_id =
|
||||
Id<void>(cached_var_ids_.find(IndexVarId(ref.lex_parent_id))->second);
|
||||
break;
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
QueryTypeId IdMap::ToQuery(IndexTypeId id) const {
|
||||
assert(cached_type_ids_.find(id) != cached_type_ids_.end());
|
||||
return QueryTypeId(cached_type_ids_.find(id)->second);
|
||||
@ -591,7 +585,7 @@ IndexUpdate::IndexUpdate(const IdMap& previous_id_map,
|
||||
PROCESS_UPDATE_DIFF(QueryTypeId, types_derived, derived, QueryTypeId);
|
||||
PROCESS_UPDATE_DIFF(QueryTypeId, types_instances, instances,
|
||||
QueryVarId);
|
||||
PROCESS_UPDATE_DIFF(QueryTypeId, types_uses, uses, QueryLocation);
|
||||
PROCESS_UPDATE_DIFF(QueryTypeId, types_uses, uses, Reference);
|
||||
});
|
||||
|
||||
// Functions
|
||||
@ -1032,7 +1026,7 @@ TEST_SUITE("query") {
|
||||
IndexFile current("foo.cc", "<empty>");
|
||||
|
||||
previous.Resolve(previous.ToTypeId(HashUsr("usr1")))
|
||||
->uses.push_back(Range(Position(1, 0)));
|
||||
->uses.push_back(Reference{Range(Position(1, 0))});
|
||||
previous.Resolve(previous.ToFuncId(HashUsr("usr2")))
|
||||
->callers.push_back(IndexFuncRef{Range(Position(2, 0)), IndexFuncId(0),
|
||||
SymbolRole::None});
|
||||
@ -1078,8 +1072,8 @@ TEST_SUITE("query") {
|
||||
IndexType* pt = previous.Resolve(previous.ToTypeId(HashUsr("usr")));
|
||||
IndexType* ct = current.Resolve(current.ToTypeId(HashUsr("usr")));
|
||||
|
||||
pt->uses.push_back(Range(Position(1, 0)));
|
||||
ct->uses.push_back(Range(Position(2, 0)));
|
||||
pt->uses.push_back(Reference{Range(Position(1, 0))});
|
||||
ct->uses.push_back(Reference{Range(Position(2, 0))});
|
||||
|
||||
IndexUpdate update = GetDelta(previous, current);
|
||||
|
||||
|
17
src/query.h
17
src/query.h
@ -57,15 +57,6 @@ struct hash<::SymbolKind> {
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
struct QueryRef {
|
||||
Range range;
|
||||
Id<void> lex_parent_id;
|
||||
SymbolKind lex_parent_kind;
|
||||
SymbolRole role;
|
||||
QueryFileId FileId(QueryDatabase*) const;
|
||||
};
|
||||
//MAKE_REFLECT_STRUCT(QueryRef, range, lex_parent_id, lex_parent_kind, role);
|
||||
|
||||
struct SymbolIdx {
|
||||
SymbolKind kind;
|
||||
RawId idx;
|
||||
@ -235,14 +226,14 @@ struct QueryType {
|
||||
using DefUpdate = WithUsr<Def>;
|
||||
using DerivedUpdate = MergeableUpdate<QueryTypeId, QueryTypeId>;
|
||||
using InstancesUpdate = MergeableUpdate<QueryTypeId, QueryVarId>;
|
||||
using UsesUpdate = MergeableUpdate<QueryTypeId, QueryLocation>;
|
||||
using UsesUpdate = MergeableUpdate<QueryTypeId, Reference>;
|
||||
|
||||
Usr usr;
|
||||
Maybe<Id<void>> symbol_idx;
|
||||
optional<Def> def;
|
||||
std::vector<QueryTypeId> derived;
|
||||
std::vector<QueryVarId> instances;
|
||||
std::vector<QueryLocation> uses;
|
||||
std::vector<Reference> uses;
|
||||
|
||||
explicit QueryType(const Usr& usr) : usr(usr) {}
|
||||
};
|
||||
@ -410,6 +401,7 @@ template <> struct IndexToQuery<IndexTypeId> { using type = QueryTypeId; };
|
||||
template <> struct IndexToQuery<IndexVarId> { using type = QueryVarId; };
|
||||
template <> struct IndexToQuery<IndexFuncRef> { using type = QueryFuncRef; };
|
||||
template <> struct IndexToQuery<Range> { using type = QueryLocation; };
|
||||
template <> struct IndexToQuery<Reference> { using type = Reference; };
|
||||
template <> struct IndexToQuery<IndexFunc::Declaration> { using type = QueryLocation; };
|
||||
template <typename I> struct IndexToQuery<optional<I>> {
|
||||
using type = optional<typename IndexToQuery<I>::type>;
|
||||
@ -428,6 +420,7 @@ struct IdMap {
|
||||
// FIXME Too verbose
|
||||
// clang-format off
|
||||
QueryLocation ToQuery(Range range, SymbolRole role) const;
|
||||
Reference ToQuery(Reference ref) const;
|
||||
QueryTypeId ToQuery(IndexTypeId id) const;
|
||||
QueryFuncId ToQuery(IndexFuncId id) const;
|
||||
QueryVarId ToQuery(IndexVarId id) const;
|
||||
@ -459,3 +452,5 @@ struct IdMap {
|
||||
spp::sparse_hash_map<IndexFuncId, QueryFuncId> cached_func_ids_;
|
||||
spp::sparse_hash_map<IndexVarId, QueryVarId> cached_var_ids_;
|
||||
};
|
||||
|
||||
QueryFileId GetFileId(const Reference& ref, QueryDatabase* db);
|
||||
|
@ -28,6 +28,34 @@ std::vector<QueryLocation> ToQueryLocationHelper(
|
||||
return locs;
|
||||
}
|
||||
|
||||
QueryFileId GetFileId(QueryDatabase* db, Reference ref) {
|
||||
switch (ref.lex_parent_kind) {
|
||||
case SymbolKind::Invalid:
|
||||
break;
|
||||
case SymbolKind::File:
|
||||
return QueryFileId(ref.lex_parent_id);
|
||||
case SymbolKind::Func: {
|
||||
QueryFunc& file = db->funcs[ref.lex_parent_id.id];
|
||||
if (file.def)
|
||||
return file.def->file;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Type: {
|
||||
QueryType& type = db->types[ref.lex_parent_id.id];
|
||||
if (type.def)
|
||||
return type.def->file;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
QueryVar& var = db->vars[ref.lex_parent_id.id];
|
||||
if (var.def)
|
||||
return var.def->file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return QueryFileId();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
|
||||
@ -151,6 +179,10 @@ optional<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db,
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
QueryLocation ToQueryLocation(QueryDatabase* db, Reference ref) {
|
||||
return QueryLocation{ref.range, GetFileId(db, ref), ref.role};
|
||||
}
|
||||
|
||||
std::vector<QueryLocation> ToQueryLocation(
|
||||
QueryDatabase* db,
|
||||
const std::vector<QueryFuncRef>& refs) {
|
||||
@ -182,7 +214,10 @@ std::vector<QueryLocation> GetUsesOfSymbol(QueryDatabase* db,
|
||||
switch (symbol.kind) {
|
||||
case SymbolKind::Type: {
|
||||
QueryType& type = db->types[symbol.idx];
|
||||
std::vector<QueryLocation> ret = type.uses;
|
||||
std::vector<QueryLocation> ret;
|
||||
ret.reserve(type.uses.size());
|
||||
for (auto& x : type.uses)
|
||||
ret.push_back(ToQueryLocation(db, x));
|
||||
if (include_decl && type.def && type.def->definition_spelling)
|
||||
ret.push_back(*type.def->definition_spelling);
|
||||
return ret;
|
||||
|
@ -19,6 +19,8 @@ optional<QueryLocation> GetDefinitionExtentOfSymbol(QueryDatabase* db,
|
||||
const SymbolIdx& symbol);
|
||||
optional<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db,
|
||||
const SymbolIdx& symbol);
|
||||
|
||||
QueryLocation ToQueryLocation(QueryDatabase* db, Reference ref);
|
||||
std::vector<QueryLocation> ToQueryLocation(
|
||||
QueryDatabase* db,
|
||||
const std::vector<QueryFuncRef>& refs);
|
||||
|
@ -44,7 +44,7 @@ void Reflect(Writer& visitor, int& value) {
|
||||
}
|
||||
|
||||
void Reflect(Reader& visitor, unsigned& value) {
|
||||
if (!visitor.IsInt())
|
||||
if (!visitor.IsUint64())
|
||||
throw std::invalid_argument("unsigned");
|
||||
value = visitor.GetUint32();
|
||||
}
|
||||
|
@ -109,9 +109,10 @@ void DiffDocuments(std::string path,
|
||||
|
||||
void VerifySerializeToFrom(IndexFile* file) {
|
||||
std::string expected = file->ToString();
|
||||
std::unique_ptr<IndexFile> result = Deserialize(
|
||||
SerializeFormat::Json, "--.cc", Serialize(SerializeFormat::Json, *file), "<empty>",
|
||||
nullopt /*expected_version*/);
|
||||
std::string serialized = Serialize(SerializeFormat::Json, *file);
|
||||
std::unique_ptr<IndexFile> result =
|
||||
Deserialize(SerializeFormat::Json, "--.cc", serialized, "<empty>",
|
||||
nullopt /*expected_version*/);
|
||||
std::string actual = result->ToString();
|
||||
if (expected != actual) {
|
||||
std::cerr << "Serialization failure" << std::endl;
|
||||
|
Loading…
Reference in New Issue
Block a user