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.
This commit is contained in:
George Marques 2024-05-06 11:16:25 -03:00
parent 22a28e07cc
commit 501c5b0900
No known key found for this signature in database
GPG key ID: 046BD46A3201E43D
5 changed files with 18 additions and 17 deletions

View file

@ -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);
}

View file

@ -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<GDScriptParserRef> 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<GDScriptParserRef> find_cached_external_parser_for_class(const GDScriptParser::ClassNode *p_class, const Ref<GDScriptParserRef> &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);
};

View file

@ -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;
}

View file

@ -392,7 +392,7 @@ void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant>
get_public_constants(&cinfo);
for (const KeyValue<StringName, int> &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<String> 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<StringName, int> &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;

View file

@ -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"))) {