diff options
Diffstat (limited to 'modules/gdscript')
68 files changed, 865 insertions, 426 deletions
diff --git a/modules/gdscript/SCsub b/modules/gdscript/SCsub index 5c8cbdf869..c6121ec7fe 100644 --- a/modules/gdscript/SCsub +++ b/modules/gdscript/SCsub @@ -21,3 +21,5 @@ if env["tools"]:  if env["tests"]:      env_gdscript.Append(CPPDEFINES=["TESTS_ENABLED"])      env_gdscript.add_source_files(env.modules_sources, "./tests/*.cpp") + +SConscript("editor_templates/SCsub") diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 9c8adb4cf1..33f4198ac1 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -4,10 +4,10 @@  		Built-in GDScript functions.  	</brief_description>  	<description> -		List of core built-in GDScript functions. Math functions and other utilities. Everything else is provided by objects. (Keywords: builtin, built in, global functions.) +		A list of GDScript-specific utility functions accessed in any script. +		For the list of the global functions and constants see [@GlobalScope].  	</description>  	<tutorials> -		<link title="Random number generation">$DOCS_URL/tutorials/math/random_number_generation.html</link>  	</tutorials>  	<methods>  		<method name="Color8"> diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index 6529154e5c..5cc295bbab 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -60,7 +60,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l  	bool in_keyword = false;  	bool in_word = false;  	bool in_function_name = false; +	bool in_lambda = false;  	bool in_variable_declaration = false; +	bool in_signal_declaration = false;  	bool in_function_args = false;  	bool in_member_variable = false;  	bool in_node_path = false; @@ -105,12 +107,15 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l  		/* color regions */  		if (is_a_symbol || in_region != -1) {  			int from = j; -			for (; from < line_length; from++) { -				if (str[from] == '\\') { -					from++; -					continue; + +			if (in_region == -1) { +				for (; from < line_length; from++) { +					if (str[from] == '\\') { +						from++; +						continue; +					} +					break;  				} -				break;  			}  			if (from != line_length) { @@ -142,6 +147,12 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l  						/* check if it's the whole line */  						if (end_key_length == 0 || color_regions[c].line_only || from + end_key_length > line_length) { +							if (from + end_key_length > line_length) { +								// If it's key length and there is a '\', dont skip to highlight esc chars. +								if (str.find("\\", from) >= 0) { +									break; +								} +							}  							prev_color = color_regions[in_region].color;  							highlighter_info["color"] = color_regions[c].color;  							color_map[j] = highlighter_info; @@ -161,13 +172,25 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l  				/* if we are in one find the end key */  				if (in_region != -1) { +					Color region_color = color_regions[in_region].color; +					if (in_node_path && (color_regions[in_region].start_key == "\"" || color_regions[in_region].start_key == "\'")) { +						region_color = node_path_color; +					} + +					prev_color = region_color; +					highlighter_info["color"] = region_color; +					color_map[j] = highlighter_info; +  					/* search the line */  					int region_end_index = -1;  					int end_key_length = color_regions[in_region].end_key.length();  					const char32_t *end_key = color_regions[in_region].end_key.get_data();  					for (; from < line_length; from++) {  						if (line_length - from < end_key_length) { -							break; +							// Don't break if '\' to highlight esc chars. +							if (str.find("\\", from) < 0) { +								break; +							}  						}  						if (!is_symbol(str[from])) { @@ -175,7 +198,16 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l  						}  						if (str[from] == '\\') { +							Dictionary escape_char_highlighter_info; +							escape_char_highlighter_info["color"] = symbol_color; +							color_map[from] = escape_char_highlighter_info; +  							from++; + +							Dictionary region_continue_highlighter_info; +							prev_color = region_color; +							region_continue_highlighter_info["color"] = region_color; +							color_map[from + 1] = region_continue_highlighter_info;  							continue;  						} @@ -192,10 +224,6 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l  						}  					} -					prev_color = color_regions[in_region].color; -					highlighter_info["color"] = color_regions[in_region].color; -					color_map[j] = highlighter_info; -  					previous_type = REGION;  					previous_text = "";  					previous_column = j; @@ -289,20 +317,36 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l  		}  		if (!in_function_name && in_word && !in_keyword) { -			int k = j; -			while (k < str.length() && !is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') { -				k++; -			} +			if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::SIGNAL)) { +				in_signal_declaration = true; +			} else { +				int k = j; +				while (k < str.length() && !is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') { +					k++; +				} -			// check for space between name and bracket -			while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) { -				k++; -			} +				// check for space between name and bracket +				while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) { +					k++; +				} -			if (str[k] == '(') { -				in_function_name = true; -			} else if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::VAR)) { -				in_variable_declaration = true; +				if (str[k] == '(') { +					in_function_name = true; +				} else if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::VAR)) { +					in_variable_declaration = true; +				} + +				// Check for lambda. +				if (in_function_name && previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) { +					k = j - 1; +					while (k > 0 && (str[k] == '\t' || str[k] == ' ')) { +						k--; +					} + +					if (str[k] == ':') { +						in_lambda = true; +					} +				}  			}  		} @@ -348,7 +392,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l  			}  			in_variable_declaration = false; +			in_signal_declaration = false;  			in_function_name = false; +			in_lambda = false;  			in_member_variable = false;  		} @@ -376,10 +422,14 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l  		} else if (in_member_variable) {  			next_type = MEMBER;  			color = member_color; +		} else if (in_signal_declaration) { +			next_type = SIGNAL; + +			color = member_color;  		} else if (in_function_name) {  			next_type = FUNCTION; -			if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) { +			if (!in_lambda && previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) {  				color = function_definition_color;  			} else {  				color = function_color; @@ -413,7 +463,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l  					previous_column = j;  					// ignore if just whitespace -					if (text != "") { +					if (!text.is_empty()) {  						previous_text = text;  					}  				} @@ -509,7 +559,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {  	for (const String &comment : comments) {  		String beg = comment.get_slice(" ", 0);  		String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String(); -		add_color_region(beg, end, comment_color, end == ""); +		add_color_region(beg, end, comment_color, end.is_empty());  	}  	/* Strings */ @@ -519,7 +569,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {  	for (const String &string : strings) {  		String beg = string.get_slice(" ", 0);  		String end = string.get_slice_count(" ") > 1 ? string.get_slice(" ", 1) : String(); -		add_color_region(beg, end, string_color, end == ""); +		add_color_region(beg, end, string_color, end.is_empty());  	}  	const Ref<Script> script = _get_edited_resource(); diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h index 07f21b34ae..1ae0d72896 100644 --- a/modules/gdscript/editor/gdscript_highlighter.h +++ b/modules/gdscript/editor/gdscript_highlighter.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -58,6 +58,7 @@ private:  		SYMBOL,  		NUMBER,  		FUNCTION, +		SIGNAL,  		KEYWORD,  		MEMBER,  		IDENTIFIER, diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp index 9d0d91162c..a8f4483cf4 100644 --- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp +++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.h b/modules/gdscript/editor/gdscript_translation_parser_plugin.h index caa80fc24c..e7b40aa367 100644 --- a/modules/gdscript/editor/gdscript_translation_parser_plugin.h +++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/editor_templates/CharacterBody2D/basic_movement.gd b/modules/gdscript/editor_templates/CharacterBody2D/basic_movement.gd new file mode 100644 index 0000000000..0824d894c5 --- /dev/null +++ b/modules/gdscript/editor_templates/CharacterBody2D/basic_movement.gd @@ -0,0 +1,29 @@ +# meta-description: Classic movement for gravity games (platformer, ...) + +extends _BASE_ + +const SPEED: float = 300.0 +const JUMP_FORCE: float = -400.0 + +# Get the gravity from the project settings to be synced with RigidDynamicBody nodes. +var gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity") + + +func _physics_process(delta: float) -> void: +	# Add the gravity. +	if not is_on_floor(): +		motion_velocity.y += gravity * delta + +	# Handle Jump. +	if Input.is_action_just_pressed("ui_accept") and is_on_floor(): +		motion_velocity.y = JUMP_FORCE + +	# Get the input direction and handle the movement/deceleration. +	# As good practice, you should replace UI actions with custom gameplay actions. +	var direction := Input.get_axis("ui_left", "ui_right") +	if direction: +		motion_velocity.x = direction * SPEED +	else: +		motion_velocity.x = move_toward(motion_velocity.x, 0, SPEED) + +	move_and_slide() diff --git a/modules/gdscript/editor_templates/CharacterBody3D/basic_movement.gd b/modules/gdscript/editor_templates/CharacterBody3D/basic_movement.gd new file mode 100644 index 0000000000..ce6d67ae84 --- /dev/null +++ b/modules/gdscript/editor_templates/CharacterBody3D/basic_movement.gd @@ -0,0 +1,32 @@ +# meta-description: Classic movement for gravity games (FPS, TPS, ...) + +extends _BASE_ + +const SPEED: float = 5.0 +const JUMP_FORCE: float = 4.5 + +# Get the gravity from the project settings to be synced with RigidDynamicBody nodes. +var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity") + + +func _physics_process(delta: float) -> void: +	# Add the gravity. +	if not is_on_floor(): +		motion_velocity.y -= gravity * delta + +	# Handle Jump. +	if Input.is_action_just_pressed("ui_accept") and is_on_floor(): +		motion_velocity.y = JUMP_FORCE + +	# Get the input direction and handle the movement/deceleration. +	# As good practice, you should replace UI actions with custom gameplay actions. +	var input_dir := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down") +	var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized() +	if direction: +		motion_velocity.x = direction.x * SPEED +		motion_velocity.z = direction.z * SPEED +	else: +		motion_velocity.x = move_toward(motion_velocity.x, 0, SPEED) +		motion_velocity.z = move_toward(motion_velocity.z, 0, SPEED) + +	move_and_slide() diff --git a/modules/gdscript/editor_templates/EditorPlugin/plugin.gd b/modules/gdscript/editor_templates/EditorPlugin/plugin.gd new file mode 100644 index 0000000000..8614bb8b17 --- /dev/null +++ b/modules/gdscript/editor_templates/EditorPlugin/plugin.gd @@ -0,0 +1,11 @@ +# meta-description: Basic plugin template +@tool +extends EditorPlugin + +func _enter_tree() -> void: +    # Initialization of the plugin goes here. +    pass + +func _exit_tree() -> void: +    # Clean-up of the plugin goes here. +    pass diff --git a/modules/gdscript/editor_templates/EditorScript/basic_editor_script.gd b/modules/gdscript/editor_templates/EditorScript/basic_editor_script.gd new file mode 100644 index 0000000000..fdb174c7ed --- /dev/null +++ b/modules/gdscript/editor_templates/EditorScript/basic_editor_script.gd @@ -0,0 +1,7 @@ +# meta-description: Basic editor script template +@tool +extends EditorScript + +func _run() -> void: +    # Called when the script is executed (using File -> Run in Script Editor). +    pass diff --git a/modules/gdscript/editor_templates/Node/default.gd b/modules/gdscript/editor_templates/Node/default.gd new file mode 100644 index 0000000000..ee5c0b99cc --- /dev/null +++ b/modules/gdscript/editor_templates/Node/default.gd @@ -0,0 +1,11 @@ +# meta-description: Base template for Node with default Godot cycle methods + +extends _BASE_ + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: +	pass # Replace with function body. + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta: float) -> void: +	pass diff --git a/modules/gdscript/editor_templates/Object/empty.gd b/modules/gdscript/editor_templates/Object/empty.gd new file mode 100644 index 0000000000..387786b0a4 --- /dev/null +++ b/modules/gdscript/editor_templates/Object/empty.gd @@ -0,0 +1,3 @@ +# meta-description: Empty template suitable for all Objects + +extends _BASE_ diff --git a/modules/gdscript/editor_templates/SCsub b/modules/gdscript/editor_templates/SCsub new file mode 100644 index 0000000000..2266ef2d01 --- /dev/null +++ b/modules/gdscript/editor_templates/SCsub @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +Import("env") + +import editor.template_builders as build_template_gd + +env["BUILDERS"]["MakeGDTemplateBuilder"] = Builder( +    action=env.Run(build_template_gd.make_templates, "Generating GDScript templates header."), +    suffix=".h", +    src_suffix=".gd", +) + +# Template files +templates_sources = Glob("*/*.gd") + +env.Alias("editor_template_gd", [env.MakeGDTemplateBuilder("templates.gen.h", templates_sources)]) diff --git a/modules/gdscript/editor_templates/VisualShaderNodeCustom/basic.gd b/modules/gdscript/editor_templates/VisualShaderNodeCustom/basic.gd new file mode 100644 index 0000000000..27383b878d --- /dev/null +++ b/modules/gdscript/editor_templates/VisualShaderNodeCustom/basic.gd @@ -0,0 +1,41 @@ +# meta-description: Visual shader's node plugin template + +@tool +extends _BASE_ +class_name VisualShaderNode_CLASS_ + +func _get_name() -> String: +	return "_CLASS_" + +func _get_category() -> String: +	return "" + +func _get_description() -> String: +	return "" + +func _get_return_icon_type() -> int: +	return PORT_TYPE_SCALAR + +func _get_input_port_count() -> int: +	return 0 + +func _get_input_port_name(port: int) -> String: +	return "" + +func _get_input_port_type(port: int) -> int: +	return PORT_TYPE_SCALAR + +func _get_output_port_count() -> int: +	return 1 + +func _get_output_port_name(port: int) -> String: +	return "result" + +func _get_output_port_type(port: int) -> int: +	return PORT_TYPE_SCALAR + +func _get_global_code(mode: Shader.Mode) -> String: +	return "" + +func _get_code(input_vars: Array[String], output_vars: Array[String], mode: Shader.Mode, type: VisualShader.Type) -> String: +	return output_vars[0] + " = 0.0;" diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 68da588c3d..84db97625b 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -49,6 +49,10 @@  #include "tests/gdscript_test_runner.h"  #endif +#ifdef TOOLS_ENABLED +#include "editor/editor_settings.h" +#endif +  ///////////////////////////  GDScriptNativeClass::GDScriptNativeClass(const StringName &p_name) { @@ -389,7 +393,7 @@ bool GDScript::instance_has(const Object *p_this) const {  }  bool GDScript::has_source_code() const { -	return source != ""; +	return !source.is_empty();  }  String GDScript::get_source_code() const { @@ -427,7 +431,7 @@ void GDScript::_add_doc(const DocData::ClassDoc &p_inner_class) {  	} else {  		for (int i = 0; i < docs.size(); i++) {  			if (docs[i].name == p_inner_class.name) { -				docs.remove(i); +				docs.remove_at(i);  				break;  			}  		} @@ -458,7 +462,7 @@ void GDScript::_update_doc() {  	doc.is_script_doc = true;  	if (base.is_valid() && base->is_valid()) { -		if (base->doc.name != String()) { +		if (!base->doc.name.is_empty()) {  			doc.inherits = base->doc.name;  		} else {  			doc.inherits = base->get_instance_base_type(); @@ -472,7 +476,7 @@ void GDScript::_update_doc() {  	doc.tutorials = doc_tutorials;  	for (const KeyValue<String, DocData::EnumDoc> &E : doc_enums) { -		if (E.value.description != "") { +		if (!E.value.description.is_empty()) {  			doc.enums[E.key] = E.value.description;  		}  	} @@ -616,11 +620,11 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc  		String basedir = path; -		if (basedir == "") { +		if (basedir.is_empty()) {  			basedir = get_path();  		} -		if (basedir != "") { +		if (!basedir.is_empty()) {  			basedir = basedir.get_base_dir();  		} @@ -642,7 +646,7 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc  					path = c->extends_path;  					if (path.is_relative_path()) {  						String base = get_path(); -						if (base == "" || base.is_relative_path()) { +						if (base.is_empty() || base.is_relative_path()) {  							ERR_PRINT(("Could not resolve relative path for parent class: " + path).utf8().get_data());  						} else {  							path = base.get_base_dir().plus_file(path); @@ -656,7 +660,7 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc  					}  				} -				if (path != "") { +				if (!path.is_empty()) {  					if (path != get_path()) {  						Ref<GDScript> bf = ResourceLoader::load(path); @@ -809,18 +813,24 @@ Error GDScript::reload(bool p_keep_state) {  	String basedir = path; -	if (basedir == "") { +	if (basedir.is_empty()) {  		basedir = get_path();  	} -	if (basedir != "") { +	if (!basedir.is_empty()) {  		basedir = basedir.get_base_dir();  	} -	if (source.find("%BASE%") != -1) { -		//loading a template, don't parse +// Loading a template, don't parse. +#ifdef TOOLS_ENABLED +	if (basedir.begins_with(EditorSettings::get_singleton()->get_project_script_templates_dir())) {  		return OK;  	} +#else +	if (source.find("_BASE_") != -1) { +		return OK; +	} +#endif  	{  		String source_path = path; @@ -1122,7 +1132,7 @@ String GDScript::_get_gdscript_reference_class_name(const GDScript *p_gdscript)  	String class_name;  	while (p_gdscript) { -		if (class_name == "") { +		if (class_name.is_empty()) {  			class_name = p_gdscript->get_script_class_name();  		} else {  			class_name = p_gdscript->get_script_class_name() + "." + class_name; @@ -1433,7 +1443,7 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const  					pinfo.type = Variant::Type(d["type"].operator int());  					ERR_CONTINUE(pinfo.type < 0 || pinfo.type >= Variant::VARIANT_MAX);  					pinfo.name = d["name"]; -					ERR_CONTINUE(pinfo.name == ""); +					ERR_CONTINUE(pinfo.name.is_empty());  					if (d.has("hint")) {  						pinfo.hint = PropertyHint(d["hint"].operator int());  					} @@ -2131,7 +2141,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b  									const GDScriptParser::ClassNode *inner_class = subclass->members[i].m_class;  									if (inner_class->identifier->name == extend_classes[0]) { -										extend_classes.remove(0); +										extend_classes.remove_at(0);  										found = true;  										subclass = inner_class;  										break; @@ -2196,7 +2206,6 @@ GDScriptLanguage::GDScriptLanguage() {  	GLOBAL_DEF("debug/gdscript/warnings/enable", true);  	GLOBAL_DEF("debug/gdscript/warnings/treat_warnings_as_errors", false);  	GLOBAL_DEF("debug/gdscript/warnings/exclude_addons", true); -	GLOBAL_DEF("debug/gdscript/completion/autocomplete_setters_and_getters", false);  	for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {  		String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower();  		bool default_enabled = !warning.begins_with("unsafe_"); diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index ade4f247c9..2b43e6d21b 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -396,7 +396,7 @@ public:  		_debug_call_stack_pos--;  	} -	virtual Vector<StackInfo> debug_get_current_stack_info() { +	virtual Vector<StackInfo> debug_get_current_stack_info() override {  		if (Thread::get_main_id() != Thread::get_caller_id()) {  			return Vector<StackInfo>();  		} @@ -430,77 +430,76 @@ public:  	_FORCE_INLINE_ static GDScriptLanguage *get_singleton() { return singleton; } -	virtual String get_name() const; +	virtual String get_name() const override;  	/* LANGUAGE FUNCTIONS */ -	virtual void init(); -	virtual String get_type() const; -	virtual String get_extension() const; -	virtual Error execute_file(const String &p_path); -	virtual void finish(); +	virtual void init() override; +	virtual String get_type() const override; +	virtual String get_extension() const override; +	virtual Error execute_file(const String &p_path) override; +	virtual void finish() override;  	/* EDITOR FUNCTIONS */ -	virtual void get_reserved_words(List<String> *p_words) const; -	virtual bool is_control_flow_keyword(String p_keywords) const; -	virtual void get_comment_delimiters(List<String> *p_delimiters) const; -	virtual void get_string_delimiters(List<String> *p_delimiters) const; -	virtual String _get_processed_template(const String &p_template, const String &p_base_class_name) const; -	virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; -	virtual bool is_using_templates(); -	virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script); -	virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; -	virtual Script *create_script() const; -	virtual bool has_named_classes() const; -	virtual bool supports_builtin_mode() const; -	virtual bool supports_documentation() const; -	virtual bool can_inherit_from_file() const { return true; } -	virtual int find_function(const String &p_function, const String &p_code) const; -	virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const; -	virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint); +	virtual void get_reserved_words(List<String> *p_words) const override; +	virtual bool is_control_flow_keyword(String p_keywords) const override; +	virtual void get_comment_delimiters(List<String> *p_delimiters) const override; +	virtual void get_string_delimiters(List<String> *p_delimiters) const override; +	virtual bool is_using_templates() override; +	virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override; +	virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override; +	virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const override; +	virtual Script *create_script() const override; +	virtual bool has_named_classes() const override; +	virtual bool supports_builtin_mode() const override; +	virtual bool supports_documentation() const override; +	virtual bool can_inherit_from_file() const override { return true; } +	virtual int find_function(const String &p_function, const String &p_code) const override; +	virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const override; +	virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) override;  #ifdef TOOLS_ENABLED -	virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result); +	virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) override;  #endif  	virtual String _get_indentation() const; -	virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const; -	virtual void add_global_constant(const StringName &p_variable, const Variant &p_value); -	virtual void add_named_global_constant(const StringName &p_name, const Variant &p_value); -	virtual void remove_named_global_constant(const StringName &p_name); +	virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const override; +	virtual void add_global_constant(const StringName &p_variable, const Variant &p_value) override; +	virtual void add_named_global_constant(const StringName &p_name, const Variant &p_value) override; +	virtual void remove_named_global_constant(const StringName &p_name) override;  	/* DEBUGGER FUNCTIONS */ -	virtual String debug_get_error() const; -	virtual int debug_get_stack_level_count() const; -	virtual int debug_get_stack_level_line(int p_level) const; -	virtual String debug_get_stack_level_function(int p_level) const; -	virtual String debug_get_stack_level_source(int p_level) const; -	virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); -	virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); -	virtual ScriptInstance *debug_get_stack_level_instance(int p_level); -	virtual void debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); -	virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1); +	virtual String debug_get_error() const override; +	virtual int debug_get_stack_level_count() const override; +	virtual int debug_get_stack_level_line(int p_level) const override; +	virtual String debug_get_stack_level_function(int p_level) const override; +	virtual String debug_get_stack_level_source(int p_level) const override; +	virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override; +	virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override; +	virtual ScriptInstance *debug_get_stack_level_instance(int p_level) override; +	virtual void debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override; +	virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1) override; -	virtual void reload_all_scripts(); -	virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload); +	virtual void reload_all_scripts() override; +	virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) override; -	virtual void frame(); +	virtual void frame() override; -	virtual void get_public_functions(List<MethodInfo> *p_functions) const; -	virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const; +	virtual void get_public_functions(List<MethodInfo> *p_functions) const override; +	virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const override; -	virtual void profiling_start(); -	virtual void profiling_stop(); +	virtual void profiling_start() override; +	virtual void profiling_stop() override; -	virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max); -	virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max); +	virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) override; +	virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) override;  	/* LOADER FUNCTIONS */ -	virtual void get_recognized_extensions(List<String> *p_extensions) const; +	virtual void get_recognized_extensions(List<String> *p_extensions) const override;  	/* GLOBAL CLASSES */ -	virtual bool handles_global_class_type(const String &p_type) const; -	virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const; +	virtual bool handles_global_class_type(const String &p_type) const override; +	virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const override;  	void add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass);  	Ref<GDScript> get_orphan_subclass(const String &p_qualified_name); diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index cd8fd361c5..0d295c3a51 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -484,7 +484,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type  			result = parser->head->get_datatype();  		} else {  			Ref<GDScriptParserRef> ref = get_parser_for(ScriptServer::get_global_class_path(first)); -			if (ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) { +			if (!ref.is_valid() || ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) {  				push_error(vformat(R"(Could not parse global class "%s" from "%s".)", first, ScriptServer::get_global_class_path(first)), p_type);  				return GDScriptParser::DataType();  			} @@ -881,12 +881,23 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {  	for (int i = 0; i < p_class->members.size(); i++) {  		GDScriptParser::ClassNode::Member member = p_class->members[i];  		if (member.type == GDScriptParser::ClassNode::Member::FUNCTION) { -			resolve_function_body(member.function); -  			// Apply annotations.  			for (GDScriptParser::AnnotationNode *&E : member.function->annotations) {  				E->apply(parser, member.function);  			} + +#ifdef DEBUG_ENABLED +			Set<uint32_t> previously_ignored = parser->ignored_warning_codes; +			for (uint32_t ignored_warning : member.function->ignored_warnings) { +				parser->ignored_warning_codes.insert(ignored_warning); +			} +#endif // DEBUG_ENABLED + +			resolve_function_body(member.function); + +#ifdef DEBUG_ENABLED +			parser->ignored_warning_codes = previously_ignored; +#endif // DEBUG_ENABLED  		} else if (member.type == GDScriptParser::ClassNode::Member::VARIABLE && member.variable->property != GDScriptParser::VariableNode::PROP_NONE) {  			if (member.variable->property == GDScriptParser::VariableNode::PROP_INLINE) {  				if (member.variable->getter != nullptr) { @@ -925,6 +936,10 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {  		GDScriptParser::ClassNode::Member member = p_class->members[i];  		if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) {  #ifdef DEBUG_ENABLED +			Set<uint32_t> previously_ignored = parser->ignored_warning_codes; +			for (uint32_t ignored_warning : member.function->ignored_warnings) { +				parser->ignored_warning_codes.insert(ignored_warning); +			}  			if (member.variable->usages == 0 && String(member.variable->identifier->name).begins_with("_")) {  				parser->push_warning(member.variable->identifier, GDScriptWarning::UNUSED_PRIVATE_CLASS_VARIABLE, member.variable->identifier->name);  			} @@ -992,6 +1007,9 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {  						push_error(vformat(R"(Getter with type "%s" cannot be used along with setter of type "%s".)", getter_function->datatype.to_string(), setter_function->parameters[0]->datatype.to_string()), member.variable);  					}  				} +#ifdef DEBUG_ENABLED +				parser->ignored_warning_codes = previously_ignored; +#endif // DEBUG_ENABLED  			}  		}  	} @@ -1186,7 +1204,23 @@ void GDScriptAnalyzer::decide_suite_type(GDScriptParser::Node *p_suite, GDScript  void GDScriptAnalyzer::resolve_suite(GDScriptParser::SuiteNode *p_suite) {  	for (int i = 0; i < p_suite->statements.size(); i++) {  		GDScriptParser::Node *stmt = p_suite->statements[i]; +		for (GDScriptParser::AnnotationNode *&annotation : stmt->annotations) { +			annotation->apply(parser, stmt); +		} + +#ifdef DEBUG_ENABLED +		Set<uint32_t> previously_ignored = parser->ignored_warning_codes; +		for (uint32_t ignored_warning : stmt->ignored_warnings) { +			parser->ignored_warning_codes.insert(ignored_warning); +		} +#endif // DEBUG_ENABLED +  		resolve_node(stmt); + +#ifdef DEBUG_ENABLED +		parser->ignored_warning_codes = previously_ignored; +#endif // DEBUG_ENABLED +  		decide_suite_type(p_suite, stmt);  	}  } @@ -1834,13 +1868,14 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig  		push_error("Cannot assign a new value to a constant.", p_assignment->assignee);  	} -	if (!assignee_type.is_variant() && assigned_value_type.is_hard_type()) { -		bool compatible = true; -		GDScriptParser::DataType op_type = assigned_value_type; -		if (p_assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) { -			op_type = get_operation_type(p_assignment->variant_op, assignee_type, assigned_value_type, compatible, p_assignment->assigned_value); -		} +	bool compatible = true; +	GDScriptParser::DataType op_type = assigned_value_type; +	if (p_assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) { +		op_type = get_operation_type(p_assignment->variant_op, assignee_type, assigned_value_type, compatible, p_assignment->assigned_value); +	} +	p_assignment->set_datatype(op_type); +	if (!assignee_type.is_variant() && assigned_value_type.is_hard_type()) {  		if (compatible) {  			compatible = is_type_compatible(assignee_type, op_type, true);  			if (!compatible) { @@ -1865,7 +1900,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig  	if (assignee_type.has_no_type() || assigned_value_type.is_variant()) {  		mark_node_unsafe(p_assignment); -		if (assignee_type.is_hard_type()) { +		if (assignee_type.is_hard_type() && !assignee_type.is_variant()) {  			p_assignment->use_conversion_assign = true;  		}  	} @@ -2606,7 +2641,8 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod  				GDScriptParser::DataType result;  				result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;  				result.kind = GDScriptParser::DataType::ENUM_VALUE; -				result.builtin_type = base.builtin_type; +				result.is_constant = true; +				result.builtin_type = Variant::INT;  				result.native_type = base.native_type;  				result.enum_type = name;  				p_identifier->set_datatype(result); @@ -3001,7 +3037,7 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {  			// TODO: Don't load if validating: use completion cache.  			p_preload->resource = ResourceLoader::load(p_preload->resolved_path);  			if (p_preload->resource.is_null()) { -				push_error(vformat(R"(Could not p_preload resource file "%s".)", p_preload->resolved_path), p_preload->path); +				push_error(vformat(R"(Could not preload resource file "%s".)", p_preload->resolved_path), p_preload->path);  			}  		}  	} @@ -3691,9 +3727,27 @@ bool GDScriptAnalyzer::validate_call_arg(const List<GDScriptParser::DataType> &p  bool GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, const String &p_context) {  	const StringName &name = p_local->name;  	GDScriptParser::DataType base = parser->current_class->get_datatype(); -  	GDScriptParser::ClassNode *base_class = base.class_type; +	{ +		List<MethodInfo> gdscript_funcs; +		GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs); + +		for (MethodInfo &info : gdscript_funcs) { +			if (info.name == name) { +				parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in function"); +				return true; +			} +		} +		if (Variant::has_utility_function(name)) { +			parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in function"); +			return true; +		} else if (ClassDB::class_exists(name)) { +			parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "global class"); +			return true; +		} +	} +  	while (base_class != nullptr) {  		if (base_class->has_member(name)) {  			parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE, p_context, p_local->name, base_class->get_member(name).get_type_name(), itos(base_class->get_member(name).get_line())); @@ -3735,6 +3789,7 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator  	// Unary version.  	GDScriptParser::DataType nil_type;  	nil_type.builtin_type = Variant::NIL; +	nil_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;  	return get_operation_type(p_operation, p_a, nil_type, r_valid, p_source);  } @@ -3744,20 +3799,31 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator  	Variant::Type a_type = p_a.builtin_type;  	Variant::Type b_type = p_b.builtin_type; -  	Variant::ValidatedOperatorEvaluator op_eval = Variant::get_validated_operator_evaluator(p_operation, a_type, b_type); -	if (op_eval == nullptr) { +	bool hard_operation = p_a.is_hard_type() && p_b.is_hard_type(); +	bool validated = op_eval != nullptr; + +	if (hard_operation && !validated) {  		r_valid = false;  		return result; +	} else if (hard_operation && validated) { +		r_valid = true; +		result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; +		result.kind = GDScriptParser::DataType::BUILTIN; +		result.builtin_type = Variant::get_operator_return_type(p_operation, a_type, b_type); +	} else if (!hard_operation && !validated) { +		r_valid = true; +		result.type_source = GDScriptParser::DataType::UNDETECTED; +		result.kind = GDScriptParser::DataType::VARIANT; +		result.builtin_type = Variant::NIL; +	} else if (!hard_operation && validated) { +		r_valid = true; +		result.type_source = GDScriptParser::DataType::INFERRED; +		result.kind = GDScriptParser::DataType::BUILTIN; +		result.builtin_type = Variant::get_operator_return_type(p_operation, a_type, b_type);  	} -	r_valid = true; -	result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; - -	result.kind = GDScriptParser::DataType::BUILTIN; -	result.builtin_type = Variant::get_operator_return_type(p_operation, a_type, b_type); -  	return result;  } @@ -3938,7 +4004,9 @@ Ref<GDScriptParserRef> GDScriptAnalyzer::get_parser_for(const String &p_path) {  	} else {  		Error err = OK;  		ref = GDScriptCache::get_parser(p_path, GDScriptParserRef::EMPTY, err, parser->script_path); -		depended_parsers[p_path] = ref; +		if (ref.is_valid()) { +			depended_parsers[p_path] = ref; +		}  	}  	return ref; diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h index ce4525190b..4cee5cb44a 100644 --- a/modules/gdscript/gdscript_analyzer.h +++ b/modules/gdscript/gdscript_analyzer.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 6a7e4278d2..82aa14795e 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -688,6 +688,7 @@ void GDScriptByteCodeGenerator::write_ternary_false_expr(const Address &p_expr)  void GDScriptByteCodeGenerator::write_end_ternary() {  	patch_jump(ternary_jump_skip_pos.back()->get());  	ternary_jump_skip_pos.pop_back(); +	ternary_result.pop_back();  }  void GDScriptByteCodeGenerator::write_set(const Address &p_target, const Address &p_index, const Address &p_source) { diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h index fbbf5802fd..db15dc55ef 100644 --- a/modules/gdscript/gdscript_byte_codegen.h +++ b/modules/gdscript/gdscript_byte_codegen.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index bb0d9e9e9b..4ac5a4a60e 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -117,7 +117,7 @@ void GDScriptCache::remove_script(const String &p_path) {  Ref<GDScriptParserRef> GDScriptCache::get_parser(const String &p_path, GDScriptParserRef::Status p_status, Error &r_error, const String &p_owner) {  	MutexLock lock(singleton->lock);  	Ref<GDScriptParserRef> ref; -	if (p_owner != String()) { +	if (!p_owner.is_empty()) {  		singleton->dependencies[p_owner].insert(p_path);  	}  	if (singleton->parser_map.has(p_path)) { @@ -163,7 +163,7 @@ String GDScriptCache::get_source_code(const String &p_path) {  Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, const String &p_owner) {  	MutexLock lock(singleton->lock); -	if (p_owner != String()) { +	if (!p_owner.is_empty()) {  		singleton->dependencies[p_owner].insert(p_path);  	}  	if (singleton->full_gdscript_cache.has(p_path)) { @@ -186,7 +186,7 @@ Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, const Stri  Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_error, const String &p_owner) {  	MutexLock lock(singleton->lock); -	if (p_owner != String()) { +	if (!p_owner.is_empty()) {  		singleton->dependencies[p_owner].insert(p_path);  	} diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h index 9fb661d031..3ce976ee14 100644 --- a/modules/gdscript/gdscript_cache.h +++ b/modules/gdscript/gdscript_cache.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h index e6ecc92d55..4542dd94ae 100644 --- a/modules/gdscript/gdscript_codegen.h +++ b/modules/gdscript/gdscript_codegen.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index ab0fe5c37d..ca125d3a07 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -65,7 +65,7 @@ bool GDScriptCompiler::_is_class_member_property(GDScript *owner, const StringNa  }  void GDScriptCompiler::_set_error(const String &p_error, const GDScriptParser::Node *p_node) { -	if (error != "") { +	if (!error.is_empty()) {  		return;  	} @@ -882,7 +882,13 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code  #endif  				/* Find chain of sets */ -				StringName assign_property; +				StringName assign_class_member_property; + +				GDScriptCodeGenerator::Address target_member_property; +				bool is_member_property = false; +				bool member_property_has_setter = false; +				bool member_property_is_in_setter = false; +				StringName member_property_setter_function;  				List<const GDScriptParser::SubscriptNode *> chain; @@ -892,11 +898,20 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code  					while (true) {  						chain.push_back(n);  						if (n->base->type != GDScriptParser::Node::SUBSCRIPT) { -							// Check for a built-in property. +							// Check for a property.  							if (n->base->type == GDScriptParser::Node::IDENTIFIER) {  								GDScriptParser::IdentifierNode *identifier = static_cast<GDScriptParser::IdentifierNode *>(n->base); -								if (_is_class_member_property(codegen, identifier->name)) { -									assign_property = identifier->name; +								StringName var_name = identifier->name; +								if (_is_class_member_property(codegen, var_name)) { +									assign_class_member_property = var_name; +								} else if (!codegen.locals.has(var_name) && codegen.script->member_indices.has(var_name)) { +									is_member_property = true; +									member_property_setter_function = codegen.script->member_indices[var_name].setter; +									member_property_has_setter = member_property_setter_function != StringName(); +									member_property_is_in_setter = member_property_has_setter && member_property_setter_function == codegen.function_name; +									target_member_property.mode = GDScriptCodeGenerator::Address::MEMBER; +									target_member_property.address = codegen.script->member_indices[var_name].index; +									target_member_property.type = codegen.script->member_indices[var_name].data_type;  								}  							}  							break; @@ -969,17 +984,19 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code  				// Perform operator if any.  				if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) { +					GDScriptCodeGenerator::Address op_result = codegen.add_temporary(_gdtype_from_datatype(assignment->get_datatype()));  					GDScriptCodeGenerator::Address value = codegen.add_temporary(_gdtype_from_datatype(subscript->get_datatype()));  					if (subscript->is_attribute) {  						gen->write_get_named(value, name, prev_base);  					} else {  						gen->write_get(value, key, prev_base);  					} -					gen->write_binary_operator(value, assignment->variant_op, value, assigned); +					gen->write_binary_operator(op_result, assignment->variant_op, value, assigned); +					gen->pop_temporary();  					if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {  						gen->pop_temporary();  					} -					assigned = value; +					assigned = op_result;  				}  				// Perform assignment. @@ -1013,10 +1030,20 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code  					assigned = info.base;  				} -				// If this is a local member, also assign to it. +				// If this is a class member property, also assign to it.  				// This allow things like: position.x += 2.0 -				if (assign_property != StringName()) { -					gen->write_set_member(assigned, assign_property); +				if (assign_class_member_property != StringName()) { +					gen->write_set_member(assigned, assign_class_member_property); +				} +				// Same as above but for members +				if (is_member_property) { +					if (member_property_has_setter && !member_property_is_in_setter) { +						Vector<GDScriptCodeGenerator::Address> args; +						args.push_back(assigned); +						gen->write_call(GDScriptCodeGenerator::Address(), GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), member_property_setter_function, args); +					} else { +						gen->write_assign(target_member_property, assigned); +					}  				}  				if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) { @@ -1035,8 +1062,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code  				StringName name = static_cast<GDScriptParser::IdentifierNode *>(assignment->assignee)->name;  				if (has_operation) { -					GDScriptCodeGenerator::Address op_result = codegen.add_temporary(); -					GDScriptCodeGenerator::Address member = codegen.add_temporary(); +					GDScriptCodeGenerator::Address op_result = codegen.add_temporary(_gdtype_from_datatype(assignment->get_datatype())); +					GDScriptCodeGenerator::Address member = codegen.add_temporary(_gdtype_from_datatype(assignment->assignee->get_datatype()));  					gen->write_get_member(member, name);  					gen->write_binary_operator(op_result, assignment->variant_op, member, assigned_value);  					gen->pop_temporary(); // Pop member temp. @@ -1053,29 +1080,26 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code  				}  			} else {  				// Regular assignment. -				GDScriptCodeGenerator::Address target; - +				ERR_FAIL_COND_V_MSG(assignment->assignee->type != GDScriptParser::Node::IDENTIFIER, GDScriptCodeGenerator::Address(), "Expected the assignee to be an identifier here."); +				GDScriptCodeGenerator::Address member; +				bool is_member = false;  				bool has_setter = false;  				bool is_in_setter = false;  				StringName setter_function; -				if (assignment->assignee->type == GDScriptParser::Node::IDENTIFIER) { -					StringName var_name = static_cast<const GDScriptParser::IdentifierNode *>(assignment->assignee)->name; -					if (!codegen.locals.has(var_name) && codegen.script->member_indices.has(var_name)) { -						setter_function = codegen.script->member_indices[var_name].setter; -						if (setter_function != StringName()) { -							has_setter = true; -							is_in_setter = setter_function == codegen.function_name; -							target.mode = GDScriptCodeGenerator::Address::MEMBER; -							target.address = codegen.script->member_indices[var_name].index; -						} -					} +				StringName var_name = static_cast<const GDScriptParser::IdentifierNode *>(assignment->assignee)->name; +				if (!codegen.locals.has(var_name) && codegen.script->member_indices.has(var_name)) { +					is_member = true; +					setter_function = codegen.script->member_indices[var_name].setter; +					has_setter = setter_function != StringName(); +					is_in_setter = has_setter && setter_function == codegen.function_name; +					member.mode = GDScriptCodeGenerator::Address::MEMBER; +					member.address = codegen.script->member_indices[var_name].index; +					member.type = codegen.script->member_indices[var_name].data_type;  				} -				if (has_setter) { -					if (!is_in_setter) { -						// Store stack slot for the temp value. -						target = codegen.add_temporary(_gdtype_from_datatype(assignment->assignee->get_datatype())); -					} +				GDScriptCodeGenerator::Address target; +				if (is_member) { +					target = member; // _parse_expression could call its getter, but we want to know the actual address  				} else {  					target = _parse_expression(codegen, r_error, assignment->assignee);  					if (r_error) { @@ -1092,7 +1116,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code  				bool has_operation = assignment->operation != GDScriptParser::AssignmentNode::OP_NONE;  				if (has_operation) {  					// Perform operation. -					GDScriptCodeGenerator::Address op_result = codegen.add_temporary(); +					GDScriptCodeGenerator::Address op_result = codegen.add_temporary(_gdtype_from_datatype(assignment->get_datatype()));  					GDScriptCodeGenerator::Address og_value = _parse_expression(codegen, r_error, assignment->assignee);  					gen->write_binary_operator(op_result, assignment->variant_op, og_value, assigned_value);  					to_assign = op_result; @@ -1995,7 +2019,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_  			codegen.generator->start_parameters();  			for (int i = p_func->parameters.size() - optional_parameters; i < p_func->parameters.size(); i++) {  				const GDScriptParser::ParameterNode *parameter = p_func->parameters[i]; -				GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, r_error, parameter->default_value, true); +				GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, r_error, parameter->default_value);  				if (r_error) {  					memdelete(codegen.generator);  					return nullptr; @@ -2020,7 +2044,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_  	if (EngineDebugger::is_active()) {  		String signature;  		// Path. -		if (p_script->get_path() != String()) { +		if (!p_script->get_path().is_empty()) {  			signature += p_script->get_path();  		}  		// Location. @@ -2069,7 +2093,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_  	if (p_func) {  		// if no return statement -> return type is void not unresolved Variant  		if (p_func->body->has_return) { -			gd_function->return_type = _gdtype_from_datatype(p_func->get_datatype()); +			gd_function->return_type = _gdtype_from_datatype(p_func->get_datatype(), p_script);  		} else {  			gd_function->return_type = GDScriptDataType();  			gd_function->return_type.has_type = true; @@ -2158,7 +2182,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar  	p_script->tool = parser->is_tool();  	p_script->name = p_class->identifier ? p_class->identifier->name : ""; -	if (p_script->name != "") { +	if (!p_script->name.is_empty()) {  		if (ClassDB::class_exists(p_script->name) && ClassDB::is_class_exposed(p_script->name)) {  			_set_error("The class '" + p_script->name + "' shadows a native class", p_class);  			return ERR_ALREADY_EXISTS; @@ -2287,7 +2311,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar  				p_script->constants.insert(name, constant->initializer->reduced_value);  #ifdef TOOLS_ENABLED  				p_script->member_lines[name] = constant->start_line; -				if (constant->doc_description != String()) { +				if (!constant->doc_description.is_empty()) {  					p_script->doc_constants[name] = constant->doc_description;  				}  #endif diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h index 7d5bee93ac..8d71437344 100644 --- a/modules/gdscript/gdscript_compiler.h +++ b/modules/gdscript/gdscript_compiler.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp index 9287df2ea0..cc0be94a9e 100644 --- a/modules/gdscript/gdscript_disassembler.cpp +++ b/modules/gdscript/gdscript_disassembler.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 71d2699c2e..d10e120410 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -33,6 +33,7 @@  #include "core/config/engine.h"  #include "core/core_constants.h"  #include "core/io/file_access.h" +#include "editor_templates/templates.gen.h"  #include "gdscript_analyzer.h"  #include "gdscript_compiler.h"  #include "gdscript_parser.h" @@ -55,68 +56,44 @@ void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {  	p_delimiters->push_back("\"\"\" \"\"\"");  } -String GDScriptLanguage::_get_processed_template(const String &p_template, const String &p_base_class_name) const { -	String processed_template = p_template; +bool GDScriptLanguage::is_using_templates() { +	return true; +} +Ref<Script> GDScriptLanguage::make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const { +	Ref<GDScript> script; +	script.instantiate(); +	String processed_template = p_template;  #ifdef TOOLS_ENABLED -	if (EDITOR_DEF("text_editor/completion/add_type_hints", false)) { -		processed_template = processed_template.replace("%INT_TYPE%", ": int"); -		processed_template = processed_template.replace("%STRING_TYPE%", ": String"); -		processed_template = processed_template.replace("%FLOAT_TYPE%", ": float"); -		processed_template = processed_template.replace("%VOID_RETURN%", " -> void"); -	} else { -		processed_template = processed_template.replace("%INT_TYPE%", ""); -		processed_template = processed_template.replace("%STRING_TYPE%", ""); -		processed_template = processed_template.replace("%FLOAT_TYPE%", ""); -		processed_template = processed_template.replace("%VOID_RETURN%", ""); +	if (!EDITOR_DEF("text_editor/completion/add_type_hints", false)) { +		processed_template = processed_template.replace(": int", "") +									 .replace(": String", "") +									 .replace(": float", "") +									 .replace(":=", "=") +									 .replace(" -> void", "");  	}  #else -	processed_template = processed_template.replace("%INT_TYPE%", ""); -	processed_template = processed_template.replace("%STRING_TYPE%", ""); -	processed_template = processed_template.replace("%FLOAT_TYPE%", ""); -	processed_template = processed_template.replace("%VOID_RETURN%", ""); +	processed_template = processed_template.replace(": int", "") +								 .replace(": String", "") +								 .replace(": float", "") +								 .replace(" -> void", "");  #endif -	processed_template = processed_template.replace("%BASE%", p_base_class_name); -	processed_template = processed_template.replace("%TS%", _get_indentation()); - -	return processed_template; -} - -Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { -	String _template = "extends %BASE%\n" -					   "\n" -					   "\n" -					   "# Declare member variables here. Examples:\n" -					   "# var a%INT_TYPE% = 2\n" -					   "# var b%STRING_TYPE% = \"text\"\n" -					   "\n" -					   "\n" -					   "# Called when the node enters the scene tree for the first time.\n" -					   "func _ready()%VOID_RETURN%:\n" -					   "%TS%pass # Replace with function body.\n" -					   "\n" -					   "\n" -					   "# Called every frame. 'delta' is the elapsed time since the previous frame.\n" -					   "#func _process(delta%FLOAT_TYPE%)%VOID_RETURN%:\n" -					   "#%TS%pass\n"; - -	_template = _get_processed_template(_template, p_base_class_name); - -	Ref<GDScript> script; -	script.instantiate(); -	script->set_source_code(_template); - +	processed_template = processed_template.replace("_BASE_", p_base_class_name) +								 .replace("_CLASS_", p_class_name) +								 .replace("_TS_", _get_indentation()); +	script->set_source_code(processed_template);  	return script;  } -bool GDScriptLanguage::is_using_templates() { -	return true; -} - -void GDScriptLanguage::make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) { -	String _template = _get_processed_template(p_script->get_source_code(), p_base_class_name); -	p_script->set_source_code(_template); +Vector<ScriptLanguage::ScriptTemplate> GDScriptLanguage::get_built_in_templates(StringName p_object) { +	Vector<ScriptLanguage::ScriptTemplate> templates; +	for (int i = 0; i < TEMPLATES_ARRAY_SIZE; i++) { +		if (TEMPLATES[i].inherit == p_object) { +			templates.append(TEMPLATES[i]); +		} +	} +	return templates;  }  static void get_function_names_recursively(const GDScriptParser::ClassNode *p_class, const String &p_prefix, Map<int, String> &r_funcs) { @@ -236,7 +213,7 @@ Script *GDScriptLanguage::create_script() const {  /* DEBUGGER FUNCTIONS */  bool GDScriptLanguage::debug_break_parse(const String &p_file, int p_line, const String &p_error) { -	//break because of parse error +	// break because of parse error  	if (EngineDebugger::is_active() && Thread::get_caller_id() == Thread::get_main_id()) {  		_debug_parse_err_line = p_line; @@ -603,12 +580,50 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio  		if (par->default_value) {  			String def_val = "<unknown>"; -			if (par->default_value->type == GDScriptParser::Node::LITERAL) { -				const GDScriptParser::LiteralNode *literal = static_cast<const GDScriptParser::LiteralNode *>(par->default_value); -				def_val = literal->value.get_construct_string(); -			} else if (par->default_value->type == GDScriptParser::Node::IDENTIFIER) { -				const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(par->default_value); -				def_val = id->name.operator String(); +			switch (par->default_value->type) { +				case GDScriptParser::Node::LITERAL: { +					const GDScriptParser::LiteralNode *literal = static_cast<const GDScriptParser::LiteralNode *>(par->default_value); +					def_val = literal->value.get_construct_string(); +				} break; +				case GDScriptParser::Node::IDENTIFIER: { +					const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(par->default_value); +					def_val = id->name.operator String(); +				} break; +				case GDScriptParser::Node::CALL: { +					const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(par->default_value); +					if (call->is_constant && call->reduced) { +						def_val = call->function_name.operator String() + call->reduced_value.operator String(); +					} +				} break; +				case GDScriptParser::Node::ARRAY: { +					const GDScriptParser::ArrayNode *arr = static_cast<const GDScriptParser::ArrayNode *>(par->default_value); +					if (arr->is_constant && arr->reduced) { +						def_val = arr->reduced_value.operator String(); +					} +				} break; +				case GDScriptParser::Node::DICTIONARY: { +					const GDScriptParser::DictionaryNode *dict = static_cast<const GDScriptParser::DictionaryNode *>(par->default_value); +					if (dict->is_constant && dict->reduced) { +						def_val = dict->reduced_value.operator String(); +					} +				} break; +				case GDScriptParser::Node::SUBSCRIPT: { +					const GDScriptParser::SubscriptNode *sub = static_cast<const GDScriptParser::SubscriptNode *>(par->default_value); +					if (sub->is_constant) { +						if (sub->datatype.kind == GDScriptParser::DataType::ENUM_VALUE) { +							def_val = sub->get_datatype().to_string(); +						} else if (sub->reduced) { +							const Variant::Type vt = sub->reduced_value.get_type(); +							if (vt == Variant::Type::NIL || vt == Variant::Type::FLOAT || vt == Variant::Type::INT || vt == Variant::Type::STRING || vt == Variant::Type::STRING_NAME || vt == Variant::Type::BOOL || vt == Variant::Type::NODE_PATH) { +								def_val = sub->reduced_value.operator String(); +							} else { +								def_val = sub->get_datatype().to_string() + sub->reduced_value.operator String(); +							} +						} +					} +				} break; +				default: +					break;  			}  			arghint += " = " + def_val;  		} @@ -669,6 +684,11 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a  			ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CLASS);  			r_result.insert(option.display, option);  		} +	} else if (p_annotation->name == "@warning_ignore") { +		for (int warning_code = 0; warning_code < GDScriptWarning::WARNING_MAX; warning_code++) { +			ScriptCodeCompletionOption warning(GDScriptWarning::get_name_from_code((GDScriptWarning::Code)warning_code).to_lower(), ScriptCodeCompletionOption::KIND_PLAIN_TEXT); +			r_result.insert(warning.display, warning); +		}  	}  } @@ -946,8 +966,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base  				if (!_static || Engine::get_singleton()->has_singleton(type)) {  					List<MethodInfo> methods; -					bool is_autocompleting_getters = GLOBAL_GET("debug/gdscript/completion/autocomplete_setters_and_getters").booleanize(); -					ClassDB::get_method_list(type, &methods, false, !is_autocompleting_getters); +					ClassDB::get_method_list(type, &methods, false, true);  					for (const MethodInfo &E : methods) {  						if (E.name.begins_with("_")) {  							continue; @@ -1182,6 +1201,10 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex  static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, const GDScriptParser::ExpressionNode *p_expression, GDScriptCompletionIdentifier &r_type) {  	bool found = false; +	if (p_expression == nullptr) { +		return false; +	} +  	if (p_expression->is_constant) {  		// Already has a value, so just use that.  		r_type = _type_from_variant(p_expression->reduced_value); @@ -1365,7 +1388,7 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,  									String arg1 = args[0];  									if (arg1.begins_with("/root/")) {  										String which = arg1.get_slice("/", 2); -										if (which != "") { +										if (!which.is_empty()) {  											// Try singletons first  											if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(which)) {  												r_type = _type_from_variant(GDScriptLanguage::get_singleton()->get_named_globals_map()[which]); @@ -1383,8 +1406,8 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,  														}  														if (!script.ends_with(".gd")) { -															//not a script, try find the script anyway, -															//may have some success +															// not a script, try find the script anyway, +															// may have some success  															script = script.get_basename() + ".gd";  														} @@ -2753,7 +2776,7 @@ void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_t  		}  		String st = l.substr(tc, l.length()).strip_edges(); -		if (st == "" || st.begins_with("#")) { +		if (st.is_empty() || st.begins_with("#")) {  			continue; //ignore!  		} @@ -2770,7 +2793,7 @@ void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_t  			}  			if (indent_stack.size() && indent_stack.back()->get() != tc) { -				indent_stack.push_back(tc); //this is not right but gets the job done +				indent_stack.push_back(tc); // this is not right but gets the job done  			}  		} @@ -2810,6 +2833,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co  						r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;  						r_result.location = base_type.class_type->get_member(p_symbol).get_line();  						r_result.class_path = base_type.script_path; +						r_result.script = GDScriptCache::get_shallow_script(r_result.class_path);  						return OK;  					}  					base_type = base_type.class_type->base_type; diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index a3f0c7dfef..9424de9d22 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -248,7 +248,7 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) {  	// If the return value is a GDScriptFunctionState reference,  	// then the function did await again after resuming. -	if (ret.is_ref()) { +	if (ret.is_ref_counted()) {  		GDScriptFunctionState *gdfs = Object::cast_to<GDScriptFunctionState>(ret);  		if (gdfs && gdfs->function == function) {  			completed = false; diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index 9d076a8e4c..db663ca48f 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -192,7 +192,7 @@ public:  	GDScriptDataType() = default; -	GDScriptDataType &operator=(const GDScriptDataType &p_other) { +	void operator=(const GDScriptDataType &p_other) {  		kind = p_other.kind;  		has_type = p_other.has_type;  		builtin_type = p_other.builtin_type; @@ -203,7 +203,6 @@ public:  		if (p_other.has_container_element_type()) {  			set_container_element_type(p_other.get_container_element_type());  		} -		return *this;  	}  	GDScriptDataType(const GDScriptDataType &p_other) { diff --git a/modules/gdscript/gdscript_lambda_callable.cpp b/modules/gdscript/gdscript_lambda_callable.cpp index 0bc109b6e1..baf93e1098 100644 --- a/modules/gdscript/gdscript_lambda_callable.cpp +++ b/modules/gdscript/gdscript_lambda_callable.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/gdscript_lambda_callable.h b/modules/gdscript/gdscript_lambda_callable.h index 336778d549..f6a54a1a2f 100644 --- a/modules/gdscript/gdscript_lambda_callable.h +++ b/modules/gdscript/gdscript_lambda_callable.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 69fa793059..05253caa8f 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -39,6 +39,7 @@  #ifdef DEBUG_ENABLED  #include "core/os/os.h"  #include "core/string/string_builder.h" +#include "gdscript_warning.h"  #endif // DEBUG_ENABLED  #ifdef TOOLS_ENABLED @@ -132,9 +133,9 @@ GDScriptParser::GDScriptParser() {  	register_annotation(MethodInfo("@export_flags_3d_render"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_RENDER, Variant::INT>);  	register_annotation(MethodInfo("@export_flags_3d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_PHYSICS, Variant::INT>);  	register_annotation(MethodInfo("@export_flags_3d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_NAVIGATION, Variant::INT>); +	register_annotation(MethodInfo("@warning_ignore", { Variant::STRING, "warning" }), AnnotationInfo::CLASS | AnnotationInfo::VARIABLE | AnnotationInfo::SIGNAL | AnnotationInfo::CONSTANT | AnnotationInfo::FUNCTION | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, 0, true);  	// Networking.  	register_annotation(MethodInfo("@rpc", { Variant::STRING, "mode" }, { Variant::STRING, "sync" }, { Variant::STRING, "transfer_mode" }, { Variant::INT, "transfer_channel" }), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<Multiplayer::RPC_MODE_AUTHORITY>, 4, true); -	// TODO: Warning annotations.  }  GDScriptParser::~GDScriptParser() { @@ -196,6 +197,10 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_  		return;  	} +	if (ignored_warning_codes.has(p_code)) { +		return; +	} +  	String warn_name = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)p_code).to_lower();  	if (ignored_warnings.has(warn_name)) {  		return; @@ -701,24 +706,21 @@ void GDScriptParser::parse_extends() {  template <class T>  void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)(), AnnotationInfo::TargetKind p_target, const String &p_member_kind) {  	advance(); -	T *member = (this->*p_parse_function)(); -	if (member == nullptr) { -		return; -	} +  #ifdef TOOLS_ENABLED -	int doc_comment_line = member->start_line - 1; +	int doc_comment_line = previous.start_line - 1;  #endif // TOOLS_ENABLED  	// Consume annotations. +	List<AnnotationNode *> annotations;  	while (!annotation_stack.is_empty()) {  		AnnotationNode *last_annotation = annotation_stack.back()->get();  		if (last_annotation->applies_to(p_target)) { -			member->annotations.push_front(last_annotation); +			annotations.push_front(last_annotation);  			annotation_stack.pop_back();  		} else {  			push_error(vformat(R"(Annotation "%s" cannot be applied to a %s.)", last_annotation->name, p_member_kind));  			clear_unused_annotations(); -			return;  		}  #ifdef TOOLS_ENABLED  		if (last_annotation->start_line == doc_comment_line) { @@ -727,6 +729,16 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)()  #endif // TOOLS_ENABLED  	} +	T *member = (this->*p_parse_function)(); +	if (member == nullptr) { +		return; +	} + +	// Apply annotations. +	for (AnnotationNode *&annotation : annotations) { +		member->annotations.push_back(annotation); +	} +  #ifdef TOOLS_ENABLED  	// Consume doc comments.  	class_doc_line = MIN(class_doc_line, doc_comment_line - 1); @@ -741,20 +753,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);  			} @@ -803,6 +817,8 @@ void GDScriptParser::parse_class_body(bool p_is_multiline) {  				class_end = true;  				break;  			default: +				// Display a completion with identifiers. +				make_completion_context(COMPLETION_IDENTIFIER, nullptr);  				push_error(vformat(R"(Unexpected "%s" in class body.)", current.get_name()));  				advance();  				break; @@ -825,27 +841,9 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_proper  		return nullptr;  	} -	GDScriptParser::IdentifierNode *identifier = parse_identifier(); - -	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; -		} -	} -	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; -	} -  	VariableNode *variable = alloc_node<VariableNode>(); -	variable->identifier = identifier; -	variable->export_info.name = identifier->name; +	variable->identifier = parse_identifier(); +	variable->export_info.name = variable->identifier->name;  	if (match(GDScriptTokenizer::Token::COLON)) {  		if (check(GDScriptTokenizer::Token::NEWLINE)) { @@ -1098,26 +1096,8 @@ GDScriptParser::ParameterNode *GDScriptParser::parse_parameter() {  		return nullptr;  	} -	GDScriptParser::IdentifierNode *identifier = parse_identifier(); - -	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; -		} -	} -	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; -	} 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; -	} -  	ParameterNode *parameter = alloc_node<ParameterNode>(); -	parameter->identifier = identifier; +	parameter->identifier = parse_identifier();  	if (match(GDScriptTokenizer::Token::COLON)) {  		if (check((GDScriptTokenizer::Token::EQUAL))) { @@ -1195,8 +1175,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 +1187,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; @@ -1541,6 +1521,8 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {  	bool unreachable = current_suite->has_return && !current_suite->has_unreachable_code;  #endif +	bool is_annotation = false; +  	switch (current.type) {  		case GDScriptTokenizer::Token::PASS:  			advance(); @@ -1610,6 +1592,7 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {  			break;  		case GDScriptTokenizer::Token::ANNOTATION: {  			advance(); +			is_annotation = true;  			AnnotationNode *annotation = parse_annotation(AnnotationInfo::STATEMENT);  			if (annotation != nullptr) {  				annotation_stack.push_back(annotation); @@ -1650,6 +1633,18 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {  		}  	} +	// Apply annotations to statement. +	while (!is_annotation && result != nullptr && !annotation_stack.is_empty()) { +		AnnotationNode *last_annotation = annotation_stack.back()->get(); +		if (last_annotation->applies_to(AnnotationInfo::STATEMENT)) { +			result->annotations.push_front(last_annotation); +			annotation_stack.pop_back(); +		} else { +			push_error(vformat(R"(Annotation "%s" cannot be applied to a statement.)", last_annotation->name)); +			clear_unused_annotations(); +		} +	} +  #ifdef DEBUG_ENABLED  	if (unreachable && result != nullptr) {  		current_suite->has_unreachable_code = true; @@ -3106,7 +3101,7 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String &  	if (!comments.has(p_line)) {  		return;  	} -	ERR_FAIL_COND(p_brief != "" || p_desc != "" || p_tutorials.size() != 0); +	ERR_FAIL_COND(!p_brief.is_empty() || !p_desc.is_empty() || p_tutorials.size() != 0);  	int line = p_line;  	bool in_codeblock = false; @@ -3138,7 +3133,7 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String &  		String striped_line = doc_line.strip_edges();  		// Set the read mode. -		if (striped_line.begins_with("@desc:") && p_desc == "") { +		if (striped_line.begins_with("@desc:") && p_desc.is_empty()) {  			mode = DESC;  			striped_line = striped_line.trim_prefix("@desc:");  			in_codeblock = _in_codeblock(doc_line, in_codeblock); @@ -3419,8 +3414,8 @@ bool GDScriptParser::validate_annotation_arguments(AnnotationNode *p_annotation)  					Variant::construct(parameter.type, r, &(name), 1, error);  					p_annotation->resolved_arguments.push_back(r);  					if (error.error != Callable::CallError::CALL_OK) { -						push_error(vformat(R"(Expected %s as argument %d of annotation "%s").)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name)); -						p_annotation->resolved_arguments.remove(p_annotation->resolved_arguments.size() - 1); +						push_error(vformat(R"(Expected %s as argument %d of annotation "%s".)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name)); +						p_annotation->resolved_arguments.remove_at(p_annotation->resolved_arguments.size() - 1);  						return false;  					}  					break; @@ -3428,13 +3423,13 @@ bool GDScriptParser::validate_annotation_arguments(AnnotationNode *p_annotation)  				[[fallthrough]];  			default: {  				if (argument->type != Node::LITERAL) { -					push_error(vformat(R"(Expected %s as argument %d of annotation "%s").)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name)); +					push_error(vformat(R"(Expected %s as argument %d of annotation "%s".)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));  					return false;  				}  				Variant value = static_cast<LiteralNode *>(argument)->value;  				if (!Variant::can_convert_strict(value.get_type(), parameter.type)) { -					push_error(vformat(R"(Expected %s as argument %d of annotation "%s").)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name)); +					push_error(vformat(R"(Expected %s as argument %d of annotation "%s".)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));  					return false;  				}  				Callable::CallError error; @@ -3443,8 +3438,8 @@ bool GDScriptParser::validate_annotation_arguments(AnnotationNode *p_annotation)  				Variant::construct(parameter.type, r, &(args), 1, error);  				p_annotation->resolved_arguments.push_back(r);  				if (error.error != Callable::CallError::CALL_OK) { -					push_error(vformat(R"(Expected %s as argument %d of annotation "%s").)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name)); -					p_annotation->resolved_arguments.remove(p_annotation->resolved_arguments.size() - 1); +					push_error(vformat(R"(Expected %s as argument %d of annotation "%s".)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name)); +					p_annotation->resolved_arguments.remove_at(p_annotation->resolved_arguments.size() - 1);  					return false;  				}  				break; @@ -3505,7 +3500,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node  	variable->export_info.hint_string = hint_string; -	// This is called after tne analyzer is done finding the type, so this should be set here. +	// This is called after the analyzer is done finding the type, so this should be set here.  	DataType export_type = variable->get_datatype();  	if (p_annotation->name == "@export") { @@ -3547,12 +3542,12 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node  				variable->export_info.hint = PROPERTY_HINT_ENUM;  				String enum_hint_string; -				for (const Map<StringName, int>::Element *E = export_type.enum_values.front(); E; E = E->next()) { -					enum_hint_string += E->key().operator String().capitalize().xml_escape(); +				for (OrderedHashMap<StringName, int>::Element E = export_type.enum_values.front(); E; E = E.next()) { +					enum_hint_string += E.key().operator String().capitalize().xml_escape();  					enum_hint_string += ":"; -					enum_hint_string += String::num_int64(E->get()).xml_escape(); +					enum_hint_string += String::num_int64(E.value()).xml_escape(); -					if (E->next()) { +					if (E.next()) {  						enum_hint_string += ",";  					}  				} @@ -3589,7 +3584,24 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node  }  bool GDScriptParser::warning_annotations(const AnnotationNode *p_annotation, Node *p_node) { -	ERR_FAIL_V_MSG(false, "Not implemented."); +#ifdef DEBUG_ENABLED +	bool has_error = false; +	for (const Variant &warning_name : p_annotation->resolved_arguments) { +		GDScriptWarning::Code warning = GDScriptWarning::get_code_from_name(String(warning_name).to_upper()); +		if (warning == GDScriptWarning::WARNING_MAX) { +			push_error(vformat(R"(Invalid warning name: "%s".)", warning_name), p_annotation); +			has_error = true; +		} else { +			p_node->ignored_warnings.push_back(warning); +		} +	} + +	return !has_error; + +#else // ! DEBUG_ENABLED +	// Only available in debug builds. +	return true; +#endif // DEBUG_ENABLED  }  template <Multiplayer::RPCMode t_mode> @@ -4227,7 +4239,11 @@ void GDScriptParser::TreePrinter::print_get_node(GetNodeNode *p_get_node) {  }  void GDScriptParser::TreePrinter::print_identifier(IdentifierNode *p_identifier) { -	push_text(p_identifier->name); +	if (p_identifier != nullptr) { +		push_text(p_identifier->name); +	} else { +		push_text("<invalid identifier>"); +	}  }  void GDScriptParser::TreePrinter::print_if(IfNode *p_if, bool p_is_elif) { diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index af9b973ada..e4311d2d5e 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -133,7 +133,7 @@ public:  		ClassNode *class_type = nullptr;  		MethodInfo method_info; // For callable/signals. -		Map<StringName, int> enum_values; // For enums. +		OrderedHashMap<StringName, int> enum_values; // For enums.  		_FORCE_INLINE_ bool is_set() const { return kind != UNRESOLVED; }  		_FORCE_INLINE_ bool has_no_type() const { return type_source == UNDETECTED; } @@ -203,7 +203,7 @@ public:  			return !(this->operator==(p_other));  		} -		DataType &operator=(const DataType &p_other) { +		void operator=(const DataType &p_other) {  			kind = p_other.kind;  			type_source = p_other.type_source;  			is_constant = p_other.is_constant; @@ -221,7 +221,6 @@ public:  			if (p_other.has_container_element_type()) {  				set_container_element_type(p_other.get_container_element_type());  			} -			return *this;  		}  		DataType() = default; @@ -298,6 +297,7 @@ public:  		int leftmost_column = 0, rightmost_column = 0;  		Node *next = nullptr;  		List<AnnotationNode *> annotations; +		Vector<uint32_t> ignored_warnings;  		DataType datatype; @@ -1205,6 +1205,7 @@ private:  #ifdef DEBUG_ENABLED  	List<GDScriptWarning> warnings;  	Set<String> ignored_warnings; +	Set<uint32_t> ignored_warning_codes;  	Set<int> unsafe_lines;  #endif diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index 3725fb58f5..05ea061798 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h index b4ee11fd9a..abd090e381 100644 --- a/modules/gdscript/gdscript_tokenizer.h +++ b/modules/gdscript/gdscript_tokenizer.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp index e997d3a51e..16b2dac343 100644 --- a/modules/gdscript/gdscript_utility_functions.cpp +++ b/modules/gdscript/gdscript_utility_functions.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/gdscript_utility_functions.h b/modules/gdscript/gdscript_utility_functions.h index c6d3718844..9ca7cf33d8 100644 --- a/modules/gdscript/gdscript_utility_functions.h +++ b/modules/gdscript/gdscript_utility_functions.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 6dd8c3e0dd..95122714f9 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -488,7 +488,12 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a  				memnew_placement(&stack[i + 3], Variant(*p_args[i]));  				continue;  			} - +			// If types already match, don't call Variant::construct(). Constructors of some types +			// (e.g. packed arrays) do copies, whereas they pass by reference when inside a Variant. +			if (argument_types[i].is_type(*p_args[i], false)) { +				memnew_placement(&stack[i + 3], Variant(*p_args[i])); +				continue; +			}  			if (!argument_types[i].is_type(*p_args[i], true)) {  				r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;  				r_err.argument = i; @@ -755,7 +760,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a  #ifdef DEBUG_ENABLED  				if (!valid) {  					String v = index->operator String(); -					if (v != "") { +					if (!v.is_empty()) {  						v = "'" + v + "'";  					} else {  						v = "of type '" + _get_var_type(index) + "'"; @@ -785,7 +790,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a  #ifdef DEBUG_ENABLED  				if (!valid) {  					String v = index->operator String(); -					if (v != "") { +					if (!v.is_empty()) {  						v = "'" + v + "'";  					} else {  						v = "of type '" + _get_var_type(index) + "'"; @@ -817,7 +822,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a  #ifdef DEBUG_ENABLED  				if (oob) {  					String v = index->operator String(); -					if (v != "") { +					if (!v.is_empty()) {  						v = "'" + v + "'";  					} else {  						v = "of type '" + _get_var_type(index) + "'"; @@ -848,7 +853,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a  #ifdef DEBUG_ENABLED  				if (!valid) {  					String v = index->operator String(); -					if (v != "") { +					if (!v.is_empty()) {  						v = "'" + v + "'";  					} else {  						v = "of type '" + _get_var_type(index) + "'"; @@ -884,7 +889,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a  #ifdef DEBUG_ENABLED  				if (!valid) {  					String v = key->operator String(); -					if (v != "") { +					if (!v.is_empty()) {  						v = "'" + v + "'";  					} else {  						v = "of type '" + _get_var_type(key) + "'"; @@ -917,7 +922,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a  #ifdef DEBUG_ENABLED  				if (oob) {  					String v = index->operator String(); -					if (v != "") { +					if (!v.is_empty()) {  						v = "'" + v + "'";  					} else {  						v = "of type '" + _get_var_type(index) + "'"; @@ -1527,7 +1532,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a  						}  					} else if (methodstr == "free") {  						if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) { -							if (base->is_ref()) { +							if (base->is_ref_counted()) {  								err_text = "Attempted to free a reference.";  								OPCODE_BREAK;  							} else if (base->get_type() == Variant::OBJECT) { @@ -1615,7 +1620,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a  						}  					} else if (methodstr == "free") {  						if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) { -							if (base->is_ref()) { +							if (base->is_ref_counted()) {  								err_text = "Attempted to free a reference.";  								OPCODE_BREAK;  							} else if (base->get_type() == Variant::OBJECT) { @@ -3295,20 +3300,20 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a  		//error  		// function, file, line, error, explanation  		String err_file; -		if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && p_instance->script->path != "") { +		if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && !p_instance->script->path.is_empty()) {  			err_file = p_instance->script->path;  		} else if (script) {  			err_file = script->path;  		} -		if (err_file == "") { +		if (err_file.is_empty()) {  			err_file = "<built-in>";  		}  		String err_func = name; -		if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && p_instance->script->name != "") { +		if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && !p_instance->script->name.is_empty()) {  			err_func = p_instance->script->name + "." + err_func;  		}  		int err_line = line; -		if (err_text == "") { +		if (err_text.is_empty()) {  			err_text = "Internal script error! Opcode: " + itos(last_opcode) + " (please report).";  		} diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp index 7a483a16ba..73536f5f8e 100644 --- a/modules/gdscript/gdscript_warning.cpp +++ b/modules/gdscript/gdscript_warning.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -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."); @@ -208,7 +213,7 @@ GDScriptWarning::Code GDScriptWarning::get_code_from_name(const String &p_name)  		}  	} -	ERR_FAIL_V_MSG(WARNING_MAX, "Invalid GDScript warning name: " + p_name); +	return WARNING_MAX;  }  #endif // DEBUG_ENABLED diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h index 8de46b08c1..112b40781a 100644 --- a/modules/gdscript/gdscript_warning.h +++ b/modules/gdscript/gdscript_warning.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -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/icons/GDScriptInternal.svg b/modules/gdscript/icons/GDScriptInternal.svg new file mode 100644 index 0000000000..fcabaafbd0 --- /dev/null +++ b/modules/gdscript/icons/GDScriptInternal.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1-.56445 2.2578c-.2364329.0758517-.4668872.16921-.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941c-.1119126.2211335-.2072287.4502818-.28516.68555l-2.2539.5625v2l2.2578.56445c.075942.2357685.1692993.465568.2793.6875l-1.1934 1.9902 1.4141 1.4141 1.9941-1.1953c.2211335.111913.4502818.207229.68555.28516l.5625 2.2539h2l.56445-2.2578c.2357685-.07594.465568-.169299.6875-.2793l1.9902 1.1934 1.4141-1.4141-1.1953-1.9941c.111913-.221133.207229-.4502818.28516-.68555l2.2539-.5625v-2l-2.2578-.56445c-.075942-.2357685-.169299-.4655679-.2793-.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953c-.221133-.1119126-.4502818-.2072287-.68555-.28516l-.5625-2.2539zm1 5c1.1045695 0 2 .8954305 2 2s-.8954305 2-2 2-2-.8954305-2-2 .8954305-2 2-2z" fill="none" stroke="#e0e0e0"/></svg> diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 80f4721e2d..49f5303ae6 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/language_server/gdscript_extend_parser.h b/modules/gdscript/language_server/gdscript_extend_parser.h index 5d7b16765b..99b0bf45d0 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.h +++ b/modules/gdscript/language_server/gdscript_extend_parser.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp index 5cf1e0fc5f..cdddab319d 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.cpp +++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -115,7 +115,7 @@ Error GDScriptLanguageProtocol::LSPeer::send_data() {  		// Response sent  		if (res_sent >= c_res.size() - 1) {  			res_sent = 0; -			res_queue.remove(0); +			res_queue.remove_at(0);  		}  	}  	return OK; diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h index a4a63a23a8..0fed8597f9 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.h +++ b/modules/gdscript/language_server/gdscript_language_protocol.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp index 41a2f9e4ad..33c1c834f1 100644 --- a/modules/gdscript/language_server/gdscript_language_server.cpp +++ b/modules/gdscript/language_server/gdscript_language_server.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/language_server/gdscript_language_server.h b/modules/gdscript/language_server/gdscript_language_server.h index f1413f0133..8de72fc9c9 100644 --- a/modules/gdscript/language_server/gdscript_language_server.h +++ b/modules/gdscript/language_server/gdscript_language_server.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -45,7 +45,7 @@ class GDScriptLanguageServer : public EditorPlugin {  	bool started = false;  	bool use_thread = false;  	String host = "127.0.0.1"; -	int port = 6008; +	int port = 6005;  	static void thread_main(void *p_userdata);  private: diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index 92ce71f395..961295b076 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -428,9 +428,6 @@ GDScriptTextDocument::~GDScriptTextDocument() {  void GDScriptTextDocument::sync_script_content(const String &p_path, const String &p_content) {  	String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(p_path); -	if (!path.begins_with("res://")) { -		return; -	}  	GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content);  	EditorFileSystem::get_singleton()->update_file(path); diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h index 9021c84a3f..eb7b2c0240 100644 --- a/modules/gdscript/language_server/gdscript_text_document.h +++ b/modules/gdscript/language_server/gdscript_text_document.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 932bfb2caa..a944844226 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -54,9 +54,13 @@ void GDScriptWorkspace::_bind_methods() {  }  void GDScriptWorkspace::apply_new_signal(Object *obj, String function, PackedStringArray args) { -	String function_signature = "func " + function;  	Ref<Script> script = obj->get_script(); +	if (script->get_language()->get_name() != "GDScript") { +		return; +	} + +	String function_signature = "func " + function;  	String source = script->get_source_code();  	if (source.find(function_signature) != -1) { diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h index 6f5600b5cf..ce5bba5f00 100644 --- a/modules/gdscript/language_server/gdscript_workspace.h +++ b/modules/gdscript/language_server/gdscript_workspace.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp index b12d1f5f3b..8e503a9df9 100644 --- a/modules/gdscript/language_server/lsp.hpp +++ b/modules/gdscript/language_server/lsp.hpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index c2b1981f31..fcf122f567 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/register_types.h b/modules/gdscript/register_types.h index ce1c03d1d0..baa7dcbbd1 100644 --- a/modules/gdscript/register_types.h +++ b/modules/gdscript/register_types.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index d2e71efee7..47772b8039 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ @@ -267,7 +267,7 @@ bool GDScriptTestRunner::generate_class_index() {  		String base_type;  		String class_name = GDScriptLanguage::get_singleton()->get_global_class_name(test.get_source_file(), &base_type); -		if (class_name == String()) { +		if (class_name.is_empty()) {  			continue;  		}  		ERR_FAIL_COND_V_MSG(ScriptServer::is_global_class(class_name), false, @@ -362,16 +362,16 @@ void GDScriptTest::error_handler(void *p_this, const char *p_function, const cha  	}  	builder.append("\n>> on function: "); -	builder.append(p_function); +	builder.append(String::utf8(p_function));  	builder.append("()\n>> "); -	builder.append(String(p_file).trim_prefix(self->base_dir)); +	builder.append(String::utf8(p_file).trim_prefix(self->base_dir));  	builder.append("\n>> ");  	builder.append(itos(p_line));  	builder.append("\n>> "); -	builder.append(p_error); +	builder.append(String::utf8(p_error));  	if (strlen(p_explanation) > 0) {  		builder.append("\n>> "); -		builder.append(p_explanation); +		builder.append(String::utf8(p_explanation));  	}  	builder.append("\n"); diff --git a/modules/gdscript/tests/gdscript_test_runner.h b/modules/gdscript/tests/gdscript_test_runner.h index 98c57dc97c..1a950c6898 100644 --- a/modules/gdscript/tests/gdscript_test_runner.h +++ b/modules/gdscript/tests/gdscript_test_runner.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/tests/gdscript_test_runner_suite.h b/modules/gdscript/tests/gdscript_test_runner_suite.h index cf4e61f07d..0722fb800e 100644 --- a/modules/gdscript/tests/gdscript_test_runner_suite.h +++ b/modules/gdscript/tests/gdscript_test_runner_suite.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.gd b/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.gd new file mode 100644 index 0000000000..05d9bd6a3d --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.gd @@ -0,0 +1,9 @@ +# https://github.com/godotengine/godot/issues/56702 + +func test(): +	# somewhat obscure feature: referencing parameters in defaults, but only earlier ones! +	ref_default("non-optional") + + +func ref_default(nondefault1, defa=nondefault1, defb=defc, defc=1): +	prints(nondefault1, nondefault2, defa, defb, defc) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.out b/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.out new file mode 100644 index 0000000000..1d5b5bf393 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Identifier "defc" not declared in the current scope. diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd new file mode 100644 index 0000000000..877a4ea221 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd @@ -0,0 +1,15 @@ +@warning_ignore(unused_private_class_variable) +var _unused = 2 + +@warning_ignore(unused_variable) +func test(): +	print("test") +	var unused = 3 + +	@warning_ignore(redundant_await) +	print(await regular_func()) + +	print("done") + +func regular_func(): +	return 0 diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out new file mode 100644 index 0000000000..42292774a0 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out @@ -0,0 +1,4 @@ +GDTEST_OK +test +0 +done diff --git a/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd b/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd index 9ad98b78a8..e4d6a72f90 100644 --- a/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd +++ b/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd @@ -6,7 +6,7 @@ signal a  # No parameters.  signal b() -# With paramters. +# With parameters.  signal c(a, b, c)  # With parameters multiline. 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..c613140eb8 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.out @@ -0,0 +1,9 @@ +GDTEST_OK +>> 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' +>> WARNING +>> Line: 2 +>> SHADOWED_GLOBAL_IDENTIFIER +>> The variable 'abs' has the same name as a built-in function. diff --git a/modules/gdscript/tests/scripts/runtime/features/params_default_values.gd b/modules/gdscript/tests/scripts/runtime/features/params_default_values.gd new file mode 100644 index 0000000000..8156b4ec68 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/params_default_values.gd @@ -0,0 +1,35 @@ +# https://github.com/godotengine/godot/issues/56702 + +func test(): +	const_default() +	func_result_default() +	# calling again will run the initializer again, +	# as the default is not evaluated at time of defining the function (as in python) +	# but every time the function is called (as in C++) +	func_result_default() +	lots_of_defaults("non-optional") +	# somewhat obscure feature: referencing earlier parameters +	ref_default("non-optional", 42) + + +func const_default(param=42): +	print(param) + + +var default_val := 0 + +func get_default(): +	default_val += 1 +	return default_val + + +func func_result_default(param=get_default()): +	print(param) + + +func lots_of_defaults(nondefault, one=1, two=2, three=get_default()): +	prints(nondefault, one, two, three) + + +func ref_default(nondefault1, nondefault2, defa=nondefault1, defb=nondefault2 - 1): +	prints(nondefault1, nondefault2, defa, defb) diff --git a/modules/gdscript/tests/scripts/runtime/features/params_default_values.out b/modules/gdscript/tests/scripts/runtime/features/params_default_values.out new file mode 100644 index 0000000000..50e0885ae5 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/params_default_values.out @@ -0,0 +1,6 @@ +GDTEST_OK +42 +1 +2 +non-optional 1 2 3 +non-optional 42 non-optional 41 diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp index 80eabc1596..4255030b4e 100644 --- a/modules/gdscript/tests/test_gdscript.cpp +++ b/modules/gdscript/tests/test_gdscript.cpp @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/modules/gdscript/tests/test_gdscript.h b/modules/gdscript/tests/test_gdscript.h index c7ee5a2208..b6b1f26203 100644 --- a/modules/gdscript/tests/test_gdscript.h +++ b/modules/gdscript/tests/test_gdscript.h @@ -5,8 +5,8 @@  /*                           GODOT ENGINE                                */  /*                      https://godotengine.org                          */  /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */  |