diff --git a/.clang_complete b/.clang_complete new file mode 100644 index 00000000..d0dac336 --- /dev/null +++ b/.clang_complete @@ -0,0 +1,6 @@ +-std=c++11 +-Ithird_party/rapidjson/include +-IC:/Program Files/LLVM/include +-std=c++11 +-fms-compatibility +-fdelayed-template-parsing \ No newline at end of file diff --git a/command_line.cc b/command_line.cc index 1fd95c44..192e8fe0 100644 --- a/command_line.cc +++ b/command_line.cc @@ -26,7 +26,8 @@ const char* kIpcLanguageClientName = "language_client"; const int kNumIndexers = 8 - 1; -std::unordered_map ParseOptions(int argc, char** argv) { +std::unordered_map ParseOptions(int argc, + char** argv) { std::unordered_map output; std::string previous_arg; @@ -36,14 +37,14 @@ std::unordered_map ParseOptions(int argc, char** argv) if (arg[0] != '-') { if (previous_arg.size() == 0) { - std::cerr << "Invalid arguments; switches must start with -" << std::endl; + std::cerr << "Invalid arguments; switches must start with -" + << std::endl; exit(1); } output[previous_arg] = arg; previous_arg = ""; - } - else { + } else { output[arg] = ""; previous_arg = arg; } @@ -52,12 +53,11 @@ std::unordered_map ParseOptions(int argc, char** argv) return output; } -bool HasOption(const std::unordered_map& options, const std::string& option) { +bool HasOption(const std::unordered_map& options, + const std::string& option) { return options.find(option) != options.end(); } - - std::unique_ptr ParseMessage() { int content_length = -1; int iteration = 0; @@ -69,7 +69,7 @@ std::unique_ptr ParseMessage() { std::string line; std::getline(std::cin, line); - //std::cin >> line; + // std::cin >> line; if (line.compare(0, 14, "Content-Length") == 0) { content_length = atoi(line.c_str() + 16); @@ -81,7 +81,8 @@ std::unique_ptr ParseMessage() { // bad input that is not a message. if (content_length < 0) { - std::cerr << "parsing command failed (no Content-Length header)" << std::endl; + std::cerr << "parsing command failed (no Content-Length header)" + << std::endl; return nullptr; } @@ -112,45 +113,7 @@ std::string Join(const std::vector& elements, std::string sep) { return result; } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -template +template struct BaseIpcMessage : public IpcMessage { BaseIpcMessage() : IpcMessage(T::kIpcId) {} @@ -165,39 +128,34 @@ struct BaseIpcMessage : public IpcMessage { } }; - struct IpcMessage_Quit : public BaseIpcMessage { static constexpr IpcId kIpcId = IpcId::Quit; }; -template +template void Reflect(TVisitor& visitor, IpcMessage_Quit& value) {} - struct IpcMessage_IsAlive : public BaseIpcMessage { static constexpr IpcId kIpcId = IpcId::IsAlive; }; -template +template void Reflect(TVisitor& visitor, IpcMessage_IsAlive& value) {} - struct IpcMessage_OpenProject : public BaseIpcMessage { static constexpr IpcId kIpcId = IpcId::OpenProject; std::string project_path; }; -template +template void Reflect(TVisitor& visitor, IpcMessage_OpenProject& value) { Reflect(visitor, value.project_path); } - - - -struct IpcMessage_IndexTranslationUnitRequest : public BaseIpcMessage { +struct IpcMessage_IndexTranslationUnitRequest + : public BaseIpcMessage { static constexpr IpcId kIpcId = IpcId::IndexTranslationUnitRequest; std::string path; std::vector args; }; -template +template void Reflect(TVisitor& visitor, IpcMessage_IndexTranslationUnitRequest& value) { REFLECT_MEMBER_START(); REFLECT_MEMBER(path); @@ -205,42 +163,43 @@ void Reflect(TVisitor& visitor, IpcMessage_IndexTranslationUnitRequest& value) { REFLECT_MEMBER_END(); } -struct IpcMessage_IndexTranslationUnitResponse : public BaseIpcMessage { +struct IpcMessage_IndexTranslationUnitResponse + : public BaseIpcMessage { static constexpr IpcId kIpcId = IpcId::IndexTranslationUnitResponse; IndexUpdate update; IpcMessage_IndexTranslationUnitResponse() {} - explicit IpcMessage_IndexTranslationUnitResponse(IndexUpdate& update) : update(update) {} + explicit IpcMessage_IndexTranslationUnitResponse(IndexUpdate& update) + : update(update) {} }; -template -void Reflect(TVisitor& visitor, IpcMessage_IndexTranslationUnitResponse& value) { +template +void Reflect(TVisitor& visitor, + IpcMessage_IndexTranslationUnitResponse& value) { REFLECT_MEMBER_START(); REFLECT_MEMBER(update); REFLECT_MEMBER_END(); } - - - -struct IpcMessage_LanguageServerRequest : public BaseIpcMessage { +struct IpcMessage_LanguageServerRequest + : public BaseIpcMessage { static constexpr IpcId kIpcId = IpcId::LanguageServerRequest; // TODO: provide a way to get the request state. lsMethodId method_id; }; -template +template void Reflect(TVisitor& visitor, IpcMessage_LanguageServerRequest& value) { REFLECT_MEMBER_START(); REFLECT_MEMBER(method_id); REFLECT_MEMBER_END(); } - -struct IpcMessage_DocumentSymbolsRequest : public BaseIpcMessage { +struct IpcMessage_DocumentSymbolsRequest + : public BaseIpcMessage { static constexpr IpcId kIpcId = IpcId::DocumentSymbolsRequest; RequestId request_id; std::string document; }; -template +template void Reflect(TVisitor& visitor, IpcMessage_DocumentSymbolsRequest& value) { REFLECT_MEMBER_START(); REFLECT_MEMBER(request_id); @@ -248,13 +207,13 @@ void Reflect(TVisitor& visitor, IpcMessage_DocumentSymbolsRequest& value) { REFLECT_MEMBER_END(); } - -struct IpcMessage_DocumentSymbolsResponse : public BaseIpcMessage { +struct IpcMessage_DocumentSymbolsResponse + : public BaseIpcMessage { static constexpr IpcId kIpcId = IpcId::DocumentSymbolsResponse; RequestId request_id; std::vector symbols; }; -template +template void Reflect(TVisitor& visitor, IpcMessage_DocumentSymbolsResponse& value) { REFLECT_MEMBER_START(); REFLECT_MEMBER(request_id); @@ -262,12 +221,13 @@ void Reflect(TVisitor& visitor, IpcMessage_DocumentSymbolsResponse& value) { REFLECT_MEMBER_END(); } -struct IpcMessage_WorkspaceSymbolsRequest : public BaseIpcMessage { +struct IpcMessage_WorkspaceSymbolsRequest + : public BaseIpcMessage { static constexpr IpcId kIpcId = IpcId::WorkspaceSymbolsRequest; RequestId request_id; std::string query; }; -template +template void Reflect(TVisitor& visitor, IpcMessage_WorkspaceSymbolsRequest& value) { REFLECT_MEMBER_START(); REFLECT_MEMBER(request_id); @@ -275,13 +235,13 @@ void Reflect(TVisitor& visitor, IpcMessage_WorkspaceSymbolsRequest& value) { REFLECT_MEMBER_END(); } - -struct IpcMessage_DocumentCodeLensRequest : public BaseIpcMessage { +struct IpcMessage_DocumentCodeLensRequest + : public BaseIpcMessage { static constexpr IpcId kIpcId = IpcId::DocumentCodeLensRequest; RequestId request_id; std::string document; }; -template +template void Reflect(TVisitor& visitor, IpcMessage_DocumentCodeLensRequest& value) { REFLECT_MEMBER_START(); REFLECT_MEMBER(request_id); @@ -289,12 +249,13 @@ void Reflect(TVisitor& visitor, IpcMessage_DocumentCodeLensRequest& value) { REFLECT_MEMBER_END(); } -struct IpcMessage_DocumentCodeLensResponse : public BaseIpcMessage { +struct IpcMessage_DocumentCodeLensResponse + : public BaseIpcMessage { static constexpr IpcId kIpcId = IpcId::DocumentCodeLensResponse; RequestId request_id; std::vector code_lens; }; -template +template void Reflect(TVisitor& visitor, IpcMessage_DocumentCodeLensResponse& value) { REFLECT_MEMBER_START(); REFLECT_MEMBER(request_id); @@ -302,13 +263,13 @@ void Reflect(TVisitor& visitor, IpcMessage_DocumentCodeLensResponse& value) { REFLECT_MEMBER_END(); } - -struct IpcMessage_CodeLensResolveRequest : public BaseIpcMessage { +struct IpcMessage_CodeLensResolveRequest + : public BaseIpcMessage { static constexpr IpcId kIpcId = IpcId::CodeLensResolveRequest; RequestId request_id; TCodeLens code_lens; }; -template +template void Reflect(TVisitor& visitor, IpcMessage_CodeLensResolveRequest& value) { REFLECT_MEMBER_START(); REFLECT_MEMBER(request_id); @@ -316,12 +277,13 @@ void Reflect(TVisitor& visitor, IpcMessage_CodeLensResolveRequest& value) { REFLECT_MEMBER_END(); } -struct IpcMessage_CodeLensResolveResponse : public BaseIpcMessage { +struct IpcMessage_CodeLensResolveResponse + : public BaseIpcMessage { static constexpr IpcId kIpcId = IpcId::CodeLensResolveResponse; RequestId request_id; TCodeLens code_lens; }; -template +template void Reflect(TVisitor& visitor, IpcMessage_CodeLensResolveResponse& value) { REFLECT_MEMBER_START(); REFLECT_MEMBER(request_id); @@ -329,15 +291,13 @@ void Reflect(TVisitor& visitor, IpcMessage_CodeLensResolveResponse& value) { REFLECT_MEMBER_END(); } - - - -struct IpcMessage_WorkspaceSymbolsResponse : public BaseIpcMessage { +struct IpcMessage_WorkspaceSymbolsResponse + : public BaseIpcMessage { static constexpr IpcId kIpcId = IpcId::WorkspaceSymbolsResponse; RequestId request_id; std::vector symbols; }; -template +template void Reflect(TVisitor& visitor, IpcMessage_WorkspaceSymbolsResponse& value) { REFLECT_MEMBER_START(); REFLECT_MEMBER(request_id); @@ -345,64 +305,58 @@ void Reflect(TVisitor& visitor, IpcMessage_WorkspaceSymbolsResponse& value) { REFLECT_MEMBER_END(); } - - - - - - - - struct Timer { using Clock = std::chrono::high_resolution_clock; std::chrono::time_point start_; - Timer() { - Reset(); - } + Timer() { Reset(); } - void Reset() { - start_ = Clock::now(); - } + void Reset() { start_ = Clock::now(); } long long ElapsedMilliseconds() { std::chrono::time_point end = Clock::now(); - return std::chrono::duration_cast(end - start_).count(); + return std::chrono::duration_cast(end - start_) + .count(); } }; - void IndexMainLoop(IpcClient* client) { std::vector> messages = client->TakeMessages(); for (auto& message : messages) { - //std::cerr << "Processing message " << static_cast(message->ipc_id) << std::endl; + // std::cerr << "Processing message " << static_cast(message->ipc_id) + // << std::endl; switch (message->ipc_id) { - case IpcId::Quit: { - exit(0); - break; - } + case IpcId::Quit: { + exit(0); + break; + } - case IpcId::IndexTranslationUnitRequest: { - IpcMessage_IndexTranslationUnitRequest* msg = static_cast(message.get()); + case IpcId::IndexTranslationUnitRequest: { + IpcMessage_IndexTranslationUnitRequest* msg = + static_cast(message.get()); - std::cerr << "Parsing file " << msg->path << " with args " << Join(msg->args, ", ") << std::endl; + std::cerr << "Parsing file " << msg->path << " with args " + << Join(msg->args, ", ") << std::endl; - Timer time; - IndexedFile file = Parse(msg->path, msg->args); - std::cerr << "Parsing/indexing took " << time.ElapsedMilliseconds() << "ms" << std::endl; + Timer time; + IndexedFile file = Parse(msg->path, msg->args); + std::cerr << "Parsing/indexing took " << time.ElapsedMilliseconds() + << "ms" << std::endl; - time.Reset(); - IndexUpdate update(file); - auto response = IpcMessage_IndexTranslationUnitResponse(update); - std::cerr << "Creating index update took " << time.ElapsedMilliseconds() << "ms" << std::endl; + time.Reset(); + IndexUpdate update(file); + auto response = IpcMessage_IndexTranslationUnitResponse(update); + std::cerr << "Creating index update took " << time.ElapsedMilliseconds() + << "ms" << std::endl; - time.Reset(); - client->SendToServer(&response); - std::cerr << "Sending to server took " << time.ElapsedMilliseconds() << "ms" << std::endl; + time.Reset(); + client->SendToServer(&response); + std::cerr << "Sending to server took " << time.ElapsedMilliseconds() + << "ms" << std::endl; - break; - } + break; + } } } } @@ -415,47 +369,11 @@ void IndexMain(int id) { } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - QueryableFile* FindFile(QueryableDatabase* db, const std::string& filename) { - //std::cerr << "Wanted file " << msg->document << std::endl; + // std::cerr << "Wanted file " << msg->document << std::endl; // TODO: hashmap lookup. for (auto& file : db->files) { - //std::cerr << " - Have file " << file.file_id << std::endl; + // std::cerr << " - Have file " << file.file_id << std::endl; if (file.file_id == filename) { std::cerr << "Found file " << filename << std::endl; return &file; @@ -466,20 +384,24 @@ QueryableFile* FindFile(QueryableDatabase* db, const std::string& filename) { return nullptr; } - - - lsLocation GetLsLocation(const QueryableLocation& location) { return lsLocation( - lsDocumentUri::FromPath(location.path), - lsRange(lsPosition(location.line - 1, location.column - 1))); + lsDocumentUri::FromPath(location.path), + lsRange(lsPosition(location.line - 1, location.column - 1))); } -void AddCodeLens(std::vector* result, QueryableLocation loc, const std::vector& uses, bool only_interesting, const char* singular, const char* plural) { +void AddCodeLens(std::vector* result, + QueryableLocation loc, + const std::vector& uses, + bool only_interesting, + const char* singular, + const char* plural) { TCodeLens code_lens; - code_lens.range.start.line = loc.line - 1; // TODO: cleanup indexer to negate by 1. - code_lens.range.start.character = loc.column - 1; // TODO: cleanup indexer to negate by 1. - // TODO: store range information. + code_lens.range.start.line = + loc.line - 1; // TODO: cleanup indexer to negate by 1. + code_lens.range.start.character = + loc.column - 1; // TODO: cleanup indexer to negate by 1. + // TODO: store range information. code_lens.range.end.line = code_lens.range.start.line; code_lens.range.end.character = code_lens.range.start.character; @@ -491,10 +413,12 @@ void AddCodeLens(std::vector* result, QueryableLocation loc, const st // Add unique uses. std::unordered_set unique_uses; for (const QueryableLocation& use : uses) { - if (only_interesting && !use.interesting) continue; + if (only_interesting && !use.interesting) + continue; unique_uses.insert(GetLsLocation(use)); } - code_lens.command->arguments.locations.assign(unique_uses.begin(), unique_uses.end()); + code_lens.command->arguments.locations.assign(unique_uses.begin(), + unique_uses.end()); // User visible label int num_usages = unique_uses.size(); @@ -508,7 +432,12 @@ void AddCodeLens(std::vector* result, QueryableLocation loc, const st result->push_back(code_lens); } -void AddCodeLens(std::vector* result, QueryableLocation loc, const std::vector& uses, bool only_interesting, const char* singular, const char* plural) { +void AddCodeLens(std::vector* result, + QueryableLocation loc, + const std::vector& uses, + bool only_interesting, + const char* singular, + const char* plural) { std::vector uses0; uses0.reserve(uses.size()); for (const UsrRef& use : uses) @@ -516,278 +445,313 @@ void AddCodeLens(std::vector* result, QueryableLocation loc, const st AddCodeLens(result, loc, uses0, only_interesting, singular, plural); } -void AddCodeLens(std::vector* result, QueryableDatabase* db, QueryableLocation loc, const std::vector& usrs, bool only_interesting, const char* singular, const char* plural) { +void AddCodeLens(std::vector* result, + QueryableDatabase* db, + QueryableLocation loc, + const std::vector& usrs, + bool only_interesting, + const char* singular, + const char* plural) { std::vector uses0; uses0.reserve(usrs.size()); for (const Usr& usr : usrs) { SymbolIdx symbol = db->usr_to_symbol[usr]; switch (symbol.kind) { - case SymbolKind::Type: { - QueryableTypeDef* def = &db->types[symbol.idx]; - if (def->def.definition) - uses0.push_back(def->def.definition.value()); - break; - } - case SymbolKind::Func: { - QueryableFuncDef* def = &db->funcs[symbol.idx]; - if (def->def.definition) - uses0.push_back(def->def.definition.value()); - break; - } - case SymbolKind::Var: { - assert(false && "unexpected"); - break; - } + case SymbolKind::Type: { + QueryableTypeDef* def = &db->types[symbol.idx]; + if (def->def.definition) + uses0.push_back(def->def.definition.value()); + break; + } + case SymbolKind::Func: { + QueryableFuncDef* def = &db->funcs[symbol.idx]; + if (def->def.definition) + uses0.push_back(def->def.definition.value()); + break; + } + case SymbolKind::Var: { + assert(false && "unexpected"); + break; + } } } AddCodeLens(result, loc, uses0, only_interesting, singular, plural); } - -void QueryDbMainLoop(IpcServer* language_client, IpcServer* indexers, QueryableDatabase* db) { - std::vector> messages = language_client->TakeMessages(); +void QueryDbMainLoop(IpcServer* language_client, + IpcServer* indexers, + QueryableDatabase* db) { + std::vector> messages = + language_client->TakeMessages(); for (auto& message : messages) { - //std::cerr << "Processing message " << static_cast(message->ipc_id) << std::endl; + // std::cerr << "Processing message " << static_cast(message->ipc_id) + // << std::endl; switch (message->ipc_id) { - case IpcId::Quit: { - break; - } - - case IpcId::IsAlive: { - IpcMessage_IsAlive response; - language_client->SendToClient(0, &response); // todo: make non-blocking - break; - } - - case IpcId::OpenProject: { - IpcMessage_OpenProject* msg = static_cast(message.get()); - std::string path = msg->project_path; - - - std::vector entries = LoadCompilationEntriesFromDirectory(path); - for (int i = 0; i < entries.size(); ++i) { - const CompilationEntry& entry = entries[i]; - std::string filepath = path + "/" + entry.filename; - std::cerr << "[" << i << "/" << (entries.size() - 1) << "] Dispatching index request for file " << filepath << std::endl; - - // TODO: indexers should steal work and load balance. - IpcMessage_IndexTranslationUnitRequest request; - request.path = filepath; - request.args = entry.args; - indexers->SendToClient(i % indexers->num_clients(), &request); - //IndexedFile file = Parse(filepath, entry.args); - //IndexUpdate update(file); - //db->ApplyIndexUpdate(&update); + case IpcId::Quit: { + break; } - std::cerr << "Done" << std::endl; - break; - } - case IpcId::DocumentSymbolsRequest: { - auto msg = static_cast(message.get()); + case IpcId::IsAlive: { + IpcMessage_IsAlive response; + language_client->SendToClient(0, &response); // todo: make non-blocking + break; + } - IpcMessage_DocumentSymbolsResponse response; - response.request_id = msg->request_id; + case IpcId::OpenProject: { + IpcMessage_OpenProject* msg = + static_cast(message.get()); + std::string path = msg->project_path; - QueryableFile* file = FindFile(db, msg->document); - if (file) { - for (UsrRef ref : file->outline) { - SymbolIdx symbol = db->usr_to_symbol[ref.usr]; + std::vector entries = + LoadCompilationEntriesFromDirectory(path); + for (int i = 0; i < entries.size(); ++i) { + const CompilationEntry& entry = entries[i]; + std::string filepath = path + "/" + entry.filename; + std::cerr << "[" << i << "/" << (entries.size() - 1) + << "] Dispatching index request for file " << filepath + << std::endl; - lsSymbolInformation info; - info.location.range.start.line = ref.loc.line - 1; // TODO: cleanup indexer to negate by 1. - info.location.range.start.character = ref.loc.column - 1; // TODO: cleanup indexer to negate by 1. - // TODO: store range information. - info.location.range.end.line = info.location.range.start.line; - info.location.range.end.character = info.location.range.start.character; - - // TODO: cleanup namespace/naming so there is only one SymbolKind. - switch (symbol.kind) { - case ::SymbolKind::Type: { - QueryableTypeDef& def = db->types[symbol.idx]; - info.name = def.def.qualified_name; - info.kind = lsSymbolKind::Class; - break; - } - case SymbolKind::Func: { - QueryableFuncDef& def = db->funcs[symbol.idx]; - info.name = def.def.qualified_name; - if (def.def.declaring_type.has_value()) { - info.kind = lsSymbolKind::Method; - Usr declaring = def.def.declaring_type.value(); - info.containerName = db->types[db->usr_to_symbol[declaring].idx].def.qualified_name; - } - else { - info.kind = lsSymbolKind::Function; - } - break; - } - case ::SymbolKind::Var: { - QueryableVarDef& def = db->vars[symbol.idx]; - info.name = def.def.qualified_name; - info.kind = lsSymbolKind::Variable; - break; - } - }; - - response.symbols.push_back(info); + // TODO: indexers should steal work and load balance. + IpcMessage_IndexTranslationUnitRequest request; + request.path = filepath; + request.args = entry.args; + indexers->SendToClient(i % indexers->num_clients(), &request); + // IndexedFile file = Parse(filepath, entry.args); + // IndexUpdate update(file); + // db->ApplyIndexUpdate(&update); } + std::cerr << "Done" << std::endl; + break; } - language_client->SendToClient(0, &response); - break; - } + case IpcId::DocumentSymbolsRequest: { + auto msg = + static_cast(message.get()); - case IpcId::DocumentCodeLensRequest: { - auto msg = static_cast(message.get()); + IpcMessage_DocumentSymbolsResponse response; + response.request_id = msg->request_id; - IpcMessage_DocumentCodeLensResponse response; - response.request_id = msg->request_id; + QueryableFile* file = FindFile(db, msg->document); + if (file) { + for (UsrRef ref : file->outline) { + SymbolIdx symbol = db->usr_to_symbol[ref.usr]; - lsDocumentUri file_as_uri; - file_as_uri.SetPath(msg->document); + lsSymbolInformation info; + info.location.range.start.line = + ref.loc.line - 1; // TODO: cleanup indexer to negate by 1. + info.location.range.start.character = + ref.loc.column - 1; // TODO: cleanup indexer to negate by 1. + // TODO: store range information. + info.location.range.end.line = info.location.range.start.line; + info.location.range.end.character = + info.location.range.start.character; - QueryableFile* file = FindFile(db, msg->document); - if (file) { - for (UsrRef ref : file->outline) { - SymbolIdx symbol = db->usr_to_symbol[ref.usr]; - switch (symbol.kind) { - case SymbolKind::Type: { - QueryableTypeDef& def = db->types[symbol.idx]; - AddCodeLens(&response.code_lens, ref.loc, def.uses, true/*only_interesting*/, "reference", "references"); - AddCodeLens(&response.code_lens, db, ref.loc, def.derived, false /*only_interesting*/, "derived", "derived"); - break; + // TODO: cleanup namespace/naming so there is only one SymbolKind. + switch (symbol.kind) { + case ::SymbolKind::Type: { + QueryableTypeDef& def = db->types[symbol.idx]; + info.name = def.def.qualified_name; + info.kind = lsSymbolKind::Class; + break; + } + case SymbolKind::Func: { + QueryableFuncDef& def = db->funcs[symbol.idx]; + info.name = def.def.qualified_name; + if (def.def.declaring_type.has_value()) { + info.kind = lsSymbolKind::Method; + Usr declaring = def.def.declaring_type.value(); + info.containerName = + db->types[db->usr_to_symbol[declaring].idx] + .def.qualified_name; + } else { + info.kind = lsSymbolKind::Function; + } + break; + } + case ::SymbolKind::Var: { + QueryableVarDef& def = db->vars[symbol.idx]; + info.name = def.def.qualified_name; + info.kind = lsSymbolKind::Variable; + break; + } + }; + + response.symbols.push_back(info); } - case SymbolKind::Func: { - QueryableFuncDef& def = db->funcs[symbol.idx]; - AddCodeLens(&response.code_lens, ref.loc, def.uses, false /*only_interesting*/, "reference", "references"); - AddCodeLens(&response.code_lens, ref.loc, def.callers, false /*only_interesting*/, "caller", "callers"); - AddCodeLens(&response.code_lens, ref.loc, def.def.callees, false /*only_interesting*/, "callee", "callees"); - AddCodeLens(&response.code_lens, db, ref.loc, def.derived, false /*only_interesting*/, "derived", "derived"); - break; - } - case SymbolKind::Var: { - QueryableVarDef& def = db->vars[symbol.idx]; - AddCodeLens(&response.code_lens, ref.loc, def.uses, false /*only_interesting*/, "reference", "references"); - break; - } - }; } + + language_client->SendToClient(0, &response); + break; } + case IpcId::DocumentCodeLensRequest: { + auto msg = + static_cast(message.get()); - language_client->SendToClient(0, &response); - break; - } + IpcMessage_DocumentCodeLensResponse response; + response.request_id = msg->request_id; - case IpcId::WorkspaceSymbolsRequest: { - auto msg = static_cast(message.get()); + lsDocumentUri file_as_uri; + file_as_uri.SetPath(msg->document); - IpcMessage_WorkspaceSymbolsResponse response; - response.request_id = msg->request_id; - - std::cerr << "- Considering " << db->qualified_names.size() << " candidates " << std::endl; - - for (int i = 0; i < db->qualified_names.size(); ++i) { - const std::string& name = db->qualified_names[i]; - //std::cerr << "- Considering " << name << std::endl; - - if (name.find(msg->query) != std::string::npos) { - - lsSymbolInformation info; - info.name = name; - - SymbolIdx symbol = db->symbols[i]; - - // TODO: dedup this code w/ above (ie, add ctor to convert symbol to SymbolInformation) - switch (symbol.kind) { - // TODO: file - case ::SymbolKind::Type: - { - QueryableTypeDef& def = db->types[symbol.idx]; - info.name = def.def.qualified_name; - info.kind = lsSymbolKind::Class; - - if (def.def.definition.has_value()) { - info.location.uri.SetPath(def.def.definition->path); - info.location.range.start.line = def.def.definition->line - 1; - info.location.range.start.character = def.def.definition->column - 1; - } - break; + QueryableFile* file = FindFile(db, msg->document); + if (file) { + for (UsrRef ref : file->outline) { + SymbolIdx symbol = db->usr_to_symbol[ref.usr]; + switch (symbol.kind) { + case SymbolKind::Type: { + QueryableTypeDef& def = db->types[symbol.idx]; + AddCodeLens(&response.code_lens, ref.loc, def.uses, + true /*only_interesting*/, "reference", + "references"); + AddCodeLens(&response.code_lens, db, ref.loc, def.derived, + false /*only_interesting*/, "derived", "derived"); + break; + } + case SymbolKind::Func: { + QueryableFuncDef& def = db->funcs[symbol.idx]; + AddCodeLens(&response.code_lens, ref.loc, def.uses, + false /*only_interesting*/, "reference", + "references"); + AddCodeLens(&response.code_lens, ref.loc, def.callers, + false /*only_interesting*/, "caller", "callers"); + AddCodeLens(&response.code_lens, ref.loc, def.def.callees, + false /*only_interesting*/, "callee", "callees"); + AddCodeLens(&response.code_lens, db, ref.loc, def.derived, + false /*only_interesting*/, "derived", "derived"); + break; + } + case SymbolKind::Var: { + QueryableVarDef& def = db->vars[symbol.idx]; + AddCodeLens(&response.code_lens, ref.loc, def.uses, + false /*only_interesting*/, "reference", + "references"); + break; + } + }; } - case ::SymbolKind::Func: - { - QueryableFuncDef& def = db->funcs[symbol.idx]; - info.name = def.def.qualified_name; - if (def.def.declaring_type.has_value()) { - info.kind = lsSymbolKind::Method; - Usr declaring = def.def.declaring_type.value(); - info.containerName = db->types[db->usr_to_symbol[declaring].idx].def.qualified_name; - } - else { - info.kind = lsSymbolKind::Function; - } - - if (def.def.definition.has_value()) { - info.location.uri.SetPath(def.def.definition->path); - info.location.range.start.line = def.def.definition->line - 1; - info.location.range.start.character = def.def.definition->column - 1; - } - break; - } - case ::SymbolKind::Var: - { - QueryableVarDef& def = db->vars[symbol.idx]; - info.name = def.def.qualified_name; - info.kind = lsSymbolKind::Variable; - - if (def.def.definition.has_value()) { - info.location.uri.SetPath(def.def.definition->path); - info.location.range.start.line = def.def.definition->line - 1; - info.location.range.start.character = def.def.definition->column - 1; - } - break; - } - }; - - - // TODO: store range information. - info.location.range.end.line = info.location.range.start.line; - info.location.range.end.character = info.location.range.start.character; - - response.symbols.push_back(info); } + + language_client->SendToClient(0, &response); + break; } - language_client->SendToClient(0, &response); - break; - } + case IpcId::WorkspaceSymbolsRequest: { + auto msg = + static_cast(message.get()); - default: { - std::cerr << "Unhandled IPC message with kind " << static_cast(message->ipc_id) << std::endl; - exit(1); - } + IpcMessage_WorkspaceSymbolsResponse response; + response.request_id = msg->request_id; + + std::cerr << "- Considering " << db->qualified_names.size() + << " candidates " << std::endl; + + for (int i = 0; i < db->qualified_names.size(); ++i) { + const std::string& name = db->qualified_names[i]; + // std::cerr << "- Considering " << name << std::endl; + + if (name.find(msg->query) != std::string::npos) { + lsSymbolInformation info; + info.name = name; + + SymbolIdx symbol = db->symbols[i]; + + // TODO: dedup this code w/ above (ie, add ctor to convert symbol to + // SymbolInformation) + switch (symbol.kind) { + // TODO: file + case ::SymbolKind::Type: { + QueryableTypeDef& def = db->types[symbol.idx]; + info.name = def.def.qualified_name; + info.kind = lsSymbolKind::Class; + + if (def.def.definition.has_value()) { + info.location.uri.SetPath(def.def.definition->path); + info.location.range.start.line = def.def.definition->line - 1; + info.location.range.start.character = + def.def.definition->column - 1; + } + break; + } + case ::SymbolKind::Func: { + QueryableFuncDef& def = db->funcs[symbol.idx]; + info.name = def.def.qualified_name; + if (def.def.declaring_type.has_value()) { + info.kind = lsSymbolKind::Method; + Usr declaring = def.def.declaring_type.value(); + info.containerName = + db->types[db->usr_to_symbol[declaring].idx] + .def.qualified_name; + } else { + info.kind = lsSymbolKind::Function; + } + + if (def.def.definition.has_value()) { + info.location.uri.SetPath(def.def.definition->path); + info.location.range.start.line = def.def.definition->line - 1; + info.location.range.start.character = + def.def.definition->column - 1; + } + break; + } + case ::SymbolKind::Var: { + QueryableVarDef& def = db->vars[symbol.idx]; + info.name = def.def.qualified_name; + info.kind = lsSymbolKind::Variable; + + if (def.def.definition.has_value()) { + info.location.uri.SetPath(def.def.definition->path); + info.location.range.start.line = def.def.definition->line - 1; + info.location.range.start.character = + def.def.definition->column - 1; + } + break; + } + }; + + // TODO: store range information. + info.location.range.end.line = info.location.range.start.line; + info.location.range.end.character = + info.location.range.start.character; + + response.symbols.push_back(info); + } + } + + language_client->SendToClient(0, &response); + break; + } + + default: { + std::cerr << "Unhandled IPC message with kind " + << static_cast(message->ipc_id) << std::endl; + exit(1); + } } } messages = indexers->TakeMessages(); for (auto& message : messages) { - //std::cerr << "Processing message " << static_cast(message->ipc_id) << std::endl; + // std::cerr << "Processing message " << static_cast(message->ipc_id) + // << std::endl; switch (message->ipc_id) { + case IpcId::IndexTranslationUnitResponse: { + IpcMessage_IndexTranslationUnitResponse* msg = + static_cast( + message.get()); + Timer time; + db->ApplyIndexUpdate(&msg->update); + std::cerr << "Applying index update took " << time.ElapsedMilliseconds() + << "ms" << std::endl; + break; + } - case IpcId::IndexTranslationUnitResponse: { - IpcMessage_IndexTranslationUnitResponse* msg = static_cast(message.get()); - Timer time; - db->ApplyIndexUpdate(&msg->update); - std::cerr << "Applying index update took " << time.ElapsedMilliseconds() << "ms" << std::endl; - break; - } - - default: { - std::cerr << "Unhandled IPC message with kind " << static_cast(message->ipc_id) << std::endl; - exit(1); - } + default: { + std::cerr << "Unhandled IPC message with kind " + << static_cast(message->ipc_id) << std::endl; + exit(1); + } } } } @@ -801,10 +765,8 @@ void QueryDbMain() { std::cerr << "!! starting processes" << std::endl; // Start indexer processes. for (int i = 0; i < kNumIndexers; ++i) { - //new Process(process_name + " --indexer " + std::to_string(i + 1)); - new std::thread([i]() { - IndexMain(i); - }); + // new Process(process_name + " --indexer " + std::to_string(i + 1)); + new std::thread([i]() { IndexMain(i); }); } std::cerr << "!! done processes" << std::endl; @@ -815,62 +777,8 @@ void QueryDbMain() { } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // TODO: global lock on stderr output. - - - - - - - - - - - - - - - - - // Separate thread whose only job is to read from stdin and // dispatch read commands to the actual indexer program. This // cannot be done on the main thread because reading from std::cin @@ -885,66 +793,67 @@ void LanguageServerStdinLoop(IpcClient* server) { if (!message) continue; - std::cerr << "[info]: Got message of type " << MethodIdToString(message->method_id) << std::endl; + std::cerr << "[info]: Got message of type " + << MethodIdToString(message->method_id) << std::endl; switch (message->method_id) { - case lsMethodId::Initialize: - { - auto request = static_cast(message.get()); - if (request->params.rootUri) { - std::string project_path = request->params.rootUri->GetPath(); - std::cerr << "Initialize in directory " << project_path << " with uri " << request->params.rootUri->raw_uri << std::endl; - IpcMessage_OpenProject open_project; - open_project.project_path = project_path; - server->SendToServer(&open_project); + case lsMethodId::Initialize: { + auto request = static_cast(message.get()); + if (request->params.rootUri) { + std::string project_path = request->params.rootUri->GetPath(); + std::cerr << "Initialize in directory " << project_path + << " with uri " << request->params.rootUri->raw_uri + << std::endl; + IpcMessage_OpenProject open_project; + open_project.project_path = project_path; + server->SendToServer(&open_project); + } + + auto response = Out_InitializeResponse(); + response.id = message->id.value(); + response.result.capabilities.documentSymbolProvider = true; + // response.result.capabilities.referencesProvider = true; + response.result.capabilities.codeLensProvider = lsCodeLensOptions(); + response.result.capabilities.codeLensProvider->resolveProvider = false; + response.result.capabilities.workspaceSymbolProvider = true; + response.Send(); + break; } - auto response = Out_InitializeResponse(); - response.id = message->id.value(); - response.result.capabilities.documentSymbolProvider = true; - //response.result.capabilities.referencesProvider = true; - response.result.capabilities.codeLensProvider = lsCodeLensOptions(); - response.result.capabilities.codeLensProvider->resolveProvider = false; - response.result.capabilities.workspaceSymbolProvider = true; - response.Send(); - break; - } + case lsMethodId::TextDocumentDocumentSymbol: { + // TODO: response should take id as input. + // TODO: message should not have top-level id. + auto request = static_cast(message.get()); - case lsMethodId::TextDocumentDocumentSymbol: - { - // TODO: response should take id as input. - // TODO: message should not have top-level id. - auto request = static_cast(message.get()); + IpcMessage_DocumentSymbolsRequest ipc_request; + ipc_request.request_id = request->id.value(); + ipc_request.document = request->params.textDocument.uri.GetPath(); + std::cerr << "Request textDocument=" << ipc_request.document + << std::endl; + server->SendToServer(&ipc_request); + break; + } - IpcMessage_DocumentSymbolsRequest ipc_request; - ipc_request.request_id = request->id.value(); - ipc_request.document = request->params.textDocument.uri.GetPath(); - std::cerr << "Request textDocument=" << ipc_request.document << std::endl; - server->SendToServer(&ipc_request); - break; - } + case lsMethodId::TextDocumentCodeLens: { + auto request = static_cast(message.get()); - case lsMethodId::TextDocumentCodeLens: - { - auto request = static_cast(message.get()); + IpcMessage_DocumentCodeLensRequest ipc_request; + ipc_request.request_id = request->id.value(); + ipc_request.document = request->params.textDocument.uri.GetPath(); + std::cerr << "Request codeLens on textDocument=" << ipc_request.document + << std::endl; + server->SendToServer(&ipc_request); + break; + } - IpcMessage_DocumentCodeLensRequest ipc_request; - ipc_request.request_id = request->id.value(); - ipc_request.document = request->params.textDocument.uri.GetPath(); - std::cerr << "Request codeLens on textDocument=" << ipc_request.document << std::endl; - server->SendToServer(&ipc_request); - break; - } - - case lsMethodId::WorkspaceSymbol: - { - auto request = static_cast(message.get()); - IpcMessage_WorkspaceSymbolsRequest ipc_request; - ipc_request.request_id = request->id.value(); - ipc_request.query = request->params.query; - std::cerr << "Request query=" << ipc_request.query << std::endl; - server->SendToServer(&ipc_request); - break; - } + case lsMethodId::WorkspaceSymbol: { + auto request = static_cast(message.get()); + IpcMessage_WorkspaceSymbolsRequest ipc_request; + ipc_request.request_id = request->id.value(); + ipc_request.query = request->params.query; + std::cerr << "Request query=" << ipc_request.query << std::endl; + server->SendToServer(&ipc_request); + break; + } } } } @@ -953,48 +862,55 @@ void LanguageServerMainLoop(IpcClient* ipc) { std::vector> messages = ipc->TakeMessages(); for (auto& message : messages) { switch (message->ipc_id) { - case IpcId::Quit: { - exit(0); - break; - } + case IpcId::Quit: { + exit(0); + break; + } - case IpcId::DocumentSymbolsResponse: { - auto msg = static_cast(message.get()); + case IpcId::DocumentSymbolsResponse: { + auto msg = + static_cast(message.get()); - auto response = Out_DocumentSymbolResponse(); - response.id = msg->request_id; - response.result = msg->symbols; - response.Send(); - std::cerr << "Sent symbol response to client (" << response.result.size() << " symbols)" << std::endl; - break; - } + auto response = Out_DocumentSymbolResponse(); + response.id = msg->request_id; + response.result = msg->symbols; + response.Send(); + std::cerr << "Sent symbol response to client (" + << response.result.size() << " symbols)" << std::endl; + break; + } - case IpcId::DocumentCodeLensResponse: { - auto msg = static_cast(message.get()); + case IpcId::DocumentCodeLensResponse: { + auto msg = + static_cast(message.get()); - auto response = Out_DocumentCodeLensResponse(); - response.id = msg->request_id; - response.result = msg->code_lens; - response.Send(); - std::cerr << "Sent code lens response to client (" << response.result.size() << " symbols)" << std::endl; - break; - } + auto response = Out_DocumentCodeLensResponse(); + response.id = msg->request_id; + response.result = msg->code_lens; + response.Send(); + std::cerr << "Sent code lens response to client (" + << response.result.size() << " symbols)" << std::endl; + break; + } - case IpcId::WorkspaceSymbolsResponse: { - auto msg = static_cast(message.get()); + case IpcId::WorkspaceSymbolsResponse: { + auto msg = + static_cast(message.get()); - auto response = Out_WorkspaceSymbolResponse(); - response.id = msg->request_id; - response.result = msg->symbols; - response.Send(); - std::cerr << "Send symbol response to client (" << response.result.size() << " symbols)" << std::endl; - break; - } + auto response = Out_WorkspaceSymbolResponse(); + response.id = msg->request_id; + response.result = msg->symbols; + response.Send(); + std::cerr << "Send symbol response to client (" + << response.result.size() << " symbols)" << std::endl; + break; + } - default: { - std::cerr << "Unhandled IPC message with kind " << static_cast(message->ipc_id) << std::endl; - exit(1); - } + default: { + std::cerr << "Unhandled IPC message with kind " + << static_cast(message->ipc_id) << std::endl; + exit(1); + } } } } @@ -1022,7 +938,7 @@ void LanguageServerMain(std::string process_name) { } } - // No server is running. Start it. +// No server is running. Start it. #if false if (!has_server) { if (process_name.empty()) @@ -1046,17 +962,11 @@ void LanguageServerMain(std::string process_name) { #endif // for debugging attach - //std::this_thread::sleep_for(std::chrono::seconds(4)); - - - - + // std::this_thread::sleep_for(std::chrono::seconds(4)); if (!has_server) { // No server. Run it in-process. - new std::thread([&]() { - QueryDbMain(); - }); + new std::thread([&]() { QueryDbMain(); }); } // Run language client. @@ -1067,76 +977,43 @@ void LanguageServerMain(std::string process_name) { } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PreMain() { - // We need to write to stdout in binary mode because in Windows, writing - // \n will implicitly write \r\n. Language server API will ignore a - // \r\r\n split request. +// We need to write to stdout in binary mode because in Windows, writing +// \n will implicitly write \r\n. Language server API will ignore a +// \r\r\n split request. #ifdef _WIN32 _setmode(_fileno(stdout), O_BINARY); _setmode(_fileno(stdin), O_BINARY); #endif IpcRegistry::instance()->Register(IpcMessage_Quit::kIpcId); - IpcRegistry::instance()->Register(IpcMessage_IsAlive::kIpcId); - IpcRegistry::instance()->Register(IpcMessage_OpenProject::kIpcId); + IpcRegistry::instance()->Register( + IpcMessage_IsAlive::kIpcId); + IpcRegistry::instance()->Register( + IpcMessage_OpenProject::kIpcId); - IpcRegistry::instance()->Register(IpcMessage_IndexTranslationUnitRequest::kIpcId); - IpcRegistry::instance()->Register(IpcMessage_IndexTranslationUnitResponse::kIpcId); + IpcRegistry::instance()->Register( + IpcMessage_IndexTranslationUnitRequest::kIpcId); + IpcRegistry::instance()->Register( + IpcMessage_IndexTranslationUnitResponse::kIpcId); - IpcRegistry::instance()->Register(IpcMessage_DocumentSymbolsRequest::kIpcId); - IpcRegistry::instance()->Register(IpcMessage_DocumentSymbolsResponse::kIpcId); - IpcRegistry::instance()->Register(IpcMessage_DocumentCodeLensRequest::kIpcId); - IpcRegistry::instance()->Register(IpcMessage_DocumentCodeLensResponse::kIpcId); - IpcRegistry::instance()->Register(IpcMessage_CodeLensResolveRequest::kIpcId); - IpcRegistry::instance()->Register(IpcMessage_CodeLensResolveResponse::kIpcId); + IpcRegistry::instance()->Register( + IpcMessage_DocumentSymbolsRequest::kIpcId); + IpcRegistry::instance()->Register( + IpcMessage_DocumentSymbolsResponse::kIpcId); + IpcRegistry::instance()->Register( + IpcMessage_DocumentCodeLensRequest::kIpcId); + IpcRegistry::instance()->Register( + IpcMessage_DocumentCodeLensResponse::kIpcId); + IpcRegistry::instance()->Register( + IpcMessage_CodeLensResolveRequest::kIpcId); + IpcRegistry::instance()->Register( + IpcMessage_CodeLensResolveResponse::kIpcId); - IpcRegistry::instance()->Register(IpcMessage_WorkspaceSymbolsRequest::kIpcId); - IpcRegistry::instance()->Register(IpcMessage_WorkspaceSymbolsResponse::kIpcId); + IpcRegistry::instance()->Register( + IpcMessage_WorkspaceSymbolsRequest::kIpcId); + IpcRegistry::instance()->Register( + IpcMessage_WorkspaceSymbolsResponse::kIpcId); MessageRegistry::instance()->Register(); MessageRegistry::instance()->Register(); @@ -1153,7 +1030,7 @@ int main(int argc, char** argv) { PreMain(); - //if (argc == 1) { + // if (argc == 1) { // QueryDbMain(); // return 0; //} @@ -1162,11 +1039,8 @@ int main(int argc, char** argv) { return 0; } - - - - - std::unordered_map options = ParseOptions(argc, argv); + std::unordered_map options = + ParseOptions(argc, argv); if (HasOption(options, "--language-server")) { std::cerr << "Running language server" << std::endl; @@ -1191,8 +1065,7 @@ int main(int argc, char** argv) { if (index == 0) std::cerr << "--indexer expects an indexer id > 0" << std::endl; IndexMain(index); - } - else { + } else { std::cerr << "Running language server" << std::endl; LanguageServerMain(argv[0]); return 0; diff --git a/compilation_database_loader.cc b/compilation_database_loader.cc index ba21774d..e27833af 100644 --- a/compilation_database_loader.cc +++ b/compilation_database_loader.cc @@ -72,6 +72,7 @@ std::vector LoadCompilationEntriesFromDirectory(const std::str entry.args.push_back(clang::ToString(clang_CompileCommand_getArg(cx_command, j))); } + result.push_back(entry); } diff --git a/indexer.cpp b/indexer.cpp index 26959f69..8a2064cf 100644 --- a/indexer.cpp +++ b/indexer.cpp @@ -4,9 +4,7 @@ #include "serializer.h" -IndexedFile::IndexedFile(const std::string& path) - : path(path) { - +IndexedFile::IndexedFile(const std::string& 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) @@ -64,7 +62,6 @@ VarId IndexedFile::ToVarId(const CXCursor& cursor) { return ToVarId(clang::Cursor(cursor).get_usr()); } - IndexedTypeDef* IndexedFile::Resolve(TypeId id) { return &types[id.id]; } @@ -79,12 +76,15 @@ std::string IndexedFile::ToString() { return Serialize(*this); } -IndexedTypeDef::IndexedTypeDef(TypeId id, const std::string& usr) : id(id), def(usr) { +IndexedTypeDef::IndexedTypeDef(TypeId id, const std::string& usr) + : id(id), def(usr) { assert(usr.size() > 0); - //std::cerr << "Creating type with usr " << usr << std::endl; + // std::cerr << "Creating type with usr " << usr << std::endl; } -void AddUsage(std::vector& uses, Location loc, bool insert_if_not_present = true) { +void AddUsage(std::vector& uses, + Location loc, + bool insert_if_not_present = true) { for (int i = uses.size() - 1; i >= 0; --i) { if (uses[i].IsEqualTo(loc)) { if (loc.interesting) @@ -97,7 +97,6 @@ void AddUsage(std::vector& uses, Location loc, bool insert_if_not_pres uses.push_back(loc); } - std::string Location::ToPrettyString(IdCache* id_cache) { // Output looks like this: // @@ -137,8 +136,7 @@ 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; @@ -161,8 +159,7 @@ Location IdCache::Resolve(const clang::Cursor& cursor, bool interesting) { return Resolve(cursor.cx_cursor, interesting); } - -template +template bool Contains(const std::vector& vec, const T& element) { for (const T& entry : vec) { if (entry == element) @@ -171,20 +168,18 @@ bool Contains(const std::vector& vec, const T& element) { return false; } - - - - - struct NamespaceHelper { std::unordered_map container_usr_to_qualified_name; - void RegisterQualifiedName(std::string usr, const CXIdxContainerInfo* container, std::string qualified_name) { + void RegisterQualifiedName(std::string usr, + const CXIdxContainerInfo* container, + std::string qualified_name) { if (container) { std::string container_usr = clang::Cursor(container->cursor).get_usr(); auto it = container_usr_to_qualified_name.find(container_usr); if (it != container_usr_to_qualified_name.end()) { - container_usr_to_qualified_name[usr] = it->second + qualified_name + "::"; + container_usr_to_qualified_name[usr] = + it->second + qualified_name + "::"; return; } } @@ -192,7 +187,8 @@ struct NamespaceHelper { container_usr_to_qualified_name[usr] = qualified_name + "::"; } - std::string QualifiedName(const CXIdxContainerInfo* container, std::string unqualified_name) { + std::string QualifiedName(const CXIdxContainerInfo* container, + std::string unqualified_name) { if (container) { std::string container_usr = clang::Cursor(container->cursor).get_usr(); auto it = container_usr_to_qualified_name.find(container_usr); @@ -202,7 +198,7 @@ struct NamespaceHelper { // Anonymous namespaces are not processed by indexDeclaration. If we // encounter one insert it into map. if (container->cursor.kind == CXCursor_Namespace) { - //assert(clang::Cursor(container->cursor).get_spelling() == ""); + // assert(clang::Cursor(container->cursor).get_spelling() == ""); container_usr_to_qualified_name[container_usr] = "::"; return "::" + unqualified_name; } @@ -224,56 +220,59 @@ struct IndexParam { IndexParam(IndexedFile* db, NamespaceHelper* ns) : db(db), ns(ns) {} }; - - - - - - -int abortQuery(CXClientData client_data, void *reserved) { +int abortQuery(CXClientData client_data, void* reserved) { // 0 -> continue return 0; } -void diagnostic(CXClientData client_data, CXDiagnosticSet diagnostics, void *reserved) { +void diagnostic(CXClientData client_data, + CXDiagnosticSet diagnostics, + void* reserved) { IndexParam* param = static_cast(client_data); // Print any diagnostics to std::cerr for (unsigned i = 0; i < clang_getNumDiagnosticsInSet(diagnostics); ++i) { CXDiagnostic diagnostic = clang_getDiagnosticInSet(diagnostics, i); - std::string spelling = clang::ToString(clang_getDiagnosticSpelling(diagnostic)); - Location location = param->db->id_cache.Resolve(clang_getDiagnosticLocation(diagnostic), false /*interesting*/); + std::string spelling = + clang::ToString(clang_getDiagnosticSpelling(diagnostic)); + Location location = param->db->id_cache.Resolve( + clang_getDiagnosticLocation(diagnostic), false /*interesting*/); - std::cerr << location.ToPrettyString(¶m->db->id_cache) << ": " << spelling << std::endl; + std::cerr << location.ToPrettyString(¶m->db->id_cache) << ": " + << spelling << std::endl; clang_disposeDiagnostic(diagnostic); } } -CXIdxClientFile enteredMainFile(CXClientData client_data, CXFile mainFile, void *reserved) { +CXIdxClientFile enteredMainFile(CXClientData client_data, + CXFile mainFile, + void* reserved) { return nullptr; } -CXIdxClientFile ppIncludedFile(CXClientData client_data, const CXIdxIncludedFileInfo *) { +CXIdxClientFile ppIncludedFile(CXClientData client_data, + const CXIdxIncludedFileInfo*) { return nullptr; } -CXIdxClientASTFile importedASTFile(CXClientData client_data, const CXIdxImportedASTFileInfo *) { +CXIdxClientASTFile importedASTFile(CXClientData client_data, + const CXIdxImportedASTFileInfo*) { return nullptr; } -CXIdxClientContainer startedTranslationUnit(CXClientData client_data, void *reserved) { +CXIdxClientContainer startedTranslationUnit(CXClientData client_data, + void* reserved) { return nullptr; } - - - - -clang::VisiterResult DumpVisitor(clang::Cursor cursor, clang::Cursor parent, int* level) { +clang::VisiterResult DumpVisitor(clang::Cursor cursor, + clang::Cursor parent, + int* level) { for (int i = 0; i < *level; ++i) std::cerr << " "; - std::cerr << clang::ToString(cursor.get_kind()) << " " << cursor.get_spelling() << std::endl; + std::cerr << clang::ToString(cursor.get_kind()) << " " + << cursor.get_spelling() << std::endl; *level += 1; cursor.VisitChildren(&DumpVisitor, level); @@ -287,10 +286,6 @@ void Dump(clang::Cursor cursor) { cursor.VisitChildren(&DumpVisitor, &level); } - - - - struct FindChildOfKindParam { CXCursorKind target_kind; optional result; @@ -298,7 +293,9 @@ struct FindChildOfKindParam { FindChildOfKindParam(CXCursorKind target_kind) : target_kind(target_kind) {} }; -clang::VisiterResult FindChildOfKindVisitor(clang::Cursor cursor, clang::Cursor parent, FindChildOfKindParam* param) { +clang::VisiterResult FindChildOfKindVisitor(clang::Cursor cursor, + clang::Cursor parent, + FindChildOfKindParam* param) { if (cursor.get_kind() == param->target_kind) { param->result = cursor; return clang::VisiterResult::Break; @@ -307,22 +304,21 @@ clang::VisiterResult FindChildOfKindVisitor(clang::Cursor cursor, clang::Cursor return clang::VisiterResult::Recurse; } -optional FindChildOfKind(clang::Cursor cursor, CXCursorKind kind) { +optional FindChildOfKind(clang::Cursor cursor, + CXCursorKind kind) { FindChildOfKindParam param(kind); cursor.VisitChildren(&FindChildOfKindVisitor, ¶m); return param.result; } - - - - -clang::VisiterResult FindTypeVisitor(clang::Cursor cursor, clang::Cursor parent, optional* result) { +clang::VisiterResult FindTypeVisitor(clang::Cursor cursor, + clang::Cursor parent, + optional* result) { switch (cursor.get_kind()) { - case CXCursor_TypeRef: - case CXCursor_TemplateRef: - *result = cursor; - return clang::VisiterResult::Break; + case CXCursor_TypeRef: + case CXCursor_TemplateRef: + *result = cursor; + return clang::VisiterResult::Break; } return clang::VisiterResult::Recurse; @@ -334,13 +330,6 @@ optional FindType(clang::Cursor cursor) { return result; } - - - - - - - /* std::string GetNamespacePrefx(const CXIdxDeclInfo* decl) { const CXIdxContainerInfo* container = decl->lexicalContainer; @@ -355,18 +344,16 @@ bool IsTypeDefinition(const CXIdxContainerInfo* container) { return false; switch (container->cursor.kind) { - case CXCursor_EnumDecl: - case CXCursor_UnionDecl: - case CXCursor_StructDecl: - case CXCursor_ClassDecl: - return true; - default: - return false; + case CXCursor_EnumDecl: + case CXCursor_UnionDecl: + case CXCursor_StructDecl: + case CXCursor_ClassDecl: + return true; + default: + return false; } } - - struct VisitDeclForTypeUsageParam { IndexedFile* db; bool is_interesting; @@ -375,14 +362,18 @@ struct VisitDeclForTypeUsageParam { optional initial_type; VisitDeclForTypeUsageParam(IndexedFile* db, bool is_interesting) - : db(db), is_interesting(is_interesting) {} + : db(db), is_interesting(is_interesting) {} }; -void VisitDeclForTypeUsageVisitorHandler(clang::Cursor cursor, VisitDeclForTypeUsageParam* param) { +void VisitDeclForTypeUsageVisitorHandler(clang::Cursor cursor, + VisitDeclForTypeUsageParam* param) { param->has_processed_any = true; IndexedFile* db = param->db; - std::string referenced_usr = cursor.get_referenced().template_specialization_to_template_definition().get_usr(); + std::string referenced_usr = + cursor.get_referenced() + .template_specialization_to_template_definition() + .get_usr(); // TODO: things in STL cause this to be empty. Figure out why and document it. if (referenced_usr == "") return; @@ -399,51 +390,58 @@ void VisitDeclForTypeUsageVisitorHandler(clang::Cursor cursor, VisitDeclForTypeU } } -clang::VisiterResult VisitDeclForTypeUsageVisitor(clang::Cursor cursor, clang::Cursor parent, VisitDeclForTypeUsageParam* param) { +clang::VisiterResult VisitDeclForTypeUsageVisitor( + clang::Cursor cursor, + clang::Cursor parent, + VisitDeclForTypeUsageParam* param) { switch (cursor.get_kind()) { - case CXCursor_TemplateRef: - case CXCursor_TypeRef: - if (param->previous_cursor) { - VisitDeclForTypeUsageVisitorHandler(param->previous_cursor.value(), param); + case CXCursor_TemplateRef: + case CXCursor_TypeRef: + if (param->previous_cursor) { + VisitDeclForTypeUsageVisitorHandler(param->previous_cursor.value(), + param); - // This if is inside the above if because if there are multiple TypeRefs, - // we always want to process the first one. If we did not always process - // the first one, we cannot tell if there are more TypeRefs after it and - // logic for fetching the return type breaks. This happens in ParmDecl - // instances which only have one TypeRef child but are not interesting - // usages. - if (!param->is_interesting) - return clang::VisiterResult::Break; - } - - param->previous_cursor = cursor; - break; + // This if is inside the above if because if there are multiple + // TypeRefs, + // we always want to process the first one. If we did not always process + // the first one, we cannot tell if there are more TypeRefs after it and + // logic for fetching the return type breaks. This happens in ParmDecl + // instances which only have one TypeRef child but are not interesting + // usages. + if (!param->is_interesting) + return clang::VisiterResult::Break; + } + param->previous_cursor = cursor; + break; // We do not want to recurse for everything, since if we do that we will end // up visiting method definition bodies/etc. Instead, we only recurse for - // things that can logically appear as part of an inline variable initializer, + // things that can logically appear as part of an inline variable + // initializer, // ie, // // class Foo { // int x = (Foo)3; // } - case CXCursor_CallExpr: - case CXCursor_CStyleCastExpr: - case CXCursor_CXXStaticCastExpr: - case CXCursor_CXXReinterpretCastExpr: - return clang::VisiterResult::Recurse; + case CXCursor_CallExpr: + case CXCursor_CStyleCastExpr: + case CXCursor_CXXStaticCastExpr: + case CXCursor_CXXReinterpretCastExpr: + return clang::VisiterResult::Recurse; } - return clang::VisiterResult::Continue; } -// Finds the cursor associated with the declaration type of |cursor|. This strips +// Finds the cursor associated with the declaration type of |cursor|. This +// strips // qualifies from |cursor| (ie, Foo* => Foo) and removes template arguments // (ie, Foo => Foo<*,*>). -optional ResolveToDeclarationType(IndexedFile* db, clang::Cursor cursor) { - clang::Cursor declaration = cursor.get_type().strip_qualifiers().get_declaration(); +optional ResolveToDeclarationType(IndexedFile* db, + clang::Cursor cursor) { + clang::Cursor declaration = + cursor.get_type().strip_qualifiers().get_declaration(); declaration = declaration.template_specialization_to_template_definition(); std::string usr = declaration.get_usr(); if (usr != "") @@ -451,16 +449,23 @@ optional ResolveToDeclarationType(IndexedFile* db, clang::Cursor cursor) return nullopt; } -// 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. -optional AddDeclTypeUsages(IndexedFile* db, clang::Cursor decl_cursor, - bool is_interesting, const CXIdxContainerInfo* semantic_container, - const CXIdxContainerInfo* lexical_container) { - - //std::cerr << std::endl << "AddDeclUsages " << decl_cursor.get_spelling() << std::endl; - //Dump(decl_cursor); +// 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. +optional AddDeclTypeUsages( + IndexedFile* db, + clang::Cursor decl_cursor, + bool is_interesting, + const CXIdxContainerInfo* semantic_container, + const CXIdxContainerInfo* lexical_container) { + // std::cerr << std::endl << "AddDeclUsages " << decl_cursor.get_spelling() << + // std::endl; + // Dump(decl_cursor); // // The general AST format for definitions follows this pattern: @@ -537,11 +542,13 @@ optional AddDeclTypeUsages(IndexedFile* db, clang::Cursor decl_cursor, // // The second TypeRef is an uninteresting usage. bool process_last_type_ref = true; - if (IsTypeDefinition(semantic_container) && !IsTypeDefinition(lexical_container)) { - + if (IsTypeDefinition(semantic_container) && + !IsTypeDefinition(lexical_container)) { // - // In some code, such as the following example, we receive a cursor which is not - // a definition and is not associated with a definition due to an error condition. + // In some code, such as the following example, we receive a cursor which is + // not + // a definition and is not associated with a definition due to an error + // condition. // In this case, it is the Foo::Foo constructor. // // struct Foo {}; @@ -553,7 +560,8 @@ optional AddDeclTypeUsages(IndexedFile* db, clang::Cursor decl_cursor, // TODO: I don't think this resolution ever works. clang::Cursor def = decl_cursor.get_definition(); if (def.get_kind() != CXCursor_FirstInvalid) { - std::cerr << "Successful resolution of decl usage to definition" << std::endl; + std::cerr << "Successful resolution of decl usage to definition" + << std::endl; decl_cursor = def; } } @@ -567,34 +575,30 @@ optional AddDeclTypeUsages(IndexedFile* db, clang::Cursor decl_cursor, // children, the first one will always be visited. if (param.previous_cursor && process_last_type_ref) { VisitDeclForTypeUsageVisitorHandler(param.previous_cursor.value(), ¶m); - } - else { + } else { // If we are not processing the last type ref, it *must* be a TypeRef or // TemplateRef. // - // We will not visit every child if the is_interseting is false, so previous_cursor + // We will not visit every child if the is_interseting is false, so + // previous_cursor // may not point to the last TemplateRef. - assert( - is_interesting == false || - param.previous_cursor.has_value() == false || - (param.previous_cursor.value().get_kind() == CXCursor_TypeRef || - param.previous_cursor.value().get_kind() == CXCursor_TemplateRef)); + assert(is_interesting == false || + param.previous_cursor.has_value() == false || + (param.previous_cursor.value().get_kind() == CXCursor_TypeRef || + param.previous_cursor.value().get_kind() == CXCursor_TemplateRef)); } return param.initial_type; } - - - - - - - -// Various versions of LLVM (ie, 4.0) will not visit inline variable references for template arguments. -clang::VisiterResult AddDeclInitializerUsagesVisitor(clang::Cursor cursor, clang::Cursor parent, IndexedFile* db) { +// Various versions of LLVM (ie, 4.0) will not visit inline variable references +// for template arguments. +clang::VisiterResult AddDeclInitializerUsagesVisitor(clang::Cursor cursor, + clang::Cursor parent, + IndexedFile* db) { /* - We need to index the |DeclRefExpr| below (ie, |var| inside of Foo::var). + We need to index the |DeclRefExpr| below (ie, |var| inside of + Foo::var). template struct Foo { @@ -613,26 +617,33 @@ clang::VisiterResult AddDeclInitializerUsagesVisitor(clang::Cursor cursor, clang */ switch (cursor.get_kind()) { - case CXCursor_DeclRefExpr: - CXCursorKind referenced_kind = cursor.get_referenced().get_kind(); - if (cursor.get_referenced().get_kind() != CXCursor_VarDecl) + case CXCursor_DeclRefExpr: + CXCursorKind referenced_kind = cursor.get_referenced().get_kind(); + if (cursor.get_referenced().get_kind() != CXCursor_VarDecl) + break; + + // TODO: when we resolve the template type to the definition, we get a + // different USR. + + // clang::Cursor ref = + // cursor.get_referenced().template_specialization_to_template_definition().get_type().strip_qualifiers().get_usr(); + // std::string ref_usr = + // cursor.get_referenced().template_specialization_to_template_definition().get_type().strip_qualifiers().get_usr(); + std::string ref_usr = + cursor.get_referenced() + .template_specialization_to_template_definition() + .get_usr(); + // std::string ref_usr = ref.get_usr(); + 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*/); + // std::cerr << "Adding usage to id=" << ref_id.id << " usr=" << ref_usr + // << " at " << loc.ToString() << std::endl; + AddUsage(ref_def->uses, loc); break; - - // TODO: when we resolve the template type to the definition, we get a different USR. - - //clang::Cursor ref = cursor.get_referenced().template_specialization_to_template_definition().get_type().strip_qualifiers().get_usr(); - //std::string ref_usr = cursor.get_referenced().template_specialization_to_template_definition().get_type().strip_qualifiers().get_usr(); - std::string ref_usr = cursor.get_referenced().template_specialization_to_template_definition().get_usr(); - //std::string ref_usr = ref.get_usr(); - 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*/); - //std::cerr << "Adding usage to id=" << ref_id.id << " usr=" << ref_usr << " at " << loc.ToString() << std::endl; - AddUsage(ref_def->uses, loc); - break; } return clang::VisiterResult::Recurse; @@ -642,15 +653,11 @@ void AddDeclInitializerUsages(IndexedFile* db, clang::Cursor decl_cursor) { decl_cursor.VisitChildren(&AddDeclInitializerUsagesVisitor, db); } - - - - - - void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { - // TODO: we can minimize processing for cursors which return false for clang_Location_isFromMainFile (ie, only add usages) - bool is_system_def = clang_Location_isInSystemHeader(clang_getCursorLocation(decl->cursor)); + // TODO: we can minimize processing for cursors which return false for + // clang_Location_isFromMainFile (ie, only add usages) + bool is_system_def = + clang_Location_isInSystemHeader(clang_getCursorLocation(decl->cursor)); if (is_system_def) return; @@ -658,474 +665,557 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { IndexedFile* db = param->db; NamespaceHelper* ns = param->ns; - // std::cerr << "DECL kind=" << decl->entityInfo->kind << " at " << db->id_cache.Resolve(decl->cursor, false).ToPrettyString(&db->id_cache) << std::endl; + // std::cerr << "DECL kind=" << decl->entityInfo->kind << " at " << + // db->id_cache.Resolve(decl->cursor, false).ToPrettyString(&db->id_cache) << + // std::endl; switch (decl->entityInfo->kind) { - case CXIdxEntity_CXXNamespace: - { - ns->RegisterQualifiedName(decl->entityInfo->USR, decl->semanticContainer, decl->entityInfo->name); - break; - } - - case CXIdxEntity_EnumConstant: - case CXIdxEntity_Field: - case CXIdxEntity_Variable: - case CXIdxEntity_CXXStaticVariable: - { - clang::Cursor decl_cursor = decl->cursor; - - // Do not index implicit template instantiations. - if (decl_cursor != decl_cursor.template_specialization_to_template_definition()) + case CXIdxEntity_CXXNamespace: { + ns->RegisterQualifiedName(decl->entityInfo->USR, decl->semanticContainer, + decl->entityInfo->name); break; - - std::string decl_usr = decl_cursor.get_usr(); - - 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 - //if (!decl->isRedeclaration) { - var_def->def.short_name = decl->entityInfo->name; - var_def->def.qualified_name = 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; - else - var_def->def.declaration = decl_loc; - AddUsage(var_def->uses, decl_loc); - - //std::cerr << std::endl << "Visiting declaration" << std::endl; - //Dump(decl_cursor); - - AddDeclInitializerUsages(db, decl_cursor); - var_def = db->Resolve(var_id); - - // Declaring variable type information. Note that we do not insert an - // interesting reference for parameter declarations - that is handled when - // the function declaration is encountered since we won't receive ParmDecl - // declarations for unnamed parameters. - AddDeclTypeUsages(db, decl_cursor, decl_cursor.get_kind() != CXCursor_ParmDecl /*is_interesting*/, decl->semanticContainer, decl->lexicalContainer); - optional var_type = ResolveToDeclarationType(db, decl_cursor); - if (var_type.has_value()) - var_def->def.variable_type = var_type.value(); - - - if (decl->isDefinition && IsTypeDefinition(decl->semanticContainer)) { - TypeId declaring_type_id = 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); } - break; - } + case CXIdxEntity_EnumConstant: + case CXIdxEntity_Field: + case CXIdxEntity_Variable: + case CXIdxEntity_CXXStaticVariable: { + clang::Cursor decl_cursor = decl->cursor; - case CXIdxEntity_Function: - case CXIdxEntity_CXXConstructor: - case CXIdxEntity_CXXDestructor: - case CXIdxEntity_CXXInstanceMethod: - case CXIdxEntity_CXXStaticMethod: - case CXIdxEntity_CXXConversionFunction: - { - clang::Cursor decl_cursor = decl->cursor; - clang::Cursor resolved = decl_cursor.template_specialization_to_template_definition(); + // Do not index implicit template instantiations. + if (decl_cursor != + decl_cursor.template_specialization_to_template_definition()) + break; - FuncId func_id = db->ToFuncId(resolved.cx_cursor); - IndexedFuncDef* func_def = db->Resolve(func_id); + std::string decl_usr = decl_cursor.get_usr(); - Location decl_loc = db->id_cache.Resolve(decl->loc, false /*interesting*/); + VarId var_id = db->ToVarId(decl->entityInfo->USR); + IndexedVarDef* var_def = db->Resolve(var_id); - AddUsage(func_def->uses, decl_loc); - // 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*/, decl->semanticContainer, decl->lexicalContainer); + var_def->is_bad_def = is_system_def; - // TODO: support multiple definitions per function; right now we are 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; - else - func_def->declarations.push_back(decl_loc); - - // If decl_cursor != resolved, then decl_cursor is a template specialization. We - // don't want to override a lot of the function definition information in 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) { - func_def->def.short_name = decl->entityInfo->name; - func_def->def.qualified_name = ns->QualifiedName(decl->semanticContainer, func_def->def.short_name); + // TODO: Eventually run with this if. Right now I want to iron out bugs + // this may shadow. + // TODO: Verify this gets called multiple times + // if (!decl->isRedeclaration) { + var_def->def.short_name = decl->entityInfo->name; + var_def->def.qualified_name = + ns->QualifiedName(decl->semanticContainer, var_def->def.short_name); //} - bool is_pure_virtual = clang_CXXMethod_isPureVirtual(decl->cursor); - bool is_ctor_or_dtor = decl->entityInfo->kind == CXIdxEntity_CXXConstructor || decl->entityInfo->kind == CXIdxEntity_CXXDestructor; - //bool process_declaring_type = is_pure_virtual || is_ctor_or_dtor; + Location decl_loc = + db->id_cache.Resolve(decl->loc, false /*interesting*/); + if (decl->isDefinition) + var_def->def.definition = decl_loc; + else + var_def->def.declaration = decl_loc; + AddUsage(var_def->uses, decl_loc); - // Add function usage information. We only want to do it once per - // definition/declaration. Do it on definition since there should only ever - // be one of those in the entire program. - if (IsTypeDefinition(decl->semanticContainer)) { - TypeId declaring_type_id = db->ToTypeId(decl->semanticContainer->cursor); + // std::cerr << std::endl << "Visiting declaration" << std::endl; + // Dump(decl_cursor); + + AddDeclInitializerUsages(db, decl_cursor); + var_def = db->Resolve(var_id); + + // Declaring variable type information. Note that we do not insert an + // interesting reference for parameter declarations - that is handled when + // the function declaration is encountered since we won't receive ParmDecl + // declarations for unnamed parameters. + AddDeclTypeUsages( + db, decl_cursor, + decl_cursor.get_kind() != CXCursor_ParmDecl /*is_interesting*/, + decl->semanticContainer, decl->lexicalContainer); + optional var_type = ResolveToDeclarationType(db, decl_cursor); + if (var_type.has_value()) + var_def->def.variable_type = var_type.value(); + + if (decl->isDefinition && IsTypeDefinition(decl->semanticContainer)) { + TypeId declaring_type_id = + db->ToTypeId(decl->semanticContainer->cursor); IndexedTypeDef* declaring_type_def = db->Resolve(declaring_type_id); - func_def->def.declaring_type = declaring_type_id; - - // 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; - AddUsage(declaring_type_def->uses, type_usage_loc); - } - - // Register function in declaring type if it hasn't been registered yet. - if (!Contains(declaring_type_def->def.funcs, func_id)) - declaring_type_def->def.funcs.push_back(func_id); + var_def->def.declaring_type = declaring_type_id; + declaring_type_def->def.vars.push_back(var_id); } - - //TypeResolution ret_type = ResolveToType(db, decl_cursor.get_type().get_return_type()); - //if (ret_type.resolved_type) - // AddInterestingUsageToType(db, ret_type, FindLocationOfTypeSpecifier(decl_cursor)); - - if (decl->isDefinition || is_pure_virtual) { - // Mark type usage for parameters as interesting. We handle this here - // instead of inside var declaration because clang will not emit a var - // declaration for an unnamed parameter, but we still want to mark the - // usage as interesting. - // TODO: Do a similar thing for function decl parameter usages. Mark - // prototype params as interesting type usages but also relate mark - // them as as usages on the primary variable - requires USR to be - // the same. We can work around it by declaring which variables a - // parameter has declared and update the USR in the definition. - clang::Cursor cursor = decl->cursor; - for (clang::Cursor arg : cursor.get_arguments()) { - switch (arg.get_kind()) { - case CXCursor_ParmDecl: - // We don't need to know the arg type, but we do want to mark it as - // an interesting usage. Note that we use semanticContainer twice - // because a parameter is not really part of the lexical container. - AddDeclTypeUsages(db, arg, true /*is_interesting*/, decl->semanticContainer, decl->semanticContainer); - - //TypeResolution arg_type = ResolveToType(db, arg.get_type()); - //if (arg_type.resolved_type) - // AddInterestingUsageToType(db, arg_type, FindLocationOfTypeSpecifier(arg)); - break; - } - } - - - // Process inheritance. - //void clang_getOverriddenCursors(CXCursor cursor, CXCursor **overridden, unsigned *num_overridden); - //void clang_disposeOverriddenCursors(CXCursor *overridden); - if (clang_CXXMethod_isVirtual(decl->cursor)) { - CXCursor* overridden; - unsigned int num_overridden; - clang_getOverriddenCursors(decl->cursor, &overridden, &num_overridden); - - // TODO: How to handle multiple parent overrides?? - for (unsigned int i = 0; i < num_overridden; ++i) { - clang::Cursor parent = overridden[i]; - FuncId parent_id = db->ToFuncId(parent.get_usr()); - IndexedFuncDef* parent_def = db->Resolve(parent_id); - func_def = db->Resolve(func_id); // ToFuncId invalidated func_def - - func_def->def.base = parent_id; - parent_def->derived.push_back(func_id); - } - - clang_disposeOverriddenCursors(overridden); - } - } + break; } - /* - optional base; - std::vector derived; - std::vector locals; - std::vector callers; - std::vector callees; - std::vector uses; - */ - break; - } + case CXIdxEntity_Function: + case CXIdxEntity_CXXConstructor: + case CXIdxEntity_CXXDestructor: + case CXIdxEntity_CXXInstanceMethod: + case CXIdxEntity_CXXStaticMethod: + case CXIdxEntity_CXXConversionFunction: { + clang::Cursor decl_cursor = decl->cursor; + clang::Cursor resolved = + decl_cursor.template_specialization_to_template_definition(); - case CXIdxEntity_Typedef: - case CXIdxEntity_CXXTypeAlias: - { - // 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. - optional alias_of = AddDeclTypeUsages(db, decl->cursor, true /*is_interesting*/, decl->semanticContainer, decl->lexicalContainer); + FuncId func_id = db->ToFuncId(resolved.cx_cursor); + IndexedFuncDef* func_def = db->Resolve(func_id); - TypeId type_id = db->ToTypeId(decl->entityInfo->USR); - IndexedTypeDef* type_def = db->Resolve(type_id); + Location decl_loc = + db->id_cache.Resolve(decl->loc, false /*interesting*/); - type_def->is_bad_def = is_system_def; + AddUsage(func_def->uses, decl_loc); + // 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*/, + decl->semanticContainer, decl->lexicalContainer); - if (alias_of) - type_def->def.alias_of = alias_of.value(); + // TODO: support multiple definitions per function; right now we are + // 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; + else + func_def->declarations.push_back(decl_loc); - type_def->def.short_name = decl->entityInfo->name; - type_def->def.qualified_name = ns->QualifiedName(decl->semanticContainer, type_def->def.short_name); + // If decl_cursor != resolved, then decl_cursor is a template + // specialization. We + // don't want to override a lot of the function definition information in + // that + // scenario. + if (decl_cursor == resolved) { + func_def->is_bad_def = is_system_def; - 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); - break; - } + // TODO: Eventually run with this if. Right now I want to iron out bugs + // this may shadow. + // if (!decl->isRedeclaration) { + func_def->def.short_name = decl->entityInfo->name; + func_def->def.qualified_name = ns->QualifiedName( + decl->semanticContainer, func_def->def.short_name); + //} - case CXIdxEntity_Enum: - case CXIdxEntity_Union: - case CXIdxEntity_Struct: - case CXIdxEntity_CXXClass: - { - TypeId type_id = db->ToTypeId(decl->entityInfo->USR); - IndexedTypeDef* type_def = db->Resolve(type_id); + bool is_pure_virtual = clang_CXXMethod_isPureVirtual(decl->cursor); + bool is_ctor_or_dtor = + decl->entityInfo->kind == CXIdxEntity_CXXConstructor || + decl->entityInfo->kind == CXIdxEntity_CXXDestructor; + // bool process_declaring_type = is_pure_virtual || is_ctor_or_dtor; - type_def->is_bad_def = is_system_def; + // Add function usage information. We only want to do it once per + // definition/declaration. Do it on definition since there should only + // ever + // be one of those in the entire program. + if (IsTypeDefinition(decl->semanticContainer)) { + TypeId declaring_type_id = + db->ToTypeId(decl->semanticContainer->cursor); + IndexedTypeDef* declaring_type_def = db->Resolve(declaring_type_id); + func_def->def.declaring_type = declaring_type_id; - // 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? - //if (!decl->isRedeclaration) { + // 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; + AddUsage(declaring_type_def->uses, type_usage_loc); + } + + // Register function in declaring type if it hasn't been registered + // yet. + if (!Contains(declaring_type_def->def.funcs, func_id)) + declaring_type_def->def.funcs.push_back(func_id); + } + + // TypeResolution ret_type = ResolveToType(db, + // decl_cursor.get_type().get_return_type()); + // if (ret_type.resolved_type) + // AddInterestingUsageToType(db, ret_type, + // FindLocationOfTypeSpecifier(decl_cursor)); + + if (decl->isDefinition || is_pure_virtual) { + // Mark type usage for parameters as interesting. We handle this here + // instead of inside var declaration because clang will not emit a var + // declaration for an unnamed parameter, but we still want to mark the + // usage as interesting. + // TODO: Do a similar thing for function decl parameter usages. Mark + // prototype params as interesting type usages but also relate + // mark + // them as as usages on the primary variable - requires USR to + // be + // the same. We can work around it by declaring which variables + // a + // parameter has declared and update the USR in the definition. + clang::Cursor cursor = decl->cursor; + for (clang::Cursor arg : cursor.get_arguments()) { + switch (arg.get_kind()) { + case CXCursor_ParmDecl: + // We don't need to know the arg type, but we do want to mark it + // as + // an interesting usage. Note that we use semanticContainer + // twice + // because a parameter is not really part of the lexical + // container. + AddDeclTypeUsages(db, arg, true /*is_interesting*/, + decl->semanticContainer, + decl->semanticContainer); + + // TypeResolution arg_type = ResolveToType(db, arg.get_type()); + // if (arg_type.resolved_type) + // AddInterestingUsageToType(db, arg_type, + // FindLocationOfTypeSpecifier(arg)); + break; + } + } + + // Process inheritance. + // void clang_getOverriddenCursors(CXCursor cursor, CXCursor + // **overridden, unsigned *num_overridden); + // void clang_disposeOverriddenCursors(CXCursor *overridden); + if (clang_CXXMethod_isVirtual(decl->cursor)) { + CXCursor* overridden; + unsigned int num_overridden; + clang_getOverriddenCursors(decl->cursor, &overridden, + &num_overridden); + + // TODO: How to handle multiple parent overrides?? + for (unsigned int i = 0; i < num_overridden; ++i) { + clang::Cursor parent = overridden[i]; + FuncId parent_id = db->ToFuncId(parent.get_usr()); + IndexedFuncDef* parent_def = db->Resolve(parent_id); + func_def = db->Resolve(func_id); // ToFuncId invalidated func_def + + func_def->def.base = parent_id; + parent_def->derived.push_back(func_id); + } + + clang_disposeOverriddenCursors(overridden); + } + } + } + + /* + optional base; + std::vector derived; + std::vector locals; + std::vector callers; + std::vector callees; + std::vector uses; + */ + break; + } + + case CXIdxEntity_Typedef: + case CXIdxEntity_CXXTypeAlias: { + // 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. + optional alias_of = + AddDeclTypeUsages(db, decl->cursor, true /*is_interesting*/, + decl->semanticContainer, decl->lexicalContainer); + + 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(); - // name can be null in an anonymous struct (see tests/types/anonymous_struct.cc). - if (decl->entityInfo->name) { - ns->RegisterQualifiedName(decl->entityInfo->USR, decl->semanticContainer, decl->entityInfo->name); type_def->def.short_name = decl->entityInfo->name; - } - else { - type_def->def.short_name = ""; + 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); + break; } - type_def->def.qualified_name = ns->QualifiedName(decl->semanticContainer, type_def->def.short_name); + case CXIdxEntity_Enum: + case CXIdxEntity_Union: + case CXIdxEntity_Struct: + case CXIdxEntity_CXXClass: { + TypeId type_id = db->ToTypeId(decl->entityInfo->USR); + IndexedTypeDef* type_def = db->Resolve(type_id); - // } + type_def->is_bad_def = is_system_def; - 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); + // 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? + // if (!decl->isRedeclaration) { - //type_def->alias_of - //type_def->funcs - //type_def->types - //type_def->uses - //type_def->vars + // name can be null in an anonymous struct (see + // tests/types/anonymous_struct.cc). + if (decl->entityInfo->name) { + ns->RegisterQualifiedName(decl->entityInfo->USR, + decl->semanticContainer, + decl->entityInfo->name); + type_def->def.short_name = decl->entityInfo->name; + } else { + type_def->def.short_name = ""; + } - // Add type-level inheritance information. - CXIdxCXXClassDeclInfo const* class_info = clang_index_getCXXClassDeclInfo(decl); - if (class_info) { - for (unsigned int i = 0; i < class_info->numBases; ++i) { - const CXIdxBaseClassInfo* base_class = class_info->bases[i]; + type_def->def.qualified_name = + ns->QualifiedName(decl->semanticContainer, type_def->def.short_name); - AddDeclTypeUsages(db, base_class->cursor, true /*is_interesting*/, decl->semanticContainer, decl->lexicalContainer); - optional parent_type_id = ResolveToDeclarationType(db, base_class->cursor); - IndexedTypeDef* type_def = db->Resolve(type_id); // type_def ptr could be invalidated by ResolveDeclToType. - if (parent_type_id) { - IndexedTypeDef* parent_type_def = db->Resolve(parent_type_id.value()); - parent_type_def->derived.push_back(type_id); - type_def->def.parents.push_back(parent_type_id.value()); + // } + + 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->alias_of + // type_def->funcs + // type_def->types + // type_def->uses + // type_def->vars + + // Add type-level inheritance information. + CXIdxCXXClassDeclInfo const* class_info = + clang_index_getCXXClassDeclInfo(decl); + if (class_info) { + for (unsigned int i = 0; i < class_info->numBases; ++i) { + const CXIdxBaseClassInfo* base_class = class_info->bases[i]; + + AddDeclTypeUsages(db, base_class->cursor, true /*is_interesting*/, + decl->semanticContainer, decl->lexicalContainer); + optional parent_type_id = + ResolveToDeclarationType(db, base_class->cursor); + IndexedTypeDef* type_def = + db->Resolve(type_id); // type_def ptr could be invalidated by + // ResolveDeclToType. + if (parent_type_id) { + IndexedTypeDef* parent_type_def = + db->Resolve(parent_type_id.value()); + parent_type_def->derived.push_back(type_id); + type_def->def.parents.push_back(parent_type_id.value()); + } } } + break; } - break; - } - default: - std::cerr << "!! Unhandled indexDeclaration: " << clang::Cursor(decl->cursor).ToString() << " at " << db->id_cache.Resolve(decl->loc, false /*interesting*/).ToString() << std::endl; - std::cerr << " entityInfo->kind = " << decl->entityInfo->kind << std::endl; - std::cerr << " entityInfo->USR = " << decl->entityInfo->USR << std::endl; - if (decl->declAsContainer) - std::cerr << " declAsContainer = " << clang::Cursor(decl->declAsContainer->cursor).ToString() << std::endl; - if (decl->semanticContainer) - std::cerr << " semanticContainer = " << clang::Cursor(decl->semanticContainer->cursor).ToString() << std::endl; - if (decl->lexicalContainer) - std::cerr << " lexicalContainer = " << clang::Cursor(decl->lexicalContainer->cursor).get_usr() << std::endl; - break; + default: + std::cerr + << "!! Unhandled indexDeclaration: " + << clang::Cursor(decl->cursor).ToString() << " at " + << db->id_cache.Resolve(decl->loc, false /*interesting*/).ToString() + << std::endl; + std::cerr << " entityInfo->kind = " << decl->entityInfo->kind + << std::endl; + std::cerr << " entityInfo->USR = " << decl->entityInfo->USR + << std::endl; + if (decl->declAsContainer) + std::cerr << " declAsContainer = " + << clang::Cursor(decl->declAsContainer->cursor).ToString() + << std::endl; + if (decl->semanticContainer) + std::cerr << " semanticContainer = " + << clang::Cursor(decl->semanticContainer->cursor).ToString() + << std::endl; + if (decl->lexicalContainer) + std::cerr << " lexicalContainer = " + << clang::Cursor(decl->lexicalContainer->cursor).get_usr() + << std::endl; + break; } } bool IsFunction(CXCursorKind kind) { switch (kind) { - case CXCursor_CXXMethod: - case CXCursor_FunctionDecl: - return true; + case CXCursor_CXXMethod: + case CXCursor_FunctionDecl: + return true; } return false; } -void indexEntityReference(CXClientData client_data, const CXIdxEntityRefInfo* ref) { +void indexEntityReference(CXClientData client_data, + const CXIdxEntityRefInfo* ref) { if (clang_Location_isInSystemHeader(clang_getCursorLocation(ref->cursor)) || - clang_Location_isInSystemHeader(clang_getCursorLocation(ref->referencedEntity->cursor))) + clang_Location_isInSystemHeader( + clang_getCursorLocation(ref->referencedEntity->cursor))) return; IndexParam* param = static_cast(client_data); IndexedFile* db = param->db; clang::Cursor cursor(ref->cursor); - //std::cerr << "REF kind=" << ref->referencedEntity->kind << " at " << db->id_cache.Resolve(cursor, false).ToPrettyString(&db->id_cache) << std::endl; + // std::cerr << "REF kind=" << ref->referencedEntity->kind << " at " << + // db->id_cache.Resolve(cursor, false).ToPrettyString(&db->id_cache) << + // std::endl; switch (ref->referencedEntity->kind) { - case CXIdxEntity_CXXNamespace: - { - // We don't index namespace usages. - break; - } - - case CXIdxEntity_EnumConstant: - case CXIdxEntity_CXXStaticVariable: - case CXIdxEntity_Variable: - case CXIdxEntity_Field: - { - 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); - break; - } - - case CXIdxEntity_CXXConversionFunction: - case CXIdxEntity_CXXStaticMethod: - case CXIdxEntity_CXXInstanceMethod: - case CXIdxEntity_Function: - case CXIdxEntity_CXXConstructor: - case CXIdxEntity_CXXDestructor: - { - // TODO: Redirect container to constructor for the following example, ie, - // we should be inserting an outgoing function call from the Foo - // ctor. - // - // int Gen() { return 5; } - // class Foo { - // int x = Gen(); - // } - - // 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) break; - param->last_func_usage_location = loc; - - // Note: be careful, calling db->ToFuncId invalidates the FuncDef* ptrs. - FuncId called_id = db->ToFuncId(ref->referencedEntity->USR); - if (IsFunction(ref->container->cursor.kind)) { - FuncId caller_id = db->ToFuncId(ref->container->cursor); - 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); - } - else { - IndexedFuncDef* called_def = db->Resolve(called_id); - AddUsage(called_def->uses, loc); + case CXIdxEntity_CXXNamespace: { + // We don't index namespace usages. + break; } - // For constructor/destructor, also add a usage against the type. Clang - // will insert and visit implicit constructor references, so we also check - // the location of the ctor call compared to the parent call. If they are - // the same, this is most likely an implicit ctors. - clang::Cursor ref_cursor = ref->cursor; - if (ref->referencedEntity->kind == CXIdxEntity_CXXConstructor || - ref->referencedEntity->kind == CXIdxEntity_CXXDestructor) { + case CXIdxEntity_EnumConstant: + case CXIdxEntity_CXXStaticVariable: + case CXIdxEntity_Variable: + case CXIdxEntity_Field: { + clang::Cursor referenced = ref->referencedEntity->cursor; + referenced = referenced.template_specialization_to_template_definition(); - Location parent_loc = db->id_cache.Resolve(ref->parentEntity->cursor, true /*interesting*/); - Location our_loc = db->id_cache.Resolve(ref->loc, true /*is_interesting*/); - if (!parent_loc.IsEqualTo(our_loc)) { + 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); + break; + } + + case CXIdxEntity_CXXConversionFunction: + case CXIdxEntity_CXXStaticMethod: + case CXIdxEntity_CXXInstanceMethod: + case CXIdxEntity_Function: + case CXIdxEntity_CXXConstructor: + case CXIdxEntity_CXXDestructor: { + // TODO: Redirect container to constructor for the following example, ie, + // we should be inserting an outgoing function call from the Foo + // ctor. + // + // int Gen() { return 5; } + // class Foo { + // int x = Gen(); + // } + + // 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) + break; + param->last_func_usage_location = loc; + + // Note: be careful, calling db->ToFuncId invalidates the FuncDef* ptrs. + FuncId called_id = db->ToFuncId(ref->referencedEntity->USR); + if (IsFunction(ref->container->cursor.kind)) { + FuncId caller_id = db->ToFuncId(ref->container->cursor); + IndexedFuncDef* caller_def = db->Resolve(caller_id); IndexedFuncDef* called_def = db->Resolve(called_id); - // I suspect it is possible for the declaring type to be null - // when the class is invalid. - if (called_def->def.declaring_type) { - //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); + + caller_def->def.callees.push_back(FuncRef(called_id, loc)); + called_def->callers.push_back(FuncRef(caller_id, loc)); + AddUsage(called_def->uses, loc); + } else { + IndexedFuncDef* called_def = db->Resolve(called_id); + AddUsage(called_def->uses, loc); + } + + // For constructor/destructor, also add a usage against the type. Clang + // will insert and visit implicit constructor references, so we also check + // the location of the ctor call compared to the parent call. If they are + // the same, this is most likely an implicit ctors. + 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, + true /*interesting*/); + Location our_loc = + db->id_cache.Resolve(ref->loc, true /*is_interesting*/); + if (!parent_loc.IsEqualTo(our_loc)) { + IndexedFuncDef* called_def = db->Resolve(called_id); + // I suspect it is possible for the declaring type to be null + // when the class is invalid. + if (called_def->def.declaring_type) { + // 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); + } } } + break; } - break; - } - case CXIdxEntity_Typedef: - case CXIdxEntity_CXXTypeAlias: - case CXIdxEntity_Enum: - case CXIdxEntity_Union: - case CXIdxEntity_Struct: - case CXIdxEntity_CXXClass: - { - clang::Cursor referenced = ref->referencedEntity->cursor; - referenced = referenced.template_specialization_to_template_definition(); - TypeId referenced_id = db->ToTypeId(referenced.get_usr()); + case CXIdxEntity_Typedef: + case CXIdxEntity_CXXTypeAlias: + case CXIdxEntity_Enum: + case CXIdxEntity_Union: + case CXIdxEntity_Struct: + case CXIdxEntity_CXXClass: { + 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); + 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; + // 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 + // CXIdxEntity_Variable, the other will be CXIdxEntity_Function. There + // does + // not appear to be a good way to disambiguate these references, as using + // parent type alone breaks other indexing tasks. + // + // To work around this, we check to see if the usage location has been + // inserted into all_uses previously. + // + // struct Foo {}; + // void Make() { + // Foo f; + // } + // + AddUsage(referenced_def->uses, + db->id_cache.Resolve(ref->loc, false /*interesting*/)); + break; } - // - // 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 - // CXIdxEntity_Variable, the other will be CXIdxEntity_Function. There does - // not appear to be a good way to disambiguate these references, as using - // parent type alone breaks other indexing tasks. - // - // To work around this, we check to see if the usage location has been - // inserted into all_uses previously. - // - // struct Foo {}; - // void Make() { - // Foo f; - // } - // - AddUsage(referenced_def->uses, db->id_cache.Resolve(ref->loc, false /*interesting*/)); - break; - } - default: - std::cerr << "!! Unhandled indexEntityReference: " << cursor.ToString() << " at " << db->id_cache.Resolve(ref->loc, false /*interesting*/).ToString() << std::endl; - std::cerr << " ref->referencedEntity->kind = " << ref->referencedEntity->kind << std::endl; - if (ref->parentEntity) - std::cerr << " ref->parentEntity->kind = " << ref->parentEntity->kind << std::endl; - std::cerr << " ref->loc = " << db->id_cache.Resolve(ref->loc, false /*interesting*/).ToString() << std::endl; - std::cerr << " ref->kind = " << ref->kind << std::endl; - if (ref->parentEntity) - std::cerr << " parentEntity = " << clang::Cursor(ref->parentEntity->cursor).ToString() << std::endl; - if (ref->referencedEntity) - std::cerr << " referencedEntity = " << clang::Cursor(ref->referencedEntity->cursor).ToString() << std::endl; - if (ref->container) - std::cerr << " container = " << clang::Cursor(ref->container->cursor).ToString() << std::endl; - break; + default: + std::cerr + << "!! Unhandled indexEntityReference: " << cursor.ToString() + << " at " + << db->id_cache.Resolve(ref->loc, false /*interesting*/).ToString() + << std::endl; + std::cerr << " ref->referencedEntity->kind = " + << ref->referencedEntity->kind << std::endl; + if (ref->parentEntity) + std::cerr << " ref->parentEntity->kind = " + << ref->parentEntity->kind << std::endl; + std::cerr + << " ref->loc = " + << db->id_cache.Resolve(ref->loc, false /*interesting*/).ToString() + << std::endl; + std::cerr << " ref->kind = " << ref->kind << std::endl; + if (ref->parentEntity) + std::cerr << " parentEntity = " + << clang::Cursor(ref->parentEntity->cursor).ToString() + << std::endl; + if (ref->referencedEntity) + std::cerr << " referencedEntity = " + << clang::Cursor(ref->referencedEntity->cursor).ToString() + << std::endl; + if (ref->container) + std::cerr << " container = " + << clang::Cursor(ref->container->cursor).ToString() + << std::endl; + break; } } +void emptyIndexDeclaration(CXClientData client_data, + const CXIdxDeclInfo* decl) {} +void emptyIndexEntityReference(CXClientData client_data, + const CXIdxEntityRefInfo* ref) {} -void emptyIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {} -void emptyIndexEntityReference(CXClientData client_data, const CXIdxEntityRefInfo* ref) {} - -IndexedFile Parse(std::string filename, std::vector args, bool dump_ast) { +IndexedFile Parse(std::string filename, + std::vector args, + bool dump_ast) { clang_toggleCrashRecovery(1); args.push_back("-std=c++11"); args.push_back("-fms-compatibility"); args.push_back("-fdelayed-template-parsing"); - //args.push_back("-isystem C:\\Users\\jacob\\Desktop\\superindex\\indexer\\libcxx-3.9.1\\include"); - //args.push_back("--sysroot C:\\Users\\jacob\\Desktop\\superindex\\indexer\\libcxx-3.9.1"); + // args.push_back("-isystem + // C:\\Users\\jacob\\Desktop\\superindex\\indexer\\libcxx-3.9.1\\include"); + // args.push_back("--sysroot + // C:\\Users\\jacob\\Desktop\\superindex\\indexer\\libcxx-3.9.1"); - clang::Index index(0 /*excludeDeclarationsFromPCH*/, 0 /*displayDiagnostics*/); + clang::Index index(0 /*excludeDeclarationsFromPCH*/, + 0 /*displayDiagnostics*/); clang::TranslationUnit tu(index, filename, args); if (dump_ast) @@ -1134,18 +1224,22 @@ IndexedFile Parse(std::string filename, std::vector args, bool dump CXIndexAction index_action = clang_IndexAction_create(index.cx_index); IndexerCallbacks callbacks[] = { - { &abortQuery, &diagnostic, &enteredMainFile, &ppIncludedFile, &importedASTFile, &startedTranslationUnit, &indexDeclaration, &indexEntityReference } - //{ &abortQuery, &diagnostic, &enteredMainFile, &ppIncludedFile, &importedASTFile, &startedTranslationUnit, &emptyIndexDeclaration, &emptyIndexEntityReference } - /* - callbacks.abortQuery = &abortQuery; - callbacks.diagnostic = &diagnostic; - callbacks.enteredMainFile = &enteredMainFile; - callbacks.ppIncludedFile = &ppIncludedFile; - callbacks.importedASTFile = &importedASTFile; - callbacks.startedTranslationUnit = &startedTranslationUnit; - callbacks.indexDeclaration = &indexDeclaration; - callbacks.indexEntityReference = &indexEntityReference; - */ + {&abortQuery, &diagnostic, &enteredMainFile, &ppIncludedFile, + &importedASTFile, &startedTranslationUnit, &indexDeclaration, + &indexEntityReference} + //{ &abortQuery, &diagnostic, &enteredMainFile, &ppIncludedFile, + //&importedASTFile, &startedTranslationUnit, &emptyIndexDeclaration, + //&emptyIndexEntityReference } + /* + callbacks.abortQuery = &abortQuery; + callbacks.diagnostic = &diagnostic; + callbacks.enteredMainFile = &enteredMainFile; + callbacks.ppIncludedFile = &ppIncludedFile; + callbacks.importedASTFile = &importedASTFile; + callbacks.startedTranslationUnit = &startedTranslationUnit; + callbacks.indexDeclaration = &indexDeclaration; + callbacks.indexEntityReference = &indexEntityReference; + */ }; IndexedFile db(filename); @@ -1154,9 +1248,10 @@ IndexedFile Parse(std::string filename, std::vector args, bool dump std::cerr << "!! [START] Indexing " << filename << std::endl; clang_indexTranslationUnit(index_action, ¶m, callbacks, sizeof(callbacks), - CXIndexOpt_IndexFunctionLocalSymbols | CXIndexOpt_SkipParsedBodiesInSession, tu.cx_tu); + CXIndexOpt_IndexFunctionLocalSymbols | + CXIndexOpt_SkipParsedBodiesInSession, + tu.cx_tu); std::cerr << "!! [END] Indexing " << filename << std::endl; - clang_IndexAction_dispose(index_action); return db; diff --git a/indexer.h b/indexer.h index 347662e3..5d101bd5 100644 --- a/indexer.h +++ b/indexer.h @@ -26,34 +26,26 @@ struct IndexedVarDef; using namespace std::experimental; - -template +template struct Id { uint64_t id; - Id() : id(0) {} // Needed for containers. Do not use directly. + Id() : id(0) {} // Needed for containers. Do not use directly. Id(uint64_t id) : id(id) {} - bool operator==(const Id& other) const { - return id == other.id; - } + bool operator==(const Id& other) const { return id == other.id; } - bool operator<(const Id& other) const { - return id < other.id; - } + bool operator<(const Id& other) const { return id < other.id; } }; namespace std { - template - struct hash> { - size_t operator()(const Id& k) const { - return hash()(k.id); - } - }; +template +struct hash> { + size_t operator()(const Id& k) const { return hash()(k.id); } +}; } - -template +template bool operator==(const Id& a, const Id& b) { assert(a.group == b.group && "Cannot compare Ids from different groups"); return a.id == b.id; @@ -87,9 +79,7 @@ struct Location { this->column = column; } - FileId file_id() const { - return FileId(raw_file_id); - } + FileId file_id() const { return FileId(raw_file_id); } explicit Location(const char* encoded) : Location() { int len = strlen(encoded); @@ -104,13 +94,15 @@ struct Location { raw_file_id = atoi(encoded); while (*encoded && *encoded != ':') ++encoded; - if (*encoded == ':') ++encoded; + if (*encoded == ':') + ++encoded; assert(encoded); line = atoi(encoded); while (*encoded && *encoded != ':') ++encoded; - if (*encoded == ':') ++encoded; + if (*encoded == ':') + ++encoded; assert(encoded); column = atoi(encoded); @@ -144,21 +136,13 @@ struct Location { // operator== doesn't seem to work properly... bool IsEqualTo(const Location& o) const { // When comparing, ignore the value of |interesting|. - return - raw_file_id == o.raw_file_id && - line == o.line && - column == o.column; + return raw_file_id == o.raw_file_id && line == o.line && column == o.column; } - bool operator==(const Location& o) const { - return IsEqualTo(o); - } + bool operator==(const Location& o) const { return IsEqualTo(o); } bool operator<(const Location& o) const { - return - interesting < o.interesting && - raw_file_id < o.raw_file_id && - line < o.line && - column < o.column; + return interesting < o.interesting && raw_file_id < o.raw_file_id && + line < o.line && column < o.column; } Location WithInteresting(bool interesting) { @@ -229,31 +213,29 @@ Location WithInteresting(bool interesting) { END_BITFIELD_TYPE() #endif -template +template struct Ref { Id id; Location loc; - Ref() {} // For serialization. + Ref() {} // For serialization. Ref(Id id, Location loc) : id(id), loc(loc) {} bool operator==(const Ref& other) { return id == other.id && loc == other.loc; } - bool operator!=(const Ref& other) { - return !(*this == other); - } + bool operator!=(const Ref& other) { return !(*this == other); } bool operator<(const Ref& other) const { return id < other.id && loc < other.loc; } }; -template +template bool operator==(const Ref& a, const Ref& b) { return a.id == b.id && a.loc == b.loc; } -template +template bool operator!=(const Ref& a, const Ref& b) { return !(a == b); } @@ -262,13 +244,15 @@ using TypeRef = Ref; using FuncRef = Ref; using VarRef = Ref; - // TODO: skip as much forward-processing as possible when |is_system_def| is // set to false. // TODO: Either eliminate the defs created as a by-product of cross-referencing, // or do not emit things we don't have definitions for. -template +template struct TypeDefDefinitionData { // General metadata. std::string usr; @@ -298,26 +282,30 @@ struct TypeDefDefinitionData { std::vector funcs; std::vector vars; - TypeDefDefinitionData() {} // For reflection. + TypeDefDefinitionData() {} // For reflection. TypeDefDefinitionData(const std::string& usr) : usr(usr) {} - bool operator==(const TypeDefDefinitionData& other) const { - return - usr == other.usr && - short_name == other.short_name && - qualified_name == other.qualified_name && - definition == other.definition && - alias_of == other.alias_of && - parents == other.parents && - types == other.types && - funcs == other.funcs && - vars == other.vars; + bool operator==(const TypeDefDefinitionData& + other) const { + return usr == other.usr && short_name == other.short_name && + qualified_name == other.qualified_name && + definition == other.definition && alias_of == other.alias_of && + parents == other.parents && types == other.types && + funcs == other.funcs && vars == other.vars; } - bool operator!=(const TypeDefDefinitionData& other) const { return !(*this == other); } + bool operator!=(const TypeDefDefinitionData& + other) const { + return !(*this == other); + } }; -template -void Reflect(TVisitor& visitor, TypeDefDefinitionData& value) { +template +void Reflect(TVisitor& visitor, + TypeDefDefinitionData& value) { REFLECT_MEMBER_START(); REFLECT_MEMBER(usr); REFLECT_MEMBER(short_name); @@ -331,7 +319,6 @@ void Reflect(TVisitor& visitor, TypeDefDefinitionData def; @@ -346,7 +333,7 @@ struct IndexedTypeDef { bool is_bad_def = true; - IndexedTypeDef() : def("") {} // For serialization + IndexedTypeDef() : def("") {} // For serialization IndexedTypeDef(TypeId id, const std::string& usr); @@ -356,15 +343,19 @@ struct IndexedTypeDef { }; namespace std { - template <> - struct hash { - size_t operator()(const IndexedTypeDef& k) const { - return hash()(k.def.usr); - } - }; +template <> +struct hash { + size_t operator()(const IndexedTypeDef& k) const { + return hash()(k.def.usr); + } +}; } -template +template struct FuncDefDefinitionData { // General metadata. std::string usr; @@ -384,27 +375,36 @@ struct FuncDefDefinitionData { // Functions that this function calls. std::vector callees; - FuncDefDefinitionData() {} // For reflection. + FuncDefDefinitionData() {} // For reflection. FuncDefDefinitionData(const std::string& usr) : usr(usr) { - //assert(usr.size() > 0); + // assert(usr.size() > 0); } - bool operator==(const FuncDefDefinitionData& other) const { - return - usr == other.usr && - short_name == other.short_name && - qualified_name == other.qualified_name && - definition == other.definition && - declaring_type == other.declaring_type && - base == other.base && - locals == other.locals && - callees == other.callees; + bool operator==( + const FuncDefDefinitionData& + other) const { + return usr == other.usr && short_name == other.short_name && + qualified_name == other.qualified_name && + definition == other.definition && + declaring_type == other.declaring_type && base == other.base && + locals == other.locals && callees == other.callees; + } + bool operator!=( + const FuncDefDefinitionData& + other) const { + return !(*this == other); } - bool operator!=(const FuncDefDefinitionData& other) const { return !(*this == other); } }; -template -void Reflect(TVisitor& visitor, FuncDefDefinitionData& value) { +template +void Reflect( + TVisitor& visitor, + FuncDefDefinitionData& value) { REFLECT_MEMBER_START(); REFLECT_MEMBER(usr); REFLECT_MEMBER(short_name); @@ -441,9 +441,9 @@ struct IndexedFuncDef { bool is_bad_def = true; - IndexedFuncDef() {} // For reflection. + IndexedFuncDef() {} // For reflection. IndexedFuncDef(FuncId id, const std::string& usr) : id(id), def(usr) { - //assert(usr.size() > 0); + // assert(usr.size() > 0); } bool operator<(const IndexedFuncDef& other) const { @@ -452,15 +452,18 @@ struct IndexedFuncDef { }; namespace std { - template <> - struct hash { - size_t operator()(const IndexedFuncDef& k) const { - return hash()(k.def.usr); - } - }; +template <> +struct hash { + size_t operator()(const IndexedFuncDef& k) const { + return hash()(k.def.usr); + } +}; } -template +template struct VarDefDefinitionData { // General metadata. std::string usr; @@ -477,24 +480,30 @@ struct VarDefDefinitionData { // Type which declares this one (ie, it is a method) optional declaring_type; - VarDefDefinitionData() {} // For reflection. + VarDefDefinitionData() {} // For reflection. VarDefDefinitionData(const std::string& usr) : usr(usr) {} - bool operator==(const VarDefDefinitionData& other) const { - return - usr == other.usr && - short_name == other.short_name && - qualified_name == other.qualified_name && - declaration == other.declaration && - definition == other.definition && - variable_type == other.variable_type && - declaring_type == other.declaring_type; + bool operator==(const VarDefDefinitionData& + other) const { + return usr == other.usr && short_name == other.short_name && + qualified_name == other.qualified_name && + declaration == other.declaration && definition == other.definition && + variable_type == other.variable_type && + declaring_type == other.declaring_type; + } + bool operator!=(const VarDefDefinitionData& + other) const { + return !(*this == other); } - bool operator!=(const VarDefDefinitionData& other) const { return !(*this == other); } }; -template -void Reflect(TVisitor& visitor, VarDefDefinitionData& value) { +template +void Reflect(TVisitor& visitor, + VarDefDefinitionData& value) { REFLECT_MEMBER_START(); REFLECT_MEMBER(usr); REFLECT_MEMBER(short_name); @@ -515,10 +524,10 @@ struct IndexedVarDef { bool is_bad_def = true; - IndexedVarDef() : def("") {} // For serialization + IndexedVarDef() : def("") {} // For serialization IndexedVarDef(VarId id, const std::string& usr) : id(id), def(usr) { - //assert(usr.size() > 0); + // assert(usr.size() > 0); } bool operator<(const IndexedVarDef& other) const { @@ -527,12 +536,12 @@ struct IndexedVarDef { }; namespace std { - template <> - struct hash { - size_t operator()(const IndexedVarDef& k) const { - return hash()(k.def.usr); - } - }; +template <> +struct hash { + size_t operator()(const IndexedVarDef& k) const { + return hash()(k.def.usr); + } +}; } struct IdCache { @@ -576,6 +585,6 @@ struct IndexedFile { std::string ToString(); }; - - -IndexedFile Parse(std::string filename, std::vector args, bool dump_ast = false); \ No newline at end of file +IndexedFile Parse(std::string filename, + std::vector args, + bool dump_ast = false); \ No newline at end of file