Browse Source

Remove script class checks when getting function signature

Adam Scott 2 years ago
parent
commit
0fef203b1f

+ 1 - 11
modules/gdscript/gdscript_analyzer.cpp

@@ -3017,7 +3017,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
 			push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parent_function->identifier->name), p_call);
 		} else if (!is_self && base_type.is_meta_type && !is_static) {
 			base_type.is_meta_type = false; // For `to_string()`.
-			push_error(vformat(R"*(Cannot call non-static function "%s()" on the class "%s" directly. Make an instance instead.)*", p_call->function_name, base_type.to_string()), p_call);
+			push_error(vformat(R"*(Cannot call non-static function "%s()" on a class directly. Make an instance instead.)*", p_call->function_name), p_call);
 		} else if (is_self && !is_static) {
 			mark_lambda_use_self();
 		}
@@ -4564,16 +4564,6 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
 		base_script = base_script->get_base_script();
 	}
 
-	// If the base is a script, it might be trying to access members of the Script class itself.
-	if (p_base_type.is_meta_type && !p_is_constructor && (p_base_type.kind == GDScriptParser::DataType::SCRIPT || p_base_type.kind == GDScriptParser::DataType::CLASS)) {
-		MethodInfo info;
-		StringName script_class = p_base_type.kind == GDScriptParser::DataType::SCRIPT ? p_base_type.script_type->get_class_name() : StringName(GDScript::get_class_static());
-
-		if (ClassDB::get_method_info(script_class, function_name, &info)) {
-			return function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
-		}
-	}
-
 	if (p_is_constructor) {
 		// Native types always have a default constructor.
 		r_return_type = p_base_type;

+ 1 - 2
modules/gdscript/gdscript_compiler.cpp

@@ -591,7 +591,6 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
 						}
 					} else if (callee->type == GDScriptParser::Node::SUBSCRIPT) {
 						const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee);
-
 						if (subscript->is_attribute) {
 							// May be static built-in method call.
 							if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) < Variant::VARIANT_MAX) {
@@ -615,7 +614,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
 									} else {
 										class_name = base.type.native_type == StringName() ? base.type.script_type->get_instance_base_type() : base.type.native_type;
 									}
-									if (ClassDB::class_exists(class_name) && ClassDB::has_method(class_name, call->function_name)) {
+									if (!subscript->base->is_constant && ClassDB::class_exists(class_name) && ClassDB::has_method(class_name, call->function_name)) {
 										MethodBind *method = ClassDB::get_method(class_name, call->function_name);
 										if (_can_use_ptrcall(method, arguments)) {
 											// Exact arguments, use ptrcall.

+ 5 - 0
modules/gdscript/tests/scripts/analyzer/errors/gdscript_duplicate.gd

@@ -0,0 +1,5 @@
+const TestClass = preload("gdscript_duplicate_class.notest.gd")
+
+func test():
+	# (TestClass as GDScript).duplicate() exists
+	TestClass.duplicate()

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

@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot call non-static function "duplicate()" on a class directly. Make an instance instead.

+ 1 - 0
modules/gdscript/tests/scripts/analyzer/errors/gdscript_duplicate_class.notest.gd

@@ -0,0 +1 @@
+extends Node

+ 6 - 0
modules/gdscript/tests/scripts/analyzer/features/gdscript_duplicate.gd

@@ -0,0 +1,6 @@
+const TestClass = preload("gdscript_duplicate_class.notest.gd")
+
+func test():
+	# TestClass.duplicate() fails
+	@warning_ignore("return_value_discarded")
+	(TestClass as GDScript).duplicate()

+ 1 - 0
modules/gdscript/tests/scripts/analyzer/features/gdscript_duplicate.out

@@ -0,0 +1 @@
+GDTEST_OK

+ 1 - 0
modules/gdscript/tests/scripts/analyzer/features/gdscript_duplicate_class.notest.gd

@@ -0,0 +1 @@
+extends Node

+ 13 - 0
modules/gdscript/tests/scripts/parser/features/super_class_check.gd

@@ -0,0 +1,13 @@
+# https://github.com/godotengine/godot/issues/71994
+
+func test():
+	pass
+
+class A extends RefCounted:
+	pass
+
+class B extends A:
+	# Parsing `duplicate()` here would throw this error:
+	# Parse Error: The function signature doesn't match the parent. Parent signature is "duplicate(bool = default) -> Resource".
+	func duplicate():
+		pass

+ 1 - 0
modules/gdscript/tests/scripts/parser/features/super_class_check.out

@@ -0,0 +1 @@
+GDTEST_OK

+ 19 - 0
modules/gdscript/tests/scripts/runtime/features/static_duplicate.gd

@@ -0,0 +1,19 @@
+const PreloadClass = preload("static_duplicate_preload.notest.gd")
+const PreloadClassAlias = PreloadClass
+
+func test():
+	var dup_preload_one = PreloadClass.duplicate()
+	print(dup_preload_one == Vector2.ONE)
+
+	var dup_preload_two = (PreloadClass as GDScript).duplicate()
+	print(dup_preload_two is GDScript)
+
+	var dup_preload_alias_one = PreloadClassAlias.duplicate()
+	print(dup_preload_alias_one == Vector2.ONE)
+
+	var dup_preload_alias_two = (PreloadClassAlias as GDScript).duplicate()
+	print(dup_preload_alias_two is GDScript)
+
+	var PreloadClassAsGDScript = PreloadClass as GDScript
+	var dup_preload_class_as_gdscript_one = PreloadClassAsGDScript.duplicate()
+	print(dup_preload_class_as_gdscript_one is GDScript)

+ 9 - 0
modules/gdscript/tests/scripts/runtime/features/static_duplicate.out

@@ -0,0 +1,9 @@
+GDTEST_OK
+preload duplicate
+true
+true
+preload duplicate
+true
+true
+preload duplicate
+false

+ 5 - 0
modules/gdscript/tests/scripts/runtime/features/static_duplicate_preload.notest.gd

@@ -0,0 +1,5 @@
+extends RefCounted
+
+static func duplicate() -> Vector2:
+	print("preload duplicate")
+	return Vector2.ONE