GDScript: Improve PROPERTY_HINT_{ARRAY,DICTIONARY}_TYPE handling
This commit is contained in:
@@ -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()) {
|
||||
|
||||
@@ -134,6 +134,7 @@ class GDScriptAnalyzer {
|
||||
Dictionary make_dictionary_from_element_datatype(const GDScriptParser::DataType &p_key_element_datatype, const GDScriptParser::DataType &p_value_element_datatype, const GDScriptParser::Node *p_source_node = nullptr);
|
||||
GDScriptParser::DataType type_from_script(const Ref<Script> &p_script, const GDScriptParser::Node *p_source, bool p_is_meta_type);
|
||||
GDScriptParser::DataType type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source);
|
||||
GDScriptParser::DataType type_from_property_hint_string(const String &p_type_name) const;
|
||||
GDScriptParser::DataType type_from_property(const PropertyInfo &p_property, bool p_is_arg = false, bool p_is_readonly = false) const;
|
||||
GDScriptParser::DataType make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source);
|
||||
bool get_function_signature(GDScriptParser::Node *p_source, bool p_is_constructor, GDScriptParser::DataType base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, BitField<MethodFlags> &r_method_flags, StringName *r_native_class = nullptr);
|
||||
|
||||
@@ -5385,6 +5385,35 @@ String GDScriptParser::DataType::to_string() const {
|
||||
ERR_FAIL_V_MSG("<unresolved type>", "Kind set outside the enum range.");
|
||||
}
|
||||
|
||||
String GDScriptParser::DataType::to_property_info_hint_string() const {
|
||||
switch (kind) {
|
||||
case BUILTIN:
|
||||
return Variant::get_type_name(builtin_type);
|
||||
case NATIVE:
|
||||
return native_type;
|
||||
case SCRIPT:
|
||||
if (script_type.is_valid() && script_type->get_global_name() != StringName()) {
|
||||
return script_type->get_global_name();
|
||||
} else {
|
||||
return native_type;
|
||||
}
|
||||
case CLASS:
|
||||
if (class_type != nullptr && class_type->get_global_name() != StringName()) {
|
||||
return class_type->get_global_name();
|
||||
} else {
|
||||
return native_type;
|
||||
}
|
||||
case ENUM:
|
||||
return String(native_type).replace("::", ".");
|
||||
case VARIANT:
|
||||
return "Variant";
|
||||
case RESOLVING:
|
||||
case UNRESOLVED:
|
||||
break;
|
||||
}
|
||||
ERR_FAIL_V_MSG("Variant", "GDScript bug: Unexpected type kind.");
|
||||
}
|
||||
|
||||
PropertyInfo GDScriptParser::DataType::to_property_info(const String &p_name) const {
|
||||
PropertyInfo result;
|
||||
result.name = p_name;
|
||||
@@ -5400,106 +5429,21 @@ PropertyInfo GDScriptParser::DataType::to_property_info(const String &p_name) co
|
||||
result.type = builtin_type;
|
||||
if (builtin_type == Variant::ARRAY && has_container_element_type(0)) {
|
||||
const DataType elem_type = get_container_element_type(0);
|
||||
switch (elem_type.kind) {
|
||||
case BUILTIN:
|
||||
result.hint = PROPERTY_HINT_ARRAY_TYPE;
|
||||
result.hint_string = Variant::get_type_name(elem_type.builtin_type);
|
||||
break;
|
||||
case NATIVE:
|
||||
result.hint = PROPERTY_HINT_ARRAY_TYPE;
|
||||
result.hint_string = elem_type.native_type;
|
||||
break;
|
||||
case SCRIPT:
|
||||
result.hint = PROPERTY_HINT_ARRAY_TYPE;
|
||||
if (elem_type.script_type.is_valid() && elem_type.script_type->get_global_name() != StringName()) {
|
||||
result.hint_string = elem_type.script_type->get_global_name();
|
||||
} else {
|
||||
result.hint_string = elem_type.native_type;
|
||||
}
|
||||
break;
|
||||
case CLASS:
|
||||
result.hint = PROPERTY_HINT_ARRAY_TYPE;
|
||||
if (elem_type.class_type != nullptr && elem_type.class_type->get_global_name() != StringName()) {
|
||||
result.hint_string = elem_type.class_type->get_global_name();
|
||||
} else {
|
||||
result.hint_string = elem_type.native_type;
|
||||
}
|
||||
break;
|
||||
case ENUM:
|
||||
result.hint = PROPERTY_HINT_ARRAY_TYPE;
|
||||
result.hint_string = String(elem_type.native_type).replace("::", ".");
|
||||
break;
|
||||
case VARIANT:
|
||||
case RESOLVING:
|
||||
case UNRESOLVED:
|
||||
break;
|
||||
if (elem_type.is_variant()) {
|
||||
break;
|
||||
}
|
||||
|
||||
result.hint = PROPERTY_HINT_ARRAY_TYPE;
|
||||
result.hint_string = elem_type.to_property_info_hint_string();
|
||||
} else if (builtin_type == Variant::DICTIONARY && has_container_element_types()) {
|
||||
const DataType key_type = get_container_element_type_or_variant(0);
|
||||
const DataType value_type = get_container_element_type_or_variant(1);
|
||||
if ((key_type.kind == VARIANT && value_type.kind == VARIANT) || key_type.kind == RESOLVING ||
|
||||
key_type.kind == UNRESOLVED || value_type.kind == RESOLVING || value_type.kind == UNRESOLVED) {
|
||||
if (key_type.is_variant() && value_type.is_variant()) {
|
||||
break;
|
||||
}
|
||||
String key_hint, value_hint;
|
||||
switch (key_type.kind) {
|
||||
case BUILTIN:
|
||||
key_hint = Variant::get_type_name(key_type.builtin_type);
|
||||
break;
|
||||
case NATIVE:
|
||||
key_hint = key_type.native_type;
|
||||
break;
|
||||
case SCRIPT:
|
||||
if (key_type.script_type.is_valid() && key_type.script_type->get_global_name() != StringName()) {
|
||||
key_hint = key_type.script_type->get_global_name();
|
||||
} else {
|
||||
key_hint = key_type.native_type;
|
||||
}
|
||||
break;
|
||||
case CLASS:
|
||||
if (key_type.class_type != nullptr && key_type.class_type->get_global_name() != StringName()) {
|
||||
key_hint = key_type.class_type->get_global_name();
|
||||
} else {
|
||||
key_hint = key_type.native_type;
|
||||
}
|
||||
break;
|
||||
case ENUM:
|
||||
key_hint = String(key_type.native_type).replace("::", ".");
|
||||
break;
|
||||
default:
|
||||
key_hint = "Variant";
|
||||
break;
|
||||
}
|
||||
switch (value_type.kind) {
|
||||
case BUILTIN:
|
||||
value_hint = Variant::get_type_name(value_type.builtin_type);
|
||||
break;
|
||||
case NATIVE:
|
||||
value_hint = value_type.native_type;
|
||||
break;
|
||||
case SCRIPT:
|
||||
if (value_type.script_type.is_valid() && value_type.script_type->get_global_name() != StringName()) {
|
||||
value_hint = value_type.script_type->get_global_name();
|
||||
} else {
|
||||
value_hint = value_type.native_type;
|
||||
}
|
||||
break;
|
||||
case CLASS:
|
||||
if (value_type.class_type != nullptr && value_type.class_type->get_global_name() != StringName()) {
|
||||
value_hint = value_type.class_type->get_global_name();
|
||||
} else {
|
||||
value_hint = value_type.native_type;
|
||||
}
|
||||
break;
|
||||
case ENUM:
|
||||
value_hint = String(value_type.native_type).replace("::", ".");
|
||||
break;
|
||||
default:
|
||||
value_hint = "Variant";
|
||||
break;
|
||||
}
|
||||
|
||||
result.hint = PROPERTY_HINT_DICTIONARY_TYPE;
|
||||
result.hint_string = key_hint + ";" + value_hint;
|
||||
result.hint_string = key_type.to_property_info_hint_string() + ";" + value_type.to_property_info_hint_string();
|
||||
}
|
||||
break;
|
||||
case NATIVE:
|
||||
|
||||
@@ -146,6 +146,8 @@ public:
|
||||
|
||||
String to_string() const;
|
||||
_FORCE_INLINE_ String to_string_strict() const { return is_hard_type() ? to_string() : "Variant"; }
|
||||
|
||||
String to_property_info_hint_string() const;
|
||||
PropertyInfo to_property_info(const String &p_name) const;
|
||||
|
||||
_FORCE_INLINE_ static DataType get_variant_type() { // Default DataType for container elements.
|
||||
|
||||
@@ -3,7 +3,7 @@ class_name TestMemberInfo
|
||||
class MyClass:
|
||||
pass
|
||||
|
||||
enum MyEnum {}
|
||||
enum MyEnum { NONE }
|
||||
|
||||
static var test_static_var_untyped
|
||||
static var test_static_var_weak_null = null
|
||||
@@ -16,14 +16,19 @@ var test_var_weak_int = 1
|
||||
@export var test_var_weak_int_exported = 1
|
||||
var test_var_weak_variant_type = TYPE_NIL
|
||||
@export var test_var_weak_variant_type_exported = TYPE_NIL
|
||||
|
||||
var test_var_hard_variant: Variant
|
||||
var test_var_hard_int: int
|
||||
var test_var_hard_variant_type: Variant.Type
|
||||
@export var test_var_hard_variant_type_exported: Variant.Type
|
||||
var test_var_hard_node_process_mode: Node.ProcessMode
|
||||
@warning_ignore("enum_variable_without_default")
|
||||
var test_var_hard_my_enum: MyEnum
|
||||
var test_var_hard_resource: Resource
|
||||
var test_var_hard_this: TestMemberInfo
|
||||
var test_var_hard_my_class: MyClass
|
||||
|
||||
var test_var_hard_array: Array
|
||||
var test_var_hard_array_variant: Array[Variant]
|
||||
var test_var_hard_array_int: Array[int]
|
||||
var test_var_hard_array_variant_type: Array[Variant.Type]
|
||||
var test_var_hard_array_node_process_mode: Array[Node.ProcessMode]
|
||||
@@ -31,7 +36,9 @@ var test_var_hard_array_my_enum: Array[MyEnum]
|
||||
var test_var_hard_array_resource: Array[Resource]
|
||||
var test_var_hard_array_this: Array[TestMemberInfo]
|
||||
var test_var_hard_array_my_class: Array[MyClass]
|
||||
|
||||
var test_var_hard_dictionary: Dictionary
|
||||
var test_var_hard_dictionary_variant_variant: Dictionary[Variant, Variant]
|
||||
var test_var_hard_dictionary_int_variant: Dictionary[int, Variant]
|
||||
var test_var_hard_dictionary_variant_int: Dictionary[Variant, int]
|
||||
var test_var_hard_dictionary_int_int: Dictionary[int, int]
|
||||
@@ -41,9 +48,6 @@ var test_var_hard_dictionary_my_enum: Dictionary[MyEnum, MyEnum]
|
||||
var test_var_hard_dictionary_resource: Dictionary[Resource, Resource]
|
||||
var test_var_hard_dictionary_this: Dictionary[TestMemberInfo, TestMemberInfo]
|
||||
var test_var_hard_dictionary_my_class: Dictionary[MyClass, MyClass]
|
||||
var test_var_hard_resource: Resource
|
||||
var test_var_hard_this: TestMemberInfo
|
||||
var test_var_hard_my_class: MyClass
|
||||
|
||||
static func test_static_func(): pass
|
||||
|
||||
|
||||
@@ -15,7 +15,11 @@ var test_var_hard_variant_type: Variant.Type
|
||||
var test_var_hard_variant_type_exported: Variant.Type
|
||||
var test_var_hard_node_process_mode: Node.ProcessMode
|
||||
var test_var_hard_my_enum: TestMemberInfo.MyEnum
|
||||
var test_var_hard_resource: Resource
|
||||
var test_var_hard_this: TestMemberInfo
|
||||
var test_var_hard_my_class: RefCounted
|
||||
var test_var_hard_array: Array
|
||||
var test_var_hard_array_variant: Array
|
||||
var test_var_hard_array_int: Array[int]
|
||||
var test_var_hard_array_variant_type: Array[Variant.Type]
|
||||
var test_var_hard_array_node_process_mode: Array[Node.ProcessMode]
|
||||
@@ -24,6 +28,7 @@ var test_var_hard_array_resource: Array[Resource]
|
||||
var test_var_hard_array_this: Array[TestMemberInfo]
|
||||
var test_var_hard_array_my_class: Array[RefCounted]
|
||||
var test_var_hard_dictionary: Dictionary
|
||||
var test_var_hard_dictionary_variant_variant: Dictionary
|
||||
var test_var_hard_dictionary_int_variant: Dictionary[int, Variant]
|
||||
var test_var_hard_dictionary_variant_int: Dictionary[Variant, int]
|
||||
var test_var_hard_dictionary_int_int: Dictionary[int, int]
|
||||
@@ -33,9 +38,6 @@ var test_var_hard_dictionary_my_enum: Dictionary[TestMemberInfo.MyEnum, TestMemb
|
||||
var test_var_hard_dictionary_resource: Dictionary[Resource, Resource]
|
||||
var test_var_hard_dictionary_this: Dictionary[TestMemberInfo, TestMemberInfo]
|
||||
var test_var_hard_dictionary_my_class: Dictionary[RefCounted, RefCounted]
|
||||
var test_var_hard_resource: Resource
|
||||
var test_var_hard_this: TestMemberInfo
|
||||
var test_var_hard_my_class: RefCounted
|
||||
static func test_static_func() -> void
|
||||
func test_func_implicit_void() -> void
|
||||
func test_func_explicit_void() -> void
|
||||
|
||||
Reference in New Issue
Block a user