{Index,Query}Type::uses: Range/QueryLocation -> Reference

And add serialization for Reference
This commit is contained in:
Fangrui Song 2018-02-08 10:38:27 -08:00
parent 5f85867f88
commit 2d255da07b
9 changed files with 159 additions and 63 deletions

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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),

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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();
}

View File

@ -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;