Browse Source

Merge pull request #75879 from dalexeev/gds-fix-extends-crash

GDScript: Add missing member type check when resolving `extends`
Yuri Sizov 2 years ago
parent
commit
afca0b8fdd

+ 21 - 1
modules/gdscript/gdscript_analyzer.cpp

@@ -479,7 +479,24 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
 					}
 					}
 					if (look_class->has_member(name)) {
 					if (look_class->has_member(name)) {
 						resolve_class_member(look_class, name, id);
 						resolve_class_member(look_class, name, id);
-						base = look_class->get_member(name).get_datatype();
+						GDScriptParser::ClassNode::Member member = look_class->get_member(name);
+						GDScriptParser::DataType member_datatype = member.get_datatype();
+
+						switch (member.type) {
+							case GDScriptParser::ClassNode::Member::CLASS:
+								break; // OK.
+							case GDScriptParser::ClassNode::Member::CONSTANT:
+								if (member_datatype.kind != GDScriptParser::DataType::SCRIPT && member_datatype.kind != GDScriptParser::DataType::CLASS) {
+									push_error(vformat(R"(Constant "%s" is not a preloaded script or class.)", name), id);
+									return ERR_PARSE_ERROR;
+								}
+								break;
+							default:
+								push_error(vformat(R"(Cannot use %s "%s" in extends chain.)", member.get_type_name(), name), id);
+								return ERR_PARSE_ERROR;
+						}
+
+						base = member_datatype;
 						found = true;
 						found = true;
 						break;
 						break;
 					}
 					}
@@ -506,6 +523,9 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
 			if (!id_type.is_set()) {
 			if (!id_type.is_set()) {
 				push_error(vformat(R"(Could not find nested type "%s".)", id->name), id);
 				push_error(vformat(R"(Could not find nested type "%s".)", id->name), id);
 				return ERR_PARSE_ERROR;
 				return ERR_PARSE_ERROR;
+			} else if (id_type.kind != GDScriptParser::DataType::SCRIPT && id_type.kind != GDScriptParser::DataType::CLASS) {
+				push_error(vformat(R"(Identifier "%s" is not a preloaded script or class.)", id->name), id);
+				return ERR_PARSE_ERROR;
 			}
 			}
 
 
 			base = id_type;
 			base = id_type;

+ 9 - 0
modules/gdscript/tests/scripts/analyzer/errors/extend_non_class_constant_1.gd

@@ -0,0 +1,9 @@
+# GH-75870
+
+const A = 1
+
+class B extends A:
+	pass
+
+func test():
+	pass

+ 2 - 0
modules/gdscript/tests/scripts/analyzer/errors/extend_non_class_constant_1.out

@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Constant "A" is not a preloaded script or class.

+ 12 - 0
modules/gdscript/tests/scripts/analyzer/errors/extend_non_class_constant_2.gd

@@ -0,0 +1,12 @@
+# GH-75870
+
+class A:
+	const X = 1
+
+const Y = A.X # A.X is now resolved.
+
+class B extends A.X:
+	pass
+
+func test():
+	pass

+ 2 - 0
modules/gdscript/tests/scripts/analyzer/errors/extend_non_class_constant_2.out

@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Identifier "X" is not a preloaded script or class.

+ 9 - 0
modules/gdscript/tests/scripts/analyzer/errors/extend_variable.gd

@@ -0,0 +1,9 @@
+# GH-75870
+
+var A = 1
+
+class B extends A:
+	pass
+
+func test():
+	pass

+ 2 - 0
modules/gdscript/tests/scripts/analyzer/errors/extend_variable.out

@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot use variable "A" in extends chain.