summaryrefslogtreecommitdiff
path: root/modules/gdscript/gdscript_analyzer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/gdscript_analyzer.cpp')
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp85
1 files changed, 56 insertions, 29 deletions
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index ab37e54cf1..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"
@@ -112,11 +113,10 @@ static GDScriptParser::DataType make_native_enum_type(const StringName &p_native
type.is_meta_type = true;
List<StringName> enum_values;
- StringName real_native_name = GDScriptParser::get_real_class_name(p_native_class);
- ClassDB::get_enum_constants(real_native_name, p_enum_name, &enum_values);
+ ClassDB::get_enum_constants(p_native_class, p_enum_name, &enum_values);
for (const StringName &E : enum_values) {
- type.enum_values[E] = ClassDB::get_integer_constant(real_native_name, E);
+ type.enum_values[E] = ClassDB::get_integer_constant(p_native_class, E);
}
return type;
@@ -229,7 +229,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class);
return err;
}
- } else if (class_exists(name) && ClassDB::can_instantiate(GDScriptParser::get_real_class_name(name))) {
+ } else if (class_exists(name) && ClassDB::can_instantiate(name)) {
base.kind = GDScriptParser::DataType::NATIVE;
base.native_type = name;
} else {
@@ -406,7 +406,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
return GDScriptParser::DataType();
}
result = ref->get_parser()->head->get_datatype();
- } else if (ClassDB::has_enum(GDScriptParser::get_real_class_name(parser->current_class->base_type.native_type), first)) {
+ } else if (ClassDB::has_enum(parser->current_class->base_type.native_type, first)) {
// Native enum in current class.
result = make_native_enum_type(parser->current_class->base_type.native_type, first);
} else {
@@ -433,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:
@@ -469,7 +489,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
}
} else if (result.kind == GDScriptParser::DataType::NATIVE) {
// Only enums allowed for native.
- if (ClassDB::has_enum(GDScriptParser::get_real_class_name(result.native_type), p_type->type_chain[1]->name)) {
+ if (ClassDB::has_enum(result.native_type, p_type->type_chain[1]->name)) {
if (p_type->type_chain.size() > 2) {
push_error(R"(Enums cannot contain nested types.)", p_type->type_chain[2]);
} else {
@@ -2130,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);
}
@@ -2252,7 +2275,7 @@ void GDScriptAnalyzer::reduce_get_node(GDScriptParser::GetNodeNode *p_get_node)
result.native_type = "Node";
result.builtin_type = Variant::OBJECT;
- if (!ClassDB::is_parent_class(GDScriptParser::get_real_class_name(parser->current_class->base_type.native_type), result.native_type)) {
+ if (!ClassDB::is_parent_class(parser->current_class->base_type.native_type, result.native_type)) {
push_error(R"*(Cannot use shorthand "get_node()" notation ("$") on a class that isn't a node.)*", p_get_node);
} else if (!lambda_stack.is_empty()) {
push_error(R"*(Cannot use shorthand "get_node()" notation ("$") inside a lambda. Use a captured variable instead.)*", p_get_node);
@@ -2393,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.
}
@@ -2421,7 +2449,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
}
// Check native members.
- const StringName &native = GDScriptParser::get_real_class_name(base.native_type);
+ const StringName &native = base.native_type;
if (class_exists(native)) {
PropertyInfo prop_info;
@@ -3202,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;
@@ -3221,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;
@@ -3258,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;
@@ -3303,11 +3334,13 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD
return true;
}
- StringName real_native = GDScriptParser::get_real_class_name(base_native);
-
MethodInfo info;
- if (ClassDB::get_method_info(real_native, function_name, &info)) {
- return function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
+ if (ClassDB::get_method_info(base_native, function_name, &info)) {
+ 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;
@@ -3398,24 +3431,23 @@ bool GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con
StringName parent = base_native;
while (parent != StringName()) {
- StringName real_class_name = GDScriptParser::get_real_class_name(parent);
- if (ClassDB::has_method(real_class_name, name, true)) {
+ if (ClassDB::has_method(parent, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "method", parent);
return true;
- } else if (ClassDB::has_signal(real_class_name, name, true)) {
+ } else if (ClassDB::has_signal(parent, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "signal", parent);
return true;
- } else if (ClassDB::has_property(real_class_name, name, true)) {
+ } else if (ClassDB::has_property(parent, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "property", parent);
return true;
- } else if (ClassDB::has_integer_constant(real_class_name, name, true)) {
+ } else if (ClassDB::has_integer_constant(parent, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "constant", parent);
return true;
- } else if (ClassDB::has_enum(real_class_name, name, true)) {
+ } else if (ClassDB::has_enum(parent, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "enum", parent);
return true;
}
- parent = ClassDB::get_parent_class(real_class_name);
+ parent = ClassDB::get_parent_class(parent);
}
return false;
@@ -3560,16 +3592,12 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ
break; // Already solved before.
}
- // Get underscore-prefixed version for some classes.
- src_native = GDScriptParser::get_real_class_name(src_native);
-
switch (p_target.kind) {
case GDScriptParser::DataType::NATIVE: {
if (p_target.is_meta_type) {
return ClassDB::is_parent_class(src_native, GDScriptNativeClass::get_class_static());
}
- StringName tgt_native = GDScriptParser::get_real_class_name(p_target.native_type);
- return ClassDB::is_parent_class(src_native, tgt_native);
+ return ClassDB::is_parent_class(src_native, p_target.native_type);
}
case GDScriptParser::DataType::SCRIPT:
if (p_target.is_meta_type) {
@@ -3618,8 +3646,7 @@ void GDScriptAnalyzer::mark_node_unsafe(const GDScriptParser::Node *p_node) {
}
bool GDScriptAnalyzer::class_exists(const StringName &p_class) const {
- StringName real_name = GDScriptParser::get_real_class_name(p_class);
- return ClassDB::class_exists(real_name) && ClassDB::is_class_exposed(real_name);
+ return ClassDB::class_exists(p_class) && ClassDB::is_class_exposed(p_class);
}
Ref<GDScriptParserRef> GDScriptAnalyzer::get_parser_for(const String &p_path) {