summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRĂ©mi Verschelde <remi@verschelde.fr>2021-08-20 17:07:18 +0200
committerGitHub <noreply@github.com>2021-08-20 17:07:18 +0200
commitf5422c55fc47523beb1f246ca2c22a467272d641 (patch)
tree18a7e923b98c74961d40438cf5e8e134655ccbf8
parent75697c0dfda2c4bbb5456b78d54cd6a2664c8a49 (diff)
parent2e84a46a0f54cea0806e98b27e911ebae6be1976 (diff)
Merge pull request #49105 from vnen/gdscript-inner-preload-type
GDScript: Fix inner classes and preloaded scripts as types
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp44
-rw-r--r--modules/gdscript/gdscript_analyzer.h2
-rw-r--r--modules/gdscript/gdscript_compiler.cpp3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.gd3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.out3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.out1
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.gd11
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.out2
11 files changed, 74 insertions, 7 deletions
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index e925350ba3..6b7403d854 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -30,6 +30,7 @@
#include "gdscript_analyzer.h"
+#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
@@ -432,8 +433,28 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
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<Script>(member.constant->initializer->reduced_value).is_valid()) {
+ Ref<GDScript> gdscript = member.constant->initializer->reduced_value;
+ if (gdscript.is_valid()) {
+ Ref<GDScriptParserRef> ref = get_parser_for(gdscript->get_path());
+ if (ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) {
+ push_error(vformat(R"(Could not parse script from "%s".)", gdscript->get_path()), p_type);
+ return GDScriptParser::DataType();
+ }
+ result = ref->get_parser()->head->get_datatype();
+ result.is_meta_type = false;
+ } else {
+ Ref<GDScript> script = member.constant->initializer->reduced_value;
+ result.kind = GDScriptParser::DataType::SCRIPT;
+ result.builtin_type = Variant::OBJECT;
+ result.script_type = script;
+ result.script_path = script->get_path();
+ result.native_type = script->get_instance_base_type();
+ }
+ break;
}
[[fallthrough]];
default:
@@ -2129,6 +2150,9 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
if (is_self && parser->current_function != nullptr && parser->current_function->is_static && !is_static) {
push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parser->current_function->identifier->name), p_call->callee);
+ } 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->callee);
} else if (is_self && !is_static && !lambda_stack.is_empty()) {
push_error(vformat(R"*(Cannot call non-static function "%s()" from a lambda function.)*", p_call->function_name), p_call->callee);
}
@@ -2392,6 +2416,11 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
resolve_function_signature(member.function);
p_identifier->set_datatype(make_callable_type(member.function->info));
break;
+ case GDScriptParser::ClassNode::Member::CLASS:
+ // For out-of-order resolution:
+ resolve_class_interface(member.m_class);
+ p_identifier->set_datatype(member.m_class->get_datatype());
+ break;
default:
break; // Type already set.
}
@@ -3201,7 +3230,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo
return result;
}
-bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GDScriptParser::DataType p_base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg) {
+bool GDScriptAnalyzer::get_function_signature(GDScriptParser::CallNode *p_source, GDScriptParser::DataType p_base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg) {
r_static = false;
r_vararg = false;
r_default_arg_count = 0;
@@ -3220,14 +3249,16 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD
for (const MethodInfo &E : methods) {
if (E.name == p_function) {
- return function_signature_from_info(E, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
+ function_signature_from_info(E, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
+ r_static = Variant::is_builtin_method_static(p_base_type.builtin_type, function_name);
+ return true;
}
}
return false;
}
- bool is_constructor = p_base_type.is_meta_type && p_function == "new";
+ bool is_constructor = (p_base_type.is_meta_type || (p_source->callee && p_source->callee->type == GDScriptParser::Node::IDENTIFIER)) && p_function == StaticCString::create("new");
if (is_constructor) {
function_name = "_init";
r_static = true;
@@ -3257,6 +3288,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD
}
}
r_return_type = found_function->get_datatype();
+ r_return_type.is_meta_type = false;
r_return_type.is_coroutine = found_function->is_coroutine;
return true;
@@ -3304,7 +3336,11 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD
MethodInfo info;
if (ClassDB::get_method_info(base_native, function_name, &info)) {
- return function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
+ bool valid = function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
+ if (valid && Engine::get_singleton()->has_singleton(base_native)) {
+ r_static = true;
+ }
+ return valid;
}
return false;
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 8cd3fcf837..32bf049fa1 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -99,7 +99,7 @@ class GDScriptAnalyzer {
GDScriptParser::DataType type_from_metatype(const GDScriptParser::DataType &p_meta_type) const;
GDScriptParser::DataType type_from_property(const PropertyInfo &p_property) const;
GDScriptParser::DataType make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source);
- bool get_function_signature(GDScriptParser::Node *p_source, GDScriptParser::DataType base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg);
+ bool get_function_signature(GDScriptParser::CallNode *p_source, GDScriptParser::DataType base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg);
bool function_signature_from_info(const MethodInfo &p_info, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg);
bool validate_call_arg(const List<GDScriptParser::DataType> &p_par_types, int p_default_args_count, bool p_is_vararg, const GDScriptParser::CallNode *p_call);
bool validate_call_arg(const MethodInfo &p_method, const GDScriptParser::CallNode *p_call);
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index fe827a5b72..ddf4f281b4 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -126,8 +126,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
names.pop_back();
}
result.kind = GDScriptDataType::GDSCRIPT;
- result.script_type_ref = script;
- result.script_type = result.script_type_ref.ptr();
+ result.script_type = script.ptr();
result.native_type = script->get_instance_base_type();
} else {
result.kind = GDScriptDataType::GDSCRIPT;
diff --git a/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.gd b/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.gd
new file mode 100644
index 0000000000..ac66b78220
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.gd
@@ -0,0 +1,3 @@
+func test():
+ print(Color.html_is_valid("00ffff"))
+ print("OK")
diff --git a/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.out b/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.out
new file mode 100644
index 0000000000..75b002aa62
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+True
+OK
diff --git a/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd b/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd
new file mode 100644
index 0000000000..fb0ace6a90
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd
@@ -0,0 +1,5 @@
+func test():
+ pass
+
+func something():
+ return "OK"
diff --git a/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.out b/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.gd b/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.gd
new file mode 100644
index 0000000000..4f4b7a4897
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.gd
@@ -0,0 +1,11 @@
+class InnerClass:
+ var val := "OK"
+ static func create_instance() -> InnerClass:
+ return new()
+
+func create_inner_instance() -> InnerClass:
+ return InnerClass.create_instance()
+
+func test():
+ var instance = create_inner_instance()
+ print(instance.val)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.out b/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.out
new file mode 100644
index 0000000000..1ccb591560
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+OK
diff --git a/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.gd b/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.gd
new file mode 100644
index 0000000000..5f73064cc0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.gd
@@ -0,0 +1,5 @@
+const preloaded : GDScript = preload("gdscript_to_preload.gd")
+
+func test():
+ var preloaded_instance: preloaded = preloaded.new()
+ print(preloaded_instance.something())
diff --git a/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.out b/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.out
new file mode 100644
index 0000000000..1ccb591560
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+OK