Fix autocompletion of static methods in built-in types in GDScript

This commit is contained in:
Yuri Roubinsky 2022-03-10 14:55:54 +03:00
parent 118f29694b
commit 0584387918
3 changed files with 73 additions and 18 deletions

View File

@ -2397,7 +2397,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
r_arghint = _make_arguments_hint(info, p_argidx);
return;
} else if (GDScriptParser::get_builtin_type(call->function_name) < Variant::VARIANT_MAX) {
// Complete constructor
// Complete constructor.
List<MethodInfo> constructors;
Variant::get_constructor_list(GDScriptParser::get_builtin_type(call->function_name), &constructors);
@ -2423,6 +2423,32 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
} else if (callee_type == GDScriptParser::Node::SUBSCRIPT) {
const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee);
if (subscript->base != nullptr && subscript->base->type == GDScriptParser::Node::IDENTIFIER) {
const GDScriptParser::IdentifierNode *base_identifier = static_cast<const GDScriptParser::IdentifierNode *>(subscript->base);
Variant::Type method_type = GDScriptParser::get_builtin_type(base_identifier->name);
if (method_type < Variant::VARIANT_MAX) {
Variant v;
Callable::CallError err;
Variant::construct(method_type, v, nullptr, 0, err);
if (err.error != Callable::CallError::CALL_OK) {
return;
}
List<MethodInfo> methods;
v.get_method_list(&methods);
for (MethodInfo &E : methods) {
if (p_argidx >= E.arguments.size()) {
continue;
}
if (E.name == call->function_name) {
r_arghint += _make_arguments_hint(E, p_argidx);
return;
}
}
}
}
if (subscript->is_attribute) {
GDScriptCompletionIdentifier ci;
if (_guess_expression_type(p_context, subscript->base, ci)) {
@ -2485,17 +2511,36 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
_find_annotation_arguments(annotation, completion_context.current_argument, quote_style, options);
r_forced = true;
} break;
case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: {
List<StringName> constants;
Variant::get_constants_for_type(completion_context.builtin_type, &constants);
for (const StringName &E : constants) {
ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
bool valid = false;
Variant default_value = Variant::get_constant_value(completion_context.builtin_type, E, &valid);
if (valid) {
option.default_value = default_value;
case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT_OR_STATIC_METHOD: {
// Constants.
{
List<StringName> constants;
Variant::get_constants_for_type(completion_context.builtin_type, &constants);
for (const StringName &E : constants) {
ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
bool valid = false;
Variant default_value = Variant::get_constant_value(completion_context.builtin_type, E, &valid);
if (valid) {
option.default_value = default_value;
}
options.insert(option.display, option);
}
}
// Methods.
{
List<StringName> methods;
Variant::get_builtin_method_list(completion_context.builtin_type, &methods);
for (const StringName &E : methods) {
if (Variant::is_builtin_method_static(completion_context.builtin_type, E)) {
ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
if (Variant::get_builtin_method_argument_count(completion_context.builtin_type, E) > 0 || Variant::is_builtin_method_vararg(completion_context.builtin_type, E)) {
option.insert_text += "(";
} else {
option.insert_text += "()";
}
options.insert(option.display, option);
}
}
options.insert(option.display, option);
}
} break;
case GDScriptParser::COMPLETION_INHERIT_TYPE: {
@ -3049,11 +3094,21 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
bool is_function = false;
switch (context.type) {
case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: {
r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
r_result.class_name = Variant::get_type_name(context.builtin_type);
r_result.class_member = p_symbol;
return OK;
case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT_OR_STATIC_METHOD: {
if (!Variant::has_builtin_method(context.builtin_type, StringName(p_symbol))) {
// A constant.
r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
r_result.class_name = Variant::get_type_name(context.builtin_type);
r_result.class_member = p_symbol;
return OK;
}
// A method.
GDScriptParser::DataType base_type;
base_type.kind = GDScriptParser::DataType::BUILTIN;
base_type.builtin_type = context.builtin_type;
if (_lookup_symbol_from_base(base_type, p_symbol, true, r_result) == OK) {
return OK;
}
} break;
case GDScriptParser::COMPLETION_SUPER_METHOD:
case GDScriptParser::COMPLETION_METHOD: {

View File

@ -2685,7 +2685,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_attribute(ExpressionNode *
const IdentifierNode *id = static_cast<const IdentifierNode *>(p_previous_operand);
Variant::Type builtin_type = get_builtin_type(id->name);
if (builtin_type < Variant::VARIANT_MAX) {
make_completion_context(COMPLETION_BUILT_IN_TYPE_CONSTANT, builtin_type, true);
make_completion_context(COMPLETION_BUILT_IN_TYPE_CONSTANT_OR_STATIC_METHOD, builtin_type, true);
is_builtin = true;
}
}

View File

@ -1146,7 +1146,7 @@ public:
COMPLETION_ASSIGN, // Assignment based on type (e.g. enum values).
COMPLETION_ATTRIBUTE, // After id.| to look for members.
COMPLETION_ATTRIBUTE_METHOD, // After id.| to look for methods.
COMPLETION_BUILT_IN_TYPE_CONSTANT, // Constants inside a built-in type (e.g. Color.blue).
COMPLETION_BUILT_IN_TYPE_CONSTANT_OR_STATIC_METHOD, // Constants inside a built-in type (e.g. Color.BLUE) or static methods (e.g. Color.html).
COMPLETION_CALL_ARGUMENTS, // Complete with nodes, input actions, enum values (or usual expressions).
// TODO: COMPLETION_DECLARATION, // Potential declaration (var, const, func).
COMPLETION_GET_NODE, // Get node with $ notation.