{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 // static
const int IndexFile::kMajorVersion = 11; const int IndexFile::kMajorVersion = 11;
const int IndexFile::kMinorVersion = 2; const int IndexFile::kMinorVersion = 3;
IndexFile::IndexFile(const std::string& path, IndexFile::IndexFile(const std::string& path,
const std::string& contents) const std::string& contents)
@ -693,6 +693,20 @@ void UniqueAdd(std::vector<T>& values, T value) {
values.push_back(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) IdCache::IdCache(const std::string& primary_file)
: primary_file(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 // seems no way to extract the spelling range of `type` and we do
// not want to do subtraction here. // not want to do subtraction here.
// See https://github.com/jacobdufault/cquery/issues/252 // 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()); 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->def.parents.push_back(parent_id);
} }
} }
ns->uses.push_back(decl_spell); AddUse(ns->uses, decl_spell);
break; break;
} }
@ -1745,7 +1759,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
if (!enum_type.is_fundamental()) { if (!enum_type.is_fundamental()) {
IndexType* int_type = IndexType* int_type =
db->Resolve(db->ToTypeId(enum_type.get_usr_hash())); 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 is invalidated.
type = db->Resolve(type_id); type = db->Resolve(type_id);
} }
@ -1899,7 +1913,7 @@ void OnIndexReference(CXClientData client_data, const CXIdxEntityRefInfo* ref) {
case CXIdxEntity_CXXNamespace: { case CXIdxEntity_CXXNamespace: {
ClangCursor referenced = ref->referencedEntity->cursor; ClangCursor referenced = ref->referencedEntity->cursor;
IndexType* ns = db->Resolve(db->ToTypeId(referenced.get_usr_hash())); 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; break;
} }
@ -2352,3 +2366,42 @@ void Reflect(Writer& visitor, IndexFuncRef& value) {
Reflect(visitor, value.role); 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 IdCache;
struct IndexLocation { struct Reference {
Range loc; Range range;
Id<void> parent_id; Id<void> lex_parent_id;
SymbolKind parent_kind = SymbolKind::Invalid; SymbolKind lex_parent_kind;
SymbolRole role = SymbolRole::None; 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 { struct IndexFuncRef {
// NOTE: id can be -1 if the function call is not coming from a function. // 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(Reader& visitor, IndexFuncRef& value);
void Reflect(Writer& visitor, IndexFuncRef& value); void Reflect(Writer& visitor, IndexFuncRef& value);
void Reflect(Reader& visitor, Reference& value);
void Reflect(Writer& visitor, Reference& value);
template <typename FileId, template <typename FileId,
typename TypeId, typename TypeId,
@ -209,7 +220,7 @@ struct IndexType {
// Every usage, useful for things like renames. // Every usage, useful for things like renames.
// NOTE: Do not insert directly! Use AddUsage instead. // NOTE: Do not insert directly! Use AddUsage instead.
std::vector<Range> uses; std::vector<Reference> uses;
IndexType() {} // For serialization. IndexType() {} // For serialization.
IndexType(IndexTypeId id, Usr usr); IndexType(IndexTypeId id, Usr usr);

View File

@ -154,8 +154,13 @@ struct TextDocumentCodeLensHandler
continue; continue;
if (type.def->kind == ClangSymbolKind::Namespace) if (type.def->kind == ClangSymbolKind::Namespace)
continue; 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), AddCodeLens("ref", "refs", &common, ref.loc.OffsetStartColumn(0),
type.uses, type.def->definition_spelling, uses, type.def->definition_spelling,
true /*force_display*/); true /*force_display*/);
AddCodeLens("derived", "derived", &common, AddCodeLens("derived", "derived", &common,
ref.loc.OffsetStartColumn(1), ref.loc.OffsetStartColumn(1),

View File

@ -254,8 +254,8 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IdMap& id_map, const IndexFile& in
*type.def.definition_spelling); *type.def.definition_spelling);
if (type.def.definition_extent.has_value()) if (type.def.definition_extent.has_value())
add_outline(id_map.ToSymbol(type.id), *type.def.definition_extent); add_outline(id_map.ToSymbol(type.id), *type.def.definition_extent);
for (const Range& use : type.uses) for (const Reference& use : type.uses)
add_all_symbols(id_map.ToSymbol(type.id), SymbolRole::Reference, use); add_all_symbols(id_map.ToSymbol(type.id), use.role, use.range);
} }
for (const IndexFunc& func : indexed.funcs) { for (const IndexFunc& func : indexed.funcs) {
if (func.def.definition_spelling.has_value()) if (func.def.definition_spelling.has_value())
@ -372,34 +372,6 @@ Maybe<QueryVarId> GetQueryVarIdFromUsr(QueryDatabase* query_db,
} // namespace } // 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( Maybe<QueryFileId> QueryDatabase::GetQueryFileIdFromPath(
const std::string& path) { const std::string& path) {
return ::GetQueryFileIdFromPath(this, path, false); 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 { QueryLocation IdMap::ToQuery(Range range, SymbolRole role) const {
return QueryLocation{range, primary_file, role}; 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 { QueryTypeId IdMap::ToQuery(IndexTypeId id) const {
assert(cached_type_ids_.find(id) != cached_type_ids_.end()); assert(cached_type_ids_.find(id) != cached_type_ids_.end());
return QueryTypeId(cached_type_ids_.find(id)->second); 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_derived, derived, QueryTypeId);
PROCESS_UPDATE_DIFF(QueryTypeId, types_instances, instances, PROCESS_UPDATE_DIFF(QueryTypeId, types_instances, instances,
QueryVarId); QueryVarId);
PROCESS_UPDATE_DIFF(QueryTypeId, types_uses, uses, QueryLocation); PROCESS_UPDATE_DIFF(QueryTypeId, types_uses, uses, Reference);
}); });
// Functions // Functions
@ -1032,7 +1026,7 @@ TEST_SUITE("query") {
IndexFile current("foo.cc", "<empty>"); IndexFile current("foo.cc", "<empty>");
previous.Resolve(previous.ToTypeId(HashUsr("usr1"))) 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"))) previous.Resolve(previous.ToFuncId(HashUsr("usr2")))
->callers.push_back(IndexFuncRef{Range(Position(2, 0)), IndexFuncId(0), ->callers.push_back(IndexFuncRef{Range(Position(2, 0)), IndexFuncId(0),
SymbolRole::None}); SymbolRole::None});
@ -1078,8 +1072,8 @@ TEST_SUITE("query") {
IndexType* pt = previous.Resolve(previous.ToTypeId(HashUsr("usr"))); IndexType* pt = previous.Resolve(previous.ToTypeId(HashUsr("usr")));
IndexType* ct = current.Resolve(current.ToTypeId(HashUsr("usr"))); IndexType* ct = current.Resolve(current.ToTypeId(HashUsr("usr")));
pt->uses.push_back(Range(Position(1, 0))); pt->uses.push_back(Reference{Range(Position(1, 0))});
ct->uses.push_back(Range(Position(2, 0))); ct->uses.push_back(Reference{Range(Position(2, 0))});
IndexUpdate update = GetDelta(previous, current); IndexUpdate update = GetDelta(previous, current);

View File

@ -57,15 +57,6 @@ struct hash<::SymbolKind> {
}; };
} // namespace std } // 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 { struct SymbolIdx {
SymbolKind kind; SymbolKind kind;
RawId idx; RawId idx;
@ -235,14 +226,14 @@ struct QueryType {
using DefUpdate = WithUsr<Def>; using DefUpdate = WithUsr<Def>;
using DerivedUpdate = MergeableUpdate<QueryTypeId, QueryTypeId>; using DerivedUpdate = MergeableUpdate<QueryTypeId, QueryTypeId>;
using InstancesUpdate = MergeableUpdate<QueryTypeId, QueryVarId>; using InstancesUpdate = MergeableUpdate<QueryTypeId, QueryVarId>;
using UsesUpdate = MergeableUpdate<QueryTypeId, QueryLocation>; using UsesUpdate = MergeableUpdate<QueryTypeId, Reference>;
Usr usr; Usr usr;
Maybe<Id<void>> symbol_idx; Maybe<Id<void>> symbol_idx;
optional<Def> def; optional<Def> def;
std::vector<QueryTypeId> derived; std::vector<QueryTypeId> derived;
std::vector<QueryVarId> instances; std::vector<QueryVarId> instances;
std::vector<QueryLocation> uses; std::vector<Reference> uses;
explicit QueryType(const Usr& usr) : usr(usr) {} 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<IndexVarId> { using type = QueryVarId; };
template <> struct IndexToQuery<IndexFuncRef> { using type = QueryFuncRef; }; template <> struct IndexToQuery<IndexFuncRef> { using type = QueryFuncRef; };
template <> struct IndexToQuery<Range> { using type = QueryLocation; }; template <> struct IndexToQuery<Range> { using type = QueryLocation; };
template <> struct IndexToQuery<Reference> { using type = Reference; };
template <> struct IndexToQuery<IndexFunc::Declaration> { using type = QueryLocation; }; template <> struct IndexToQuery<IndexFunc::Declaration> { using type = QueryLocation; };
template <typename I> struct IndexToQuery<optional<I>> { template <typename I> struct IndexToQuery<optional<I>> {
using type = optional<typename IndexToQuery<I>::type>; using type = optional<typename IndexToQuery<I>::type>;
@ -428,6 +420,7 @@ struct IdMap {
// FIXME Too verbose // FIXME Too verbose
// clang-format off // clang-format off
QueryLocation ToQuery(Range range, SymbolRole role) const; QueryLocation ToQuery(Range range, SymbolRole role) const;
Reference ToQuery(Reference ref) const;
QueryTypeId ToQuery(IndexTypeId id) const; QueryTypeId ToQuery(IndexTypeId id) const;
QueryFuncId ToQuery(IndexFuncId id) const; QueryFuncId ToQuery(IndexFuncId id) const;
QueryVarId ToQuery(IndexVarId 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<IndexFuncId, QueryFuncId> cached_func_ids_;
spp::sparse_hash_map<IndexVarId, QueryVarId> cached_var_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; 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 } // namespace
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db, optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
@ -151,6 +179,10 @@ optional<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db,
return nullopt; return nullopt;
} }
QueryLocation ToQueryLocation(QueryDatabase* db, Reference ref) {
return QueryLocation{ref.range, GetFileId(db, ref), ref.role};
}
std::vector<QueryLocation> ToQueryLocation( std::vector<QueryLocation> ToQueryLocation(
QueryDatabase* db, QueryDatabase* db,
const std::vector<QueryFuncRef>& refs) { const std::vector<QueryFuncRef>& refs) {
@ -182,7 +214,10 @@ std::vector<QueryLocation> GetUsesOfSymbol(QueryDatabase* db,
switch (symbol.kind) { switch (symbol.kind) {
case SymbolKind::Type: { case SymbolKind::Type: {
QueryType& type = db->types[symbol.idx]; 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) if (include_decl && type.def && type.def->definition_spelling)
ret.push_back(*type.def->definition_spelling); ret.push_back(*type.def->definition_spelling);
return ret; return ret;

View File

@ -19,6 +19,8 @@ optional<QueryLocation> GetDefinitionExtentOfSymbol(QueryDatabase* db,
const SymbolIdx& symbol); const SymbolIdx& symbol);
optional<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db, optional<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db,
const SymbolIdx& symbol); const SymbolIdx& symbol);
QueryLocation ToQueryLocation(QueryDatabase* db, Reference ref);
std::vector<QueryLocation> ToQueryLocation( std::vector<QueryLocation> ToQueryLocation(
QueryDatabase* db, QueryDatabase* db,
const std::vector<QueryFuncRef>& refs); const std::vector<QueryFuncRef>& refs);

View File

@ -44,7 +44,7 @@ void Reflect(Writer& visitor, int& value) {
} }
void Reflect(Reader& visitor, unsigned& value) { void Reflect(Reader& visitor, unsigned& value) {
if (!visitor.IsInt()) if (!visitor.IsUint64())
throw std::invalid_argument("unsigned"); throw std::invalid_argument("unsigned");
value = visitor.GetUint32(); value = visitor.GetUint32();
} }

View File

@ -109,9 +109,10 @@ void DiffDocuments(std::string path,
void VerifySerializeToFrom(IndexFile* file) { void VerifySerializeToFrom(IndexFile* file) {
std::string expected = file->ToString(); std::string expected = file->ToString();
std::unique_ptr<IndexFile> result = Deserialize( std::string serialized = Serialize(SerializeFormat::Json, *file);
SerializeFormat::Json, "--.cc", Serialize(SerializeFormat::Json, *file), "<empty>", std::unique_ptr<IndexFile> result =
nullopt /*expected_version*/); Deserialize(SerializeFormat::Json, "--.cc", serialized, "<empty>",
nullopt /*expected_version*/);
std::string actual = result->ToString(); std::string actual = result->ToString();
if (expected != actual) { if (expected != actual) {
std::cerr << "Serialization failure" << std::endl; std::cerr << "Serialization failure" << std::endl;