From 65a49bad5ad744d3df48ab84b3a46aee681c041b Mon Sep 17 00:00:00 2001 From: Adam Scott Date: Sun, 4 Dec 2022 16:55:40 -0500 Subject: [PATCH] Fix constant base typing in extended GDScript class --- modules/gdscript/gdscript_analyzer.cpp | 101 ++++++++++-------- modules/gdscript/gdscript_analyzer.h | 2 + .../features/base_outer_resolution.gd | 14 +++ .../features/base_outer_resolution.out | 7 ++ .../base_outer_resolution_a.notest.gd | 2 + .../base_outer_resolution_b.notest.gd | 0 .../base_outer_resolution_base.notest.gd | 4 + .../base_outer_resolution_c.notest.gd | 3 + .../base_outer_resolution_extend.notest.gd | 23 ++++ 9 files changed, 112 insertions(+), 44 deletions(-) create mode 100644 modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution.gd create mode 100644 modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution.out create mode 100644 modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_a.notest.gd create mode 100644 modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_b.notest.gd create mode 100644 modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_base.notest.gd create mode 100644 modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_c.notest.gd create mode 100644 modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_extend.notest.gd diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 0c86bce2ce1c..2892ae3f4e14 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -219,6 +219,22 @@ Error GDScriptAnalyzer::check_class_member_name_conflict(const GDScriptParser::C return OK; } +void GDScriptAnalyzer::get_class_node_current_scope_classes(GDScriptParser::ClassNode *p_node, List *p_list) { + if (p_list->find(p_node) != nullptr) { + return; + } + p_list->push_back(p_node); + + // Prioritize node base type over its outer class + if (p_node->base_type.class_type != nullptr) { + get_class_node_current_scope_classes(p_node->base_type.class_type, p_list); + } + + if (p_node->outer != nullptr) { + get_class_node_current_scope_classes(p_node->outer, p_list); + } +} + Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class, bool p_recursive) { if (p_class->base_type.is_set()) { // Already resolved @@ -327,9 +343,10 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class, base.native_type = name; } else { // Look for other classes in script. - GDScriptParser::ClassNode *look_class = p_class; bool found = false; - while (look_class != nullptr) { + List script_classes; + get_class_node_current_scope_classes(p_class, &script_classes); + for (GDScriptParser::ClassNode *look_class : script_classes) { if (look_class->identifier && look_class->identifier->name == name) { if (!look_class->get_datatype().is_set()) { Error err = resolve_inheritance(look_class, false); @@ -353,7 +370,6 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class, found = true; break; } - look_class = look_class->outer; } if (!found) { @@ -517,12 +533,11 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type result = make_native_enum_type(parser->current_class->base_type.native_type, first); } else { // Classes in current scope. - GDScriptParser::ClassNode *script_class = parser->current_class; - bool found = false; - while (!found && script_class != nullptr) { + List script_classes; + get_class_node_current_scope_classes(parser->current_class, &script_classes); + for (GDScriptParser::ClassNode *script_class : script_classes) { if (script_class->identifier && script_class->identifier->name == first) { result = script_class->get_datatype(); - found = true; break; } if (script_class->members_indices.has(first)) { @@ -530,17 +545,14 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type switch (member.type) { case GDScriptParser::ClassNode::Member::CLASS: result = member.m_class->get_datatype(); - found = true; break; case GDScriptParser::ClassNode::Member::ENUM: result = member.m_enum->get_datatype(); - found = true; break; case GDScriptParser::ClassNode::Member::CONSTANT: if (member.constant->get_datatype().is_meta_type) { result = member.constant->get_datatype(); result.is_meta_type = false; - found = true; break; } else if (Ref