From 501c5b0900f147f242554a9215393e32448771ee Mon Sep 17 00:00:00 2001 From: George Marques Date: Mon, 6 May 2024 11:16:25 -0300 Subject: [PATCH] GDScript: Make check for exposed classes more consistent Some places were already checking if classes from ClassDB were exposed, while others didn't. This makes the check more consistent to avoid disparities which can lead to crashes. --- modules/gdscript/gdscript_analyzer.cpp | 2 +- modules/gdscript/gdscript_analyzer.h | 2 +- modules/gdscript/gdscript_compiler.cpp | 5 +++-- modules/gdscript/gdscript_editor.cpp | 24 ++++++++++++------------ modules/gdscript/gdscript_parser.cpp | 2 +- 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 08a6005faab..28d4dd5d116 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -6415,7 +6415,7 @@ void GDScriptAnalyzer::resolve_pending_lambda_bodies() { static_context = previous_static_context; } -bool GDScriptAnalyzer::class_exists(const StringName &p_class) const { +bool GDScriptAnalyzer::class_exists(const StringName &p_class) { return ClassDB::class_exists(p_class) && ClassDB::is_class_exposed(p_class); } diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h index 576276471d3..b966fb290c7 100644 --- a/modules/gdscript/gdscript_analyzer.h +++ b/modules/gdscript/gdscript_analyzer.h @@ -143,7 +143,6 @@ class GDScriptAnalyzer { void downgrade_node_type_source(GDScriptParser::Node *p_node); void mark_lambda_use_self(); void resolve_pending_lambda_bodies(); - bool class_exists(const StringName &p_class) const; void reduce_identifier_from_base_set_class(GDScriptParser::IdentifierNode *p_identifier, GDScriptParser::DataType p_identifier_datatype); Ref ensure_cached_external_parser_for_class(const GDScriptParser::ClassNode *p_class, const GDScriptParser::ClassNode *p_from_class, const char *p_context, const GDScriptParser::Node *p_source); Ref find_cached_external_parser_for_class(const GDScriptParser::ClassNode *p_class, const Ref &p_dependant_parser); @@ -164,6 +163,7 @@ public: static bool check_type_compatibility(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion = false, const GDScriptParser::Node *p_source_node = nullptr); static GDScriptParser::DataType type_from_metatype(const GDScriptParser::DataType &p_meta_type); + static bool class_exists(const StringName &p_class); GDScriptAnalyzer(GDScriptParser *p_parser); }; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index e5ad8d0f3d4..44e2daac973 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -31,6 +31,7 @@ #include "gdscript_compiler.h" #include "gdscript.h" +#include "gdscript_analyzer.h" #include "gdscript_byte_codegen.h" #include "gdscript_cache.h" #include "gdscript_utility_functions.h" @@ -699,7 +700,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } else { class_name = base.type.native_type == StringName() ? base.type.script_type->get_instance_base_type() : base.type.native_type; } - if (ClassDB::class_exists(class_name) && ClassDB::has_method(class_name, call->function_name)) { + if (GDScriptAnalyzer::class_exists(class_name) && ClassDB::has_method(class_name, call->function_name)) { MethodBind *method = ClassDB::get_method(class_name, call->function_name); if (_can_use_validate_call(method, arguments)) { // Exact arguments, use validated call. @@ -2756,7 +2757,7 @@ Error GDScriptCompiler::_prepare_compilation(GDScript *p_script, const GDScriptP p_script->_is_abstract = p_class->is_abstract; if (p_script->local_name != StringName()) { - if (ClassDB::class_exists(p_script->local_name) && ClassDB::is_class_exposed(p_script->local_name)) { + if (GDScriptAnalyzer::class_exists(p_script->local_name)) { _set_error(vformat(R"(The class "%s" shadows a native class)", p_script->local_name), p_class); return ERR_ALREADY_EXISTS; } diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 4450a798428..ad8e8afb3c1 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -392,7 +392,7 @@ void GDScriptLanguage::debug_get_globals(List *p_globals, List get_public_constants(&cinfo); for (const KeyValue &E : name_idx) { - if (ClassDB::class_exists(E.key) || Engine::get_singleton()->has_singleton(E.key)) { + if (GDScriptAnalyzer::class_exists(E.key) || Engine::get_singleton()->has_singleton(E.key)) { continue; } @@ -710,7 +710,7 @@ static String _trim_parent_class(const String &p_class, const String &p_base_cla Vector names = p_class.split(".", false, 1); if (names.size() == 2) { const String &first = names[0]; - if (ClassDB::class_exists(p_base_class) && ClassDB::class_exists(first) && ClassDB::is_parent_class(p_base_class, first)) { + if (GDScriptAnalyzer::class_exists(p_base_class) && GDScriptAnalyzer::class_exists(first) && ClassDB::is_parent_class(p_base_class, first)) { const String &rest = names[1]; return rest; } @@ -1347,7 +1347,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base } break; case GDScriptParser::DataType::NATIVE: { StringName type = base_type.native_type; - if (!ClassDB::class_exists(type)) { + if (!GDScriptAnalyzer::class_exists(type)) { return; } @@ -1627,7 +1627,7 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context // Native classes and global constants. for (const KeyValue &E : GDScriptLanguage::get_singleton()->get_global_map()) { ScriptLanguage::CodeCompletionOption option; - if (ClassDB::class_exists(E.key) || Engine::get_singleton()->has_singleton(E.key)) { + if (GDScriptAnalyzer::class_exists(E.key) || Engine::get_singleton()->has_singleton(E.key)) { option = ScriptLanguage::CodeCompletionOption(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CLASS); } else { option = ScriptLanguage::CodeCompletionOption(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); @@ -2510,7 +2510,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, } // Check ClassDB. - if (ClassDB::class_exists(p_identifier->name) && ClassDB::is_class_exposed(p_identifier->name)) { + if (GDScriptAnalyzer::class_exists(p_identifier->name)) { r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; r_type.type.kind = GDScriptParser::DataType::NATIVE; r_type.type.builtin_type = Variant::OBJECT; @@ -2658,7 +2658,7 @@ static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext & } break; case GDScriptParser::DataType::NATIVE: { StringName class_name = base_type.native_type; - if (!ClassDB::class_exists(class_name)) { + if (!GDScriptAnalyzer::class_exists(class_name)) { return false; } @@ -2849,7 +2849,7 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex } } break; case GDScriptParser::DataType::NATIVE: { - if (!ClassDB::class_exists(base_type.native_type)) { + if (!GDScriptAnalyzer::class_exists(base_type.native_type)) { return false; } MethodBind *mb = ClassDB::get_method(base_type.native_type, p_method); @@ -2925,7 +2925,7 @@ static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_co String class_name = p_enum_hint.get_slicec('.', 0); String enum_name = p_enum_hint.get_slicec('.', 1); - if (!ClassDB::class_exists(class_name)) { + if (!GDScriptAnalyzer::class_exists(class_name)) { return; } @@ -2998,7 +2998,7 @@ static void _list_call_arguments(GDScriptParser::CompletionContext &p_context, c } break; case GDScriptParser::DataType::NATIVE: { StringName class_name = base_type.native_type; - if (!ClassDB::class_exists(class_name)) { + if (!GDScriptAnalyzer::class_exists(class_name)) { base_type.kind = GDScriptParser::DataType::UNRESOLVED; break; } @@ -3720,7 +3720,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c } StringName class_name = native_type.native_type; - if (!ClassDB::class_exists(class_name)) { + if (!GDScriptAnalyzer::class_exists(class_name)) { break; } @@ -4101,7 +4101,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co case GDScriptParser::DataType::NATIVE: { const StringName &class_name = base_type.native_type; - ERR_FAIL_COND_V(!ClassDB::class_exists(class_name), ERR_BUG); + ERR_FAIL_COND_V(!GDScriptAnalyzer::class_exists(class_name), ERR_BUG); if (ClassDB::has_method(class_name, p_symbol, true)) { r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD; @@ -4295,7 +4295,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co ::Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) { // Before parsing, try the usual stuff. - if (ClassDB::class_exists(p_symbol)) { + if (GDScriptAnalyzer::class_exists(p_symbol)) { r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS; r_result.class_name = p_symbol; return OK; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 06056ca940d..b2c901a8a4e 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -4677,7 +4677,7 @@ bool GDScriptParser::export_annotations(AnnotationNode *p_annotation, Node *p_ta if (ScriptServer::is_global_class(arg_string)) { native_class = ScriptServer::get_global_class_native_base(arg_string); } - if (!ClassDB::class_exists(native_class)) { + if (!ClassDB::class_exists(native_class) || !ClassDB::is_class_exposed(native_class)) { push_error(vformat(R"(Invalid argument %d of annotation "@export_node_path": The class "%s" was not found in the global scope.)", i + 1, arg_string), p_annotation->arguments[i]); return false; } else if (!ClassDB::is_parent_class(native_class, SNAME("Node"))) {