mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 07:08:10 +00:00
CppLanguageServer: Add "get_parameters_hint" capability
Given a call site, the C++ language server can now return the declared parameters of the called function, as well as the index of the parameter that the cursor is currently at.
This commit is contained in:
parent
232013c05b
commit
32be65a8b4
9 changed files with 181 additions and 2 deletions
|
@ -177,6 +177,7 @@ Vector<StringView> CppComprehensionEngine::scope_of_reference_to_symbol(const AS
|
|||
{
|
||||
const Name* name = nullptr;
|
||||
if (node.is_name()) {
|
||||
// FIXME It looks like this code path is never taken
|
||||
name = reinterpret_cast<const Name*>(&node);
|
||||
} else if (node.is_identifier()) {
|
||||
auto* parent = node.parent();
|
||||
|
@ -454,6 +455,7 @@ RefPtr<Declaration> CppComprehensionEngine::find_declaration_of(const DocumentDa
|
|||
dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "find_declaration_of: {} ({})", document_data.parser().text_of_node(node), node.class_name());
|
||||
if (!node.is_identifier()) {
|
||||
dbgln("node is not an identifier, can't find declaration");
|
||||
return {};
|
||||
}
|
||||
|
||||
auto target_decl = get_target_declaration(node);
|
||||
|
@ -726,4 +728,113 @@ bool CppComprehensionEngine::is_symbol_available(const Symbol& symbol, const Vec
|
|||
return true;
|
||||
}
|
||||
|
||||
Optional<CodeComprehensionEngine::FunctionParamsHint> CppComprehensionEngine::get_function_params_hint(const String& filename, const GUI::TextPosition& identifier_position)
|
||||
{
|
||||
const auto* document_ptr = get_or_create_document_data(filename);
|
||||
if (!document_ptr)
|
||||
return {};
|
||||
|
||||
const auto& document = *document_ptr;
|
||||
Cpp::Position cpp_position { identifier_position.line(), identifier_position.column() };
|
||||
auto node = document.parser().node_at(cpp_position);
|
||||
if (!node) {
|
||||
dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "no node at position {}:{}", identifier_position.line(), identifier_position.column());
|
||||
return {};
|
||||
}
|
||||
|
||||
dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "node type: {}", node->class_name());
|
||||
|
||||
FunctionCall* call_node { nullptr };
|
||||
|
||||
if (node->is_function_call()) {
|
||||
call_node = ((FunctionCall*)node.ptr());
|
||||
|
||||
auto token = document.parser().token_at(cpp_position);
|
||||
|
||||
// If we're in a function call with 0 arguments
|
||||
if (token.has_value() && (token->type() == Token::Type::LeftParen || token->type() == Token::Type::RightParen)) {
|
||||
return get_function_params_hint(document, *call_node, call_node->m_arguments.is_empty() ? 0 : call_node->m_arguments.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Walk upwards in the AST to find a FunctionCall node
|
||||
while (!call_node && node) {
|
||||
auto parent_is_call = node->parent() && node->parent()->is_function_call();
|
||||
if (parent_is_call) {
|
||||
call_node = (FunctionCall*)node->parent();
|
||||
break;
|
||||
}
|
||||
node = node->parent();
|
||||
}
|
||||
|
||||
if (!call_node) {
|
||||
dbgln("did not find function call");
|
||||
return {};
|
||||
}
|
||||
|
||||
Optional<size_t> invoked_arg_index;
|
||||
for (size_t arg_index = 0; arg_index < call_node->m_arguments.size(); ++arg_index) {
|
||||
if (&call_node->m_arguments[arg_index] == node.ptr()) {
|
||||
invoked_arg_index = arg_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!invoked_arg_index.has_value()) {
|
||||
dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "could not find argument index, defaulting to the last argument");
|
||||
invoked_arg_index = call_node->m_arguments.is_empty() ? 0 : call_node->m_arguments.size() - 1;
|
||||
}
|
||||
|
||||
dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "arg index: {}", invoked_arg_index.value());
|
||||
return get_function_params_hint(document, *call_node, invoked_arg_index.value());
|
||||
}
|
||||
|
||||
Optional<CppComprehensionEngine::FunctionParamsHint> CppComprehensionEngine::get_function_params_hint(
|
||||
DocumentData const& document,
|
||||
FunctionCall& call_node,
|
||||
size_t argument_index)
|
||||
{
|
||||
Identifier* callee = nullptr;
|
||||
if (call_node.m_callee->is_identifier()) {
|
||||
callee = (Identifier*)call_node.m_callee.ptr();
|
||||
} else if (call_node.m_callee->is_name()) {
|
||||
callee = ((Name&)*call_node.m_callee).m_name.ptr();
|
||||
} else if (call_node.m_callee->is_member_expression()) {
|
||||
auto& member_exp = ((MemberExpression&)*call_node.m_callee);
|
||||
if (member_exp.m_property->is_identifier()) {
|
||||
callee = (Identifier*)member_exp.m_property.ptr();
|
||||
}
|
||||
}
|
||||
|
||||
if (!callee) {
|
||||
dbgln("unexpected node type for function call: {}", call_node.m_callee->class_name());
|
||||
return {};
|
||||
}
|
||||
VERIFY(callee);
|
||||
|
||||
auto decl = find_declaration_of(document, *callee);
|
||||
if (!decl) {
|
||||
dbgln("func decl not found");
|
||||
return {};
|
||||
}
|
||||
if (!decl->is_function()) {
|
||||
dbgln("declaration is not a function");
|
||||
return {};
|
||||
}
|
||||
|
||||
auto& func_decl = (FunctionDeclaration&)*decl;
|
||||
auto document_of_declaration = get_document_data(func_decl.filename());
|
||||
|
||||
FunctionParamsHint hint {};
|
||||
hint.current_index = argument_index;
|
||||
for (auto& arg : func_decl.m_parameters) {
|
||||
Vector<StringView> tokens_text;
|
||||
for (auto token : document_of_declaration->parser().tokens_in_range(arg.start(), arg.end())) {
|
||||
tokens_text.append(token.text());
|
||||
}
|
||||
hint.params.append(String::join(" ", tokens_text));
|
||||
}
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue