mirror of
https://github.com/MaskRay/ccls.git
synced 2025-02-21 07:59:27 +00:00
wip
This commit is contained in:
parent
cf6456c904
commit
ae993d6446
@ -30,8 +30,16 @@ const int kQueueSizeBytes = 1024 * 8;
|
||||
}
|
||||
|
||||
struct IndexTranslationUnitRequest {
|
||||
enum class Type {
|
||||
Import,
|
||||
Update
|
||||
};
|
||||
|
||||
std::string path;
|
||||
std::vector<std::string> args;
|
||||
Type type;
|
||||
|
||||
IndexTranslationUnitRequest(Type type) : type(type) {}
|
||||
};
|
||||
|
||||
struct IndexTranslationUnitResponse {
|
||||
@ -152,23 +160,39 @@ void RegisterMessageTypes() {
|
||||
MessageRegistry::instance()->Register<Ipc_WorkspaceSymbol>();
|
||||
}
|
||||
|
||||
void WriteToCache(std::string filename, IndexedFile& file) {
|
||||
std::string GetCachedFileName(std::string source_file) {
|
||||
// TODO/FIXME
|
||||
const char* kCacheDirectory = "C:/Users/jacob/Desktop/superindex/indexer/CACHE/";
|
||||
|
||||
|
||||
std::replace(filename.begin(), filename.end(), '\\', '_');
|
||||
std::replace(filename.begin(), filename.end(), '/', '_');
|
||||
std::replace(filename.begin(), filename.end(), ':', '_');
|
||||
std::replace(filename.begin(), filename.end(), '.', '_');
|
||||
std::string cache_file = kCacheDirectory + filename + ".json";
|
||||
std::replace(source_file.begin(), source_file.end(), '\\', '_');
|
||||
std::replace(source_file.begin(), source_file.end(), '/', '_');
|
||||
std::replace(source_file.begin(), source_file.end(), ':', '_');
|
||||
std::replace(source_file.begin(), source_file.end(), '.', '_');
|
||||
return kCacheDirectory + source_file + ".json";
|
||||
}
|
||||
|
||||
optional<IndexedFile> LoadCachedFile(std::string filename) {
|
||||
// TODO FIXME FIXME FIXME
|
||||
return nullopt;
|
||||
|
||||
std::string cache_file = GetCachedFileName(filename);
|
||||
|
||||
std::ifstream cache;
|
||||
cache.open(GetCachedFileName(filename));
|
||||
if (!cache.good())
|
||||
return nullopt;
|
||||
|
||||
std::string file_content = std::string(
|
||||
std::istreambuf_iterator<char>(cache),
|
||||
std::istreambuf_iterator<char>());
|
||||
|
||||
return Deserialize(filename, file_content);
|
||||
}
|
||||
|
||||
void WriteToCache(std::string filename, IndexedFile& file) {
|
||||
std::string indexed_content = Serialize(file);
|
||||
|
||||
|
||||
std::cerr << "Caching to " << cache_file << std::endl;
|
||||
std::ofstream cache;
|
||||
cache.open(cache_file);
|
||||
cache.open(GetCachedFileName(filename));
|
||||
assert(cache.good());
|
||||
cache << indexed_content;
|
||||
cache.close();
|
||||
@ -184,24 +208,60 @@ void IndexMain(IndexRequestQueue* requests, IndexResponseQueue* responses) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Timer time;
|
||||
|
||||
// If the index update is an import, then we will load the previous index
|
||||
// into memory if we have a previous index. After that, we dispatch an
|
||||
// update request to get the latest version.
|
||||
if (request->type == IndexTranslationUnitRequest::Type::Import) {
|
||||
request->type = IndexTranslationUnitRequest::Type::Update;
|
||||
|
||||
// TODO: we're not serializing out the files cache. We only ever want to import references
|
||||
// from the primary file though, so that should be ok. We need to cleanup indexer output.
|
||||
optional<IndexedFile> old_index = LoadCachedFile(request->path);
|
||||
if (old_index.has_value()) {
|
||||
IndexUpdate update(old_index.value());
|
||||
IndexTranslationUnitResponse response(update);
|
||||
responses->Enqueue(response);
|
||||
time.ResetAndPrint("Loading cached index");
|
||||
requests->Enqueue(request.value());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
assert(request->type == IndexTranslationUnitRequest::Type::Update);
|
||||
|
||||
// Parse request and send a response.
|
||||
std::cerr << "Parsing file " << request->path << " with args "
|
||||
<< Join(request->args, ", ") << std::endl;
|
||||
|
||||
Timer time;
|
||||
IndexedFile file = Parse(request->path, request->args);
|
||||
IndexedFile new_index = Parse(request->path, request->args);
|
||||
time.ResetAndPrint("Parsing/indexing");
|
||||
|
||||
// TODO: Check cache for existing index; compute diff if there is one.
|
||||
IndexUpdate update(file);
|
||||
IndexTranslationUnitResponse response(update);
|
||||
time.ResetAndPrint("Creating index update/response");
|
||||
|
||||
responses->Enqueue(response);
|
||||
time.ResetAndPrint("Sending update to server");
|
||||
// If we have a cached index, that means it is already imported, which
|
||||
// means we want to apply a delta update.
|
||||
optional<IndexedFile> old_index = LoadCachedFile(request->path);
|
||||
time.ResetAndPrint("Loading previous index");
|
||||
if (old_index) {
|
||||
// Apply delta update.
|
||||
IndexUpdate update(old_index.value(), new_index);
|
||||
IndexTranslationUnitResponse response(update);
|
||||
time.ResetAndPrint("Creating delta index update/response");
|
||||
responses->Enqueue(response);
|
||||
time.ResetAndPrint("Sending update to server");
|
||||
}
|
||||
else {
|
||||
// Apply full update.
|
||||
IndexUpdate update(new_index);
|
||||
IndexTranslationUnitResponse response(update);
|
||||
time.ResetAndPrint("Creating index update/response");
|
||||
responses->Enqueue(response);
|
||||
time.ResetAndPrint("Sending update to server");
|
||||
}
|
||||
|
||||
// Cache file so we can diff it later.
|
||||
WriteToCache(request->path, file);
|
||||
WriteToCache(request->path, new_index);
|
||||
time.ResetAndPrint("Cache index update to disk");
|
||||
}
|
||||
}
|
||||
@ -230,6 +290,7 @@ lsLocation GetLsLocation(const QueryableLocation& location) {
|
||||
void AddCodeLens(std::vector<TCodeLens>* result,
|
||||
QueryableLocation loc,
|
||||
const std::vector<QueryableLocation>& uses,
|
||||
bool exclude_loc,
|
||||
bool only_interesting,
|
||||
const char* singular,
|
||||
const char* plural) {
|
||||
@ -248,6 +309,8 @@ void AddCodeLens(std::vector<TCodeLens>* result,
|
||||
// Add unique uses.
|
||||
std::unordered_set<lsLocation> unique_uses;
|
||||
for (const QueryableLocation& use : uses) {
|
||||
if (exclude_loc && use == loc)
|
||||
continue;
|
||||
if (only_interesting && !use.interesting)
|
||||
continue;
|
||||
unique_uses.insert(GetLsLocation(use));
|
||||
@ -263,13 +326,14 @@ void AddCodeLens(std::vector<TCodeLens>* result,
|
||||
else
|
||||
code_lens.command->title += plural;
|
||||
|
||||
if (unique_uses.size() > 0)
|
||||
if (exclude_loc || unique_uses.size() > 0)
|
||||
result->push_back(code_lens);
|
||||
}
|
||||
|
||||
void AddCodeLens(std::vector<TCodeLens>* result,
|
||||
QueryableLocation loc,
|
||||
const std::vector<UsrRef>& uses,
|
||||
bool exclude_loc,
|
||||
bool only_interesting,
|
||||
const char* singular,
|
||||
const char* plural) {
|
||||
@ -277,13 +341,14 @@ void AddCodeLens(std::vector<TCodeLens>* result,
|
||||
uses0.reserve(uses.size());
|
||||
for (const UsrRef& use : uses)
|
||||
uses0.push_back(use.loc);
|
||||
AddCodeLens(result, loc, uses0, only_interesting, singular, plural);
|
||||
AddCodeLens(result, loc, uses0, exclude_loc, only_interesting, singular, plural);
|
||||
}
|
||||
|
||||
void AddCodeLens(std::vector<TCodeLens>* result,
|
||||
QueryableDatabase* db,
|
||||
QueryableLocation loc,
|
||||
const std::vector<Usr>& usrs,
|
||||
bool exclude_loc,
|
||||
bool only_interesting,
|
||||
const char* singular,
|
||||
const char* plural) {
|
||||
@ -317,7 +382,7 @@ void AddCodeLens(std::vector<TCodeLens>* result,
|
||||
}
|
||||
}
|
||||
}
|
||||
AddCodeLens(result, loc, uses0, only_interesting, singular, plural);
|
||||
AddCodeLens(result, loc, uses0, exclude_loc, only_interesting, singular, plural);
|
||||
}
|
||||
|
||||
void QueryDbMainLoop(
|
||||
@ -362,7 +427,7 @@ void QueryDbMainLoop(
|
||||
<< "] Dispatching index request for file " << filepath
|
||||
<< std::endl;
|
||||
|
||||
IndexTranslationUnitRequest request;
|
||||
IndexTranslationUnitRequest request(IndexTranslationUnitRequest::Type::Import);
|
||||
request.path = filepath;
|
||||
request.args = entry.args;
|
||||
index_requests->Enqueue(request);
|
||||
@ -488,34 +553,39 @@ void QueryDbMainLoop(
|
||||
}
|
||||
|
||||
for (UsrRef ref : file->outline) {
|
||||
// NOTE: We OffsetColumn so that the code lens always show up in a
|
||||
// predictable order. Otherwise, the client may randomize it.
|
||||
|
||||
SymbolIdx symbol = db->usr_to_symbol[ref.usr];
|
||||
switch (symbol.kind) {
|
||||
case SymbolKind::Type: {
|
||||
QueryableTypeDef& def = db->types[symbol.idx];
|
||||
AddCodeLens(&response.result, ref.loc, def.uses,
|
||||
true /*only_interesting*/, "reference",
|
||||
AddCodeLens(&response.result, ref.loc.OffsetColumn(0), def.uses,
|
||||
false /*exclude_loc*/, true /*only_interesting*/, "reference",
|
||||
"references");
|
||||
AddCodeLens(&response.result, db, ref.loc, def.derived,
|
||||
false /*only_interesting*/, "derived", "derived");
|
||||
AddCodeLens(&response.result, db, ref.loc.OffsetColumn(1), def.derived,
|
||||
false /*exclude_loc*/, false /*only_interesting*/, "derived", "derived");
|
||||
AddCodeLens(&response.result, db, ref.loc.OffsetColumn(2), def.instantiations,
|
||||
false /*exclude_loc*/, false /*only_interesting*/, "instantiation", "instantiations");
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Func: {
|
||||
QueryableFuncDef& def = db->funcs[symbol.idx];
|
||||
AddCodeLens(&response.result, ref.loc, def.uses,
|
||||
false /*only_interesting*/, "reference",
|
||||
"references");
|
||||
AddCodeLens(&response.result, ref.loc, def.callers,
|
||||
false /*only_interesting*/, "caller", "callers");
|
||||
AddCodeLens(&response.result, ref.loc, def.def.callees,
|
||||
false /*only_interesting*/, "callee", "callees");
|
||||
AddCodeLens(&response.result, db, ref.loc, def.derived,
|
||||
false /*only_interesting*/, "derived", "derived");
|
||||
//AddCodeLens(&response.result, ref.loc.OffsetColumn(0), def.uses,
|
||||
// false /*exclude_loc*/, false /*only_interesting*/, "reference",
|
||||
// "references");
|
||||
AddCodeLens(&response.result, ref.loc.OffsetColumn(1), def.callers,
|
||||
false /*exclude_loc*/, false /*only_interesting*/, "caller", "callers");
|
||||
AddCodeLens(&response.result, ref.loc.OffsetColumn(2), def.def.callees,
|
||||
false /*exclude_loc*/, false /*only_interesting*/, "callee", "callees");
|
||||
AddCodeLens(&response.result, db, ref.loc.OffsetColumn(3), def.derived,
|
||||
false /*exclude_loc*/, false /*only_interesting*/, "derived", "derived");
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
QueryableVarDef& def = db->vars[symbol.idx];
|
||||
AddCodeLens(&response.result, ref.loc, def.uses,
|
||||
false /*only_interesting*/, "reference",
|
||||
AddCodeLens(&response.result, ref.loc.OffsetColumn(0), def.uses,
|
||||
true /*exclude_loc*/, false /*only_interesting*/, "reference",
|
||||
"references");
|
||||
break;
|
||||
}
|
||||
@ -830,9 +900,10 @@ void LanguageServerMain(std::string process_name) {
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
bool loop = false;
|
||||
while (loop)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
//bool loop = true;
|
||||
//while (loop)
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
|
||||
PlatformInit();
|
||||
RegisterMessageTypes();
|
||||
|
214
src/indexer.cpp
214
src/indexer.cpp
@ -5,7 +5,7 @@
|
||||
|
||||
#include "serializer.h"
|
||||
|
||||
IndexedFile::IndexedFile(const std::string& path) : path(path) {
|
||||
IndexedFile::IndexedFile(const std::string& path) : id_cache(path), path(path) {
|
||||
// TODO: Reconsider if we should still be reusing the same id_cache.
|
||||
// Preallocate any existing resolved ids.
|
||||
for (const auto& entry : id_cache.usr_to_type_id)
|
||||
@ -119,13 +119,13 @@ std::string Location::ToPrettyString(IdCache* id_cache) {
|
||||
return result;
|
||||
}
|
||||
|
||||
IdCache::IdCache() {
|
||||
IdCache::IdCache(const std::string& primary_file) : primary_file(primary_file) {
|
||||
// Reserve id 0 for unfound.
|
||||
file_path_to_file_id[""] = FileId(0);
|
||||
file_id_to_file_path[FileId(0)] = "";
|
||||
}
|
||||
|
||||
Location IdCache::Resolve(const CXSourceLocation& cx_loc, bool interesting) {
|
||||
Location IdCache::ForceResolve(const CXSourceLocation& cx_loc, bool interesting) {
|
||||
CXFile file;
|
||||
unsigned int line, column, offset;
|
||||
clang_getSpellingLocation(cx_loc, &file, &line, &column, &offset);
|
||||
@ -137,7 +137,8 @@ Location IdCache::Resolve(const CXSourceLocation& cx_loc, bool interesting) {
|
||||
auto it = file_path_to_file_id.find(path);
|
||||
if (it != file_path_to_file_id.end()) {
|
||||
file_id = it->second;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
file_id = FileId(file_path_to_file_id.size());
|
||||
file_path_to_file_id[path] = file_id;
|
||||
file_id_to_file_path[file_id] = path;
|
||||
@ -147,16 +148,32 @@ Location IdCache::Resolve(const CXSourceLocation& cx_loc, bool interesting) {
|
||||
return Location(interesting, file_id, line, column);
|
||||
}
|
||||
|
||||
Location IdCache::Resolve(const CXIdxLoc& cx_idx_loc, bool interesting) {
|
||||
Location IdCache::ForceResolve(const CXIdxLoc& cx_idx_loc, bool interesting) {
|
||||
CXSourceLocation cx_loc = clang_indexLoc_getCXSourceLocation(cx_idx_loc);
|
||||
return ForceResolve(cx_loc, interesting);
|
||||
}
|
||||
|
||||
Location IdCache::ForceResolve(const CXCursor& cx_cursor, bool interesting) {
|
||||
return ForceResolve(clang_getCursorLocation(cx_cursor), interesting);
|
||||
}
|
||||
|
||||
|
||||
optional<Location> IdCache::Resolve(const CXSourceLocation& cx_loc, bool interesting) {
|
||||
if (!clang_Location_isFromMainFile(cx_loc))
|
||||
return nullopt;
|
||||
return ForceResolve(cx_loc, interesting);
|
||||
}
|
||||
|
||||
optional<Location> IdCache::Resolve(const CXIdxLoc& cx_idx_loc, bool interesting) {
|
||||
CXSourceLocation cx_loc = clang_indexLoc_getCXSourceLocation(cx_idx_loc);
|
||||
return Resolve(cx_loc, interesting);
|
||||
}
|
||||
|
||||
Location IdCache::Resolve(const CXCursor& cx_cursor, bool interesting) {
|
||||
optional<Location> IdCache::Resolve(const CXCursor& cx_cursor, bool interesting) {
|
||||
return Resolve(clang_getCursorLocation(cx_cursor), interesting);
|
||||
}
|
||||
|
||||
Location IdCache::Resolve(const clang::Cursor& cursor, bool interesting) {
|
||||
optional<Location> IdCache::Resolve(const clang::Cursor& cursor, bool interesting) {
|
||||
return Resolve(cursor.cx_cursor, interesting);
|
||||
}
|
||||
|
||||
@ -236,7 +253,7 @@ void diagnostic(CXClientData client_data,
|
||||
|
||||
std::string spelling =
|
||||
clang::ToString(clang_getDiagnosticSpelling(diagnostic));
|
||||
Location location = param->db->id_cache.Resolve(
|
||||
Location location = param->db->id_cache.ForceResolve(
|
||||
clang_getDiagnosticLocation(diagnostic), false /*interesting*/);
|
||||
|
||||
std::cerr << location.ToPrettyString(¶m->db->id_cache) << ": "
|
||||
@ -386,8 +403,11 @@ void VisitDeclForTypeUsageVisitorHandler(clang::Cursor cursor,
|
||||
|
||||
if (param->is_interesting) {
|
||||
IndexedTypeDef* ref_type_def = db->Resolve(ref_type_id);
|
||||
Location loc = db->id_cache.Resolve(cursor, true /*interesting*/);
|
||||
AddUsage(ref_type_def->uses, loc);
|
||||
// TODO: Should we even be visiting this if the file is not from the main
|
||||
// def? Try adding assert on |loc| later.
|
||||
optional<Location> loc = db->id_cache.Resolve(cursor, true /*interesting*/);
|
||||
if (loc)
|
||||
AddUsage(ref_type_def->uses, loc.value());
|
||||
}
|
||||
}
|
||||
|
||||
@ -451,13 +471,10 @@ optional<TypeId> ResolveToDeclarationType(IndexedFile* db,
|
||||
}
|
||||
|
||||
// Add usages to any seen TypeRef or TemplateRef under the given |decl_cursor|.
|
||||
// This
|
||||
// returns the first seen TypeRef or TemplateRef value, which can be useful if
|
||||
// trying
|
||||
// to figure out ie, what a using statement refers to. If trying to generally
|
||||
// resolve
|
||||
// a cursor to a type, use ResolveToDeclarationType, which works in more
|
||||
// scenarios.
|
||||
// This returns the first seen TypeRef or TemplateRef value, which can be
|
||||
// useful if trying to figure out ie, what a using statement refers to. If
|
||||
// trying to generally resolve a cursor to a type, use
|
||||
// ResolveToDeclarationType, which works in more scenarios.
|
||||
optional<TypeId> AddDeclTypeUsages(
|
||||
IndexedFile* db,
|
||||
clang::Cursor decl_cursor,
|
||||
@ -638,12 +655,14 @@ clang::VisiterResult AddDeclInitializerUsagesVisitor(clang::Cursor cursor,
|
||||
if (ref_usr == "")
|
||||
break;
|
||||
|
||||
VarId ref_id = db->ToVarId(ref_usr);
|
||||
IndexedVarDef* ref_def = db->Resolve(ref_id);
|
||||
Location loc = db->id_cache.Resolve(cursor, false /*interesting*/);
|
||||
optional<Location> loc = db->id_cache.Resolve(cursor, false /*interesting*/);
|
||||
// std::cerr << "Adding usage to id=" << ref_id.id << " usr=" << ref_usr
|
||||
// << " at " << loc.ToString() << std::endl;
|
||||
AddUsage(ref_def->uses, loc);
|
||||
if (loc) {
|
||||
VarId ref_id = db->ToVarId(ref_usr);
|
||||
IndexedVarDef* ref_def = db->Resolve(ref_id);
|
||||
AddUsage(ref_def->uses, loc.value());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -680,6 +699,11 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
case CXIdxEntity_Field:
|
||||
case CXIdxEntity_Variable:
|
||||
case CXIdxEntity_CXXStaticVariable: {
|
||||
optional<Location> decl_loc =
|
||||
db->id_cache.Resolve(decl->loc, false /*interesting*/);
|
||||
if (!decl_loc)
|
||||
break;
|
||||
|
||||
clang::Cursor decl_cursor = decl->cursor;
|
||||
|
||||
// Do not index implicit template instantiations.
|
||||
@ -692,8 +716,6 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
VarId var_id = db->ToVarId(decl->entityInfo->USR);
|
||||
IndexedVarDef* var_def = db->Resolve(var_id);
|
||||
|
||||
var_def->is_bad_def = is_system_def;
|
||||
|
||||
// TODO: Eventually run with this if. Right now I want to iron out bugs
|
||||
// this may shadow.
|
||||
// TODO: Verify this gets called multiple times
|
||||
@ -703,13 +725,11 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
ns->QualifiedName(decl->semanticContainer, var_def->def.short_name);
|
||||
//}
|
||||
|
||||
Location decl_loc =
|
||||
db->id_cache.Resolve(decl->loc, false /*interesting*/);
|
||||
if (decl->isDefinition)
|
||||
var_def->def.definition = decl_loc;
|
||||
var_def->def.definition = decl_loc.value();
|
||||
else
|
||||
var_def->def.declaration = decl_loc;
|
||||
AddUsage(var_def->uses, decl_loc);
|
||||
var_def->def.declaration = decl_loc.value();
|
||||
AddUsage(var_def->uses, decl_loc.value());
|
||||
|
||||
// std::cerr << std::endl << "Visiting declaration" << std::endl;
|
||||
// Dump(decl_cursor);
|
||||
@ -725,13 +745,25 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
db, decl_cursor,
|
||||
decl_cursor.get_kind() != CXCursor_ParmDecl /*is_interesting*/,
|
||||
decl->semanticContainer, decl->lexicalContainer);
|
||||
optional<TypeId> var_type = ResolveToDeclarationType(db, decl_cursor);
|
||||
if (var_type.has_value())
|
||||
var_def->def.variable_type = var_type.value();
|
||||
|
||||
// We don't need to assign declaring type multiple times if this variable
|
||||
// has already been seen.
|
||||
if (!decl->isRedeclaration) {
|
||||
optional<TypeId> var_type = ResolveToDeclarationType(db, decl_cursor);
|
||||
if (var_type.has_value()) {
|
||||
// Don't treat enum definition variables as instantiations.
|
||||
bool is_enum_member = decl->semanticContainer && decl->semanticContainer->cursor.kind == CXCursor_EnumDecl;
|
||||
if (!is_enum_member)
|
||||
db->Resolve(var_type.value())->instantiations.push_back(var_id.id);
|
||||
|
||||
var_def->def.variable_type = var_type.value();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Refactor handlers so more things are under 'if (!decl->isRedeclaration)'
|
||||
if (decl->isDefinition && IsTypeDefinition(decl->semanticContainer)) {
|
||||
TypeId declaring_type_id =
|
||||
db->ToTypeId(decl->semanticContainer->cursor);
|
||||
db->ToTypeId(decl->semanticContainer->cursor);
|
||||
IndexedTypeDef* declaring_type_def = db->Resolve(declaring_type_id);
|
||||
var_def->def.declaring_type = declaring_type_id;
|
||||
declaring_type_def->def.vars.push_back(var_id);
|
||||
@ -746,6 +778,11 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
case CXIdxEntity_CXXInstanceMethod:
|
||||
case CXIdxEntity_CXXStaticMethod:
|
||||
case CXIdxEntity_CXXConversionFunction: {
|
||||
optional<Location> decl_loc =
|
||||
db->id_cache.Resolve(decl->loc, false /*interesting*/);
|
||||
if (!decl_loc)
|
||||
break;
|
||||
|
||||
clang::Cursor decl_cursor = decl->cursor;
|
||||
clang::Cursor resolved =
|
||||
decl_cursor.template_specialization_to_template_definition();
|
||||
@ -753,10 +790,7 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
FuncId func_id = db->ToFuncId(resolved.cx_cursor);
|
||||
IndexedFuncDef* func_def = db->Resolve(func_id);
|
||||
|
||||
Location decl_loc =
|
||||
db->id_cache.Resolve(decl->loc, false /*interesting*/);
|
||||
|
||||
AddUsage(func_def->uses, decl_loc);
|
||||
AddUsage(func_def->uses, decl_loc.value());
|
||||
// We don't actually need to know the return type, but we need to mark it
|
||||
// as an interesting usage.
|
||||
AddDeclTypeUsages(db, decl_cursor, true /*is_interesting*/,
|
||||
@ -766,9 +800,9 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
// hacking the 'declarations' field by
|
||||
// adding a definition when we really don't have one.
|
||||
if (decl->isDefinition && !func_def->def.definition.has_value())
|
||||
func_def->def.definition = decl_loc;
|
||||
func_def->def.definition = decl_loc.value();
|
||||
else
|
||||
func_def->declarations.push_back(decl_loc);
|
||||
func_def->declarations.push_back(decl_loc.value());
|
||||
|
||||
// If decl_cursor != resolved, then decl_cursor is a template
|
||||
// specialization. We
|
||||
@ -776,8 +810,6 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
// that
|
||||
// scenario.
|
||||
if (decl_cursor == resolved) {
|
||||
func_def->is_bad_def = is_system_def;
|
||||
|
||||
// TODO: Eventually run with this if. Right now I want to iron out bugs
|
||||
// this may shadow.
|
||||
// if (!decl->isRedeclaration) {
|
||||
@ -805,7 +837,7 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
// Mark a type reference at the ctor/dtor location.
|
||||
// TODO: Should it be interesting?
|
||||
if (is_ctor_or_dtor) {
|
||||
Location type_usage_loc = decl_loc;
|
||||
Location type_usage_loc = decl_loc.value();
|
||||
AddUsage(declaring_type_def->uses, type_usage_loc);
|
||||
}
|
||||
|
||||
@ -895,6 +927,10 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
|
||||
case CXIdxEntity_Typedef:
|
||||
case CXIdxEntity_CXXTypeAlias: {
|
||||
optional<Location> decl_loc = db->id_cache.Resolve(decl->loc, true /*interesting*/);
|
||||
if (!decl_loc)
|
||||
break;
|
||||
|
||||
// Note we want to fetch the first TypeRef. Running
|
||||
// ResolveCursorType(decl->cursor) would return
|
||||
// the type of the typedef/using, not the type of the referenced type.
|
||||
@ -905,8 +941,6 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
TypeId type_id = db->ToTypeId(decl->entityInfo->USR);
|
||||
IndexedTypeDef* type_def = db->Resolve(type_id);
|
||||
|
||||
type_def->is_bad_def = is_system_def;
|
||||
|
||||
if (alias_of)
|
||||
type_def->def.alias_of = alias_of.value();
|
||||
|
||||
@ -914,9 +948,8 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
type_def->def.qualified_name =
|
||||
ns->QualifiedName(decl->semanticContainer, type_def->def.short_name);
|
||||
|
||||
Location decl_loc = db->id_cache.Resolve(decl->loc, true /*interesting*/);
|
||||
type_def->def.definition = decl_loc.WithInteresting(false);
|
||||
AddUsage(type_def->uses, decl_loc);
|
||||
type_def->def.definition = decl_loc.value().WithInteresting(false);
|
||||
AddUsage(type_def->uses, decl_loc.value());
|
||||
break;
|
||||
}
|
||||
|
||||
@ -924,11 +957,13 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
case CXIdxEntity_Union:
|
||||
case CXIdxEntity_Struct:
|
||||
case CXIdxEntity_CXXClass: {
|
||||
optional<Location> decl_loc = db->id_cache.Resolve(decl->loc, true /*interesting*/);
|
||||
if (!decl_loc)
|
||||
break;
|
||||
|
||||
TypeId type_id = db->ToTypeId(decl->entityInfo->USR);
|
||||
IndexedTypeDef* type_def = db->Resolve(type_id);
|
||||
|
||||
type_def->is_bad_def = is_system_def;
|
||||
|
||||
// TODO: Eventually run with this if. Right now I want to iron out bugs
|
||||
// this may shadow.
|
||||
// TODO: For type section, verify if this ever runs for non definitions?
|
||||
@ -951,9 +986,8 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
// }
|
||||
|
||||
assert(decl->isDefinition);
|
||||
Location decl_loc = db->id_cache.Resolve(decl->loc, true /*interesting*/);
|
||||
type_def->def.definition = decl_loc.WithInteresting(false);
|
||||
AddUsage(type_def->uses, decl_loc);
|
||||
type_def->def.definition = decl_loc.value().WithInteresting(false);
|
||||
AddUsage(type_def->uses, decl_loc.value());
|
||||
|
||||
// type_def->alias_of
|
||||
// type_def->funcs
|
||||
@ -972,9 +1006,8 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
decl->semanticContainer, decl->lexicalContainer);
|
||||
optional<TypeId> parent_type_id =
|
||||
ResolveToDeclarationType(db, base_class->cursor);
|
||||
IndexedTypeDef* type_def =
|
||||
db->Resolve(type_id); // type_def ptr could be invalidated by
|
||||
// ResolveDeclToType.
|
||||
// type_def ptr could be invalidated by ResolveToDeclarationType.
|
||||
IndexedTypeDef* type_def = db->Resolve(type_id);
|
||||
if (parent_type_id) {
|
||||
IndexedTypeDef* parent_type_def =
|
||||
db->Resolve(parent_type_id.value());
|
||||
@ -990,7 +1023,7 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
std::cerr
|
||||
<< "!! Unhandled indexDeclaration: "
|
||||
<< clang::Cursor(decl->cursor).ToString() << " at "
|
||||
<< db->id_cache.Resolve(decl->loc, false /*interesting*/).ToString()
|
||||
<< db->id_cache.ForceResolve(decl->loc, false /*interesting*/).ToString()
|
||||
<< std::endl;
|
||||
std::cerr << " entityInfo->kind = " << decl->entityInfo->kind
|
||||
<< std::endl;
|
||||
@ -1024,9 +1057,16 @@ bool IsFunction(CXCursorKind kind) {
|
||||
|
||||
void indexEntityReference(CXClientData client_data,
|
||||
const CXIdxEntityRefInfo* ref) {
|
||||
if (clang_Location_isInSystemHeader(clang_getCursorLocation(ref->cursor)) ||
|
||||
clang_Location_isInSystemHeader(
|
||||
clang_getCursorLocation(ref->referencedEntity->cursor)))
|
||||
// if (clang_Location_isInSystemHeader(clang_getCursorLocation(ref->cursor)) ||
|
||||
// clang_Location_isInSystemHeader(
|
||||
// clang_getCursorLocation(ref->referencedEntity->cursor)))
|
||||
// return;
|
||||
|
||||
// Don't index references that are not from the main file.
|
||||
if (!clang_Location_isFromMainFile(clang_getCursorLocation(ref->cursor)))
|
||||
return;
|
||||
// Don't index references to system headers.
|
||||
if (clang_Location_isInSystemHeader(clang_getCursorLocation(ref->referencedEntity->cursor)))
|
||||
return;
|
||||
|
||||
IndexParam* param = static_cast<IndexParam*>(client_data);
|
||||
@ -1047,13 +1087,16 @@ void indexEntityReference(CXClientData client_data,
|
||||
case CXIdxEntity_CXXStaticVariable:
|
||||
case CXIdxEntity_Variable:
|
||||
case CXIdxEntity_Field: {
|
||||
optional<Location> loc = db->id_cache.Resolve(ref->loc, false /*interesting*/);
|
||||
if (!loc)
|
||||
break;
|
||||
|
||||
clang::Cursor referenced = ref->referencedEntity->cursor;
|
||||
referenced = referenced.template_specialization_to_template_definition();
|
||||
|
||||
VarId var_id = db->ToVarId(referenced.get_usr());
|
||||
IndexedVarDef* var_def = db->Resolve(var_id);
|
||||
Location loc = db->id_cache.Resolve(ref->loc, false /*interesting*/);
|
||||
AddUsage(var_def->uses, loc);
|
||||
AddUsage(var_def->uses, loc.value());
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1074,10 +1117,14 @@ void indexEntityReference(CXClientData client_data,
|
||||
|
||||
// Don't report duplicate usages.
|
||||
// TODO: search full history?
|
||||
Location loc = db->id_cache.Resolve(ref->loc, false /*interesting*/);
|
||||
if (param->last_func_usage_location == loc)
|
||||
optional<Location> loc = db->id_cache.Resolve(ref->loc, false /*interesting*/);
|
||||
if (!loc)
|
||||
break;
|
||||
param->last_func_usage_location = loc;
|
||||
|
||||
// TODO: cleanup/remove this
|
||||
if (param->last_func_usage_location == loc.value())
|
||||
break;
|
||||
param->last_func_usage_location = loc.value();
|
||||
|
||||
// Note: be careful, calling db->ToFuncId invalidates the FuncDef* ptrs.
|
||||
FuncId called_id = db->ToFuncId(ref->referencedEntity->USR);
|
||||
@ -1086,12 +1133,12 @@ void indexEntityReference(CXClientData client_data,
|
||||
IndexedFuncDef* caller_def = db->Resolve(caller_id);
|
||||
IndexedFuncDef* called_def = db->Resolve(called_id);
|
||||
|
||||
caller_def->def.callees.push_back(FuncRef(called_id, loc));
|
||||
called_def->callers.push_back(FuncRef(caller_id, loc));
|
||||
AddUsage(called_def->uses, loc);
|
||||
caller_def->def.callees.push_back(FuncRef(called_id, loc.value()));
|
||||
called_def->callers.push_back(FuncRef(caller_id, loc.value()));
|
||||
AddUsage(called_def->uses, loc.value());
|
||||
} else {
|
||||
IndexedFuncDef* called_def = db->Resolve(called_id);
|
||||
AddUsage(called_def->uses, loc);
|
||||
AddUsage(called_def->uses, loc.value());
|
||||
}
|
||||
|
||||
// For constructor/destructor, also add a usage against the type. Clang
|
||||
@ -1101,11 +1148,9 @@ void indexEntityReference(CXClientData client_data,
|
||||
clang::Cursor ref_cursor = ref->cursor;
|
||||
if (ref->referencedEntity->kind == CXIdxEntity_CXXConstructor ||
|
||||
ref->referencedEntity->kind == CXIdxEntity_CXXDestructor) {
|
||||
Location parent_loc = db->id_cache.Resolve(ref->parentEntity->cursor,
|
||||
Location parent_loc = db->id_cache.ForceResolve(ref->parentEntity->cursor,
|
||||
true /*interesting*/);
|
||||
Location our_loc =
|
||||
db->id_cache.Resolve(ref->loc, true /*is_interesting*/);
|
||||
if (!parent_loc.IsEqualTo(our_loc)) {
|
||||
if (!parent_loc.IsEqualTo(loc.value())) {
|
||||
IndexedFuncDef* called_def = db->Resolve(called_id);
|
||||
// I suspect it is possible for the declaring type to be null
|
||||
// when the class is invalid.
|
||||
@ -1113,7 +1158,7 @@ void indexEntityReference(CXClientData client_data,
|
||||
// assert(called_def->def.declaring_type.has_value());
|
||||
IndexedTypeDef* type_def =
|
||||
db->Resolve(called_def->def.declaring_type.value());
|
||||
AddUsage(type_def->uses, our_loc);
|
||||
AddUsage(type_def->uses, loc.value().WithInteresting(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1126,23 +1171,16 @@ void indexEntityReference(CXClientData client_data,
|
||||
case CXIdxEntity_Union:
|
||||
case CXIdxEntity_Struct:
|
||||
case CXIdxEntity_CXXClass: {
|
||||
optional<Location> loc = db->id_cache.Resolve(ref->loc, false /*interesting*/);
|
||||
if (!loc)
|
||||
break;
|
||||
|
||||
clang::Cursor referenced = ref->referencedEntity->cursor;
|
||||
referenced = referenced.template_specialization_to_template_definition();
|
||||
TypeId referenced_id = db->ToTypeId(referenced.get_usr());
|
||||
|
||||
IndexedTypeDef* referenced_def = db->Resolve(referenced_id);
|
||||
|
||||
// We will not get a declaration visit for forward declared types. Try to
|
||||
// mark them as non-bad
|
||||
// defs here so we will output usages/etc.
|
||||
if (referenced_def->is_bad_def) {
|
||||
bool is_system_def = clang_Location_isInSystemHeader(
|
||||
clang_getCursorLocation(ref->referencedEntity->cursor));
|
||||
Location loc = db->id_cache.Resolve(ref->referencedEntity->cursor,
|
||||
false /*interesting*/);
|
||||
if (!is_system_def && loc.raw_file_id != -1)
|
||||
referenced_def->is_bad_def = false;
|
||||
}
|
||||
//
|
||||
// The following will generate two TypeRefs to Foo, both located at the
|
||||
// same spot (line 3, column 3). One of the parents will be set to
|
||||
@ -1159,8 +1197,7 @@ void indexEntityReference(CXClientData client_data,
|
||||
// Foo f;
|
||||
// }
|
||||
//
|
||||
AddUsage(referenced_def->uses,
|
||||
db->id_cache.Resolve(ref->loc, false /*interesting*/));
|
||||
AddUsage(referenced_def->uses, loc.value());
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1168,7 +1205,7 @@ void indexEntityReference(CXClientData client_data,
|
||||
std::cerr
|
||||
<< "!! Unhandled indexEntityReference: " << cursor.ToString()
|
||||
<< " at "
|
||||
<< db->id_cache.Resolve(ref->loc, false /*interesting*/).ToString()
|
||||
<< db->id_cache.ForceResolve(ref->loc, false /*interesting*/).ToString()
|
||||
<< std::endl;
|
||||
std::cerr << " ref->referencedEntity->kind = "
|
||||
<< ref->referencedEntity->kind << std::endl;
|
||||
@ -1177,7 +1214,7 @@ void indexEntityReference(CXClientData client_data,
|
||||
<< ref->parentEntity->kind << std::endl;
|
||||
std::cerr
|
||||
<< " ref->loc = "
|
||||
<< db->id_cache.Resolve(ref->loc, false /*interesting*/).ToString()
|
||||
<< db->id_cache.ForceResolve(ref->loc, false /*interesting*/).ToString()
|
||||
<< std::endl;
|
||||
std::cerr << " ref->kind = " << ref->kind << std::endl;
|
||||
if (ref->parentEntity)
|
||||
@ -1239,8 +1276,7 @@ IndexedFile Parse(std::string filename,
|
||||
|
||||
std::cerr << "!! [START] Indexing " << filename << std::endl;
|
||||
clang_indexTranslationUnit(index_action, ¶m, callbacks, sizeof(callbacks),
|
||||
CXIndexOpt_IndexFunctionLocalSymbols |
|
||||
CXIndexOpt_SkipParsedBodiesInSession,
|
||||
CXIndexOpt_IndexFunctionLocalSymbols | CXIndexOpt_SkipParsedBodiesInSession | CXIndexOpt_IndexImplicitTemplateInstantiations,
|
||||
tu.cx_tu);
|
||||
std::cerr << "!! [END] Indexing " << filename << std::endl;
|
||||
clang_IndexAction_dispose(index_action);
|
||||
|
@ -323,16 +323,27 @@ struct IndexedTypeDef {
|
||||
// Immediate derived types.
|
||||
std::vector<TypeId> derived;
|
||||
|
||||
// Declared variables of this type.
|
||||
// TODO: this needs a lot more work and lots of tests.
|
||||
// TODO: add instantiation on ctor / dtor, do not add instantiation if type is ptr
|
||||
std::vector<VarId> instantiations;
|
||||
|
||||
// Every usage, useful for things like renames.
|
||||
// NOTE: Do not insert directly! Use AddUsage instead.
|
||||
std::vector<Location> uses;
|
||||
|
||||
bool is_bad_def = true;
|
||||
|
||||
IndexedTypeDef() : def("") {} // For serialization
|
||||
|
||||
IndexedTypeDef(TypeId id, const std::string& usr);
|
||||
|
||||
bool HasInterestingState() const {
|
||||
return
|
||||
def.definition ||
|
||||
!derived.empty() ||
|
||||
!instantiations.empty() ||
|
||||
!uses.empty();
|
||||
}
|
||||
|
||||
bool operator<(const IndexedTypeDef& other) const {
|
||||
return def.usr < other.def.usr;
|
||||
}
|
||||
@ -428,13 +439,21 @@ struct IndexedFuncDef {
|
||||
// All usages. For interesting usages, see callees.
|
||||
std::vector<Location> uses;
|
||||
|
||||
bool is_bad_def = true;
|
||||
|
||||
IndexedFuncDef() {} // For reflection.
|
||||
IndexedFuncDef(FuncId id, const std::string& usr) : def(usr), id(id) {
|
||||
// assert(usr.size() > 0);
|
||||
}
|
||||
|
||||
bool HasInterestingState() const {
|
||||
return
|
||||
def.definition ||
|
||||
!def.callees.empty() ||
|
||||
!declarations.empty() ||
|
||||
!derived.empty() ||
|
||||
!callers.empty() ||
|
||||
!uses.empty();
|
||||
}
|
||||
|
||||
bool operator<(const IndexedFuncDef& other) const {
|
||||
return def.usr < other.def.usr;
|
||||
}
|
||||
@ -503,14 +522,18 @@ struct IndexedVarDef {
|
||||
// Usages.
|
||||
std::vector<Location> uses;
|
||||
|
||||
bool is_bad_def = true;
|
||||
|
||||
IndexedVarDef() : def("") {} // For serialization
|
||||
|
||||
IndexedVarDef(VarId id, const std::string& usr) : def(usr), id(id) {
|
||||
// assert(usr.size() > 0);
|
||||
}
|
||||
|
||||
bool HasInterestingState() const {
|
||||
return
|
||||
def.definition ||
|
||||
!uses.empty();
|
||||
}
|
||||
|
||||
bool operator<(const IndexedVarDef& other) const {
|
||||
return def.usr < other.def.usr;
|
||||
}
|
||||
@ -518,6 +541,7 @@ struct IndexedVarDef {
|
||||
MAKE_HASHABLE(IndexedVarDef, t.def.usr);
|
||||
|
||||
struct IdCache {
|
||||
std::string primary_file;
|
||||
std::unordered_map<std::string, FileId> file_path_to_file_id;
|
||||
std::unordered_map<std::string, TypeId> usr_to_type_id;
|
||||
std::unordered_map<std::string, FuncId> usr_to_func_id;
|
||||
@ -527,11 +551,14 @@ struct IdCache {
|
||||
std::unordered_map<FuncId, std::string> func_id_to_usr;
|
||||
std::unordered_map<VarId, std::string> var_id_to_usr;
|
||||
|
||||
IdCache();
|
||||
Location Resolve(const CXSourceLocation& cx_loc, bool interesting);
|
||||
Location Resolve(const CXIdxLoc& cx_idx_loc, bool interesting);
|
||||
Location Resolve(const CXCursor& cx_cursor, bool interesting);
|
||||
Location Resolve(const clang::Cursor& cursor, bool interesting);
|
||||
IdCache(const std::string& primary_file);
|
||||
Location ForceResolve(const CXSourceLocation& cx_loc, bool interesting);
|
||||
Location ForceResolve(const CXIdxLoc& cx_idx_loc, bool interesting);
|
||||
Location ForceResolve(const CXCursor& cx_cursor, bool interesting);
|
||||
optional<Location> Resolve(const CXSourceLocation& cx_loc, bool interesting);
|
||||
optional<Location> Resolve(const CXIdxLoc& cx_idx_loc, bool interesting);
|
||||
optional<Location> Resolve(const CXCursor& cx_cursor, bool interesting);
|
||||
optional<Location> Resolve(const clang::Cursor& cursor, bool interesting);
|
||||
};
|
||||
|
||||
struct IndexedFile {
|
||||
|
@ -24,6 +24,11 @@ TranslationUnit::TranslationUnit(
|
||||
for (const auto& arg : platform_args)
|
||||
args.push_back(arg.c_str());
|
||||
|
||||
std::cerr << "Parsing " << filepath << " with args ";
|
||||
for (const auto& arg : args)
|
||||
std::cerr << arg << " ";
|
||||
std::cerr << std::endl;
|
||||
|
||||
CXErrorCode error_code = clang_parseTranslationUnit2(
|
||||
index.cx_index,
|
||||
filepath.c_str(),
|
||||
|
23
src/query.cc
23
src/query.cc
@ -46,8 +46,10 @@ Usr MapIdToUsr(const IdCache& id_cache, const VarId& id) {
|
||||
return id_cache.var_id_to_usr.find(id)->second;
|
||||
}
|
||||
QueryableLocation MapIdToUsr(const IdCache& id_cache, const Location& id) {
|
||||
assert(id_cache.file_id_to_file_path.find(id.file_id()) != id_cache.file_id_to_file_path.end());
|
||||
return QueryableLocation(id_cache.file_id_to_file_path.find(id.file_id())->second, id.line, id.column, id.interesting);
|
||||
assert(id.raw_file_id == 1);
|
||||
return QueryableLocation(id_cache.primary_file, id.line, id.column, id.interesting);
|
||||
//assert(id_cache.file_id_to_file_path.find(id.file_id()) != id_cache.file_id_to_file_path.end());
|
||||
//return QueryableLocation(id_cache.file_id_to_file_path.find(id.file_id())->second, id.line, id.column, id.interesting);
|
||||
}
|
||||
|
||||
std::vector<Usr> MapIdToUsr(const IdCache& id_cache, const std::vector<TypeId>& ids) {
|
||||
@ -173,6 +175,7 @@ QueryableFile::QueryableFile(const IndexedFile& indexed)
|
||||
QueryableTypeDef::QueryableTypeDef(IdCache& id_cache, const IndexedTypeDef& indexed)
|
||||
: def(MapIdToUsr(id_cache, indexed.def)) {
|
||||
derived = MapIdToUsr(id_cache, indexed.derived);
|
||||
instantiations = MapIdToUsr(id_cache, indexed.instantiations);
|
||||
uses = MapIdToUsr(id_cache, indexed.uses);
|
||||
}
|
||||
|
||||
@ -314,12 +317,12 @@ void CompareGroups(
|
||||
while (prev_it != previous_data.end() && curr_it != current_data.end()) {
|
||||
// same id
|
||||
if (prev_it->def.usr == curr_it->def.usr) {
|
||||
if (!prev_it->is_bad_def && !curr_it->is_bad_def)
|
||||
//if (!prev_it->is_bad_def && !curr_it->is_bad_def)
|
||||
on_found(&*prev_it, &*curr_it);
|
||||
else if (prev_it->is_bad_def)
|
||||
on_added(&*curr_it);
|
||||
else if (curr_it->is_bad_def)
|
||||
on_removed(&*curr_it);
|
||||
//else if (prev_it->is_bad_def)
|
||||
// on_added(&*curr_it);
|
||||
//else if (curr_it->is_bad_def)
|
||||
// on_removed(&*curr_it);
|
||||
|
||||
++prev_it;
|
||||
++curr_it;
|
||||
@ -368,17 +371,16 @@ void CompareGroups(
|
||||
|
||||
|
||||
IndexUpdate::IndexUpdate(IndexedFile& file) {
|
||||
// TODO: Do not add empty data (ie, def has nothing but USR)
|
||||
|
||||
files_added.push_back(QueryableFile(file));
|
||||
for (const IndexedTypeDef& def : file.types) {
|
||||
if (def.is_bad_def) continue;
|
||||
types_added.push_back(QueryableTypeDef(file.id_cache, def));
|
||||
}
|
||||
for (const IndexedFuncDef& def : file.funcs) {
|
||||
if (def.is_bad_def) continue;
|
||||
funcs_added.push_back(QueryableFuncDef(file.id_cache, def));
|
||||
}
|
||||
for (const IndexedVarDef& def : file.vars) {
|
||||
if (def.is_bad_def) continue;
|
||||
vars_added.push_back(QueryableVarDef(file.id_cache, def));
|
||||
}
|
||||
}
|
||||
@ -491,6 +493,7 @@ void IndexUpdate::Merge(const IndexUpdate& update) {
|
||||
INDEX_UPDATE_MERGE(types_added);
|
||||
INDEX_UPDATE_MERGE(types_def_changed);
|
||||
INDEX_UPDATE_MERGE(types_derived);
|
||||
INDEX_UPDATE_MERGE(types_instantiations);
|
||||
INDEX_UPDATE_MERGE(types_uses);
|
||||
|
||||
INDEX_UPDATE_MERGE(funcs_removed);
|
||||
|
@ -22,6 +22,10 @@ struct QueryableLocation {
|
||||
QueryableLocation(Usr path, int line, int column, bool interesting)
|
||||
: path(path), line(line), column(column), interesting(interesting) {}
|
||||
|
||||
QueryableLocation OffsetColumn(int offset) const {
|
||||
return QueryableLocation(path, line, column + offset, interesting);
|
||||
}
|
||||
|
||||
bool operator==(const QueryableLocation& other) const {
|
||||
// Note: We ignore |is_interesting|.
|
||||
return
|
||||
@ -104,16 +108,18 @@ MAKE_REFLECT_STRUCT(QueryableFile, file_id, outline);
|
||||
struct QueryableTypeDef {
|
||||
using DefUpdate = TypeDefDefinitionData<Usr, Usr, Usr, QueryableLocation>;
|
||||
using DerivedUpdate = MergeableUpdate<Usr>;
|
||||
using InstantiationsUpdate = MergeableUpdate<Usr>;
|
||||
using UsesUpdate = MergeableUpdate<QueryableLocation>;
|
||||
|
||||
DefUpdate def;
|
||||
std::vector<Usr> derived;
|
||||
std::vector<Usr> instantiations;
|
||||
std::vector<QueryableLocation> uses;
|
||||
|
||||
QueryableTypeDef() : def("") {} // For serialization.
|
||||
QueryableTypeDef(IdCache& id_cache, const IndexedTypeDef& indexed);
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(QueryableTypeDef, def, derived, uses);
|
||||
MAKE_REFLECT_STRUCT(QueryableTypeDef, def, derived, instantiations, uses);
|
||||
|
||||
struct QueryableFuncDef {
|
||||
using DefUpdate = FuncDefDefinitionData<Usr, Usr, Usr, UsrRef, QueryableLocation>;
|
||||
@ -186,6 +192,7 @@ struct IndexUpdate {
|
||||
std::vector<QueryableTypeDef> types_added;
|
||||
std::vector<QueryableTypeDef::DefUpdate> types_def_changed;
|
||||
std::vector<QueryableTypeDef::DerivedUpdate> types_derived;
|
||||
std::vector<QueryableTypeDef::InstantiationsUpdate> types_instantiations;
|
||||
std::vector<QueryableTypeDef::UsesUpdate> types_uses;
|
||||
|
||||
// Function updates.
|
||||
|
@ -40,6 +40,9 @@ void Reflect(Reader& visitor, Location& value) {
|
||||
value = Location(visitor.GetString());
|
||||
}
|
||||
void Reflect(Writer& visitor, Location& value) {
|
||||
// We only ever want to emit id=1 files.
|
||||
assert(value.raw_file_id == 1);
|
||||
|
||||
std::string output = value.ToString();
|
||||
visitor.String(output.c_str(), output.size());
|
||||
}
|
||||
@ -76,15 +79,22 @@ void Reflect(Writer& visitor, Ref<IndexedFuncDef>& value) {
|
||||
|
||||
|
||||
|
||||
// TODO: Move this to indexer.cpp
|
||||
// TODO: Rename indexer.cpp to indexer.cc
|
||||
// TODO: Do not serialize a USR if it has no usages/etc outside of USR info.
|
||||
|
||||
// IndexedTypeDef
|
||||
bool ReflectMemberStart(Reader& reader, IndexedTypeDef& value) {
|
||||
value.is_bad_def = false;
|
||||
//value.is_bad_def = false;
|
||||
return true;
|
||||
}
|
||||
bool ReflectMemberStart(Writer& writer, IndexedTypeDef& value) {
|
||||
if (value.is_bad_def)
|
||||
return false;
|
||||
if (!value.HasInterestingState())
|
||||
std::cerr << "bad";
|
||||
assert(value.HasInterestingState());
|
||||
|
||||
//if (value.is_bad_def)
|
||||
// return false;
|
||||
DefaultReflectMemberStart(writer);
|
||||
return true;
|
||||
}
|
||||
@ -102,6 +112,7 @@ void Reflect(TVisitor& visitor, IndexedTypeDef& value) {
|
||||
REFLECT_MEMBER2("types", value.def.types);
|
||||
REFLECT_MEMBER2("funcs", value.def.funcs);
|
||||
REFLECT_MEMBER2("vars", value.def.vars);
|
||||
REFLECT_MEMBER2("instantiations", value.instantiations);
|
||||
REFLECT_MEMBER2("uses", value.uses);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
@ -109,12 +120,16 @@ void Reflect(TVisitor& visitor, IndexedTypeDef& value) {
|
||||
|
||||
// IndexedFuncDef
|
||||
bool ReflectMemberStart(Reader& reader, IndexedFuncDef& value) {
|
||||
value.is_bad_def = false;
|
||||
//value.is_bad_def = false;
|
||||
return true;
|
||||
}
|
||||
bool ReflectMemberStart(Writer& writer, IndexedFuncDef& value) {
|
||||
if (value.is_bad_def)
|
||||
return false;
|
||||
if (!value.HasInterestingState())
|
||||
std::cerr << "bad";
|
||||
assert(value.HasInterestingState());
|
||||
|
||||
//if (value.is_bad_def)
|
||||
// return false;
|
||||
DefaultReflectMemberStart(writer);
|
||||
return true;
|
||||
}
|
||||
@ -140,12 +155,16 @@ void Reflect(TVisitor& visitor, IndexedFuncDef& value) {
|
||||
|
||||
// IndexedVarDef
|
||||
bool ReflectMemberStart(Reader& reader, IndexedVarDef& value) {
|
||||
value.is_bad_def = false;
|
||||
//value.is_bad_def = false;
|
||||
return true;
|
||||
}
|
||||
bool ReflectMemberStart(Writer& writer, IndexedVarDef& value) {
|
||||
if (value.is_bad_def)
|
||||
return false;
|
||||
if (!value.HasInterestingState())
|
||||
std::cerr << "bad";
|
||||
assert(value.HasInterestingState());
|
||||
|
||||
//if (value.is_bad_def)
|
||||
// return false;
|
||||
DefaultReflectMemberStart(writer);
|
||||
return true;
|
||||
}
|
||||
@ -204,9 +223,11 @@ std::string Serialize(IndexedFile& file) {
|
||||
return output.GetString();
|
||||
}
|
||||
|
||||
IndexedFile Deserialize(std::string path, std::string serialized) {
|
||||
optional<IndexedFile> Deserialize(std::string path, std::string serialized) {
|
||||
rapidjson::Document reader;
|
||||
reader.Parse(serialized.c_str());
|
||||
if (reader.HasParseError())
|
||||
return nullopt;
|
||||
|
||||
IndexedFile file(path);
|
||||
Reflect(reader, file);
|
||||
|
@ -204,4 +204,4 @@ void ReflectMember(Reader& visitor, const char* name, T& value) {
|
||||
}
|
||||
|
||||
std::string Serialize(IndexedFile& file);
|
||||
IndexedFile Deserialize(std::string path, std::string serialized);
|
||||
optional<IndexedFile> Deserialize(std::string path, std::string serialized);
|
||||
|
58
src/test.cc
58
src/test.cc
@ -22,7 +22,7 @@ std::string ToString(const rapidjson::Document& document) {
|
||||
return buffer.GetString();
|
||||
}
|
||||
|
||||
std::vector<std::string> split_string(const std::string& str, const std::string& delimiter) {
|
||||
std::vector<std::string> SplitString(const std::string& str, const std::string& delimiter) {
|
||||
// http://stackoverflow.com/a/13172514
|
||||
std::vector<std::string> strings;
|
||||
|
||||
@ -40,22 +40,30 @@ std::vector<std::string> split_string(const std::string& str, const std::string&
|
||||
}
|
||||
|
||||
|
||||
void DiffDocuments(rapidjson::Document& expected, rapidjson::Document& actual) {
|
||||
std::vector<std::string> actual_output;
|
||||
{
|
||||
std::string buffer = ToString(actual);
|
||||
actual_output = split_string(buffer, "\n");
|
||||
}
|
||||
void DiffDocuments(std::string path, rapidjson::Document& expected, rapidjson::Document& actual) {
|
||||
std::string joined_actual_output = ToString(actual);
|
||||
std::vector<std::string> actual_output = SplitString(joined_actual_output, "\n");
|
||||
std::string joined_expected_output = ToString(expected);
|
||||
std::vector<std::string> expected_output = SplitString(joined_expected_output, "\n");
|
||||
|
||||
std::vector<std::string> expected_output;
|
||||
{
|
||||
std::string buffer = ToString(expected);
|
||||
expected_output = split_string(buffer, "\n");
|
||||
}
|
||||
|
||||
std::cout << "[FAILED] " << path << std::endl;
|
||||
std::cout << "Expected output for " << path << ":" << std::endl;
|
||||
std::cout << joined_expected_output << std::endl;
|
||||
std::cout << "Actual output for " << path << ":" << std::endl;
|
||||
std::cout << joined_actual_output << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
int max_diff = 5;
|
||||
|
||||
int len = std::min(actual_output.size(), expected_output.size());
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (actual_output[i] != expected_output[i]) {
|
||||
if (--max_diff < 0) {
|
||||
std::cout << "(... more lines may differ ...)" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
std::cout << "Line " << i << " differs:" << std::endl;
|
||||
std::cout << " expected: " << expected_output[i] << std::endl;
|
||||
std::cout << " actual: " << actual_output[i] << std::endl;
|
||||
@ -78,7 +86,7 @@ void DiffDocuments(rapidjson::Document& expected, rapidjson::Document& actual) {
|
||||
void VerifySerializeToFrom(IndexedFile& file) {
|
||||
return; // TODO: reenable
|
||||
std::string expected = file.ToString();
|
||||
std::string actual = Deserialize("foo.cc", Serialize(file)).ToString();
|
||||
std::string actual = Deserialize("foo.cc", Serialize(file)).value().ToString();
|
||||
if (expected != actual) {
|
||||
std::cerr << "Serialization failure" << std::endl;;
|
||||
assert(false);
|
||||
@ -99,9 +107,11 @@ void RunTests() {
|
||||
for (std::string path : GetFilesInFolder("tests", true /*recursive*/, true /*add_folder_to_path*/)) {
|
||||
//if (path != "tests/templates/specialized_func_definition.cc") continue;
|
||||
//if (path != "tests/templates/namespace_template_class_template_func_usage_folded_into_one.cc") continue;
|
||||
//if (path != "tests/foo2.cc") continue;
|
||||
//if (path != "tests/namespaces/namespace_reference.cc") continue;
|
||||
//if (path != "tests/multi_file/header.h") continue;
|
||||
//if (path != "tests/multi_file/impl.cc") continue;
|
||||
//if (path != "tests/inheritance/class_inherit_templated_parent.cc") continue;
|
||||
//if (path != "tests/templates/implicit_variable_instantiation.cc") continue;
|
||||
//if (path != "tests/_empty_test.cc") continue;
|
||||
|
||||
//if (path != "tests/templates/template_class_type_usage_folded_into_one.cc") continue;
|
||||
//path = "C:/Users/jacob/Desktop/superindex/indexer/" + path;
|
||||
@ -114,7 +124,14 @@ void RunTests() {
|
||||
|
||||
// Run test.
|
||||
std::cout << "[START] " << path << std::endl;
|
||||
IndexedFile db = Parse(path, {}, false /*dump_ast*/);
|
||||
IndexedFile db = Parse(path, {
|
||||
"-xc++",
|
||||
"-std=c++11",
|
||||
"-IC:/Users/jacob/Desktop/superindex/indexer/third_party/",
|
||||
"-IC:/Users/jacob/Desktop/superindex/indexer/third_party/doctest/",
|
||||
"-IC:/Users/jacob/Desktop/superindex/indexer/third_party/rapidjson/include",
|
||||
"-IC:/Users/jacob/Desktop/superindex/indexer/src"
|
||||
}, false /*dump_ast*/);
|
||||
VerifySerializeToFrom(db);
|
||||
std::string actual_output = db.ToString();
|
||||
|
||||
@ -125,14 +142,7 @@ void RunTests() {
|
||||
std::cout << "[PASSED] " << path << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << "[FAILED] " << path << std::endl;
|
||||
std::cout << "Expected output for " << path << ":" << std::endl;
|
||||
std::cout << expected_output;
|
||||
std::cout << "Actual output for " << path << ":" << std::endl;
|
||||
std::cout << actual_output;
|
||||
std::cout << std::endl;
|
||||
std::cout << std::endl;
|
||||
DiffDocuments(expected, actual);
|
||||
DiffDocuments(path, expected, actual);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ OUTPUT:
|
||||
"qualified_name": "Foo",
|
||||
"definition": "1:1:7",
|
||||
"funcs": [0],
|
||||
"instantiations": [0, 1],
|
||||
"uses": ["*1:1:7", "1:3:3", "*1:7:3", "*1:8:3", "*1:8:17"]
|
||||
}],
|
||||
"funcs": [{
|
||||
|
@ -23,6 +23,7 @@ OUTPUT:
|
||||
"qualified_name": "Foo",
|
||||
"definition": "1:1:7",
|
||||
"funcs": [0, 1],
|
||||
"instantiations": [0],
|
||||
"uses": ["*1:1:7", "1:3:3", "1:4:3", "*1:8:3"]
|
||||
}],
|
||||
"funcs": [{
|
||||
|
@ -15,6 +15,7 @@ OUTPUT:
|
||||
"qualified_name": "Foo",
|
||||
"definition": "1:1:12",
|
||||
"vars": [0, 1],
|
||||
"instantiations": [2],
|
||||
"uses": ["*1:1:12", "*1:6:1", "1:6:9"]
|
||||
}],
|
||||
"vars": [{
|
||||
|
@ -31,6 +31,7 @@ OUTPUT:
|
||||
"short_name": "Foo",
|
||||
"qualified_name": "Foo",
|
||||
"definition": "1:5:8",
|
||||
"instantiations": [1],
|
||||
"uses": ["*1:5:8", "*1:9:1", "*1:10:1"]
|
||||
}, {
|
||||
"id": 3,
|
||||
@ -38,6 +39,7 @@ OUTPUT:
|
||||
"short_name": "Inner",
|
||||
"qualified_name": "Foo::Inner",
|
||||
"definition": "1:6:10",
|
||||
"instantiations": [0],
|
||||
"uses": ["*1:6:10", "*1:9:9"]
|
||||
}],
|
||||
"vars": [{
|
||||
|
@ -49,6 +49,10 @@ OUTPUT:
|
||||
"parents": [1],
|
||||
"derived": [5],
|
||||
"uses": ["*1:11:7", "*1:13:56"]
|
||||
}, {
|
||||
"id": 4,
|
||||
"usr": "c:class_inherit_templated_parent.cc@154",
|
||||
"uses": ["*1:11:24"]
|
||||
}, {
|
||||
"id": 5,
|
||||
"usr": "c:@S@Derived",
|
||||
|
121
tests/multi_file/header.h
Normal file
121
tests/multi_file/header.h
Normal file
@ -0,0 +1,121 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../third_party/doctest/doctest/doctest.h"
|
||||
#include "../../third_party/macro_map.h"
|
||||
#include "../../third_party/optional.h"
|
||||
#include <rapidjson/rapidjson.h>
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/prettywriter.h>
|
||||
|
||||
struct Base {};
|
||||
|
||||
struct SameFileDerived : Base {};
|
||||
|
||||
using Foo0 = SameFileDerived;
|
||||
|
||||
template <typename T>
|
||||
void Foo1() {}
|
||||
|
||||
template <typename T>
|
||||
struct Foo2 {};
|
||||
|
||||
enum Foo3 { A, B, C };
|
||||
|
||||
int Foo4;
|
||||
static int Foo5;
|
||||
|
||||
/*
|
||||
OUTPUT:
|
||||
{
|
||||
"types": [{
|
||||
"id": 0,
|
||||
"usr": "c:@S@Base",
|
||||
"short_name": "Base",
|
||||
"qualified_name": "Base",
|
||||
"definition": "1:10:8",
|
||||
"derived": [1],
|
||||
"uses": ["*1:10:8", "*1:12:26"]
|
||||
}, {
|
||||
"id": 1,
|
||||
"usr": "c:@S@SameFileDerived",
|
||||
"short_name": "SameFileDerived",
|
||||
"qualified_name": "SameFileDerived",
|
||||
"definition": "1:12:8",
|
||||
"parents": [0],
|
||||
"uses": ["*1:12:8", "*1:14:14"]
|
||||
}, {
|
||||
"id": 2,
|
||||
"usr": "c:@Foo0",
|
||||
"short_name": "Foo0",
|
||||
"qualified_name": "Foo0",
|
||||
"definition": "1:14:7",
|
||||
"alias_of": 1,
|
||||
"uses": ["*1:14:7"]
|
||||
}, {
|
||||
"id": 3,
|
||||
"usr": "c:@ST>1#T@Foo2",
|
||||
"short_name": "Foo2",
|
||||
"qualified_name": "Foo2",
|
||||
"definition": "1:20:8",
|
||||
"uses": ["*1:20:8"]
|
||||
}, {
|
||||
"id": 4,
|
||||
"usr": "c:@E@Foo3",
|
||||
"short_name": "Foo3",
|
||||
"qualified_name": "Foo3",
|
||||
"definition": "1:22:6",
|
||||
"vars": [0, 1, 2],
|
||||
"uses": ["*1:22:6"]
|
||||
}],
|
||||
"funcs": [{
|
||||
"id": 0,
|
||||
"usr": "c:@FT@>1#TFoo1#v#",
|
||||
"short_name": "Foo1",
|
||||
"qualified_name": "Foo1",
|
||||
"definition": "1:17:6",
|
||||
"uses": ["1:17:6"]
|
||||
}],
|
||||
"vars": [{
|
||||
"id": 0,
|
||||
"usr": "c:@E@Foo3@A",
|
||||
"short_name": "A",
|
||||
"qualified_name": "Foo3::A",
|
||||
"definition": "1:22:13",
|
||||
"variable_type": 4,
|
||||
"declaring_type": 4,
|
||||
"uses": ["1:22:13"]
|
||||
}, {
|
||||
"id": 1,
|
||||
"usr": "c:@E@Foo3@B",
|
||||
"short_name": "B",
|
||||
"qualified_name": "Foo3::B",
|
||||
"definition": "1:22:16",
|
||||
"variable_type": 4,
|
||||
"declaring_type": 4,
|
||||
"uses": ["1:22:16"]
|
||||
}, {
|
||||
"id": 2,
|
||||
"usr": "c:@E@Foo3@C",
|
||||
"short_name": "C",
|
||||
"qualified_name": "Foo3::C",
|
||||
"definition": "1:22:19",
|
||||
"variable_type": 4,
|
||||
"declaring_type": 4,
|
||||
"uses": ["1:22:19"]
|
||||
}, {
|
||||
"id": 3,
|
||||
"usr": "c:@Foo4",
|
||||
"short_name": "Foo4",
|
||||
"qualified_name": "Foo4",
|
||||
"definition": "1:24:5",
|
||||
"uses": ["1:24:5"]
|
||||
}, {
|
||||
"id": 4,
|
||||
"usr": "c:header.h@Foo5",
|
||||
"short_name": "Foo5",
|
||||
"qualified_name": "Foo5",
|
||||
"definition": "1:25:12",
|
||||
"uses": ["1:25:12"]
|
||||
}]
|
||||
}
|
||||
*/
|
1053
tests/multi_file/impl.cc
Normal file
1053
tests/multi_file/impl.cc
Normal file
File diff suppressed because it is too large
Load Diff
@ -17,6 +17,11 @@ OUTPUT:
|
||||
"definition": "1:3:8",
|
||||
"vars": [0, 1, 2],
|
||||
"uses": ["*1:3:8"]
|
||||
}, {
|
||||
"id": 1,
|
||||
"usr": "c:@N@std@ST>2#T#T@vector",
|
||||
"instantiations": [2],
|
||||
"uses": ["*1:6:8"]
|
||||
}],
|
||||
"vars": [{
|
||||
"id": 0,
|
||||
|
@ -22,6 +22,16 @@ OUTPUT:
|
||||
"definition": "1:6:8",
|
||||
"vars": [0, 1, 2],
|
||||
"uses": ["*1:6:8", "*1:12:13"]
|
||||
}, {
|
||||
"id": 1,
|
||||
"usr": "c:@N@std@T@string",
|
||||
"instantiations": [0, 1],
|
||||
"uses": ["*1:7:8", "*1:8:8", "*1:9:20"]
|
||||
}, {
|
||||
"id": 2,
|
||||
"usr": "c:@N@std@ST>2#T#T@vector",
|
||||
"instantiations": [2],
|
||||
"uses": ["*1:9:8", "*1:12:6"]
|
||||
}],
|
||||
"funcs": [{
|
||||
"id": 0,
|
||||
|
@ -23,6 +23,7 @@ OUTPUT:
|
||||
"short_name": "VarType",
|
||||
"qualified_name": "ns::VarType",
|
||||
"definition": "1:2:8",
|
||||
"instantiations": [0],
|
||||
"uses": ["*1:2:8", "*1:6:22", "*1:6:44", "*1:10:18"]
|
||||
}, {
|
||||
"id": 1,
|
||||
|
@ -15,6 +15,7 @@ OUTPUT:
|
||||
"short_name": "Foo",
|
||||
"qualified_name": "ns::Foo",
|
||||
"definition": "1:3:9",
|
||||
"instantiations": [0, 1],
|
||||
"uses": ["*1:3:9", "*1:5:3", "*1:6:3"]
|
||||
}],
|
||||
"vars": [{
|
||||
|
@ -57,6 +57,7 @@ OUTPUT:
|
||||
"short_name": "Inner",
|
||||
"qualified_name": "Foo::Inner",
|
||||
"definition": "1:6:10",
|
||||
"instantiations": [0, 1],
|
||||
"uses": ["*1:6:10", "*1:9:9", "*1:10:9"]
|
||||
}],
|
||||
"vars": [{
|
||||
|
@ -13,6 +13,7 @@ OUTPUT:
|
||||
"short_name": "Foo",
|
||||
"qualified_name": "Foo",
|
||||
"definition": "1:2:7",
|
||||
"instantiations": [0, 1],
|
||||
"uses": ["*1:2:7", "*1:4:1", "*1:5:1"]
|
||||
}],
|
||||
"vars": [{
|
||||
|
@ -44,6 +44,10 @@ OUTPUT:
|
||||
"qualified_name": "B",
|
||||
"definition": "1:2:6",
|
||||
"uses": ["*1:2:6", "1:8:13"]
|
||||
}, {
|
||||
"id": 2,
|
||||
"usr": "c:template_var_usage_folded_into_one.cc@35",
|
||||
"uses": ["*1:5:1"]
|
||||
}],
|
||||
"vars": [{
|
||||
"id": 0,
|
||||
|
@ -10,6 +10,8 @@ void act(Foo*) {
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO: instantiations on Foo should include parameter?
|
||||
|
||||
OUTPUT:
|
||||
{
|
||||
"types": [{
|
||||
@ -19,6 +21,7 @@ OUTPUT:
|
||||
"qualified_name": "Foo",
|
||||
"definition": "1:1:7",
|
||||
"vars": [0, 1],
|
||||
"instantiations": [2],
|
||||
"uses": ["*1:1:7", "*1:6:1", "*1:8:10"]
|
||||
}],
|
||||
"funcs": [{
|
||||
|
@ -17,6 +17,7 @@ OUTPUT:
|
||||
"qualified_name": "Foo",
|
||||
"definition": "1:1:8",
|
||||
"funcs": [0],
|
||||
"instantiations": [0],
|
||||
"uses": ["*1:1:8", "*1:6:3"]
|
||||
}],
|
||||
"funcs": [{
|
||||
|
@ -16,6 +16,7 @@ OUTPUT:
|
||||
"qualified_name": "Foo",
|
||||
"definition": "1:1:8",
|
||||
"funcs": [0],
|
||||
"instantiations": [0],
|
||||
"uses": ["*1:1:8", "*1:6:3"]
|
||||
}],
|
||||
"funcs": [{
|
||||
|
@ -16,6 +16,7 @@ OUTPUT:
|
||||
"types": [{
|
||||
"id": 0,
|
||||
"usr": "c:@ST>1#T@unique_ptr",
|
||||
"instantiations": [0, 1, 2],
|
||||
"uses": ["1:2:7", "*1:6:8", "*1:7:8", "*1:9:1", "*1:10:3"]
|
||||
}, {
|
||||
"id": 1,
|
||||
|
@ -84,6 +84,7 @@ OUTPUT:
|
||||
"types": [{
|
||||
"id": 0,
|
||||
"usr": "c:@ST>2#T#T@unique_ptr",
|
||||
"instantiations": [0, 1],
|
||||
"uses": ["1:2:7", "*1:15:8", "*1:15:19", "*1:33:1", "*1:33:12", "*1:33:52", "*1:54:3", "*1:54:14", "*1:65:3", "*1:79:1"]
|
||||
}, {
|
||||
"id": 1,
|
||||
|
@ -14,6 +14,7 @@ OUTPUT:
|
||||
"short_name": "unique_ptr",
|
||||
"qualified_name": "unique_ptr",
|
||||
"definition": "1:2:7",
|
||||
"instantiations": [0],
|
||||
"uses": ["*1:2:7", "*1:6:8"]
|
||||
}, {
|
||||
"id": 1,
|
||||
|
@ -10,6 +10,7 @@ OUTPUT:
|
||||
"short_name": "T",
|
||||
"qualified_name": "T",
|
||||
"definition": "1:1:8",
|
||||
"instantiations": [0],
|
||||
"uses": ["*1:1:8", "*1:3:8"]
|
||||
}],
|
||||
"vars": [{
|
||||
|
@ -12,6 +12,7 @@ OUTPUT:
|
||||
"types": [{
|
||||
"id": 0,
|
||||
"usr": "c:@S@ForwardType",
|
||||
"instantiations": [0],
|
||||
"uses": ["1:1:8", "*1:5:3"]
|
||||
}, {
|
||||
"id": 1,
|
||||
@ -19,6 +20,7 @@ OUTPUT:
|
||||
"short_name": "ImplementedType",
|
||||
"qualified_name": "ImplementedType",
|
||||
"definition": "1:2:8",
|
||||
"instantiations": [1],
|
||||
"uses": ["*1:2:8", "*1:6:3"]
|
||||
}, {
|
||||
"id": 2,
|
||||
|
@ -12,6 +12,7 @@ OUTPUT:
|
||||
"types": [{
|
||||
"id": 0,
|
||||
"usr": "c:@S@ForwardType",
|
||||
"instantiations": [0],
|
||||
"uses": ["1:1:8", "*1:5:3"]
|
||||
}, {
|
||||
"id": 1,
|
||||
@ -19,6 +20,7 @@ OUTPUT:
|
||||
"short_name": "ImplementedType",
|
||||
"qualified_name": "ImplementedType",
|
||||
"definition": "1:2:8",
|
||||
"instantiations": [1],
|
||||
"uses": ["*1:2:8", "*1:6:3"]
|
||||
}],
|
||||
"funcs": [{
|
||||
|
@ -9,6 +9,7 @@ OUTPUT:
|
||||
"types": [{
|
||||
"id": 0,
|
||||
"usr": "c:@S@ForwardType",
|
||||
"instantiations": [0],
|
||||
"uses": ["1:1:8", "*1:4:10"]
|
||||
}, {
|
||||
"id": 1,
|
||||
@ -16,6 +17,7 @@ OUTPUT:
|
||||
"short_name": "ImplementedType",
|
||||
"qualified_name": "ImplementedType",
|
||||
"definition": "1:2:8",
|
||||
"instantiations": [1],
|
||||
"uses": ["*1:2:8", "*1:4:26"]
|
||||
}],
|
||||
"funcs": [{
|
||||
|
@ -14,6 +14,7 @@ OUTPUT:
|
||||
"types": [{
|
||||
"id": 0,
|
||||
"usr": "c:@S@Foo",
|
||||
"instantiations": [0],
|
||||
"uses": ["1:1:8", "1:3:10", "1:3:18", "*1:4:10", "*1:4:18"]
|
||||
}],
|
||||
"funcs": [{
|
||||
|
@ -15,6 +15,7 @@ OUTPUT:
|
||||
"short_name": "Type",
|
||||
"qualified_name": "Type",
|
||||
"definition": "1:1:8",
|
||||
"instantiations": [0, 1, 2, 3, 4, 5],
|
||||
"uses": ["*1:1:8", "*1:3:10", "*1:3:26", "*1:4:3", "*1:5:3", "*1:6:9", "*1:7:9"]
|
||||
}],
|
||||
"funcs": [{
|
||||
|
@ -6,6 +6,7 @@ OUTPUT:
|
||||
"types": [{
|
||||
"id": 0,
|
||||
"usr": "c:@S@Type",
|
||||
"instantiations": [0],
|
||||
"uses": ["1:1:8", "*1:2:8"]
|
||||
}],
|
||||
"vars": [{
|
||||
|
@ -19,6 +19,7 @@ OUTPUT:
|
||||
"qualified_name": "Foo",
|
||||
"definition": "1:1:7",
|
||||
"funcs": [0],
|
||||
"instantiations": [0, 1],
|
||||
"uses": ["*1:1:7", "*1:2:3", "*1:5:1", "1:5:6", "*1:6:3", "*1:10:8"]
|
||||
}],
|
||||
"funcs": [{
|
||||
|
@ -27,6 +27,7 @@ OUTPUT:
|
||||
"qualified_name": "Foo",
|
||||
"definition": "1:1:7",
|
||||
"vars": [0, 1],
|
||||
"instantiations": [2],
|
||||
"uses": ["*1:1:7", "*1:11:3"]
|
||||
}],
|
||||
"funcs": [{
|
||||
|
@ -16,6 +16,7 @@ OUTPUT:
|
||||
"short_name": "VarType",
|
||||
"qualified_name": "VarType",
|
||||
"definition": "1:1:6",
|
||||
"instantiations": [0],
|
||||
"uses": ["*1:1:6", "*1:4:20", "*1:4:42", "*1:7:7"]
|
||||
}, {
|
||||
"id": 1,
|
||||
|
@ -11,6 +11,7 @@ OUTPUT:
|
||||
"qualified_name": "Foo",
|
||||
"definition": "1:1:7",
|
||||
"vars": [0],
|
||||
"instantiations": [0],
|
||||
"uses": ["*1:1:7", "*1:2:3"]
|
||||
}],
|
||||
"vars": [{
|
||||
|
@ -13,6 +13,7 @@ OUTPUT:
|
||||
"qualified_name": "Foo",
|
||||
"definition": "1:1:7",
|
||||
"vars": [0],
|
||||
"instantiations": [0],
|
||||
"uses": ["*1:1:7", "*1:2:10", "*1:4:1", "1:4:6"]
|
||||
}],
|
||||
"vars": [{
|
||||
|
@ -10,6 +10,7 @@ OUTPUT:
|
||||
"types": [{
|
||||
"id": 0,
|
||||
"usr": "c:@S@Foo",
|
||||
"instantiations": [0],
|
||||
"uses": ["1:1:8", "*1:4:3"]
|
||||
}],
|
||||
"funcs": [{
|
||||
|
@ -8,6 +8,7 @@ OUTPUT:
|
||||
"types": [{
|
||||
"id": 0,
|
||||
"usr": "c:@S@Foo",
|
||||
"instantiations": [0, 1],
|
||||
"uses": ["1:1:8", "*1:3:10", "*1:3:19"]
|
||||
}],
|
||||
"funcs": [{
|
||||
|
Loading…
Reference in New Issue
Block a user