GDScript: Improve PROPERTY_HINT_{ARRAY,DICTIONARY}_TYPE handling

This commit is contained in:
Danil Alexeev
2026-04-08 17:53:56 +03:00
parent 653fed37e0
commit 7db019d44d
6 changed files with 88 additions and 180 deletions
+34 -79
View File
@@ -5779,6 +5779,37 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_metatype(const GDScriptPars
return result;
}
GDScriptParser::DataType GDScriptAnalyzer::type_from_property_hint_string(const String &p_type_name) const {
GDScriptParser::DataType result;
result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
result.is_constant = false;
const Variant::Type builtin_type = GDScriptParser::get_builtin_type(p_type_name);
if (builtin_type < Variant::VARIANT_MAX) {
// Built-in type.
result.kind = GDScriptParser::DataType::BUILTIN;
result.builtin_type = builtin_type;
} else if (class_exists(p_type_name)) {
result.kind = GDScriptParser::DataType::NATIVE;
result.builtin_type = Variant::OBJECT;
result.native_type = p_type_name;
} else if (ScriptServer::is_global_class(p_type_name)) {
// Just load this as it shouldn't be a GDScript.
Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(p_type_name));
result.kind = GDScriptParser::DataType::SCRIPT;
result.builtin_type = Variant::OBJECT;
result.native_type = script->get_instance_base_type();
result.script_type = script;
} else if (p_type_name == SNAME("Variant")) {
result.kind = GDScriptParser::DataType::VARIANT;
} else {
result.kind = GDScriptParser::DataType::VARIANT;
ERR_FAIL_V_MSG(result, "Could not find type from property hint string.");
}
return result;
}
GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo &p_property, bool p_is_arg, bool p_is_readonly) const {
GDScriptParser::DataType result;
result.is_read_only = p_is_readonly;
@@ -5807,86 +5838,10 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo
result.kind = GDScriptParser::DataType::BUILTIN;
result.builtin_type = p_property.type;
if (p_property.type == Variant::ARRAY && p_property.hint == PROPERTY_HINT_ARRAY_TYPE) {
// Check element type.
StringName elem_type_name = p_property.hint_string;
GDScriptParser::DataType elem_type;
elem_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
Variant::Type elem_builtin_type = GDScriptParser::get_builtin_type(elem_type_name);
if (elem_builtin_type < Variant::VARIANT_MAX) {
// Builtin type.
elem_type.kind = GDScriptParser::DataType::BUILTIN;
elem_type.builtin_type = elem_builtin_type;
} else if (class_exists(elem_type_name)) {
elem_type.kind = GDScriptParser::DataType::NATIVE;
elem_type.builtin_type = Variant::OBJECT;
elem_type.native_type = elem_type_name;
} else if (ScriptServer::is_global_class(elem_type_name)) {
// Just load this as it shouldn't be a GDScript.
Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(elem_type_name));
elem_type.kind = GDScriptParser::DataType::SCRIPT;
elem_type.builtin_type = Variant::OBJECT;
elem_type.native_type = script->get_instance_base_type();
elem_type.script_type = script;
} else {
ERR_FAIL_V_MSG(result, "Could not find element type from property hint of a typed array.");
}
elem_type.is_constant = false;
result.set_container_element_type(0, elem_type);
result.set_container_element_type(0, type_from_property_hint_string(p_property.hint_string));
} else if (p_property.type == Variant::DICTIONARY && p_property.hint == PROPERTY_HINT_DICTIONARY_TYPE) {
// Check element type.
StringName key_elem_type_name = p_property.hint_string.get_slicec(';', 0);
GDScriptParser::DataType key_elem_type;
key_elem_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
Variant::Type key_elem_builtin_type = GDScriptParser::get_builtin_type(key_elem_type_name);
if (key_elem_builtin_type < Variant::VARIANT_MAX) {
// Builtin type.
key_elem_type.kind = GDScriptParser::DataType::BUILTIN;
key_elem_type.builtin_type = key_elem_builtin_type;
} else if (class_exists(key_elem_type_name)) {
key_elem_type.kind = GDScriptParser::DataType::NATIVE;
key_elem_type.builtin_type = Variant::OBJECT;
key_elem_type.native_type = key_elem_type_name;
} else if (ScriptServer::is_global_class(key_elem_type_name)) {
// Just load this as it shouldn't be a GDScript.
Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(key_elem_type_name));
key_elem_type.kind = GDScriptParser::DataType::SCRIPT;
key_elem_type.builtin_type = Variant::OBJECT;
key_elem_type.native_type = script->get_instance_base_type();
key_elem_type.script_type = script;
} else {
ERR_FAIL_V_MSG(result, "Could not find element type from property hint of a typed dictionary.");
}
key_elem_type.is_constant = false;
StringName value_elem_type_name = p_property.hint_string.get_slicec(';', 1);
GDScriptParser::DataType value_elem_type;
value_elem_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
Variant::Type value_elem_builtin_type = GDScriptParser::get_builtin_type(value_elem_type_name);
if (value_elem_builtin_type < Variant::VARIANT_MAX) {
// Builtin type.
value_elem_type.kind = GDScriptParser::DataType::BUILTIN;
value_elem_type.builtin_type = value_elem_builtin_type;
} else if (class_exists(value_elem_type_name)) {
value_elem_type.kind = GDScriptParser::DataType::NATIVE;
value_elem_type.builtin_type = Variant::OBJECT;
value_elem_type.native_type = value_elem_type_name;
} else if (ScriptServer::is_global_class(value_elem_type_name)) {
// Just load this as it shouldn't be a GDScript.
Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(value_elem_type_name));
value_elem_type.kind = GDScriptParser::DataType::SCRIPT;
value_elem_type.builtin_type = Variant::OBJECT;
value_elem_type.native_type = script->get_instance_base_type();
value_elem_type.script_type = script;
} else {
ERR_FAIL_V_MSG(result, "Could not find element type from property hint of a typed dictionary.");
}
value_elem_type.is_constant = false;
result.set_container_element_type(0, key_elem_type);
result.set_container_element_type(1, value_elem_type);
result.set_container_element_type(0, type_from_property_hint_string(p_property.hint_string.get_slicec(';', 0)));
result.set_container_element_type(1, type_from_property_hint_string(p_property.hint_string.get_slicec(';', 1)));
} else if (p_property.type == Variant::INT) {
// Check if it's enum.
if ((p_property.usage & PROPERTY_USAGE_CLASS_IS_ENUM) && p_property.class_name != StringName()) {