Browse Source

Fix ability to overload "script" variable

ocean (they/them) 2 years ago
parent
commit
13be0ab733

+ 12 - 4
modules/gdscript/gdscript_analyzer.cpp

@@ -32,6 +32,7 @@
 
 #include "core/config/engine.h"
 #include "core/config/project_settings.h"
+#include "core/core_string_names.h"
 #include "core/io/file_access.h"
 #include "core/io/resource_loader.h"
 #include "core/object/class_db.h"
@@ -132,7 +133,7 @@ static GDScriptParser::DataType make_builtin_meta_type(Variant::Type p_type) {
 	return type;
 }
 
-bool GDScriptAnalyzer::has_member_name_conflict_in_script_class(const StringName &p_member_name, const GDScriptParser::ClassNode *p_class) {
+bool GDScriptAnalyzer::has_member_name_conflict_in_script_class(const StringName &p_member_name, const GDScriptParser::ClassNode *p_class, const GDScriptParser::Node *p_member) {
 	if (p_class->members_indices.has(p_member_name)) {
 		int index = p_class->members_indices[p_member_name];
 		const GDScriptParser::ClassNode::Member *member = &p_class->members[index];
@@ -145,6 +146,9 @@ bool GDScriptAnalyzer::has_member_name_conflict_in_script_class(const StringName
 				member->type == GDScriptParser::ClassNode::Member::SIGNAL) {
 			return true;
 		}
+		if (p_member->type != GDScriptParser::Node::FUNCTION && member->type == GDScriptParser::ClassNode::Member::FUNCTION) {
+			return true;
+		}
 	}
 
 	return false;
@@ -160,6 +164,9 @@ bool GDScriptAnalyzer::has_member_name_conflict_in_native_type(const StringName
 	if (ClassDB::has_integer_constant(p_native_type_string, p_member_name)) {
 		return true;
 	}
+	if (p_member_name == CoreStringNames::get_singleton()->_script) {
+		return true;
+	}
 
 	return false;
 }
@@ -187,14 +194,15 @@ Error GDScriptAnalyzer::check_class_member_name_conflict(const GDScriptParser::C
 	const GDScriptParser::DataType *current_data_type = &p_class_node->base_type;
 	while (current_data_type && current_data_type->kind == GDScriptParser::DataType::Kind::CLASS) {
 		GDScriptParser::ClassNode *current_class_node = current_data_type->class_type;
-		if (has_member_name_conflict_in_script_class(p_member_name, current_class_node)) {
-			push_error(vformat(R"(The member "%s" already exists in a parent class.)", p_member_name),
+		if (has_member_name_conflict_in_script_class(p_member_name, current_class_node, p_member_node)) {
+			push_error(vformat(R"(The member "%s" already exists in parent class %s.)", p_member_name, current_class_node->identifier->name),
 					p_member_node);
 			return ERR_PARSE_ERROR;
 		}
 		current_data_type = &current_class_node->base_type;
 	}
 
+	// No need for native class recursion because Node exposes all Object's properties.
 	if (current_data_type && current_data_type->kind == GDScriptParser::DataType::Kind::NATIVE) {
 		if (current_data_type->native_type != StringName()) {
 			return check_native_member_name_conflict(
@@ -2912,7 +2920,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
 		base_class = base_class->base_type.class_type;
 	}
 
-	// Check native members.
+	// Check native members. No need for native class recursion because Node exposes all Object's properties.
 	const StringName &native = base.native_type;
 
 	if (class_exists(native)) {

+ 1 - 1
modules/gdscript/gdscript_analyzer.h

@@ -45,7 +45,7 @@ class GDScriptAnalyzer {
 	List<GDScriptParser::LambdaNode *> lambda_stack;
 
 	// Tests for detecting invalid overloading of script members
-	static _FORCE_INLINE_ bool has_member_name_conflict_in_script_class(const StringName &p_name, const GDScriptParser::ClassNode *p_current_class_node);
+	static _FORCE_INLINE_ bool has_member_name_conflict_in_script_class(const StringName &p_name, const GDScriptParser::ClassNode *p_current_class_node, const GDScriptParser::Node *p_member);
 	static _FORCE_INLINE_ bool has_member_name_conflict_in_native_type(const StringName &p_name, const StringName &p_native_type_string);
 	Error check_native_member_name_conflict(const StringName &p_member_name, const GDScriptParser::Node *p_member_node, const StringName &p_native_type_string);
 	Error check_class_member_name_conflict(const GDScriptParser::ClassNode *p_class_node, const StringName &p_member_name, const GDScriptParser::Node *p_member_node);

+ 6 - 0
modules/gdscript/tests/scripts/analyzer/errors/overload_script_variable.gd

@@ -0,0 +1,6 @@
+extends Node
+
+var script: int
+
+func test():
+	pass

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

@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Member "script" redefined (original in native class 'Node')

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

@@ -0,0 +1,9 @@
+func test():
+	pass
+
+class A:
+	func overload_me():
+		pass
+
+class B extends A:
+	var overload_me

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

@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+The member "overload_me" already exists in parent class A.