summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/Node.xml1
-rw-r--r--doc/classes/ProjectSettings.xml3
-rw-r--r--editor/editor_node.cpp4
-rw-r--r--editor/editor_node.h1
-rw-r--r--editor/editor_vcs_interface.cpp21
-rw-r--r--editor/editor_vcs_interface.h6
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp33
-rw-r--r--editor/plugins/version_control_editor_plugin.h4
-rw-r--r--editor/project_manager.cpp69
-rw-r--r--modules/gdscript/gdscript_parser.cpp51
-rw-r--r--modules/gdscript/gdscript_warning.cpp5
-rw-r--r--modules/gdscript/gdscript_warning.h1
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.out9
14 files changed, 165 insertions, 45 deletions
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 6b3aa30dd2..8a12314ba8 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -571,6 +571,7 @@
<description>
Replaces a node in a scene by the given one. Subscriptions that pass through this node will be lost.
If [code]keep_groups[/code] is [code]true[/code], the [code]node[/code] is added to the same groups that the replaced node is in.
+ Note that the replaced node is not automatically freed, so you either need to keep it in a variable for later use or free it using [method Object.free].
</description>
</method>
<method name="request_ready">
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 6f22a53dd1..69ee51ca99 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -372,6 +372,9 @@
<member name="debug/gdscript/warnings/return_value_discarded" type="bool" setter="" getter="" default="true">
If [code]true[/code], enables warnings when calling a function without using its return value (by assigning it to a variable or using it as a function argument). Such return values are sometimes used to denote possible errors using the [enum Error] enum.
</member>
+ <member name="debug/gdscript/warnings/shadowed_global_identifier" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], enables warnings when defining a local or subclass member variable, signal, or enum that would have the same name as a built-in function or global class name, which possibly shadow it.
+ </member>
<member name="debug/gdscript/warnings/shadowed_variable" type="bool" setter="" getter="" default="true">
If [code]true[/code], enables warnings when defining a local or subclass member variable that would shadow a variable at an upper level (such as a member variable).
</member>
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 6a9d47bcc5..69a59b7ddb 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -383,6 +383,9 @@ void EditorNode::_update_scene_tabs() {
void EditorNode::_version_control_menu_option(int p_idx) {
switch (vcs_actions_menu->get_item_id(p_idx)) {
+ case RUN_VCS_METADATA: {
+ VersionControlEditorPlugin::get_singleton()->popup_vcs_metadata_dialog();
+ } break;
case RUN_VCS_SETTINGS: {
VersionControlEditorPlugin::get_singleton()->popup_vcs_set_up_dialog(gui_base);
} break;
@@ -6432,6 +6435,7 @@ EditorNode::EditorNode() {
p->add_separator();
p->add_child(vcs_actions_menu);
p->add_submenu_item(TTR("Version Control"), "Version Control");
+ vcs_actions_menu->add_item(TTR("Create Version Control Metadata"), RUN_VCS_METADATA);
vcs_actions_menu->add_item(TTR("Set Up Version Control"), RUN_VCS_SETTINGS);
vcs_actions_menu->add_item(TTR("Shut Down Version Control"), RUN_VCS_SHUT_DOWN);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 98aa4b697c..d74ec33f25 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -170,6 +170,7 @@ private:
RUN_PROJECT_DATA_FOLDER,
RUN_RELOAD_CURRENT_PROJECT,
RUN_PROJECT_MANAGER,
+ RUN_VCS_METADATA,
RUN_VCS_SETTINGS,
RUN_VCS_SHUT_DOWN,
SETTINGS_UPDATE_CONTINUOUSLY,
diff --git a/editor/editor_vcs_interface.cpp b/editor/editor_vcs_interface.cpp
index eaa8f891ec..b4b740d7c6 100644
--- a/editor/editor_vcs_interface.cpp
+++ b/editor/editor_vcs_interface.cpp
@@ -166,3 +166,24 @@ EditorVCSInterface *EditorVCSInterface::get_singleton() {
void EditorVCSInterface::set_singleton(EditorVCSInterface *p_singleton) {
singleton = p_singleton;
}
+
+void EditorVCSInterface::create_vcs_metadata_files(VCSMetadata p_vcs_metadata_type, String &p_dir) {
+ if (p_vcs_metadata_type == VCSMetadata::GIT) {
+ FileAccess *f = FileAccess::open(p_dir.plus_file(".gitignore"), FileAccess::WRITE);
+ if (!f) {
+ ERR_FAIL_MSG(TTR("Couldn't create .gitignore in project path."));
+ } else {
+ f->store_line("# Godot 4+ specific ignores");
+ f->store_line(".godot/");
+ memdelete(f);
+ }
+ f = FileAccess::open(p_dir.plus_file(".gitattributes"), FileAccess::WRITE);
+ if (!f) {
+ ERR_FAIL_MSG(TTR("Couldn't create .gitattributes in project path."));
+ } else {
+ f->store_line("# Normalize EOL for all files that Git considers text files.");
+ f->store_line("* text=auto eol=lf");
+ memdelete(f);
+ }
+ }
+}
diff --git a/editor/editor_vcs_interface.h b/editor/editor_vcs_interface.h
index 52ab6d68ee..1a2adeb148 100644
--- a/editor/editor_vcs_interface.h
+++ b/editor/editor_vcs_interface.h
@@ -61,6 +61,12 @@ public:
static EditorVCSInterface *get_singleton();
static void set_singleton(EditorVCSInterface *p_singleton);
+ enum class VCSMetadata {
+ NONE,
+ GIT,
+ };
+ static void create_vcs_metadata_files(VCSMetadata p_vcs_metadata_type, String &p_dir);
+
bool is_addon_ready();
// Proxy functions to the editor for use
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index b97095ef39..28352d25eb 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -49,6 +49,11 @@ void VersionControlEditorPlugin::_bind_methods() {
BIND_ENUM_CONSTANT(CHANGE_TYPE_TYPECHANGE);
}
+void VersionControlEditorPlugin::_create_vcs_metadata_files() {
+ String dir = "res://";
+ EditorVCSInterface::create_vcs_metadata_files(EditorVCSInterface::VCSMetadata(metadata_selection->get_selected()), dir);
+}
+
void VersionControlEditorPlugin::_selected_a_vcs(int p_id) {
List<StringName> available_addons = get_available_vcs_names();
const StringName selected_vcs = set_up_choice->get_item_text(p_id);
@@ -71,6 +76,10 @@ VersionControlEditorPlugin *VersionControlEditorPlugin::get_singleton() {
return singleton ? singleton : memnew(VersionControlEditorPlugin);
}
+void VersionControlEditorPlugin::popup_vcs_metadata_dialog() {
+ metadata_dialog->popup_centered();
+}
+
void VersionControlEditorPlugin::popup_vcs_set_up_dialog(const Control *p_gui_base) {
fetch_available_vcs_addon_names();
List<StringName> available_addons = get_available_vcs_names();
@@ -374,6 +383,30 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
version_control_actions = memnew(PopupMenu);
+ metadata_dialog = memnew(ConfirmationDialog);
+ metadata_dialog->set_title(TTR("Create Version Control Metadata"));
+ metadata_dialog->set_min_size(Size2(200, 40));
+ version_control_actions->add_child(metadata_dialog);
+
+ VBoxContainer *metadata_vb = memnew(VBoxContainer);
+ HBoxContainer *metadata_hb = memnew(HBoxContainer);
+ metadata_hb->set_custom_minimum_size(Size2(200, 20));
+ Label *l = memnew(Label);
+ l->set_text(TTR("Create VCS metadata files for:"));
+ metadata_hb->add_child(l);
+ metadata_selection = memnew(OptionButton);
+ metadata_selection->set_custom_minimum_size(Size2(100, 20));
+ metadata_selection->add_item("None", (int)EditorVCSInterface::VCSMetadata::NONE);
+ metadata_selection->add_item("Git", (int)EditorVCSInterface::VCSMetadata::GIT);
+ metadata_selection->select((int)EditorVCSInterface::VCSMetadata::GIT);
+ metadata_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_create_vcs_metadata_files));
+ metadata_hb->add_child(metadata_selection);
+ metadata_vb->add_child(metadata_hb);
+ l = memnew(Label);
+ l->set_text(TTR("Existing VCS metadata files will be overwritten."));
+ metadata_vb->add_child(l);
+ metadata_dialog->add_child(metadata_vb);
+
set_up_dialog = memnew(AcceptDialog);
set_up_dialog->set_title(TTR("Set Up Version Control"));
set_up_dialog->set_min_size(Size2(400, 100));
diff --git a/editor/plugins/version_control_editor_plugin.h b/editor/plugins/version_control_editor_plugin.h
index d2ba63c86c..2782c1d9dc 100644
--- a/editor/plugins/version_control_editor_plugin.h
+++ b/editor/plugins/version_control_editor_plugin.h
@@ -57,6 +57,8 @@ private:
List<StringName> available_addons;
PopupMenu *version_control_actions;
+ ConfirmationDialog *metadata_dialog;
+ OptionButton *metadata_selection;
AcceptDialog *set_up_dialog;
VBoxContainer *set_up_vbc;
HBoxContainer *set_up_hbc;
@@ -98,6 +100,7 @@ private:
RichTextLabel *diff;
void _populate_available_vcs_names();
+ void _create_vcs_metadata_files();
void _selected_a_vcs(int p_id);
void _initialize_vcs();
void _send_commit_msg();
@@ -121,6 +124,7 @@ protected:
public:
static VersionControlEditorPlugin *get_singleton();
+ void popup_vcs_metadata_dialog();
void popup_vcs_set_up_dialog(const Control *p_gui_base);
void set_version_control_tool_button(Button *p_button) { version_control_dock_button = p_button; }
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 7b942adb54..8ee90a1184 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -41,6 +41,7 @@
#include "core/string/translation.h"
#include "core/version.h"
#include "core/version_hash.gen.h"
+#include "editor/editor_vcs_interface.h"
#include "editor_scale.h"
#include "editor_settings.h"
#include "editor_themes.h"
@@ -67,19 +68,19 @@ public:
MODE_NEW,
MODE_IMPORT,
MODE_INSTALL,
- MODE_RENAME
+ MODE_RENAME,
};
private:
enum MessageType {
MESSAGE_ERROR,
MESSAGE_WARNING,
- MESSAGE_SUCCESS
+ MESSAGE_SUCCESS,
};
enum InputType {
PROJECT_PATH,
- INSTALL_PATH
+ INSTALL_PATH,
};
Mode mode;
@@ -90,6 +91,7 @@ private:
Container *path_container;
Container *install_path_container;
Container *rasterizer_container;
+ HBoxContainer *default_files_container;
Ref<ButtonGroup> rasterizer_button_group;
Label *msg;
LineEdit *project_path;
@@ -99,6 +101,8 @@ private:
TextureRect *install_status_rect;
FileDialog *fdialog;
FileDialog *fdialog_install;
+ OptionButton *vcs_metadata_selection;
+ CheckBox *create_default_environment;
String zip_path;
String zip_title;
AcceptDialog *dialog_error;
@@ -478,28 +482,34 @@ private:
initial_settings["rendering/vulkan/rendering/back_end"] = rasterizer_button_group->get_pressed_button()->get_meta(SNAME("driver_name"));
initial_settings["application/config/name"] = project_name->get_text().strip_edges();
initial_settings["application/config/icon"] = "res://icon.png";
- initial_settings["rendering/environment/defaults/default_environment"] = "res://default_env.tres";
+
+ if (create_default_environment->is_pressed()) {
+ initial_settings["rendering/environment/defaults/default_environment"] = "res://default_env.tres";
+ }
if (ProjectSettings::get_singleton()->save_custom(dir.plus_file("project.godot"), initial_settings, Vector<String>(), false) != OK) {
set_message(TTR("Couldn't create project.godot in project path."), MESSAGE_ERROR);
} else {
ResourceSaver::save(dir.plus_file("icon.png"), create_unscaled_default_project_icon());
-
- FileAccess *f = FileAccess::open(dir.plus_file("default_env.tres"), FileAccess::WRITE);
- if (!f) {
- set_message(TTR("Couldn't create project.godot in project path."), MESSAGE_ERROR);
- } else {
- f->store_line("[gd_resource type=\"Environment\" load_steps=2 format=3]");
- f->store_line("");
- f->store_line("[sub_resource type=\"Sky\" id=\"1\"]");
- f->store_line("");
- f->store_line("[resource]");
- f->store_line("background_mode = 2");
- f->store_line("sky = SubResource( \"1\" )");
- memdelete(f);
+ FileAccess *f;
+ if (create_default_environment->is_pressed()) {
+ f = FileAccess::open(dir.plus_file("default_env.tres"), FileAccess::WRITE);
+ if (!f) {
+ set_message(TTR("Couldn't create default_env.tres in project path."), MESSAGE_ERROR);
+ } else {
+ f->store_line("[gd_resource type=\"Environment\" load_steps=2 format=2]");
+ f->store_line("");
+ f->store_line("[sub_resource type=\"Sky\" id=\"1\"]");
+ f->store_line("");
+ f->store_line("[resource]");
+ f->store_line("background_mode = 2");
+ f->store_line("sky = SubResource( \"1\" )");
+ memdelete(f);
+ }
}
- }
+ EditorVCSInterface::create_vcs_metadata_files(EditorVCSInterface::VCSMetadata(vcs_metadata_selection->get_selected()), dir);
+ }
} else if (mode == MODE_INSTALL) {
if (project_path->get_text().ends_with(".zip")) {
dir = install_path->get_text();
@@ -694,6 +704,7 @@ public:
install_path_container->hide();
install_status_rect->hide();
rasterizer_container->hide();
+ default_files_container->hide();
get_ok_button()->set_disabled(false);
ProjectSettings *current = memnew(ProjectSettings);
@@ -745,6 +756,7 @@ public:
name_container->hide();
install_path_container->hide();
rasterizer_container->hide();
+ default_files_container->hide();
project_path->grab_focus();
} else if (mode == MODE_NEW) {
@@ -753,6 +765,7 @@ public:
name_container->show();
install_path_container->hide();
rasterizer_container->show();
+ default_files_container->show();
project_name->call_deferred(SNAME("grab_focus"));
project_name->call_deferred(SNAME("select_all"));
@@ -763,6 +776,7 @@ public:
name_container->show();
install_path_container->hide();
rasterizer_container->hide();
+ default_files_container->hide();
project_path->grab_focus();
}
@@ -905,6 +919,25 @@ public:
l->set_modulate(Color(1, 1, 1, 0.7));
rasterizer_container->add_child(l);
+ default_files_container = memnew(HBoxContainer);
+ vb->add_child(default_files_container);
+ l = memnew(Label);
+ l->set_text(TTR("Version Control Metadata:"));
+ default_files_container->add_child(l);
+ vcs_metadata_selection = memnew(OptionButton);
+ vcs_metadata_selection->set_custom_minimum_size(Size2(100, 20));
+ vcs_metadata_selection->add_item("None", (int)EditorVCSInterface::VCSMetadata::NONE);
+ vcs_metadata_selection->add_item("Git", (int)EditorVCSInterface::VCSMetadata::GIT);
+ vcs_metadata_selection->select((int)EditorVCSInterface::VCSMetadata::GIT);
+ default_files_container->add_child(vcs_metadata_selection);
+ Control *spacer = memnew(Control);
+ spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ default_files_container->add_child(spacer);
+ create_default_environment = memnew(CheckBox);
+ create_default_environment->set_text("Create Default Environment");
+ create_default_environment->set_pressed(true);
+ default_files_container->add_child(create_default_environment);
+
fdialog = memnew(FileDialog);
fdialog->set_access(FileDialog::ACCESS_FILESYSTEM);
fdialog_install = memnew(FileDialog);
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index bde6783322..d9cf9f4f10 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -741,20 +741,22 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)()
if (member->identifier != nullptr) {
if (!((String)member->identifier->name).is_empty()) { // Enums may be unnamed.
+
+#ifdef DEBUG_ENABLED
List<MethodInfo> gdscript_funcs;
GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs);
for (MethodInfo &info : gdscript_funcs) {
if (info.name == member->identifier->name) {
- push_error(vformat(R"(%s "%s" has the same name as a built-in function.)", p_member_kind.capitalize(), member->identifier->name), member->identifier);
- return;
+ push_warning(member->identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_member_kind, member->identifier->name, "built-in function");
}
}
+ if (Variant::has_utility_function(member->identifier->name)) {
+ push_warning(member->identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_member_kind, member->identifier->name, "built-in function");
+ }
+#endif
+
if (current_class->members_indices.has(member->identifier->name)) {
push_error(vformat(R"(%s "%s" has the same name as a previously declared %s.)", p_member_kind.capitalize(), member->identifier->name, current_class->get_member(member->identifier->name).get_type_name()), member->identifier);
- } else if (Variant::has_utility_function(member->identifier->name)) {
- push_error(vformat(R"(%s "%s" has the same name as a built-in function.)", p_member_kind.capitalize(), member->identifier->name), member->identifier);
- } else if (ClassDB::class_exists(member->identifier->name)) {
- push_error(vformat(R"(%s "%s" has the same name as a global class.)", p_member_kind.capitalize(), member->identifier->name), member->identifier);
} else {
current_class->add_member(member);
}
@@ -827,21 +829,18 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_proper
GDScriptParser::IdentifierNode *identifier = parse_identifier();
+#ifdef DEBUG_ENABLED
List<MethodInfo> gdscript_funcs;
GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs);
for (MethodInfo &info : gdscript_funcs) {
if (info.name == identifier->name) {
- push_error(vformat(R"(Local var "%s" has the same name as a built-in function.)", identifier->name), identifier);
- return nullptr;
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "local variable", identifier->name, "built-in function");
}
}
if (Variant::has_utility_function(identifier->name)) {
- push_error(vformat(R"(Local var "%s" has the same name as a built-in function.)", identifier->name), identifier);
- return nullptr;
- } else if (ClassDB::class_exists(identifier->name)) {
- push_error(vformat(R"(Local var "%s" has the same name as a global class.)", identifier->name), identifier);
- return nullptr;
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "local variable", identifier->name, "built-in function");
}
+#endif
VariableNode *variable = alloc_node<VariableNode>();
variable->identifier = identifier;
@@ -1099,22 +1098,20 @@ GDScriptParser::ParameterNode *GDScriptParser::parse_parameter() {
}
GDScriptParser::IdentifierNode *identifier = parse_identifier();
-
+#ifdef DEBUG_ENABLED
List<MethodInfo> gdscript_funcs;
GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs);
for (MethodInfo &info : gdscript_funcs) {
if (info.name == identifier->name) {
- push_error(vformat(R"(Parameter "%s" has the same name as a built-in function.)", identifier->name), identifier);
- return nullptr;
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "parameter", identifier->name, "built-in function");
}
}
if (Variant::has_utility_function(identifier->name)) {
- push_error(vformat(R"(Parameter "%s" has the same name as a built-in function.)", identifier->name), identifier);
- return nullptr;
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "parameter", identifier->name, "built-in function");
} else if (ClassDB::class_exists(identifier->name)) {
- push_error(vformat(R"(Parameter "%s" has the same name as a global class.)", identifier->name), identifier);
- return nullptr;
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "parameter", identifier->name, "global class");
}
+#endif
ParameterNode *parameter = alloc_node<ParameterNode>();
parameter->identifier = identifier;
@@ -1195,8 +1192,10 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
HashMap<StringName, int> elements;
+#ifdef DEBUG_ENABLED
List<MethodInfo> gdscript_funcs;
GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs);
+#endif
do {
if (check(GDScriptTokenizer::Token::BRACE_CLOSE)) {
@@ -1205,20 +1204,18 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected identifier for enum key.)")) {
EnumNode::Value item;
GDScriptParser::IdentifierNode *identifier = parse_identifier();
-
+#ifdef DEBUG_ENABLED
for (MethodInfo &info : gdscript_funcs) {
if (info.name == identifier->name) {
- push_error(vformat(R"(Enum member "%s" has the same name as a built-in function.)", identifier->name), identifier);
- return nullptr;
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "enum member", identifier->name, "built-in function");
}
}
if (Variant::has_utility_function(identifier->name)) {
- push_error(vformat(R"(Enum member "%s" has the same name as a built-in function.)", identifier->name), identifier);
- return nullptr;
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "enum member", identifier->name, "built-in function");
} else if (ClassDB::class_exists(identifier->name)) {
- push_error(vformat(R"(Enum member "%s" has the same name as a global class.)", identifier->name), identifier);
- return nullptr;
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "enum member", identifier->name, "global class");
}
+#endif
item.identifier = identifier;
item.parent_enum = enum_node;
item.line = previous.start_line;
diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp
index 7a483a16ba..a351bd6dad 100644
--- a/modules/gdscript/gdscript_warning.cpp
+++ b/modules/gdscript/gdscript_warning.cpp
@@ -148,6 +148,10 @@ String GDScriptWarning::get_message() const {
case EMPTY_FILE: {
return "Empty script file.";
}
+ case SHADOWED_GLOBAL_IDENTIFIER: {
+ CHECK_SYMBOLS(3);
+ return vformat(R"(The %s '%s' has the same name as a %s.)", symbols[0], symbols[1], symbols[2]);
+ }
case WARNING_MAX:
break; // Can't happen, but silences warning
}
@@ -194,6 +198,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"ASSERT_ALWAYS_FALSE",
"REDUNDANT_AWAIT",
"EMPTY_FILE",
+ "SHADOWED_GLOBAL_IDENTIFIER",
};
static_assert((sizeof(names) / sizeof(*names)) == WARNING_MAX, "Amount of warning types don't match the amount of warning names.");
diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h
index 8de46b08c1..d05f47efe7 100644
--- a/modules/gdscript/gdscript_warning.h
+++ b/modules/gdscript/gdscript_warning.h
@@ -69,6 +69,7 @@ public:
ASSERT_ALWAYS_FALSE, // Expression for assert argument is always false.
REDUNDANT_AWAIT, // await is used but expression is synchronous (not a signal nor a coroutine).
EMPTY_FILE, // A script file is empty.
+ SHADOWED_GLOBAL_IDENTIFIER, // A global class or function has the same name as variable.
WARNING_MAX,
};
diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.gd b/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.gd
new file mode 100644
index 0000000000..3c64be571b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.gd
@@ -0,0 +1,2 @@
+func test():
+ var abs = "This variable has the same name as the built-in function."
diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.out b/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.out
new file mode 100644
index 0000000000..f2b29e5bad
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.out
@@ -0,0 +1,9 @@
+GDTEST_OK
+>> WARNING
+>> Line: 2
+>> SHADOWED_GLOBAL_IDENTIFIER
+>> The local variable 'abs' has the same name as a built-in function.
+>> WARNING
+>> Line: 2
+>> UNUSED_VARIABLE
+>> The local variable 'abs' is declared but never used in the block. If this is intended, prefix it with an underscore: '_abs'