diff --git a/CodeLite/CxxCodeCompletion.cpp b/CodeLite/CxxCodeCompletion.cpp index e693adbd72..a341541d4b 100644 --- a/CodeLite/CxxCodeCompletion.cpp +++ b/CodeLite/CxxCodeCompletion.cpp @@ -166,15 +166,48 @@ void CxxCodeCompletion::shrink_scope(const wxString& text, unordered_map<wxStrin locals->reserve(variables.size()); vector<TagEntryPtr> parameters; - vector<TagEntryPtr> lambdas; - vector<TagEntryPtr> lambda_parameters; if(m_current_function_tag && m_current_function_tag->IsFunction()) { + vector<TagEntryPtr> all_lambdas; + vector<TagEntryPtr> lambdas; // get the current function parameters m_lookup->GetParameters(m_current_function_tag->GetPath(), parameters); - m_lookup->GetLambdas(m_current_function_tag->GetPath(), lambdas); + m_lookup->GetLambdas(m_current_function_tag->GetPath(), all_lambdas); + + // read all lambdas paramteres + unordered_map<wxString, TagEntryPtr> lambda_parameters_map; + unordered_map<wxString, TagEntryPtr> function_parameters_map; + + for(auto param : parameters) { + function_parameters_map.insert({ param->GetName(), param }); + } + + for(auto lambda : all_lambdas) { + if(lambda->GetLine() <= m_line_number) { + // load this lambda parameters and add them + vector<TagEntryPtr> lambda_parameters; + m_lookup->GetParameters(lambda->GetPath(), lambda_parameters); + for(auto param : lambda_parameters) { + // if a function parameter with this name alrady exists, skip it + if(function_parameters_map.count(param->GetName())) + continue; + + // if we already encoutered a lambda parameter with this name, replace it + if(lambda_parameters_map.count(param->GetName())) { + lambda_parameters_map.erase(param->GetName()); + } + lambda_parameters_map.insert({ param->GetName(), param }); + } + } + } + + // all the lambda paramters to the list of parameters + for(const auto& vt : lambda_parameters_map) { + parameters.emplace_back(vt.second); + } } if(file_tags) { + // set the function parameters (this includes any lambda parameters) file_tags->set_function_parameters(parameters); } @@ -1404,6 +1437,7 @@ size_t CxxCodeCompletion::get_word_completions(const CxxRemainder& remainder, ve { vector<TagEntryPtr> locals; + vector<TagEntryPtr> function_parameters; vector<TagEntryPtr> keywords; vector<TagEntryPtr> scope_members; vector<TagEntryPtr> other_scopes_members; @@ -1418,6 +1452,7 @@ size_t CxxCodeCompletion::get_word_completions(const CxxRemainder& remainder, ve vector<wxString> scopes = prepend_extra_scopes(visible_scopes); locals = get_locals(remainder.filter); + function_parameters = m_file_only_tags.get_function_parameters(remainder.filter); vector<wxString> kinds; // based on the lasts operand, build the list of items to fetch @@ -1453,10 +1488,11 @@ size_t CxxCodeCompletion::get_word_completions(const CxxRemainder& remainder, ve get_keywords_tags(remainder.filter, keywords); } candidates.reserve(sorted_locals.size() + sorted_scope_members.size() + sorted_other_scopes_members.size() + - sorted_global_scopes_members.size() + keywords.size()); + sorted_global_scopes_members.size() + keywords.size() + function_parameters.size()); // place the keywords first candidates.insert(candidates.end(), sorted_locals.begin(), sorted_locals.end()); + candidates.insert(candidates.end(), function_parameters.begin(), function_parameters.end()); candidates.insert(candidates.end(), keywords.begin(), keywords.end()); candidates.insert(candidates.end(), sorted_scope_members.begin(), sorted_scope_members.end()); candidates.insert(candidates.end(), sorted_other_scopes_members.begin(), sorted_other_scopes_members.end()); diff --git a/CodeLite/CxxCodeCompletion.hpp b/CodeLite/CxxCodeCompletion.hpp index 8dc35cb4f7..4277355dd5 100644 --- a/CodeLite/CxxCodeCompletion.hpp +++ b/CodeLite/CxxCodeCompletion.hpp @@ -127,6 +127,26 @@ struct FileScope { return nullptr; } + /** + * @brief return all function paramters that match the filter + * if filter is empty, return all of the parameters + */ + vector<TagEntryPtr> get_function_parameters(const wxString& filter) const + { + vector<TagEntryPtr> tags; + tags.reserve(function_parameters.size()); + + wxString lowercase_filter = filter.Lower(); + for(const auto& vt : function_parameters) { + if(filter.empty()) { + tags.push_back(vt.second); + } else if(vt.second->GetName().Lower().StartsWith(lowercase_filter)) { + tags.push_back(vt.second); + } + } + return tags; + } + const vector<wxString>& get_file_scopes() const { return local_scopes; } void set_file_scopes(const wxStringSet_t& scopes) { diff --git a/TODO.TXT b/TODO.TXT index 70edba1035..2f72aeabdb 100644 --- a/TODO.TXT +++ b/TODO.TXT @@ -81,4 +81,3 @@ New CTagsd CC engine: TODO: ----- - Change the open resource dialog to use clTerminalCtrl view similar to the LSPOutlineView dialog - diff --git a/ctagsd/tests/main.cpp b/ctagsd/tests/main.cpp index c99f11688e..cd28afc745 100644 --- a/ctagsd/tests/main.cpp +++ b/ctagsd/tests/main.cpp @@ -1101,6 +1101,7 @@ TEST_FUNC(test_cxx_code_completion_function_arguments) { ENSURE_DB_LOADED(); wxString filepath = R"(C:\src\codelite\ctagsd\lib\ProtocolHandler.cpp)"; + wxString filepath2 = R"(C:\src\codelite\Plugin\navigationmanager.cpp)"; if(wxFileExists(filepath)) { { completer->set_text(wxEmptyString, filepath, @@ -1116,6 +1117,23 @@ TEST_FUNC(test_cxx_code_completion_function_arguments) CHECK_BOOL(resolved); CHECK_STRING(resolved->GetPath(), "Channel"); } + { + vector<TagEntryPtr> candidates; + completer->set_text(wxEmptyString, filepath, + 430); // ProtocolHandler::on_initialize(unique_ptr<JSON>&& msg, Channel::ptr_t channel) + size_t count = + completer->word_complete(filepath, 430, "channel", wxEmptyString, { "std" }, true, candidates, {}); + CHECK_BOOL(count > 0); + CHECK_BOOL(is_tag_exists("ProtocolHandler::on_initialize::channel", candidates)); + } + } + if(wxFileExists(filepath2)) { + { + vector<TagEntryPtr> candidates; + size_t count = completer->word_complete(filepath2, 86, "editor", wxEmptyString, {}, true, candidates, {}); + CHECK_BOOL(count == 1); + CHECK_STRING(candidates[0]->GetTypename(), "IEditor *"); + } } return true; }