GDScript: Add recursion depth limit for completion
To avoid crashes when there's a dependency loop.
This commit is contained in:
parent
ff16ba1eaa
commit
4a3fca47e5
@ -483,6 +483,8 @@ String GDScriptLanguage::make_function(const String &p_class, const String &p_na
|
|||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
|
|
||||||
|
#define COMPLETION_RECURSION_LIMIT 200
|
||||||
|
|
||||||
struct GDScriptCompletionIdentifier {
|
struct GDScriptCompletionIdentifier {
|
||||||
GDScriptParser::DataType type;
|
GDScriptParser::DataType type;
|
||||||
String enumeration;
|
String enumeration;
|
||||||
@ -766,9 +768,11 @@ static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result);
|
static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth);
|
||||||
|
|
||||||
|
static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, bool p_only_functions, bool p_static, bool p_parent_only, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth) {
|
||||||
|
ERR_FAIL_COND(p_recursion_depth > COMPLETION_RECURSION_LIMIT);
|
||||||
|
|
||||||
static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, bool p_only_functions, bool p_static, bool p_parent_only, Map<String, ScriptCodeCompletionOption> &r_result) {
|
|
||||||
if (!p_parent_only) {
|
if (!p_parent_only) {
|
||||||
bool outer = false;
|
bool outer = false;
|
||||||
const GDScriptParser::ClassNode *clss = p_class;
|
const GDScriptParser::ClassNode *clss = p_class;
|
||||||
@ -839,10 +843,12 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
|
|||||||
base_type.type = p_class->base_type;
|
base_type.type = p_class->base_type;
|
||||||
base_type.type.is_meta_type = p_static;
|
base_type.type.is_meta_type = p_static;
|
||||||
|
|
||||||
_find_identifiers_in_base(base_type, p_only_functions, r_result);
|
_find_identifiers_in_base(base_type, p_only_functions, r_result, p_recursion_depth + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result) {
|
static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth) {
|
||||||
|
ERR_FAIL_COND(p_recursion_depth > COMPLETION_RECURSION_LIMIT);
|
||||||
|
|
||||||
GDScriptParser::DataType base_type = p_base.type;
|
GDScriptParser::DataType base_type = p_base.type;
|
||||||
bool _static = base_type.is_meta_type;
|
bool _static = base_type.is_meta_type;
|
||||||
|
|
||||||
@ -855,7 +861,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
|
|||||||
while (!base_type.has_no_type()) {
|
while (!base_type.has_no_type()) {
|
||||||
switch (base_type.kind) {
|
switch (base_type.kind) {
|
||||||
case GDScriptParser::DataType::CLASS: {
|
case GDScriptParser::DataType::CLASS: {
|
||||||
_find_identifiers_in_class(base_type.class_type, p_only_functions, _static, false, r_result);
|
_find_identifiers_in_class(base_type.class_type, p_only_functions, _static, false, r_result, p_recursion_depth + 1);
|
||||||
// This already finds all parent identifiers, so we are done.
|
// This already finds all parent identifiers, so we are done.
|
||||||
base_type = GDScriptParser::DataType();
|
base_type = GDScriptParser::DataType();
|
||||||
} break;
|
} break;
|
||||||
@ -1006,14 +1012,14 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result) {
|
static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth) {
|
||||||
if (!p_only_functions && p_context.current_suite) {
|
if (!p_only_functions && p_context.current_suite) {
|
||||||
// This includes function parameters, since they are also locals.
|
// This includes function parameters, since they are also locals.
|
||||||
_find_identifiers_in_suite(p_context.current_suite, r_result);
|
_find_identifiers_in_suite(p_context.current_suite, r_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_context.current_class) {
|
if (p_context.current_class) {
|
||||||
_find_identifiers_in_class(p_context.current_class, p_only_functions, (!p_context.current_function || p_context.current_function->is_static), false, r_result);
|
_find_identifiers_in_class(p_context.current_class, p_only_functions, (!p_context.current_function || p_context.current_function->is_static), false, r_result, p_recursion_depth + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
|
for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
|
||||||
@ -2452,7 +2458,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!_guess_expression_type(completion_context, static_cast<const GDScriptParser::AssignmentNode *>(completion_context.node)->assignee, type)) {
|
if (!_guess_expression_type(completion_context, static_cast<const GDScriptParser::AssignmentNode *>(completion_context.node)->assignee, type)) {
|
||||||
_find_identifiers(completion_context, false, options);
|
_find_identifiers(completion_context, false, options, 0);
|
||||||
r_forced = true;
|
r_forced = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2461,7 +2467,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
|
|||||||
_find_enumeration_candidates(completion_context, type.enumeration, options);
|
_find_enumeration_candidates(completion_context, type.enumeration, options);
|
||||||
r_forced = options.size() > 0;
|
r_forced = options.size() > 0;
|
||||||
} else {
|
} else {
|
||||||
_find_identifiers(completion_context, false, options);
|
_find_identifiers(completion_context, false, options, 0);
|
||||||
r_forced = true;
|
r_forced = true;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
@ -2469,7 +2475,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
|
|||||||
is_function = true;
|
is_function = true;
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case GDScriptParser::COMPLETION_IDENTIFIER: {
|
case GDScriptParser::COMPLETION_IDENTIFIER: {
|
||||||
_find_identifiers(completion_context, is_function, options);
|
_find_identifiers(completion_context, is_function, options, 0);
|
||||||
} break;
|
} break;
|
||||||
case GDScriptParser::COMPLETION_ATTRIBUTE_METHOD:
|
case GDScriptParser::COMPLETION_ATTRIBUTE_METHOD:
|
||||||
is_function = true;
|
is_function = true;
|
||||||
@ -2483,7 +2489,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_find_identifiers_in_base(base, is_function, options);
|
_find_identifiers_in_base(base, is_function, options, 0);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case GDScriptParser::COMPLETION_SUBSCRIPT: {
|
case GDScriptParser::COMPLETION_SUBSCRIPT: {
|
||||||
@ -2503,7 +2509,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
|
|||||||
c.current_class = nullptr;
|
c.current_class = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
_find_identifiers_in_base(base, false, options);
|
_find_identifiers_in_base(base, false, options, 0);
|
||||||
} break;
|
} break;
|
||||||
case GDScriptParser::COMPLETION_TYPE_ATTRIBUTE: {
|
case GDScriptParser::COMPLETION_TYPE_ATTRIBUTE: {
|
||||||
if (!completion_context.current_class) {
|
if (!completion_context.current_class) {
|
||||||
@ -2529,7 +2535,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
|
|||||||
|
|
||||||
// TODO: Improve this to only list types.
|
// TODO: Improve this to only list types.
|
||||||
if (found) {
|
if (found) {
|
||||||
_find_identifiers_in_base(base, false, options);
|
_find_identifiers_in_base(base, false, options, 0);
|
||||||
}
|
}
|
||||||
r_forced = true;
|
r_forced = true;
|
||||||
} break;
|
} break;
|
||||||
@ -2650,7 +2656,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
|
|||||||
if (!completion_context.current_class) {
|
if (!completion_context.current_class) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_find_identifiers_in_class(completion_context.current_class, true, false, true, options);
|
_find_identifiers_in_class(completion_context.current_class, true, false, true, options, 0);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user