summaryrefslogtreecommitdiff
path: root/modules/gdscript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp8
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.h2
-rw-r--r--modules/gdscript/gdscript.cpp9
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp85
-rw-r--r--modules/gdscript/gdscript_analyzer.h2
-rw-r--r--modules/gdscript/gdscript_cache.cpp2
-rw-r--r--modules/gdscript/gdscript_compiler.cpp3
-rw-r--r--modules/gdscript/gdscript_editor.cpp43
-rw-r--r--modules/gdscript/gdscript_function.h6
-rw-r--r--modules/gdscript/gdscript_parser.cpp45
-rw-r--r--modules/gdscript/gdscript_parser.h1
-rw-r--r--modules/gdscript/gdscript_vm.cpp2
-rw-r--r--modules/gdscript/tests/README.md8
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.out2
-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
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/assignment_empty_assignee.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/assignment_empty_assignee.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/str_preserves_case.gd7
-rw-r--r--modules/gdscript/tests/scripts/parser/features/str_preserves_case.out4
26 files changed, 143 insertions, 123 deletions
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index 3441233811..8b9bd2659d 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -45,7 +45,7 @@ static bool _is_bin_symbol(char32_t c) {
return (c == '0' || c == '1');
}
-Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line) {
+Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_line) {
Dictionary color_map;
Type next_type = NONE;
@@ -459,11 +459,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
List<StringName> types;
ClassDB::get_class_list(&types);
for (const StringName &E : types) {
- String n = E;
- if (n.begins_with("_")) {
- n = n.substr(1, n.length());
- }
- keywords[n] = types_color;
+ keywords[E] = types_color;
}
/* User types. */
diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h
index d07c182aa6..fabd64dab8 100644
--- a/modules/gdscript/editor/gdscript_highlighter.h
+++ b/modules/gdscript/editor/gdscript_highlighter.h
@@ -80,7 +80,7 @@ private:
public:
virtual void _update_cache() override;
- virtual Dictionary _get_line_syntax_highlighting(int p_line) override;
+ virtual Dictionary _get_line_syntax_highlighting_impl(int p_line) override;
virtual String _get_name() const override;
virtual Array _get_supported_languages() const override;
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 8957b00a1b..4589cf1a36 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -1644,16 +1644,11 @@ void GDScriptLanguage::init() {
List<StringName> class_list;
ClassDB::get_class_list(&class_list);
for (const StringName &n : class_list) {
- String s = String(n);
- if (s.begins_with("_")) {
- s = s.substr(1, s.length());
- }
-
- if (globals.has(s)) {
+ if (globals.has(n)) {
continue;
}
Ref<GDScriptNativeClass> nc = memnew(GDScriptNativeClass(n));
- _add_global(s, nc);
+ _add_global(n, nc);
}
//populate singletons
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) {
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_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index 1a844bf241..07f50d14dc 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -200,7 +200,9 @@ Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_erro
if (singleton->full_gdscript_cache.has(p_path)) {
return singleton->full_gdscript_cache[p_path];
}
+
Ref<GDScript> script = get_shallow_script(p_path);
+ ERR_FAIL_COND_V(script.is_null(), Ref<GDScript>());
r_error = script->load_source_code(p_path);
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/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 73661855b4..372a726d71 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -912,7 +912,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
}
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName type = GDScriptParser::get_real_class_name(base_type.native_type);
+ StringName type = base_type.native_type;
if (!ClassDB::class_exists(type)) {
return;
}
@@ -1326,10 +1326,7 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
native_type.kind = GDScriptParser::DataType::NATIVE;
native_type.native_type = native_type.script_type->get_instance_base_type();
if (!ClassDB::class_exists(native_type.native_type)) {
- native_type.native_type = String("_") + native_type.native_type;
- if (!ClassDB::class_exists(native_type.native_type)) {
- native_type.kind = GDScriptParser::DataType::UNRESOLVED;
- }
+ native_type.kind = GDScriptParser::DataType::UNRESOLVED;
}
}
}
@@ -1765,9 +1762,8 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
base_type = GDScriptParser::DataType();
break;
}
- StringName real_native = GDScriptParser::get_real_class_name(base_type.native_type);
MethodInfo info;
- if (ClassDB::get_method_info(real_native, p_context.current_function->identifier->name, &info)) {
+ if (ClassDB::get_method_info(base_type.native_type, p_context.current_function->identifier->name, &info)) {
for (const PropertyInfo &E : info.arguments) {
if (E.name == p_identifier) {
r_type = _type_from_property(E);
@@ -1836,13 +1832,12 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
}
// Check ClassDB.
- StringName class_name = GDScriptParser::get_real_class_name(p_identifier);
- if (ClassDB::class_exists(class_name) && ClassDB::is_class_exposed(class_name)) {
+ if (ClassDB::class_exists(p_identifier) && ClassDB::is_class_exposed(p_identifier)) {
r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
r_type.type.kind = GDScriptParser::DataType::NATIVE;
r_type.type.native_type = p_identifier;
r_type.type.is_constant = true;
- r_type.type.is_meta_type = !Engine::get_singleton()->has_singleton(class_name);
+ r_type.type.is_meta_type = !Engine::get_singleton()->has_singleton(p_identifier);
r_type.value = Variant();
}
@@ -1951,7 +1946,7 @@ static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext &
}
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type);
+ StringName class_name = base_type.native_type;
if (!ClassDB::class_exists(class_name)) {
return false;
}
@@ -2113,11 +2108,10 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex
}
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName native = GDScriptParser::get_real_class_name(base_type.native_type);
- if (!ClassDB::class_exists(native)) {
+ if (!ClassDB::class_exists(base_type.native_type)) {
return false;
}
- MethodBind *mb = ClassDB::get_method(native, p_method);
+ MethodBind *mb = ClassDB::get_method(base_type.native_type, p_method);
if (mb) {
r_type = _type_from_property(mb->get_return_info());
return true;
@@ -2209,7 +2203,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
base_type = base_type.class_type->base_type;
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type);
+ StringName class_name = base_type.native_type;
if (!ClassDB::class_exists(class_name)) {
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
break;
@@ -2592,7 +2586,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
break;
}
- StringName class_name = GDScriptParser::get_real_class_name(native_type.native_type);
+ StringName class_name = native_type.native_type;
if (!ClassDB::class_exists(class_name)) {
break;
}
@@ -2821,7 +2815,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type);
+ StringName class_name = base_type.native_type;
if (!ClassDB::class_exists(class_name)) {
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
break;
@@ -2873,11 +2867,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
StringName parent = ClassDB::get_parent_class(class_name);
if (parent != StringName()) {
- if (String(parent).begins_with("_")) {
- base_type.native_type = String(parent).substr(1);
- } else {
- base_type.native_type = parent;
- }
+ base_type.native_type = parent;
} else {
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
}
@@ -2931,18 +2921,11 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
::Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) {
- //before parsing, try the usual stuff
+ // Before parsing, try the usual stuff
if (ClassDB::class_exists(p_symbol)) {
r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS;
r_result.class_name = p_symbol;
return OK;
- } else {
- String under_prefix = "_" + p_symbol;
- if (ClassDB::class_exists(under_prefix)) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS;
- r_result.class_name = p_symbol;
- return OK;
- }
}
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index 9e5ef0f632..87d8c03494 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -111,11 +111,7 @@ public:
}
if (!ClassDB::is_parent_class(obj->get_class_name(), native_type)) {
- // Try with underscore prefix
- StringName underscore_native_type = "_" + native_type;
- if (!ClassDB::is_parent_class(obj->get_class_name(), underscore_native_type)) {
- return false;
- }
+ return false;
}
return true;
} break;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 8c3bb1ea57..029e30080b 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -94,43 +94,8 @@ Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) {
return Variant::VARIANT_MAX;
}
-// TODO: Move this to a central location (maybe core?).
-static HashMap<StringName, StringName> underscore_map;
-static const char *underscore_classes[] = {
- "ClassDB",
- "Directory",
- "Engine",
- "File",
- "Geometry",
- "GodotSharp",
- "JSON",
- "Marshalls",
- "Mutex",
- "OS",
- "ResourceLoader",
- "ResourceSaver",
- "Semaphore",
- "Thread",
- "VisualScriptEditor",
- nullptr,
-};
-StringName GDScriptParser::get_real_class_name(const StringName &p_source) {
- if (underscore_map.is_empty()) {
- const char **class_name = underscore_classes;
- while (*class_name != nullptr) {
- underscore_map[*class_name] = String("_") + *class_name;
- class_name++;
- }
- }
- if (underscore_map.has(p_source)) {
- return underscore_map[p_source];
- }
- return p_source;
-}
-
void GDScriptParser::cleanup() {
builtin_types.clear();
- underscore_map.clear();
}
void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const {
@@ -1152,7 +1117,6 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
}
item.custom_value = value;
}
- item.rightmost_column = previous.rightmost_column;
item.index = enum_node->values.size();
enum_node->values.push_back(item);
@@ -2401,6 +2365,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_assignment(ExpressionNode
}
assignment->assignee = p_previous_operand;
assignment->assigned_value = parse_expression(false);
+ if (assignment->assigned_value == nullptr) {
+ push_error(R"(Expected an expression after "=".)");
+ }
#ifdef DEBUG_ENABLED
if (has_operator && source_variable != nullptr && source_variable->assignments == 0) {
@@ -2986,7 +2953,7 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String &
} else {
/* Syntax:
- @tutorial ( The Title Here ) : http://the.url/
+ @tutorial ( The Title Here ) : https://the.url/
^ open ^ close ^ colon ^ url
*/
int open_bracket_pos = begin_scan, close_bracket_pos = 0;
@@ -3363,10 +3330,10 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
variable->export_info.hint_string = Variant::get_type_name(export_type.builtin_type);
break;
case GDScriptParser::DataType::NATIVE:
- if (ClassDB::is_parent_class(get_real_class_name(export_type.native_type), "Resource")) {
+ if (ClassDB::is_parent_class(export_type.native_type, "Resource")) {
variable->export_info.type = Variant::OBJECT;
variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE;
- variable->export_info.hint_string = get_real_class_name(export_type.native_type);
+ variable->export_info.hint_string = export_type.native_type;
} else {
push_error(R"(Export type can only be built-in, a resource, or an enum.)", variable);
return false;
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 6a227a55e5..0bce8d7ddd 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -1399,7 +1399,6 @@ public:
ClassNode *get_tree() const { return head; }
bool is_tool() const { return _is_tool; }
static Variant::Type get_builtin_type(const StringName &p_type);
- static StringName get_real_class_name(const StringName &p_source);
CompletionContext get_completion_context() const { return completion_context; }
CompletionCall get_completion_call() const { return completion_call; }
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 8a261a88e3..882256b7e3 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -174,7 +174,7 @@ void (*type_init_function_table[])(Variant *) = {
&VariantInitializer<StringName>::init, // STRING_NAME.
&VariantInitializer<NodePath>::init, // NODE_PATH.
&VariantInitializer<RID>::init, // RID.
- &VariantTypeAdjust<Object *>::adjust, // OBJECT.
+ &VariantInitializer<Object *>::init, // OBJECT.
&VariantInitializer<Callable>::init, // CALLABLE.
&VariantInitializer<Signal>::init, // SIGNAL.
&VariantInitializer<Dictionary>::init, // DICTIONARY.
diff --git a/modules/gdscript/tests/README.md b/modules/gdscript/tests/README.md
new file mode 100644
index 0000000000..6e54085962
--- /dev/null
+++ b/modules/gdscript/tests/README.md
@@ -0,0 +1,8 @@
+# GDScript integration tests
+
+The `scripts/` folder contains integration tests in the form of GDScript files
+and output files.
+
+See the
+[Integration tests for GDScript documentation](https://docs.godotengine.org/en/latest/development/cpp/unit_testing.html#integration-tests-for-gdscript)
+for information about creating and running GDScript integration tests.
diff --git a/modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.out b/modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.out
index dc4348d9c3..2c8cc9c03f 100644
--- a/modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.out
+++ b/modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.out
@@ -1,3 +1,3 @@
GDTEST_OK
Name is equal
-True
+true
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..ad6beeb646
--- /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
diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_empty_assignee.gd b/modules/gdscript/tests/scripts/parser/errors/assignment_empty_assignee.gd
new file mode 100644
index 0000000000..17c65ad60a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/assignment_empty_assignee.gd
@@ -0,0 +1,3 @@
+func test():
+ var a = 0
+ a =
diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_empty_assignee.out b/modules/gdscript/tests/scripts/parser/errors/assignment_empty_assignee.out
new file mode 100644
index 0000000000..1369a7a0dc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/assignment_empty_assignee.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected an expression after "=".
diff --git a/modules/gdscript/tests/scripts/parser/features/str_preserves_case.gd b/modules/gdscript/tests/scripts/parser/features/str_preserves_case.gd
new file mode 100644
index 0000000000..ad1694de81
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/str_preserves_case.gd
@@ -0,0 +1,7 @@
+func test():
+ var null_var = null
+ var true_var:bool = true
+ var false_var:bool = false
+ print(str(null_var))
+ print(str(true_var))
+ print(str(false_var))
diff --git a/modules/gdscript/tests/scripts/parser/features/str_preserves_case.out b/modules/gdscript/tests/scripts/parser/features/str_preserves_case.out
new file mode 100644
index 0000000000..abba38e87c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/str_preserves_case.out
@@ -0,0 +1,4 @@
+GDTEST_OK
+null
+true
+false