From 4a0bad8da6ad35b015ea2377c06050bf5849db37 Mon Sep 17 00:00:00 2001 From: rune-scape Date: Sun, 23 Feb 2025 02:38:54 -0800 Subject: [PATCH] GDScript: Fix error when using a string literal suffix in subscript of class --- modules/gdscript/gdscript_analyzer.cpp | 56 ++++++++++++------- .../subscript_constant_string_of_class.gd | 6 ++ .../subscript_constant_string_of_class.out | 2 + 3 files changed, 44 insertions(+), 20 deletions(-) create mode 100644 modules/gdscript/tests/scripts/analyzer/features/subscript_constant_string_of_class.gd create mode 100644 modules/gdscript/tests/scripts/analyzer/features/subscript_constant_string_of_class.out diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 60109efc4d5b..d996c40bfe07 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -4728,7 +4728,28 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri if (p_subscript->attribute == nullptr) { return; } + } else { + if (p_subscript->index != nullptr) { + reduce_expression(p_subscript->index); + } else { + return; + } + } + bool is_attribute_like = false; + GDScriptParser::IdentifierNode *attribute = nullptr; + if (p_subscript->is_attribute) { + is_attribute_like = true; + attribute = p_subscript->attribute; + } else if (p_subscript->index && p_subscript->index->is_constant && (p_subscript->index->reduced_value.get_type() == Variant::STRING || p_subscript->index->reduced_value.get_type() == Variant::STRING_NAME)) { + is_attribute_like = true; + attribute = parser->alloc_node(); + parser->reset_extents(attribute, p_subscript->index); + parser->complete_extents(attribute); + attribute->name = p_subscript->index->reduced_value; + } + + if (is_attribute_like) { GDScriptParser::DataType base_type = p_subscript->base->get_datatype(); bool valid = false; @@ -4743,23 +4764,23 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri // Makes a metatype from a constant GDScript, since `base_type` is not a metatype. GDScriptParser::DataType base_type_meta = type_from_variant(gdscript, p_subscript); // First try to reduce the attribute from the metatype. - reduce_identifier_from_base(p_subscript->attribute, &base_type_meta); - GDScriptParser::DataType attr_type = p_subscript->attribute->get_datatype(); + reduce_identifier_from_base(attribute, &base_type_meta); + GDScriptParser::DataType attr_type = attribute->get_datatype(); if (attr_type.is_set()) { valid = !attr_type.is_pseudo_type || p_can_be_pseudo_type; result_type = attr_type; - p_subscript->is_constant = p_subscript->attribute->is_constant; - p_subscript->reduced_value = p_subscript->attribute->reduced_value; + p_subscript->is_constant = attribute->is_constant; + p_subscript->reduced_value = attribute->reduced_value; } if (!valid) { // If unsuccessful, reset and return to the normal route. - p_subscript->attribute->set_datatype(GDScriptParser::DataType()); + attribute->set_datatype(GDScriptParser::DataType()); } } } if (!base_is_gdscript) { // Just try to get it. - Variant value = p_subscript->base->reduced_value.get_named(p_subscript->attribute->name, valid); + Variant value = p_subscript->base->reduced_value.get_named(attribute->name, valid); if (valid) { p_subscript->is_constant = true; p_subscript->reduced_value = value; @@ -4777,7 +4798,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri // Special case: it may be a global enum with pseudo base (e.g. Variant.Type). String enum_name; if (p_subscript->base->type == GDScriptParser::Node::IDENTIFIER) { - enum_name = String(static_cast(p_subscript->base)->name) + ENUM_SEPARATOR + String(p_subscript->attribute->name); + enum_name = String(static_cast(p_subscript->base)->name) + ENUM_SEPARATOR + String(attribute->name); } if (CoreConstants::is_global_enum(enum_name)) { result_type = make_global_enum_type(enum_name, StringName()); @@ -4789,8 +4810,8 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri mark_node_unsafe(p_subscript); } } else { - reduce_identifier_from_base(p_subscript->attribute, &base_type); - GDScriptParser::DataType attr_type = p_subscript->attribute->get_datatype(); + reduce_identifier_from_base(attribute, &base_type); + GDScriptParser::DataType attr_type = attribute->get_datatype(); if (attr_type.is_set()) { if (base_type.builtin_type == Variant::DICTIONARY && base_type.has_container_element_types()) { Variant::Type key_type = base_type.get_container_element_type_or_variant(0).builtin_type; @@ -4806,14 +4827,14 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri } else { valid = !attr_type.is_pseudo_type || p_can_be_pseudo_type; result_type = attr_type; - p_subscript->is_constant = p_subscript->attribute->is_constant; - p_subscript->reduced_value = p_subscript->attribute->reduced_value; + p_subscript->is_constant = attribute->is_constant; + p_subscript->reduced_value = attribute->reduced_value; } } else if (!base_type.is_meta_type || !base_type.is_constant) { valid = base_type.kind != GDScriptParser::DataType::BUILTIN; #ifdef DEBUG_ENABLED if (valid) { - parser->push_warning(p_subscript, GDScriptWarning::UNSAFE_PROPERTY_ACCESS, p_subscript->attribute->name, base_type.to_string()); + parser->push_warning(p_subscript, GDScriptWarning::UNSAFE_PROPERTY_ACCESS, attribute->name, base_type.to_string()); } #endif result_type.kind = GDScriptParser::DataType::VARIANT; @@ -4822,20 +4843,15 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri } if (!valid) { - GDScriptParser::DataType attr_type = p_subscript->attribute->get_datatype(); + GDScriptParser::DataType attr_type = attribute->get_datatype(); if (!p_can_be_pseudo_type && (attr_type.is_pseudo_type || result_type.is_pseudo_type)) { - push_error(vformat(R"(Type "%s" in base "%s" cannot be used on its own.)", p_subscript->attribute->name, type_from_metatype(base_type).to_string()), p_subscript->attribute); + push_error(vformat(R"(Type "%s" in base "%s" cannot be used on its own.)", attribute->name, type_from_metatype(base_type).to_string()), attribute); } else { - push_error(vformat(R"(Cannot find member "%s" in base "%s".)", p_subscript->attribute->name, type_from_metatype(base_type).to_string()), p_subscript->attribute); + push_error(vformat(R"(Cannot find member "%s" in base "%s".)", attribute->name, type_from_metatype(base_type).to_string()), attribute); } result_type.kind = GDScriptParser::DataType::VARIANT; } } else { - if (p_subscript->index == nullptr) { - return; - } - reduce_expression(p_subscript->index); - if (p_subscript->base->is_constant && p_subscript->index->is_constant) { // Just try to get it. bool valid = false; diff --git a/modules/gdscript/tests/scripts/analyzer/features/subscript_constant_string_of_class.gd b/modules/gdscript/tests/scripts/analyzer/features/subscript_constant_string_of_class.gd new file mode 100644 index 000000000000..7eff62d44284 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/subscript_constant_string_of_class.gd @@ -0,0 +1,6 @@ +class MyClass: + static func my_static() -> void: + print("success") + +func test(): + print(MyClass["my_static"]) diff --git a/modules/gdscript/tests/scripts/analyzer/features/subscript_constant_string_of_class.out b/modules/gdscript/tests/scripts/analyzer/features/subscript_constant_string_of_class.out new file mode 100644 index 000000000000..a65b0caf64e8 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/subscript_constant_string_of_class.out @@ -0,0 +1,2 @@ +GDTEST_OK +GDScript::my_static