diff options
Diffstat (limited to 'modules/gdscript')
42 files changed, 808 insertions, 614 deletions
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 58620f2b3e..51b3452a3a 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -11,16 +11,11 @@ </tutorials> <methods> <method name="Color8"> - <return type="Color"> - </return> - <argument index="0" name="r8" type="int"> - </argument> - <argument index="1" name="g8" type="int"> - </argument> - <argument index="2" name="b8" type="int"> - </argument> - <argument index="3" name="a8" type="int" default="255"> - </argument> + <return type="Color" /> + <argument index="0" name="r8" type="int" /> + <argument index="1" name="g8" type="int" /> + <argument index="2" name="b8" type="int" /> + <argument index="3" name="a8" type="int" default="255" /> <description> Returns a color constructed from integer red, green, blue, and alpha channels. Each channel should have 8 bits of information ranging from 0 to 255. [code]r8[/code] red channel @@ -33,12 +28,9 @@ </description> </method> <method name="assert"> - <return type="void"> - </return> - <argument index="0" name="condition" type="bool"> - </argument> - <argument index="1" name="message" type="String" default=""""> - </argument> + <return type="void" /> + <argument index="0" name="condition" type="bool" /> + <argument index="1" name="message" type="String" default="""" /> <description> Asserts that the [code]condition[/code] is [code]true[/code]. If the [code]condition[/code] is [code]false[/code], an error is generated. When running from the editor, the running project will also be paused until you resume it. This can be used as a stronger form of [method @GlobalScope.push_error] for reporting errors to project developers or add-on users. [b]Note:[/b] For performance reasons, the code inside [method assert] is only executed in debug builds or when running the project from the editor. Don't include code that has side effects in an [method assert] call. Otherwise, the project will behave differently when exported in release mode. @@ -54,10 +46,8 @@ </description> </method> <method name="char"> - <return type="String"> - </return> - <argument index="0" name="char" type="int"> - </argument> + <return type="String" /> + <argument index="0" name="char" type="int" /> <description> Returns a character as a String of the given Unicode code point (which is compatible with ASCII code). [codeblock] @@ -68,12 +58,9 @@ </description> </method> <method name="convert"> - <return type="Variant"> - </return> - <argument index="0" name="what" type="Variant"> - </argument> - <argument index="1" name="type" type="int"> - </argument> + <return type="Variant" /> + <argument index="0" name="what" type="Variant" /> + <argument index="1" name="type" type="int" /> <description> Converts from a type to another in the best way possible. The [code]type[/code] parameter uses the [enum Variant.Type] values. [codeblock] @@ -87,17 +74,14 @@ </description> </method> <method name="dict2inst"> - <return type="Object"> - </return> - <argument index="0" name="dictionary" type="Dictionary"> - </argument> + <return type="Object" /> + <argument index="0" name="dictionary" type="Dictionary" /> <description> Converts a dictionary (previously created with [method inst2dict]) back to an instance. Useful for deserializing. </description> </method> <method name="get_stack"> - <return type="Array"> - </return> + <return type="Array" /> <description> Returns an array of dictionaries representing the current call stack. [codeblock] @@ -117,10 +101,8 @@ </description> </method> <method name="inst2dict"> - <return type="Dictionary"> - </return> - <argument index="0" name="instance" type="Object"> - </argument> + <return type="Dictionary" /> + <argument index="0" name="instance" type="Object" /> <description> Returns the passed instance converted to a dictionary (useful for serializing). [codeblock] @@ -138,10 +120,8 @@ </description> </method> <method name="len"> - <return type="int"> - </return> - <argument index="0" name="var" type="Variant"> - </argument> + <return type="int" /> + <argument index="0" name="var" type="Variant" /> <description> Returns length of Variant [code]var[/code]. Length is the character count of String, element count of Array, size of Dictionary, etc. [b]Note:[/b] Generates a fatal error if Variant can not provide a length. @@ -152,10 +132,8 @@ </description> </method> <method name="load"> - <return type="Resource"> - </return> - <argument index="0" name="path" type="String"> - </argument> + <return type="Resource" /> + <argument index="0" name="path" type="String" /> <description> Loads a resource from the filesystem located at [code]path[/code]. The resource is loaded on the method call (unless it's referenced already elsewhere, e.g. in another script or in the scene), which might cause slight delay, especially when loading scenes. To avoid unnecessary delays when loading something multiple times, either store the resource in a variable or use [method preload]. [b]Note:[/b] Resource paths can be obtained by right-clicking on a resource in the FileSystem dock and choosing "Copy Path" or by dragging the file from the FileSystem dock into the script. @@ -168,29 +146,25 @@ </description> </method> <method name="preload"> - <return type="Resource"> - </return> - <argument index="0" name="path" type="String"> - </argument> + <return type="Resource" /> + <argument index="0" name="path" type="String" /> <description> Returns a [Resource] from the filesystem located at [code]path[/code]. The resource is loaded during script parsing, i.e. is loaded with the script and [method preload] effectively acts as a reference to that resource. Note that the method requires a constant path. If you want to load a resource from a dynamic/variable path, use [method load]. [b]Note:[/b] Resource paths can be obtained by right clicking on a resource in the Assets Panel and choosing "Copy Path" or by dragging the file from the FileSystem dock into the script. [codeblock] # Instance a scene. - var diamond = preload("res://diamond.tscn").instance() + var diamond = preload("res://diamond.tscn").instantiate() [/codeblock] </description> </method> <method name="print_debug" qualifiers="vararg"> - <return type="void"> - </return> + <return type="void" /> <description> Like [method @GlobalScope.print], but prints only when used in debug mode. </description> </method> <method name="print_stack"> - <return type="void"> - </return> + <return type="void" /> <description> Prints a stack track at code location, only works when running with debugger turned on. Output in the console would look something like this: @@ -200,8 +174,7 @@ </description> </method> <method name="range" qualifiers="vararg"> - <return type="Array"> - </return> + <return type="Array" /> <description> Returns an array with the given range. Range can be 1 argument N (0 to N-1), two arguments (initial, final-1) or three arguments (initial, final-1, increment). [codeblock] @@ -218,8 +191,7 @@ </description> </method> <method name="str" qualifiers="vararg"> - <return type="String"> - </return> + <return type="String" /> <description> Converts one or more arguments to string in the best way possible. [codeblock] @@ -231,26 +203,26 @@ </description> </method> <method name="type_exists"> - <return type="bool"> - </return> - <argument index="0" name="type" type="StringName"> - </argument> + <return type="bool" /> + <argument index="0" name="type" type="StringName" /> <description> </description> </method> </methods> <constants> <constant name="PI" value="3.14159265358979"> - Constant that represents how many times the diameter of a circle fits around its perimeter. This is equivalent to [code]TAU / 2[/code]. + Constant that represents how many times the diameter of a circle fits around its perimeter. This is equivalent to [code]TAU / 2[/code], or 180 degrees in rotations. </constant> <constant name="TAU" value="6.28318530717959"> - The circle constant, the circumference of the unit circle in radians. + The circle constant, the circumference of the unit circle in radians. This is equivalent to [code]PI * 2[/code], or 360 degrees in rotations. </constant> <constant name="INF" value="inf"> - Positive infinity. For negative infinity, use -INF. + Positive floating-point infinity. This is the result of floating-point division when the divisor is [code]0.0[/code]. For negative infinity, use [code]-INF[/code]. Dividing by [code]-0.0[/code] will result in negative infinity if the numerator is positive, so dividing by [code]0.0[/code] is not the same as dividing by [code]-0.0[/code] (despite [code]0.0 == -0.0[/code] returning [code]true[/code]). + [b]Note:[/b] Numeric infinity is only a concept with floating-point numbers, and has no equivalent for integers. Dividing an integer number by [code]0[/code] will not result in [constant INF] and will result in a run-time error instead. </constant> <constant name="NAN" value="nan"> - "Not a Number", an invalid value. [code]NaN[/code] has special properties, including that it is not equal to itself. It is output by some invalid operations, such as dividing zero by zero. + "Not a Number", an invalid floating-point value. [constant NAN] has special properties, including that it is not equal to itself ([code]NAN == NAN[/code] returns [code]false[/code]). It is output by some invalid operations, such as dividing floating-point [code]0.0[/code] by [code]0.0[/code]. + [b]Note:[/b] "Not a Number" is only a concept with floating-point numbers, and has no equivalent for integers. Dividing an integer [code]0[/code] by [code]0[/code] will not result in [constant NAN] and will result in a run-time error instead. </constant> </constants> </class> diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml index 631a102130..72738f027a 100644 --- a/modules/gdscript/doc_classes/GDScript.xml +++ b/modules/gdscript/doc_classes/GDScript.xml @@ -12,15 +12,13 @@ </tutorials> <methods> <method name="get_as_byte_code" qualifiers="const"> - <return type="PackedByteArray"> - </return> + <return type="PackedByteArray" /> <description> Returns byte code for the script source code. </description> </method> <method name="new" qualifiers="vararg"> - <return type="Variant"> - </return> + <return type="Variant" /> <description> Returns a new instance of the script. For example: diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index b867b03903..8b9bd2659d 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -45,7 +45,7 @@ static bool _is_bin_symbol(char32_t c) { return (c == '0' || c == '1'); } -Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line) { +Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_line) { Dictionary color_map; Type next_type = NONE; @@ -448,30 +448,26 @@ void GDScriptSyntaxHighlighter::_update_cache() { color_regions.clear(); color_region_cache.clear(); - font_color = text_edit->get_theme_color("font_color"); - symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color"); - function_color = EDITOR_GET("text_editor/highlighting/function_color"); - number_color = EDITOR_GET("text_editor/highlighting/number_color"); - member_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); + font_color = text_edit->get_theme_color(SNAME("font_color")); + symbol_color = EDITOR_GET("text_editor/theme/highlighting/symbol_color"); + function_color = EDITOR_GET("text_editor/theme/highlighting/function_color"); + number_color = EDITOR_GET("text_editor/theme/highlighting/number_color"); + member_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color"); /* Engine types. */ - const Color types_color = EDITOR_GET("text_editor/highlighting/engine_type_color"); + const Color types_color = EDITOR_GET("text_editor/theme/highlighting/engine_type_color"); List<StringName> types; ClassDB::get_class_list(&types); - for (List<StringName>::Element *E = types.front(); E; E = E->next()) { - String n = E->get(); - if (n.begins_with("_")) { - n = n.substr(1, n.length()); - } - keywords[n] = types_color; + for (const StringName &E : types) { + keywords[E] = types_color; } /* User types. */ - const Color usertype_color = EDITOR_GET("text_editor/highlighting/user_type_color"); + const Color usertype_color = EDITOR_GET("text_editor/theme/highlighting/user_type_color"); List<StringName> global_classes; ScriptServer::get_global_class_list(&global_classes); - for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) { - keywords[String(E->get())] = usertype_color; + for (const StringName &E : global_classes) { + keywords[String(E)] = usertype_color; } /* Autoloads. */ @@ -486,43 +482,41 @@ void GDScriptSyntaxHighlighter::_update_cache() { const GDScriptLanguage *gdscript = GDScriptLanguage::get_singleton(); /* Core types. */ - const Color basetype_color = EDITOR_GET("text_editor/highlighting/base_type_color"); + const Color basetype_color = EDITOR_GET("text_editor/theme/highlighting/base_type_color"); List<String> core_types; gdscript->get_core_type_words(&core_types); - for (List<String>::Element *E = core_types.front(); E; E = E->next()) { - keywords[E->get()] = basetype_color; + for (const String &E : core_types) { + keywords[E] = basetype_color; } /* Reserved words. */ - const Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); - const Color control_flow_keyword_color = EDITOR_GET("text_editor/highlighting/control_flow_keyword_color"); + const Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color"); + const Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color"); List<String> keyword_list; gdscript->get_reserved_words(&keyword_list); - for (List<String>::Element *E = keyword_list.front(); E; E = E->next()) { - if (gdscript->is_control_flow_keyword(E->get())) { - keywords[E->get()] = control_flow_keyword_color; + for (const String &E : keyword_list) { + if (gdscript->is_control_flow_keyword(E)) { + keywords[E] = control_flow_keyword_color; } else { - keywords[E->get()] = keyword_color; + keywords[E] = keyword_color; } } /* Comments */ - const Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); + const Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color"); List<String> comments; gdscript->get_comment_delimiters(&comments); - for (List<String>::Element *E = comments.front(); E; E = E->next()) { - String comment = E->get(); + 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 == ""); } /* Strings */ - const Color string_color = EDITOR_GET("text_editor/highlighting/string_color"); + const Color string_color = EDITOR_GET("text_editor/theme/highlighting/string_color"); List<String> strings; gdscript->get_string_delimiters(&strings); - for (List<String>::Element *E = strings.front(); E; E = E->next()) { - String string = E->get(); + 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 == ""); @@ -531,14 +525,14 @@ void GDScriptSyntaxHighlighter::_update_cache() { const Ref<Script> script = _get_edited_resource(); if (script.is_valid()) { /* Member types. */ - const Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); + const Color member_variable_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color"); StringName instance_base = script->get_instance_base_type(); if (instance_base != StringName()) { List<PropertyInfo> plist; ClassDB::get_property_list(instance_base, &plist); - for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { - String name = E->get().name; - if (E->get().usage & PROPERTY_USAGE_CATEGORY || E->get().usage & PROPERTY_USAGE_GROUP || E->get().usage & PROPERTY_USAGE_SUBGROUP) { + for (const PropertyInfo &E : plist) { + String name = E.name; + if (E.usage & PROPERTY_USAGE_CATEGORY || E.usage & PROPERTY_USAGE_GROUP || E.usage & PROPERTY_USAGE_SUBGROUP) { continue; } if (name.find("/") != -1) { @@ -549,8 +543,8 @@ void GDScriptSyntaxHighlighter::_update_cache() { List<String> clist; ClassDB::get_integer_constant_list(instance_base, &clist); - for (List<String>::Element *E = clist.front(); E; E = E->next()) { - member_keywords[E->get()] = member_variable_color; + for (const String &E : clist) { + member_keywords[E] = member_variable_color; } } } @@ -568,28 +562,28 @@ void GDScriptSyntaxHighlighter::_update_cache() { annotation_color = Color(0.8, 0.5, 0.25); } - EDITOR_DEF("text_editor/highlighting/gdscript/function_definition_color", function_definition_color); - EDITOR_DEF("text_editor/highlighting/gdscript/node_path_color", node_path_color); - EDITOR_DEF("text_editor/highlighting/gdscript/annotation_color", annotation_color); + EDITOR_DEF("text_editor/theme/highlighting/gdscript/function_definition_color", function_definition_color); + EDITOR_DEF("text_editor/theme/highlighting/gdscript/node_path_color", node_path_color); + EDITOR_DEF("text_editor/theme/highlighting/gdscript/annotation_color", annotation_color); if (text_edit_color_theme == "Default" || godot_2_theme) { EditorSettings::get_singleton()->set_initial_value( - "text_editor/highlighting/gdscript/function_definition_color", + "text_editor/theme/highlighting/gdscript/function_definition_color", function_definition_color, true); EditorSettings::get_singleton()->set_initial_value( - "text_editor/highlighting/gdscript/node_path_color", + "text_editor/theme/highlighting/gdscript/node_path_color", node_path_color, true); EditorSettings::get_singleton()->set_initial_value( - "text_editor/highlighting/gdscript/annotation_color", + "text_editor/theme/highlighting/gdscript/annotation_color", annotation_color, true); } - function_definition_color = EDITOR_GET("text_editor/highlighting/gdscript/function_definition_color"); - node_path_color = EDITOR_GET("text_editor/highlighting/gdscript/node_path_color"); - annotation_color = EDITOR_GET("text_editor/highlighting/gdscript/annotation_color"); - type_color = EDITOR_GET("text_editor/highlighting/base_type_color"); + function_definition_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/function_definition_color"); + node_path_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/node_path_color"); + annotation_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/annotation_color"); + type_color = EDITOR_GET("text_editor/theme/highlighting/base_type_color"); } void GDScriptSyntaxHighlighter::add_color_region(const String &p_start_key, const String &p_end_key, const Color &p_color, bool p_line_only) { @@ -622,6 +616,6 @@ void GDScriptSyntaxHighlighter::add_color_region(const String &p_start_key, cons Ref<EditorSyntaxHighlighter> GDScriptSyntaxHighlighter::_create() const { Ref<GDScriptSyntaxHighlighter> syntax_highlighter; - syntax_highlighter.instance(); + syntax_highlighter.instantiate(); return syntax_highlighter; } diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h index d07c182aa6..fabd64dab8 100644 --- a/modules/gdscript/editor/gdscript_highlighter.h +++ b/modules/gdscript/editor/gdscript_highlighter.h @@ -80,7 +80,7 @@ private: public: virtual void _update_cache() override; - virtual Dictionary _get_line_syntax_highlighting(int p_line) override; + virtual Dictionary _get_line_syntax_highlighting_impl(int p_line) override; virtual String _get_name() const override; virtual Array _get_supported_languages() const override; diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.h b/modules/gdscript/editor/gdscript_translation_parser_plugin.h index fcf438422a..caa80fc24c 100644 --- a/modules/gdscript/editor/gdscript_translation_parser_plugin.h +++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.h @@ -34,7 +34,6 @@ #include "core/templates/set.h" #include "editor/editor_translation_parser.h" #include "modules/gdscript/gdscript_parser.h" -#include "modules/regex/regex.h" class GDScriptEditorTranslationParserPlugin : public EditorTranslationParserPlugin { GDCLASS(GDScriptEditorTranslationParserPlugin, EditorTranslationParserPlugin); diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 1567576009..4589cf1a36 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -72,7 +72,7 @@ void GDScriptNativeClass::_bind_methods() { } Variant GDScriptNativeClass::_new() { - Object *o = instance(); + Object *o = instantiate(); ERR_FAIL_COND_V_MSG(!o, Variant(), "Class type: '" + String(name) + "' is not instantiable."); RefCounted *rc = Object::cast_to<RefCounted>(o); @@ -83,8 +83,8 @@ Variant GDScriptNativeClass::_new() { } } -Object *GDScriptNativeClass::instance() { - return ClassDB::instance(name); +Object *GDScriptNativeClass::instantiate() { + return ClassDB::instantiate(name); } void GDScript::_super_implicit_constructor(GDScript *p_script, GDScriptInstance *p_instance, Callable::CallError &r_error) { @@ -170,7 +170,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr ERR_FAIL_COND_V(_baseptr->native.is_null(), Variant()); if (_baseptr->native.ptr()) { - owner = _baseptr->native->instance(); + owner = _baseptr->native->instantiate(); } else { owner = memnew(RefCounted); //by default, no base means use reference } @@ -196,7 +196,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr } } -bool GDScript::can_instance() const { +bool GDScript::can_instantiate() const { #ifdef TOOLS_ENABLED return valid && (tool || ScriptServer::is_scripting_enabled()); #else @@ -291,8 +291,8 @@ void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_incl sptr = sptr->_base; } - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - r_list->push_back(E->get()); + for (const PropertyInfo &E : props) { + r_list->push_back(E); } } @@ -346,9 +346,9 @@ ScriptInstance *GDScript::instance_create(Object *p_this) { if (top->native.is_valid()) { if (!ClassDB::is_parent_class(p_this->get_class_name(), top->native->get_name())) { if (EngineDebugger::is_active()) { - GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), 1, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'"); + GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), 1, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'"); } - ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type '" + p_this->get_class() + "'" + "."); + ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instantiated in object of type '" + p_this->get_class() + "'" + "."); } } @@ -401,8 +401,8 @@ void GDScript::_update_exports_values(Map<StringName, Variant> &values, List<Pro values[E->key()] = E->get(); } - for (List<PropertyInfo>::Element *E = members_cache.front(); E; E = E->next()) { - propnames.push_back(E->get()); + for (const PropertyInfo &E : members_cache) { + propnames.push_back(E); } } @@ -861,8 +861,7 @@ Error GDScript::reload(bool p_keep_state) { } } #ifdef DEBUG_ENABLED - for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E; E = E->next()) { - const GDScriptWarning &warning = E->get(); + for (const GDScriptWarning &warning : parser.get_warnings()) { if (EngineDebugger::is_active()) { Vector<ScriptLanguage::StackInfo> si; EngineDebugger::get_script_debugger()->send_error("", get_path(), warning.start_line, warning.get_name(), warning.get_message(), ERR_HANDLER_WARNING, si); @@ -1165,15 +1164,11 @@ void GDScript::_init_rpc_methods_properties() { while (cscript) { // RPC Methods for (Map<StringName, GDScriptFunction *>::Element *E = cscript->member_functions.front(); E; E = E->next()) { - if (E->get()->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) { - MultiplayerAPI::RPCConfig nd; - nd.name = E->key(); - nd.rpc_mode = E->get()->get_rpc_mode(); - // TODO - nd.transfer_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE; - nd.channel = 0; - if (-1 == rpc_functions.find(nd)) { - rpc_functions.push_back(nd); + MultiplayerAPI::RPCConfig config = E->get()->get_rpc_config(); + if (config.rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) { + config.name = E->get()->get_name(); + if (rpc_functions.find(config) == -1) { + rpc_functions.push_back(config); } } } @@ -1449,8 +1444,8 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const sptr = sptr->_base; } - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - p_properties->push_back(E->get()); + for (const PropertyInfo &E : props) { + p_properties->push_back(E); } } @@ -1641,24 +1636,18 @@ void GDScriptLanguage::init() { _add_global(StaticCString::create("PI"), Math_PI); _add_global(StaticCString::create("TAU"), Math_TAU); - _add_global(StaticCString::create("INF"), Math_INF); - _add_global(StaticCString::create("NAN"), Math_NAN); + _add_global(StaticCString::create("INF"), INFINITY); + _add_global(StaticCString::create("NAN"), NAN); //populate native classes List<StringName> class_list; ClassDB::get_class_list(&class_list); - for (List<StringName>::Element *E = class_list.front(); E; E = E->next()) { - StringName n = E->get(); - String s = String(n); - if (s.begins_with("_")) { - n = s.substr(1, s.length()); - } - + for (const StringName &n : class_list) { if (globals.has(n)) { continue; } - Ref<GDScriptNativeClass> nc = memnew(GDScriptNativeClass(E->get())); + Ref<GDScriptNativeClass> nc = memnew(GDScriptNativeClass(n)); _add_global(n, nc); } @@ -1666,8 +1655,8 @@ void GDScriptLanguage::init() { List<Engine::Singleton> singletons; Engine::get_singleton()->get_singletons(&singletons); - for (List<Engine::Singleton>::Element *E = singletons.front(); E; E = E->next()) { - _add_global(E->get().name, E->get().ptr); + for (const Engine::Singleton &E : singletons) { + _add_global(E.name, E.ptr); } #ifdef TESTS_ENABLED @@ -1810,10 +1799,10 @@ void GDScriptLanguage::reload_all_scripts() { scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order - for (List<Ref<GDScript>>::Element *E = scripts.front(); E; E = E->next()) { - print_verbose("GDScript: Reloading: " + E->get()->get_path()); - E->get()->load_source_code(E->get()->get_path()); - E->get()->reload(true); + for (Ref<GDScript> &script : scripts) { + print_verbose("GDScript: Reloading: " + script->get_path()); + script->load_source_code(script->get_path()); + script->reload(true); } #endif } @@ -1842,21 +1831,21 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order - for (List<Ref<GDScript>>::Element *E = scripts.front(); E; E = E->next()) { - bool reload = E->get() == p_script || to_reload.has(E->get()->get_base()); + for (Ref<GDScript> &script : scripts) { + bool reload = script == p_script || to_reload.has(script->get_base()); if (!reload) { continue; } - to_reload.insert(E->get(), Map<ObjectID, List<Pair<StringName, Variant>>>()); + to_reload.insert(script, Map<ObjectID, List<Pair<StringName, Variant>>>()); if (!p_soft_reload) { //save state and remove script from instances - Map<ObjectID, List<Pair<StringName, Variant>>> &map = to_reload[E->get()]; + Map<ObjectID, List<Pair<StringName, Variant>>> &map = to_reload[script]; - while (E->get()->instances.front()) { - Object *obj = E->get()->instances.front()->get(); + while (script->instances.front()) { + Object *obj = script->instances.front()->get(); //save instance info List<Pair<StringName, Variant>> state; if (obj->get_script_instance()) { @@ -1869,8 +1858,8 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so //same thing for placeholders #ifdef TOOLS_ENABLED - while (E->get()->placeholders.size()) { - Object *obj = E->get()->placeholders.front()->get()->get_owner(); + while (script->placeholders.size()) { + Object *obj = script->placeholders.front()->get()->get_owner(); //save instance info if (obj->get_script_instance()) { @@ -1880,13 +1869,13 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so obj->set_script(Variant()); } else { // no instance found. Let's remove it so we don't loop forever - E->get()->placeholders.erase(E->get()->placeholders.front()->get()); + script->placeholders.erase(script->placeholders.front()->get()); } } #endif - for (Map<ObjectID, List<Pair<StringName, Variant>>>::Element *F = E->get()->pending_reload_state.front(); F; F = F->next()) { + for (Map<ObjectID, List<Pair<StringName, Variant>>>::Element *F = script->pending_reload_state.front(); F; F = F->next()) { map[F->key()] = F->get(); //pending to reload, use this one instead } } @@ -2029,8 +2018,8 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { List<StringName> functions; GDScriptUtilityFunctions::get_function_list(&functions); - for (const List<StringName>::Element *E = functions.front(); E; E = E->next()) { - p_words->push_back(String(E->get())); + for (const StringName &E : functions) { + p_words->push_back(String(E)); } } @@ -2256,7 +2245,7 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_ori if (script.is_null()) { // Don't fail loading because of parsing error. - script.instance(); + script.instantiate(); } if (r_error) { @@ -2300,8 +2289,8 @@ void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<S return; } - for (const List<String>::Element *E = parser.get_dependencies().front(); E; E = E->next()) { - p_dependencies->push_back(E->get()); + for (const String &E : parser.get_dependencies()) { + p_dependencies->push_back(E); } } diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 602553bb1a..24809ad5fd 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -51,7 +51,7 @@ protected: public: _FORCE_INLINE_ const StringName &get_name() const { return name; } Variant _new(); - Object *instance(); + Object *instantiate(); GDScriptNativeClass(const StringName &p_name); }; @@ -64,7 +64,6 @@ class GDScript : public Script { int index = 0; StringName setter; StringName getter; - MultiplayerAPI::RPCMode rpc_mode; GDScriptDataType data_type; }; @@ -80,10 +79,10 @@ class GDScript : public Script { GDScript *_base = nullptr; //fast pointer access GDScript *_owner = nullptr; //for subclasses - Set<StringName> members; //members are just indices to the instanced script. + Set<StringName> members; //members are just indices to the instantiated script. Map<StringName, Variant> constants; Map<StringName, GDScriptFunction *> member_functions; - Map<StringName, MemberInfo> member_indices; //members are just indices to the instanced script. + Map<StringName, MemberInfo> member_indices; //members are just indices to the instantiated script. Map<StringName, Ref<GDScript>> subclasses; Map<StringName, Vector<StringName>> _signals; Vector<MultiplayerAPI::RPCConfig> rpc_functions; @@ -196,7 +195,7 @@ public: StringName debug_get_member_by_index(int p_idx) const; Variant _new(const Variant **p_args, int p_argcount, Callable::CallError &r_error); - virtual bool can_instance() const override; + virtual bool can_instantiate() const override; virtual Ref<Script> get_base_script() const override; @@ -447,7 +446,7 @@ public: 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, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; + 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; diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index c3edc813d2..6b7403d854 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -30,6 +30,7 @@ #include "gdscript_analyzer.h" +#include "core/config/engine.h" #include "core/config/project_settings.h" #include "core/io/file_access.h" #include "core/io/resource_loader.h" @@ -112,11 +113,10 @@ static GDScriptParser::DataType make_native_enum_type(const StringName &p_native type.is_meta_type = true; List<StringName> enum_values; - StringName real_native_name = GDScriptParser::get_real_class_name(p_native_class); - ClassDB::get_enum_constants(real_native_name, p_enum_name, &enum_values); + ClassDB::get_enum_constants(p_native_class, p_enum_name, &enum_values); - for (const List<StringName>::Element *E = enum_values.front(); E != nullptr; E = E->next()) { - type.enum_values[E->get()] = ClassDB::get_integer_constant(real_native_name, E->get()); + for (const StringName &E : enum_values) { + type.enum_values[E] = ClassDB::get_integer_constant(p_native_class, E); } return type; @@ -229,7 +229,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class, push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class); return err; } - } else if (class_exists(name) && ClassDB::can_instance(GDScriptParser::get_real_class_name(name))) { + } else if (class_exists(name) && ClassDB::can_instantiate(name)) { base.kind = GDScriptParser::DataType::NATIVE; base.native_type = name; } else { @@ -406,7 +406,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type return GDScriptParser::DataType(); } result = ref->get_parser()->head->get_datatype(); - } else if (ClassDB::has_enum(GDScriptParser::get_real_class_name(parser->current_class->base_type.native_type), first)) { + } else if (ClassDB::has_enum(parser->current_class->base_type.native_type, first)) { // Native enum in current class. result = make_native_enum_type(parser->current_class->base_type.native_type, first); } else { @@ -433,8 +433,28 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type case GDScriptParser::ClassNode::Member::CONSTANT: if (member.constant->get_datatype().is_meta_type) { result = member.constant->get_datatype(); + result.is_meta_type = false; found = true; break; + } else if (Ref<Script>(member.constant->initializer->reduced_value).is_valid()) { + Ref<GDScript> gdscript = member.constant->initializer->reduced_value; + if (gdscript.is_valid()) { + Ref<GDScriptParserRef> ref = get_parser_for(gdscript->get_path()); + if (ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) { + push_error(vformat(R"(Could not parse script from "%s".)", gdscript->get_path()), p_type); + return GDScriptParser::DataType(); + } + result = ref->get_parser()->head->get_datatype(); + result.is_meta_type = false; + } else { + Ref<GDScript> script = member.constant->initializer->reduced_value; + result.kind = GDScriptParser::DataType::SCRIPT; + result.builtin_type = Variant::OBJECT; + result.script_type = script; + result.script_path = script->get_path(); + result.native_type = script->get_instance_base_type(); + } + break; } [[fallthrough]]; default: @@ -469,7 +489,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type } } else if (result.kind == GDScriptParser::DataType::NATIVE) { // Only enums allowed for native. - if (ClassDB::has_enum(GDScriptParser::get_real_class_name(result.native_type), p_type->type_chain[1]->name)) { + if (ClassDB::has_enum(result.native_type, p_type->type_chain[1]->name)) { if (p_type->type_chain.size() > 2) { push_error(R"(Enums cannot contain nested types.)", p_type->type_chain[2]); } else { @@ -573,8 +593,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas member.variable->set_datatype(datatype); // Apply annotations. - for (List<GDScriptParser::AnnotationNode *>::Element *E = member.variable->annotations.front(); E; E = E->next()) { - E->get()->apply(parser, member.variable); + for (GDScriptParser::AnnotationNode *&E : member.variable->annotations) { + E->apply(parser, member.variable); } } break; case GDScriptParser::ClassNode::Member::CONSTANT: { @@ -622,8 +642,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas member.constant->set_datatype(datatype); // Apply annotations. - for (List<GDScriptParser::AnnotationNode *>::Element *E = member.constant->annotations.front(); E; E = E->next()) { - E->get()->apply(parser, member.constant); + for (GDScriptParser::AnnotationNode *&E : member.constant->annotations) { + E->apply(parser, member.constant); } } break; case GDScriptParser::ClassNode::Member::SIGNAL: { @@ -641,8 +661,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas member.signal->set_datatype(signal_type); // Apply annotations. - for (List<GDScriptParser::AnnotationNode *>::Element *E = member.signal->annotations.front(); E; E = E->next()) { - E->get()->apply(parser, member.signal); + for (GDScriptParser::AnnotationNode *&E : member.signal->annotations) { + E->apply(parser, member.signal); } } break; case GDScriptParser::ClassNode::Member::ENUM: { @@ -688,8 +708,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas member.m_enum->set_datatype(enum_type); // Apply annotations. - for (List<GDScriptParser::AnnotationNode *>::Element *E = member.m_enum->annotations.front(); E; E = E->next()) { - E->get()->apply(parser, member.m_enum); + for (GDScriptParser::AnnotationNode *&E : member.m_enum->annotations) { + E->apply(parser, member.m_enum); } } break; case GDScriptParser::ClassNode::Member::FUNCTION: @@ -761,8 +781,8 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) { resolve_function_body(member.function); // Apply annotations. - for (List<GDScriptParser::AnnotationNode *>::Element *E = member.function->annotations.front(); E; E = E->next()) { - E->get()->apply(parser, member.function); + for (GDScriptParser::AnnotationNode *&E : member.function->annotations) { + E->apply(parser, member.function); } } @@ -1779,10 +1799,10 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o } else { if (p_binary_op->variant_op < Variant::OP_MAX) { bool valid = false; - result = get_operation_type(p_binary_op->variant_op, p_binary_op->left_operand->get_datatype(), right_type, valid, p_binary_op); + result = get_operation_type(p_binary_op->variant_op, left_type, right_type, valid, p_binary_op); if (!valid) { - push_error(vformat(R"(Invalid operands "%s" and "%s" for "%s" operator.)", p_binary_op->left_operand->get_datatype().to_string(), right_type.to_string(), Variant::get_operator_name(p_binary_op->variant_op)), p_binary_op); + push_error(vformat(R"(Invalid operands "%s" and "%s" for "%s" operator.)", left_type.to_string(), right_type.to_string(), Variant::get_operator_name(p_binary_op->variant_op)), p_binary_op); } } else { if (p_binary_op->operation == GDScriptParser::BinaryOpNode::OP_TYPE_TEST) { @@ -1927,9 +1947,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa Variant::get_constructor_list(builtin_type, &constructors); bool match = false; - for (const List<MethodInfo>::Element *E = constructors.front(); E != nullptr; E = E->next()) { - const MethodInfo &info = E->get(); - + for (const MethodInfo &info : constructors) { if (p_call->arguments.size() < info.arguments.size() - info.default_arguments.size()) { continue; } @@ -2132,6 +2150,9 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa if (is_self && parser->current_function != nullptr && parser->current_function->is_static && !is_static) { push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parser->current_function->identifier->name), p_call->callee); + } else if (!is_self && base_type.is_meta_type && !is_static) { + base_type.is_meta_type = false; // For `to_string()`. + push_error(vformat(R"*(Cannot call non-static function "%s()" on the class "%s" directly. Make an instance instead.)*", p_call->function_name, base_type.to_string()), p_call->callee); } else if (is_self && !is_static && !lambda_stack.is_empty()) { push_error(vformat(R"*(Cannot call non-static function "%s()" from a lambda function.)*", p_call->function_name), p_call->callee); } @@ -2254,7 +2275,7 @@ void GDScriptAnalyzer::reduce_get_node(GDScriptParser::GetNodeNode *p_get_node) result.native_type = "Node"; result.builtin_type = Variant::OBJECT; - if (!ClassDB::is_parent_class(GDScriptParser::get_real_class_name(parser->current_class->base_type.native_type), result.native_type)) { + if (!ClassDB::is_parent_class(parser->current_class->base_type.native_type, result.native_type)) { push_error(R"*(Cannot use shorthand "get_node()" notation ("$") on a class that isn't a node.)*", p_get_node); } else if (!lambda_stack.is_empty()) { push_error(R"*(Cannot use shorthand "get_node()" notation ("$") inside a lambda. Use a captured variable instead.)*", p_get_node); @@ -2326,8 +2347,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod Variant::construct(base.builtin_type, dummy, nullptr, 0, temp); List<PropertyInfo> properties; dummy.get_property_list(&properties); - for (const List<PropertyInfo>::Element *E = properties.front(); E != nullptr; E = E->next()) { - const PropertyInfo &prop = E->get(); + for (const PropertyInfo &prop : properties) { if (prop.name == name) { p_identifier->set_datatype(type_from_property(prop)); return; @@ -2349,6 +2369,7 @@ 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.native_type = base.native_type; result.enum_type = name; p_identifier->set_datatype(result); @@ -2395,6 +2416,11 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod resolve_function_signature(member.function); p_identifier->set_datatype(make_callable_type(member.function->info)); break; + case GDScriptParser::ClassNode::Member::CLASS: + // For out-of-order resolution: + resolve_class_interface(member.m_class); + p_identifier->set_datatype(member.m_class->get_datatype()); + break; default: break; // Type already set. } @@ -2423,7 +2449,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod } // Check native members. - const StringName &native = GDScriptParser::get_real_class_name(base.native_type); + const StringName &native = base.native_type; if (class_exists(native)) { PropertyInfo prop_info; @@ -3124,8 +3150,8 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va GDScriptParser::ClassNode *found = ref->get_parser()->head; // It should be okay to assume this exists, since we have a complete script already. - for (const List<StringName>::Element *E = class_chain.front(); E; E = E->next()) { - found = found->get_member(E->get()).m_class; + for (const StringName &E : class_chain) { + found = found->get_member(E).m_class; } result.class_type = found; @@ -3204,7 +3230,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo return result; } -bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GDScriptParser::DataType p_base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg) { +bool GDScriptAnalyzer::get_function_signature(GDScriptParser::CallNode *p_source, GDScriptParser::DataType p_base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg) { r_static = false; r_vararg = false; r_default_arg_count = 0; @@ -3221,16 +3247,18 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD List<MethodInfo> methods; dummy.get_method_list(&methods); - for (const List<MethodInfo>::Element *E = methods.front(); E != nullptr; E = E->next()) { - if (E->get().name == p_function) { - return function_signature_from_info(E->get(), r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg); + for (const MethodInfo &E : methods) { + if (E.name == p_function) { + function_signature_from_info(E, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg); + r_static = Variant::is_builtin_method_static(p_base_type.builtin_type, function_name); + return true; } } return false; } - bool is_constructor = p_base_type.is_meta_type && p_function == "new"; + bool is_constructor = (p_base_type.is_meta_type || (p_source->callee && p_source->callee->type == GDScriptParser::Node::IDENTIFIER)) && p_function == StaticCString::create("new"); if (is_constructor) { function_name = "_init"; r_static = true; @@ -3260,6 +3288,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD } } r_return_type = found_function->get_datatype(); + r_return_type.is_meta_type = false; r_return_type.is_coroutine = found_function->is_coroutine; return true; @@ -3305,11 +3334,13 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD return true; } - StringName real_native = GDScriptParser::get_real_class_name(base_native); - MethodInfo info; - if (ClassDB::get_method_info(real_native, function_name, &info)) { - return function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg); + if (ClassDB::get_method_info(base_native, function_name, &info)) { + bool valid = function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg); + if (valid && Engine::get_singleton()->has_singleton(base_native)) { + r_static = true; + } + return valid; } return false; @@ -3320,8 +3351,8 @@ bool GDScriptAnalyzer::function_signature_from_info(const MethodInfo &p_info, GD r_default_arg_count = p_info.default_arguments.size(); r_vararg = (p_info.flags & METHOD_FLAG_VARARG) != 0; - for (const List<PropertyInfo>::Element *E = p_info.arguments.front(); E != nullptr; E = E->next()) { - r_par_types.push_back(type_from_property(E->get())); + for (const PropertyInfo &E : p_info.arguments) { + r_par_types.push_back(type_from_property(E)); } return true; } @@ -3329,8 +3360,8 @@ bool GDScriptAnalyzer::function_signature_from_info(const MethodInfo &p_info, GD bool GDScriptAnalyzer::validate_call_arg(const MethodInfo &p_method, const GDScriptParser::CallNode *p_call) { List<GDScriptParser::DataType> arg_types; - for (const List<PropertyInfo>::Element *E = p_method.arguments.front(); E != nullptr; E = E->next()) { - arg_types.push_back(type_from_property(E->get())); + for (const PropertyInfo &E : p_method.arguments) { + arg_types.push_back(type_from_property(E)); } return validate_call_arg(arg_types, p_method.default_arguments.size(), (p_method.flags & METHOD_FLAG_VARARG) != 0, p_call); @@ -3400,24 +3431,23 @@ bool GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con StringName parent = base_native; while (parent != StringName()) { - StringName real_class_name = GDScriptParser::get_real_class_name(parent); - if (ClassDB::has_method(real_class_name, name, true)) { + if (ClassDB::has_method(parent, name, true)) { parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "method", parent); return true; - } else if (ClassDB::has_signal(real_class_name, name, true)) { + } else if (ClassDB::has_signal(parent, name, true)) { parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "signal", parent); return true; - } else if (ClassDB::has_property(real_class_name, name, true)) { + } else if (ClassDB::has_property(parent, name, true)) { parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "property", parent); return true; - } else if (ClassDB::has_integer_constant(real_class_name, name, true)) { + } else if (ClassDB::has_integer_constant(parent, name, true)) { parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "constant", parent); return true; - } else if (ClassDB::has_enum(real_class_name, name, true)) { + } else if (ClassDB::has_enum(parent, name, true)) { parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "enum", parent); return true; } - parent = ClassDB::get_parent_class(real_class_name); + parent = ClassDB::get_parent_class(parent); } return false; @@ -3446,6 +3476,7 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator } 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); @@ -3561,16 +3592,12 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ break; // Already solved before. } - // Get underscore-prefixed version for some classes. - src_native = GDScriptParser::get_real_class_name(src_native); - switch (p_target.kind) { case GDScriptParser::DataType::NATIVE: { if (p_target.is_meta_type) { return ClassDB::is_parent_class(src_native, GDScriptNativeClass::get_class_static()); } - StringName tgt_native = GDScriptParser::get_real_class_name(p_target.native_type); - return ClassDB::is_parent_class(src_native, tgt_native); + return ClassDB::is_parent_class(src_native, p_target.native_type); } case GDScriptParser::DataType::SCRIPT: if (p_target.is_meta_type) { @@ -3619,8 +3646,7 @@ void GDScriptAnalyzer::mark_node_unsafe(const GDScriptParser::Node *p_node) { } bool GDScriptAnalyzer::class_exists(const StringName &p_class) const { - StringName real_name = GDScriptParser::get_real_class_name(p_class); - return ClassDB::class_exists(real_name) && ClassDB::is_class_exposed(real_name); + return ClassDB::class_exists(p_class) && ClassDB::is_class_exposed(p_class); } Ref<GDScriptParserRef> GDScriptAnalyzer::get_parser_for(const String &p_path) { @@ -3656,11 +3682,11 @@ Error GDScriptAnalyzer::resolve_program() { List<String> parser_keys; depended_parsers.get_key_list(&parser_keys); - for (const List<String>::Element *E = parser_keys.front(); E != nullptr; E = E->next()) { - if (depended_parsers[E->get()].is_null()) { + for (const String &E : parser_keys) { + if (depended_parsers[E].is_null()) { return ERR_PARSE_ERROR; } - depended_parsers[E->get()]->raise_status(GDScriptParserRef::FULLY_SOLVED); + depended_parsers[E]->raise_status(GDScriptParserRef::FULLY_SOLVED); } return parser->errors.is_empty() ? OK : ERR_PARSE_ERROR; } diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h index 8cd3fcf837..32bf049fa1 100644 --- a/modules/gdscript/gdscript_analyzer.h +++ b/modules/gdscript/gdscript_analyzer.h @@ -99,7 +99,7 @@ class GDScriptAnalyzer { GDScriptParser::DataType type_from_metatype(const GDScriptParser::DataType &p_meta_type) const; GDScriptParser::DataType type_from_property(const PropertyInfo &p_property) const; GDScriptParser::DataType make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source); - bool get_function_signature(GDScriptParser::Node *p_source, GDScriptParser::DataType base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg); + bool get_function_signature(GDScriptParser::CallNode *p_source, GDScriptParser::DataType base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg); bool function_signature_from_info(const MethodInfo &p_info, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg); bool validate_call_arg(const List<GDScriptParser::DataType> &p_par_types, int p_default_args_count, bool p_is_vararg, const GDScriptParser::CallNode *p_call); bool validate_call_arg(const MethodInfo &p_method, const GDScriptParser::CallNode *p_call); diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 6998cc5bb7..5958326315 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -155,7 +155,7 @@ void GDScriptByteCodeGenerator::end_parameters() { function->default_arguments.reverse(); } -void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCMode p_rpc_mode, const GDScriptDataType &p_return_type) { +void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCConfig p_rpc_config, const GDScriptDataType &p_return_type) { function = memnew(GDScriptFunction); debug_stack = EngineDebugger::is_active(); @@ -170,7 +170,7 @@ void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName function->_static = p_static; function->return_type = p_return_type; - function->rpc_mode = p_rpc_mode; + function->rpc_config = p_rpc_config; function->_argument_count = 0; } @@ -554,6 +554,14 @@ void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Va void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) { if (HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand)) { + if (p_target.mode == Address::TEMPORARY) { + Variant::Type result_type = Variant::get_operator_return_type(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type); + Variant::Type temp_type = temporaries[p_target.address].type; + if (result_type != temp_type) { + write_type_adjust(p_target, result_type); + } + } + // Gather specific operator. Variant::ValidatedOperatorEvaluator op_func = Variant::get_validated_operator_evaluator(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type); @@ -1451,8 +1459,8 @@ void GDScriptByteCodeGenerator::write_endfor() { } // Patch break statements. - for (const List<int>::Element *E = current_breaks_to_patch.back()->get().front(); E; E = E->next()) { - patch_jump(E->get()); + for (const int &E : current_breaks_to_patch.back()->get()) { + patch_jump(E); } current_breaks_to_patch.pop_back(); @@ -1486,8 +1494,8 @@ void GDScriptByteCodeGenerator::write_endwhile() { while_jmp_addrs.pop_back(); // Patch break statements. - for (const List<int>::Element *E = current_breaks_to_patch.back()->get().front(); E; E = E->next()) { - patch_jump(E->get()); + for (const int &E : current_breaks_to_patch.back()->get()) { + patch_jump(E); } current_breaks_to_patch.pop_back(); } @@ -1498,8 +1506,8 @@ void GDScriptByteCodeGenerator::start_match() { void GDScriptByteCodeGenerator::start_match_branch() { // Patch continue statements. - for (const List<int>::Element *E = match_continues_to_patch.back()->get().front(); E; E = E->next()) { - patch_jump(E->get()); + for (const int &E : match_continues_to_patch.back()->get()) { + patch_jump(E); } match_continues_to_patch.pop_back(); // Start a new list for next branch. @@ -1508,8 +1516,8 @@ void GDScriptByteCodeGenerator::start_match_branch() { void GDScriptByteCodeGenerator::end_match() { // Patch continue statements. - for (const List<int>::Element *E = match_continues_to_patch.back()->get().front(); E; E = E->next()) { - patch_jump(E->get()); + for (const int &E : match_continues_to_patch.back()->get()) { + patch_jump(E); } match_continues_to_patch.pop_back(); } diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h index b1f3cd5fb3..3d6fb291ad 100644 --- a/modules/gdscript/gdscript_byte_codegen.h +++ b/modules/gdscript/gdscript_byte_codegen.h @@ -419,7 +419,7 @@ public: virtual void start_block() override; virtual void end_block() override; - virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCMode p_rpc_mode, const GDScriptDataType &p_return_type) override; + virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCConfig p_rpc_config, const GDScriptDataType &p_return_type) override; virtual GDScriptFunction *write_end() override; #ifdef DEBUG_ENABLED diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index a3b1fb93f9..07f50d14dc 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -134,7 +134,7 @@ Ref<GDScriptParserRef> GDScriptCache::get_parser(const String &p_path, GDScriptP return ref; } GDScriptParser *parser = memnew(GDScriptParser); - ref.instance(); + ref.instantiate(); ref->parser = parser; ref->path = p_path; singleton->parser_map[p_path] = ref.ptr(); @@ -180,7 +180,7 @@ Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, const Stri } Ref<GDScript> script; - script.instance(); + script.instantiate(); script->set_path(p_path, true); script->set_script_path(p_path); script->load_source_code(p_path); @@ -200,7 +200,9 @@ Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_erro if (singleton->full_gdscript_cache.has(p_path)) { return singleton->full_gdscript_cache[p_path]; } + Ref<GDScript> script = get_shallow_script(p_path); + ERR_FAIL_COND_V(script.is_null(), Ref<GDScript>()); r_error = script->load_source_code(p_path); diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h index cac6544f03..ecc86c37f3 100644 --- a/modules/gdscript/gdscript_codegen.h +++ b/modules/gdscript/gdscript_codegen.h @@ -80,7 +80,7 @@ public: virtual void start_block() = 0; virtual void end_block() = 0; - virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCMode p_rpc_mode, const GDScriptDataType &p_return_type) = 0; + virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCConfig p_rpc_config, const GDScriptDataType &p_return_type) = 0; virtual GDScriptFunction *write_end() = 0; #ifdef DEBUG_ENABLED diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 6d6b9e15af..ddf4f281b4 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -107,7 +107,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D // Locate class by constructing the path to it and following that path GDScriptParser::ClassNode *class_type = p_datatype.class_type; if (class_type) { - if (class_type->fqcn.begins_with(main_script->path) || (!main_script->name.is_empty() && class_type->fqcn.begins_with(main_script->name))) { + if ((!main_script->path.is_empty() && class_type->fqcn.begins_with(main_script->path)) || (!main_script->name.is_empty() && class_type->fqcn.begins_with(main_script->name))) { // Local class. List<StringName> names; while (class_type->outer) { @@ -126,8 +126,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D names.pop_back(); } result.kind = GDScriptDataType::GDSCRIPT; - result.script_type_ref = script; - result.script_type = result.script_type_ref.ptr(); + result.script_type = script.ptr(); result.native_type = script->get_instance_base_type(); } else { result.kind = GDScriptDataType::GDSCRIPT; @@ -981,8 +980,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code assigned = prev_base; // Set back the values into their bases. - for (List<ChainInfo>::Element *E = set_chain.front(); E; E = E->next()) { - const ChainInfo &info = E->get(); + for (const ChainInfo &info : set_chain) { if (!info.is_named) { gen->write_set(info.base, info.key, assigned); if (info.key.mode == GDScriptCodeGenerator::Address::TEMPORARY) { @@ -1859,7 +1857,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ StringName func_name; bool is_static = false; - MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; + MultiplayerAPI::RPCConfig rpc_config; GDScriptDataType return_type; return_type.has_type = true; return_type.kind = GDScriptDataType::BUILTIN; @@ -1872,7 +1870,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ func_name = "<anonymous lambda>"; } is_static = p_func->is_static; - rpc_mode = p_func->rpc_mode; + rpc_config = p_func->rpc_config; return_type = _gdtype_from_datatype(p_func->get_datatype(), p_script); } else { if (p_for_ready) { @@ -1883,7 +1881,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ } codegen.function_name = func_name; - codegen.generator->write_start(p_script, func_name, is_static, rpc_mode, return_type); + codegen.generator->write_start(p_script, func_name, is_static, rpc_config, return_type); int optional_parameters = 0; @@ -2088,7 +2086,7 @@ Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptP return_type = _gdtype_from_datatype(p_variable->get_datatype(), p_script); } - codegen.generator->write_start(p_script, func_name, false, p_variable->rpc_mode, return_type); + codegen.generator->write_start(p_script, func_name, false, MultiplayerAPI::RPCConfig(), return_type); if (p_is_setter) { uint32_t par_addr = codegen.generator->add_parameter(p_variable->setter_parameter->name, false, _gdtype_from_datatype(p_variable->get_datatype())); @@ -2268,7 +2266,6 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar } break; } - minfo.rpc_mode = variable->rpc_mode; minfo.data_type = _gdtype_from_datatype(variable->get_datatype(), p_script); PropertyInfo prop_info = minfo.data_type; @@ -2587,7 +2584,7 @@ void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::C if (orphan_subclass.is_valid()) { subclass = orphan_subclass; } else { - subclass.instance(); + subclass.instantiate(); } } diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 18b7810919..372a726d71 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -104,7 +104,7 @@ Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const Str _template = _get_processed_template(_template, p_base_class_name); Ref<GDScript> script; - script.instance(); + script.instantiate(); script->set_source_code(_template); return script; @@ -131,7 +131,7 @@ static void get_function_names_recursively(const GDScriptParser::ClassNode *p_cl } } -bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { +bool GDScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { GDScriptParser parser; GDScriptAnalyzer analyzer(&parser); @@ -141,8 +141,8 @@ bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int & } #ifdef DEBUG_ENABLED if (r_warnings) { - for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E; E = E->next()) { - const GDScriptWarning &warn = E->get(); + for (const GDScriptWarning &E : parser.get_warnings()) { + const GDScriptWarning &warn = E; ScriptLanguage::Warning w; w.start_line = warn.start_line; w.end_line = warn.end_line; @@ -156,10 +156,16 @@ bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int & } #endif if (err) { - GDScriptParser::ParserError parse_error = parser.get_errors().front()->get(); - r_line_error = parse_error.line; - r_col_error = parse_error.column; - r_test_error = parse_error.message; + if (r_errors) { + for (const GDScriptParser::ParserError &E : parser.get_errors()) { + const GDScriptParser::ParserError &pe = E; + ScriptLanguage::ScriptError e; + e.line = pe.line; + e.column = pe.column; + e.message = pe.message; + r_errors->push_back(e); + } + } return false; } else { const GDScriptParser::ClassNode *cl = parser.get_tree(); @@ -313,9 +319,9 @@ void GDScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p List<Pair<StringName, int>> locals; f->debug_get_stack_member_state(*_call_stack[l].line, &locals); - for (List<Pair<StringName, int>>::Element *E = locals.front(); E; E = E->next()) { - p_locals->push_back(E->get().first); - p_values->push_back(_call_stack[l].stack[E->get().second]); + for (const Pair<StringName, int> &E : locals) { + p_locals->push_back(E.first); + p_values->push_back(_call_stack[l].stack[E.second]); } } @@ -415,8 +421,8 @@ void GDScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const List<StringName> functions; GDScriptUtilityFunctions::get_function_list(&functions); - for (const List<StringName>::Element *E = functions.front(); E; E = E->next()) { - p_functions->push_back(GDScriptUtilityFunctions::get_function_info(E->get())); + for (const StringName &E : functions) { + p_functions->push_back(GDScriptUtilityFunctions::get_function_info(E)); } // Not really "functions", but show in documentation. @@ -451,12 +457,12 @@ void GDScriptLanguage::get_public_constants(List<Pair<String, Variant>> *p_const Pair<String, Variant> infinity; infinity.first = "INF"; - infinity.second = Math_INF; + infinity.second = INFINITY; p_constants->push_back(infinity); Pair<String, Variant> nan; nan.first = "NAN"; - nan.second = Math_NAN; + nan.second = NAN; p_constants->push_back(nan); } @@ -542,7 +548,7 @@ static String _make_arguments_hint(const MethodInfo &p_info, int p_arg_idx, bool int def_args = p_info.arguments.size() - p_info.default_arguments.size(); int i = 0; - for (const List<PropertyInfo>::Element *E = p_info.arguments.front(); E; E = E->next()) { + for (const PropertyInfo &E : p_info.arguments) { if (i > 0) { arghint += ", "; } @@ -550,7 +556,7 @@ static String _make_arguments_hint(const MethodInfo &p_info, int p_arg_idx, bool if (i == p_arg_idx) { arghint += String::chr(0xFFFF); } - arghint += E->get().name + ": " + _get_visual_datatype(E->get(), true); + arghint += E.name + ": " + _get_visual_datatype(E, true); if (i - def_args >= 0) { arghint += String(" = ") + p_info.default_arguments[i - def_args].get_construct_string(); @@ -617,11 +623,11 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio } static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String, ScriptCodeCompletionOption> &r_list) { - const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; + const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; for (int i = 0; i < p_dir->get_file_count(); i++) { ScriptCodeCompletionOption option(p_dir->get_file_path(i), ScriptCodeCompletionOption::KIND_FILE_PATH); - option.insert_text = quote_style + option.display + quote_style; + option.insert_text = option.display.quote(quote_style); r_list.insert(option.display, option); } @@ -635,20 +641,20 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a if (p_argument == 3 || p_argument == 4) { // Slider hint. ScriptCodeCompletionOption slider1("or_greater", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); - slider1.insert_text = p_quote_style + slider1.display + p_quote_style; + slider1.insert_text = slider1.display.quote(p_quote_style); r_result.insert(slider1.display, slider1); ScriptCodeCompletionOption slider2("or_lesser", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); - slider2.insert_text = p_quote_style + slider2.display + p_quote_style; + slider2.insert_text = slider2.display.quote(p_quote_style); r_result.insert(slider2.display, slider2); } } else if (p_annotation->name == "@export_exp_easing") { if (p_argument == 0 || p_argument == 1) { // Easing hint. ScriptCodeCompletionOption hint1("attenuation", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); - hint1.insert_text = p_quote_style + hint1.display + p_quote_style; + hint1.insert_text = hint1.display.quote(p_quote_style); r_result.insert(hint1.display, hint1); ScriptCodeCompletionOption hint2("inout", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); - hint2.insert_text = p_quote_style + hint2.display + p_quote_style; + hint2.insert_text = hint2.display.quote(p_quote_style); r_result.insert(hint2.display, hint2); } } else if (p_annotation->name == "@export_node_path") { @@ -656,11 +662,11 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a r_result.insert(node.display, node); List<StringName> node_types; ClassDB::get_inheriters_from_class("Node", &node_types); - for (const List<StringName>::Element *E = node_types.front(); E != nullptr; E = E->next()) { - if (!ClassDB::is_class_exposed(E->get())) { + for (const StringName &E : node_types) { + if (!ClassDB::is_class_exposed(E)) { continue; } - ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_CLASS); + ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CLASS); r_result.insert(option.display, option); } } @@ -669,9 +675,9 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a static void _list_available_types(bool p_inherit_only, GDScriptParser::CompletionContext &p_context, Map<String, ScriptCodeCompletionOption> &r_result) { List<StringName> native_types; ClassDB::get_class_list(&native_types); - for (const List<StringName>::Element *E = native_types.front(); E != nullptr; E = E->next()) { - if (ClassDB::is_class_exposed(E->get()) && !Engine::get_singleton()->has_singleton(E->get())) { - ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_CLASS); + for (const StringName &E : native_types) { + if (ClassDB::is_class_exposed(E) && !Engine::get_singleton()->has_singleton(E)) { + ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CLASS); r_result.insert(option.display, option); } } @@ -681,8 +687,8 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio // Native enums from base class List<StringName> enums; ClassDB::get_enum_list(p_context.current_class->base_type.native_type, &enums); - for (const List<StringName>::Element *E = enums.front(); E != nullptr; E = E->next()) { - ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_ENUM); + for (const StringName &E : enums) { + ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_ENUM); r_result.insert(option.display, option); } } @@ -719,8 +725,8 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio // Global scripts List<StringName> global_classes; ScriptServer::get_global_class_list(&global_classes); - for (const List<StringName>::Element *E = global_classes.front(); E != nullptr; E = E->next()) { - ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_CLASS); + for (const StringName &E : global_classes) { + ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CLASS); r_result.insert(option.display, option); } @@ -859,8 +865,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base if (!_static) { List<PropertyInfo> members; scr->get_script_property_list(&members); - for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { - ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER); + for (const PropertyInfo &E : members) { + ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_MEMBER); r_result.insert(option.display, option); } } @@ -873,20 +879,20 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base List<MethodInfo> signals; scr->get_script_signal_list(&signals); - for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { - ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_SIGNAL); + for (const MethodInfo &E : signals) { + ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_SIGNAL); r_result.insert(option.display, option); } } List<MethodInfo> methods; scr->get_script_method_list(&methods); - for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - if (E->get().name.begins_with("@")) { + for (const MethodInfo &E : methods) { + if (E.name.begins_with("@")) { continue; } - ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION); - if (E->get().arguments.size()) { + ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_FUNCTION); + if (E.arguments.size()) { option.insert_text += "("; } else { option.insert_text += "()"; @@ -906,7 +912,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base } } break; case GDScriptParser::DataType::NATIVE: { - StringName type = GDScriptParser::get_real_class_name(base_type.native_type); + StringName type = base_type.native_type; if (!ClassDB::class_exists(type)) { return; } @@ -914,22 +920,22 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base if (!p_only_functions) { List<String> constants; ClassDB::get_integer_constant_list(type, &constants); - for (List<String>::Element *E = constants.front(); E; E = E->next()) { - ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_CONSTANT); + for (const String &E : constants) { + ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CONSTANT); r_result.insert(option.display, option); } if (!_static || Engine::get_singleton()->has_singleton(type)) { List<PropertyInfo> pinfo; ClassDB::get_property_list(type, &pinfo); - for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { - if (E->get().usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)) { + for (const PropertyInfo &E : pinfo) { + if (E.usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)) { continue; } - if (E->get().name.find("/") != -1) { + if (E.name.find("/") != -1) { continue; } - ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER); + ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_MEMBER); r_result.insert(option.display, option); } } @@ -939,12 +945,12 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base 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); - for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - if (E->get().name.begins_with("_")) { + for (const MethodInfo &E : methods) { + if (E.name.begins_with("_")) { continue; } - ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION); - if (E->get().arguments.size()) { + ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_FUNCTION); + if (E.arguments.size()) { option.insert_text += "("; } else { option.insert_text += "()"; @@ -971,9 +977,9 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base tmp.get_property_list(&members); } - for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { - if (String(E->get().name).find("/") == -1) { - ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER); + for (const PropertyInfo &E : members) { + if (String(E.name).find("/") == -1) { + ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_MEMBER); r_result.insert(option.display, option); } } @@ -981,9 +987,9 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base List<MethodInfo> methods; tmp.get_method_list(&methods); - for (const List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION); - if (E->get().arguments.size()) { + for (const MethodInfo &E : methods) { + ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_FUNCTION); + if (E.arguments.size()) { option.insert_text += "("; } else { option.insert_text += "()"; @@ -1013,9 +1019,9 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool List<StringName> functions; GDScriptUtilityFunctions::get_function_list(&functions); - for (const List<StringName>::Element *E = functions.front(); E; E = E->next()) { - MethodInfo function = GDScriptUtilityFunctions::get_function_info(E->get()); - ScriptCodeCompletionOption option(String(E->get()), ScriptCodeCompletionOption::KIND_FUNCTION); + for (const StringName &E : functions) { + MethodInfo function = GDScriptUtilityFunctions::get_function_info(E); + ScriptCodeCompletionOption option(String(E), ScriptCodeCompletionOption::KIND_FUNCTION); if (function.arguments.size() || (function.flags & METHOD_FLAG_VARARG)) { option.insert_text += "("; } else { @@ -1320,10 +1326,7 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, native_type.kind = GDScriptParser::DataType::NATIVE; native_type.native_type = native_type.script_type->get_instance_base_type(); if (!ClassDB::class_exists(native_type.native_type)) { - native_type.native_type = String("_") + native_type.native_type; - if (!ClassDB::class_exists(native_type.native_type)) { - native_type.kind = GDScriptParser::DataType::UNRESOLVED; - } + native_type.kind = GDScriptParser::DataType::UNRESOLVED; } } } @@ -1759,12 +1762,11 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, base_type = GDScriptParser::DataType(); break; } - StringName real_native = GDScriptParser::get_real_class_name(base_type.native_type); MethodInfo info; - if (ClassDB::get_method_info(real_native, p_context.current_function->identifier->name, &info)) { - for (const List<PropertyInfo>::Element *E = info.arguments.front(); E; E = E->next()) { - if (E->get().name == p_identifier) { - r_type = _type_from_property(E->get()); + if (ClassDB::get_method_info(base_type.native_type, p_context.current_function->identifier->name, &info)) { + for (const PropertyInfo &E : info.arguments) { + if (E.name == p_identifier) { + r_type = _type_from_property(E); return true; } } @@ -1830,13 +1832,12 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, } // Check ClassDB. - StringName class_name = GDScriptParser::get_real_class_name(p_identifier); - if (ClassDB::class_exists(class_name) && ClassDB::is_class_exposed(class_name)) { + if (ClassDB::class_exists(p_identifier) && ClassDB::is_class_exposed(p_identifier)) { r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; r_type.type.kind = GDScriptParser::DataType::NATIVE; r_type.type.native_type = p_identifier; r_type.type.is_constant = true; - r_type.type.is_meta_type = !Engine::get_singleton()->has_singleton(class_name); + r_type.type.is_meta_type = !Engine::get_singleton()->has_singleton(p_identifier); r_type.value = Variant(); } @@ -1926,8 +1927,7 @@ static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext & if (!is_static) { List<PropertyInfo> members; scr->get_script_property_list(&members); - for (const List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { - const PropertyInfo &prop = E->get(); + for (const PropertyInfo &prop : members) { if (prop.name == p_identifier) { r_type = _type_from_property(prop); return true; @@ -1946,7 +1946,7 @@ static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext & } } break; case GDScriptParser::DataType::NATIVE: { - StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type); + StringName class_name = base_type.native_type; if (!ClassDB::class_exists(class_name)) { return false; } @@ -2090,8 +2090,7 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex if (scr.is_valid()) { List<MethodInfo> methods; scr->get_script_method_list(&methods); - for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - MethodInfo &mi = E->get(); + for (const MethodInfo &mi : methods) { if (mi.name == p_method) { r_type = _type_from_property(mi.return_val); return true; @@ -2109,11 +2108,10 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex } } break; case GDScriptParser::DataType::NATIVE: { - StringName native = GDScriptParser::get_real_class_name(base_type.native_type); - if (!ClassDB::class_exists(native)) { + if (!ClassDB::class_exists(base_type.native_type)) { return false; } - MethodBind *mb = ClassDB::get_method(native, p_method); + MethodBind *mb = ClassDB::get_method(base_type.native_type, p_method); if (mb) { r_type = _type_from_property(mb->get_return_info()); return true; @@ -2131,8 +2129,7 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex List<MethodInfo> methods; tmp.get_method_list(&methods); - for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - MethodInfo &mi = E->get(); + for (const MethodInfo &mi : methods) { if (mi.name == p_method) { r_type = _type_from_property(mi.return_val); return true; @@ -2177,8 +2174,8 @@ static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_co List<StringName> enum_constants; ClassDB::get_enum_constants(class_name, enum_name, &enum_constants); - for (List<StringName>::Element *E = enum_constants.front(); E; E = E->next()) { - String candidate = class_name + "." + E->get(); + for (const StringName &E : enum_constants) { + String candidate = class_name + "." + E; ScriptCodeCompletionOption option(candidate, ScriptCodeCompletionOption::KIND_ENUM); r_result.insert(option.display, option); } @@ -2189,7 +2186,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c Variant base = p_base.value; GDScriptParser::DataType base_type = p_base.type; - const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; + const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; while (base_type.is_set() && !base_type.is_variant()) { switch (base_type.kind) { @@ -2206,7 +2203,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c base_type = base_type.class_type->base_type; } break; case GDScriptParser::DataType::NATIVE: { - StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type); + StringName class_name = base_type.native_type; if (!ClassDB::class_exists(class_name)) { base_type.kind = GDScriptParser::DataType::UNRESOLVED; break; @@ -2222,8 +2219,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c if (obj) { List<String> options; obj->get_argument_options(p_method, p_argidx, &options); - for (List<String>::Element *F = options.front(); F; F = F->next()) { - ScriptCodeCompletionOption option(F->get(), ScriptCodeCompletionOption::KIND_FUNCTION); + for (const String &F : options) { + ScriptCodeCompletionOption option(F, ScriptCodeCompletionOption::KIND_FUNCTION); r_result.insert(option.display, option); } } @@ -2244,14 +2241,14 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c List<PropertyInfo> props; ProjectSettings::get_singleton()->get_property_list(&props); - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - String s = E->get().name; + for (const PropertyInfo &E : props) { + String s = E.name; if (!s.begins_with("autoload/")) { continue; } String name = s.get_slice("/", 1); ScriptCodeCompletionOption option("/root/" + name, ScriptCodeCompletionOption::KIND_NODE_PATH); - option.insert_text = quote_style + option.display + quote_style; + option.insert_text = option.display.quote(quote_style); r_result.insert(option.display, option); } } @@ -2260,14 +2257,14 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c // Get input actions List<PropertyInfo> props; ProjectSettings::get_singleton()->get_property_list(&props); - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - String s = E->get().name; + for (const PropertyInfo &E : props) { + String s = E.name; if (!s.begins_with("input/")) { continue; } String name = s.get_slice("/", 1); ScriptCodeCompletionOption option(name, ScriptCodeCompletionOption::KIND_CONSTANT); - option.insert_text = quote_style + option.display + quote_style; + option.insert_text = option.display.quote(quote_style); r_result.insert(option.display, option); } } @@ -2285,9 +2282,9 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c List<MethodInfo> methods; base.get_method_list(&methods); - for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - if (E->get().name == p_method) { - r_arghint = _make_arguments_hint(E->get(), p_argidx); + for (const MethodInfo &E : methods) { + if (E.name == p_method) { + r_arghint = _make_arguments_hint(E, p_argidx); return; } } @@ -2302,8 +2299,6 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c } static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptParser::Node *p_call, int p_argidx, Map<String, ScriptCodeCompletionOption> &r_result, bool &r_forced, String &r_arghint) { - const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; - if (p_call->type == GDScriptParser::Node::PRELOAD) { if (p_argidx == 0 && bool(EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths"))) { _get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), r_result); @@ -2334,14 +2329,14 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c Variant::get_constructor_list(GDScriptParser::get_builtin_type(call->function_name), &constructors); int i = 0; - for (List<MethodInfo>::Element *E = constructors.front(); E; E = E->next()) { - if (p_argidx >= E->get().arguments.size()) { + for (const MethodInfo &E : constructors) { + if (p_argidx >= E.arguments.size()) { continue; } if (i > 0) { r_arghint += "\n"; } - r_arghint += _make_arguments_hint(E->get(), p_argidx); + r_arghint += _make_arguments_hint(E, p_argidx); i++; } return; @@ -2378,8 +2373,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c r_forced = r_result.size() > 0; } -Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) { - const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; +::Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) { + const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; GDScriptParser parser; GDScriptAnalyzer analyzer(&parser); @@ -2400,9 +2395,9 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path case GDScriptParser::COMPLETION_ANNOTATION: { List<MethodInfo> annotations; parser.get_annotation_list(&annotations); - for (const List<MethodInfo>::Element *E = annotations.front(); E != nullptr; E = E->next()) { - ScriptCodeCompletionOption option(E->get().name.substr(1), ScriptCodeCompletionOption::KIND_PLAIN_TEXT); - if (E->get().arguments.size() > 0) { + for (const MethodInfo &E : annotations) { + ScriptCodeCompletionOption option(E.name.substr(1), ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + if (E.arguments.size() > 0) { option.insert_text += "("; } options.insert(option.display, option); @@ -2420,10 +2415,10 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: { List<StringName> constants; Variant::get_constants_for_type(completion_context.builtin_type, &constants); - for (const List<StringName>::Element *E = constants.front(); E != nullptr; E = E->next()) { - ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_CONSTANT); + for (const StringName &E : constants) { + ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CONSTANT); bool valid = false; - Variant default_value = Variant::get_constant_value(completion_context.builtin_type, E->get(), &valid); + Variant default_value = Variant::get_constant_value(completion_context.builtin_type, E, &valid); if (valid) { option.default_value = default_value; } @@ -2591,7 +2586,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path break; } - StringName class_name = GDScriptParser::get_real_class_name(native_type.native_type); + StringName class_name = native_type.native_type; if (!ClassDB::class_exists(class_name)) { break; } @@ -2600,8 +2595,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path List<MethodInfo> virtual_methods; ClassDB::get_virtual_methods(class_name, &virtual_methods); - for (List<MethodInfo>::Element *E = virtual_methods.front(); E; E = E->next()) { - MethodInfo &mi = E->get(); + for (const MethodInfo &mi : virtual_methods) { String method_hint = mi.name; if (method_hint.find(":") != -1) { method_hint = method_hint.get_slice(":", 0); @@ -2650,8 +2644,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path List<String> opts; p_owner->get_argument_options("get_node", 0, &opts); - for (List<String>::Element *E = opts.front(); E; E = E->next()) { - String opt = E->get().strip_edges(); + for (const String &E : opts) { + String opt = E.strip_edges(); if (opt.is_quoted()) { r_forced = true; String idopt = opt.unquote(); @@ -2669,8 +2663,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) { - String name = E->key(); - ScriptCodeCompletionOption option(quote_style + "/root/" + name + quote_style, ScriptCodeCompletionOption::KIND_NODE_PATH); + String path = "/root/" + E->key(); + ScriptCodeCompletionOption option(path.quote(quote_style), ScriptCodeCompletionOption::KIND_NODE_PATH); options.insert(option.display, option); } } @@ -2703,10 +2697,10 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path String GDScriptLanguage::_get_indentation() const { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { - bool use_space_indentation = EDITOR_DEF("text_editor/indent/type", false); + bool use_space_indentation = EDITOR_DEF("text_editor/behavior/indent/type", false); if (use_space_indentation) { - int indent_size = EDITOR_DEF("text_editor/indent/size", 4); + int indent_size = EDITOR_DEF("text_editor/behavior/indent/size", 4); String space_indent = ""; for (int i = 0; i < indent_size; i++) { @@ -2793,6 +2787,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co if (base_type.class_type->has_member(p_symbol)) { 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; return OK; } base_type = base_type.class_type->base_type; @@ -2820,7 +2815,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co } } break; case GDScriptParser::DataType::NATIVE: { - StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type); + StringName class_name = base_type.native_type; if (!ClassDB::class_exists(class_name)) { base_type.kind = GDScriptParser::DataType::UNRESOLVED; break; @@ -2835,8 +2830,8 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co List<MethodInfo> virtual_methods; ClassDB::get_virtual_methods(class_name, &virtual_methods, true); - for (List<MethodInfo>::Element *E = virtual_methods.front(); E; E = E->next()) { - if (E->get().name == p_symbol) { + for (const MethodInfo &E : virtual_methods) { + if (E.name == p_symbol) { r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; r_result.class_name = base_type.native_type; r_result.class_member = p_symbol; @@ -2854,8 +2849,8 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co List<String> constants; ClassDB::get_integer_constant_list(class_name, &constants, true); - for (List<String>::Element *E = constants.front(); E; E = E->next()) { - if (E->get() == p_symbol) { + for (const String &E : constants) { + if (E == p_symbol) { r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; r_result.class_name = base_type.native_type; r_result.class_member = p_symbol; @@ -2872,11 +2867,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co StringName parent = ClassDB::get_parent_class(class_name); if (parent != StringName()) { - if (String(parent).begins_with("_")) { - base_type.native_type = String(parent).substr(1); - } else { - base_type.native_type = parent; - } + base_type.native_type = parent; } else { base_type.kind = GDScriptParser::DataType::UNRESOLVED; } @@ -2894,7 +2885,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co Variant v; REF v_ref; if (base_type.builtin_type == Variant::OBJECT) { - v_ref.instance(); + v_ref.instantiate(); v = v_ref; } else { Callable::CallError err; @@ -2929,19 +2920,12 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co return ERR_CANT_RESOLVE; } -Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) { - //before parsing, try the usual stuff +::Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) { + // Before parsing, try the usual stuff if (ClassDB::class_exists(p_symbol)) { r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS; r_result.class_name = p_symbol; return OK; - } else { - String under_prefix = "_" + p_symbol; - if (ClassDB::class_exists(under_prefix)) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS; - r_result.class_name = p_symbol; - return OK; - } } for (int i = 0; i < Variant::VARIANT_MAX; i++) { @@ -3032,9 +3016,9 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol if (!is_function) { // Guess in autoloads as singletons. if (ProjectSettings::get_singleton()->has_autoload(p_symbol)) { - const ProjectSettings::AutoloadInfo &singleton = ProjectSettings::get_singleton()->get_autoload(p_symbol); - if (singleton.is_singleton) { - String script = singleton.path; + const ProjectSettings::AutoloadInfo &autoload = ProjectSettings::get_singleton()->get_autoload(p_symbol); + if (autoload.is_singleton) { + String script = autoload.path; if (!script.ends_with(".gd")) { // Not a script, try find the script anyway, // may have some success. diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index 78399114a5..876c508689 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -94,8 +94,7 @@ struct _GDFKCS { void GDScriptFunction::debug_get_stack_member_state(int p_line, List<Pair<StringName, int>> *r_stackvars) const { int oc = 0; Map<StringName, _GDFKC> sdmap; - for (const List<StackDebug>::Element *E = stack_debug.front(); E; E = E->next()) { - const StackDebug &sd = E->get(); + for (const StackDebug &sd : stack_debug) { if (sd.line > p_line) { break; } @@ -131,10 +130,10 @@ void GDScriptFunction::debug_get_stack_member_state(int p_line, List<Pair<String stackpositions.sort(); - for (List<_GDFKCS>::Element *E = stackpositions.front(); E; E = E->next()) { + for (_GDFKCS &E : stackpositions) { Pair<StringName, int> p; - p.first = E->get().id; - p.second = E->get().pos; + p.first = E.id; + p.second = E.pos; r_stackvars->push_back(p); } } @@ -262,9 +261,9 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) { if (completed) { if (first_state.is_valid()) { - first_state->emit_signal("completed", ret); + first_state->emit_signal(SNAME("completed"), ret); } else { - emit_signal("completed", ret); + emit_signal(SNAME("completed"), ret); } #ifdef DEBUG_ENABLED diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index 553c2ecc01..87d8c03494 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -111,11 +111,7 @@ public: } if (!ClassDB::is_parent_class(obj->get_class_name(), native_type)) { - // Try with underscore prefix - StringName underscore_native_type = "_" + native_type; - if (!ClassDB::is_parent_class(obj->get_class_name(), underscore_native_type)) { - return false; - } + return false; } return true; } break; @@ -472,7 +468,7 @@ private: int _initial_line = 0; bool _static = false; - MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; + MultiplayerAPI::RPCConfig rpc_config; GDScript *_script = nullptr; @@ -592,7 +588,7 @@ public: void disassemble(const Vector<String> &p_code_lines) const; #endif - _FORCE_INLINE_ MultiplayerAPI::RPCMode get_rpc_mode() const { return rpc_mode; } + _FORCE_INLINE_ MultiplayerAPI::RPCConfig get_rpc_config() const { return rpc_config; } GDScriptFunction(); ~GDScriptFunction(); }; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index ba208ebfe8..af872e49e2 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -94,50 +94,15 @@ Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) { return Variant::VARIANT_MAX; } -// TODO: Move this to a central location (maybe core?). -static HashMap<StringName, StringName> underscore_map; -static const char *underscore_classes[] = { - "ClassDB", - "Directory", - "Engine", - "File", - "Geometry", - "GodotSharp", - "JSON", - "Marshalls", - "Mutex", - "OS", - "ResourceLoader", - "ResourceSaver", - "Semaphore", - "Thread", - "VisualScriptEditor", - nullptr, -}; -StringName GDScriptParser::get_real_class_name(const StringName &p_source) { - if (underscore_map.is_empty()) { - const char **class_name = underscore_classes; - while (*class_name != nullptr) { - underscore_map[*class_name] = String("_") + *class_name; - class_name++; - } - } - if (underscore_map.has(p_source)) { - return underscore_map[p_source]; - } - return p_source; -} - void GDScriptParser::cleanup() { builtin_types.clear(); - underscore_map.clear(); } void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const { List<StringName> keys; valid_annotations.get_key_list(&keys); - for (const List<StringName>::Element *E = keys.front(); E != nullptr; E = E->next()) { - r_annotations->push_back(valid_annotations[E->get()].info); + for (const StringName &E : keys) { + r_annotations->push_back(valid_annotations[E].info); } } @@ -157,7 +122,6 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@export_multiline"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_MULTILINE_TEXT, Variant::STRING>); register_annotation(MethodInfo("@export_placeholder"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_PLACEHOLDER_TEXT, Variant::STRING>); register_annotation(MethodInfo("@export_range", { Variant::FLOAT, "min" }, { Variant::FLOAT, "max" }, { Variant::FLOAT, "step" }, { Variant::STRING, "slider1" }, { Variant::STRING, "slider2" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_RANGE, Variant::FLOAT>, 3); - register_annotation(MethodInfo("@export_exp_range", { Variant::FLOAT, "min" }, { Variant::FLOAT, "max" }, { Variant::FLOAT, "step" }, { Variant::STRING, "slider1" }, { Variant::STRING, "slider2" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_EXP_RANGE, Variant::FLOAT>, 3); register_annotation(MethodInfo("@export_exp_easing", { Variant::STRING, "hint1" }, { Variant::STRING, "hint2" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_EXP_EASING, Variant::FLOAT>, 2); register_annotation(MethodInfo("@export_color_no_alpha"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_COLOR_NO_ALPHA, Variant::COLOR>); register_annotation(MethodInfo("@export_node_path", { Variant::STRING, "type" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NODE_PATH_VALID_TYPES, Variant::NODE_PATH>, 1, true); @@ -169,12 +133,7 @@ GDScriptParser::GDScriptParser() { 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>); // Networking. - register_annotation(MethodInfo("@remote"), AnnotationInfo::VARIABLE | AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_REMOTE>); - register_annotation(MethodInfo("@master"), AnnotationInfo::VARIABLE | AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_MASTER>); - register_annotation(MethodInfo("@puppet"), AnnotationInfo::VARIABLE | AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_PUPPET>); - register_annotation(MethodInfo("@remotesync"), AnnotationInfo::VARIABLE | AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_REMOTESYNC>); - register_annotation(MethodInfo("@mastersync"), AnnotationInfo::VARIABLE | AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_MASTERSYNC>); - register_annotation(MethodInfo("@puppetsync"), AnnotationInfo::VARIABLE | AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_PUPPETSYNC>); + register_annotation(MethodInfo("@rpc", { Variant::STRING, "mode" }, { Variant::STRING, "sync" }, { Variant::STRING, "transfer_mode" }, { Variant::INT, "transfer_channel" }), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_PUPPET>, 4, true); // TODO: Warning annotations. } @@ -254,7 +213,7 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_ warning.rightmost_column = p_source->rightmost_column; List<GDScriptWarning>::Element *before = nullptr; - for (List<GDScriptWarning>::Element *E = warnings.front(); E != nullptr; E = E->next()) { + for (List<GDScriptWarning>::Element *E = warnings.front(); E; E = E->next()) { if (E->get().start_line > warning.start_line) { break; } @@ -343,7 +302,7 @@ Error GDScriptParser::parse(const String &p_source_code, const String &p_script_ int tab_size = 4; #ifdef TOOLS_ENABLED if (EditorSettings::get_singleton()) { - tab_size = EditorSettings::get_singleton()->get_setting("text_editor/indent/size"); + tab_size = EditorSettings::get_singleton()->get_setting("text_editor/behavior/indent/size"); } #endif // TOOLS_ENABLED @@ -1158,7 +1117,6 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() { } item.custom_value = value; } - item.rightmost_column = previous.rightmost_column; item.index = enum_node->values.size(); enum_node->values.push_back(item); @@ -1338,8 +1296,7 @@ GDScriptParser::AnnotationNode *GDScriptParser::parse_annotation(uint32_t p_vali } void GDScriptParser::clear_unused_annotations() { - for (const List<AnnotationNode *>::Element *E = annotation_stack.front(); E != nullptr; E = E->next()) { - AnnotationNode *annotation = E->get(); + for (const AnnotationNode *annotation : annotation_stack) { push_error(vformat(R"(Annotation "%s" does not precedes a valid target, so it will have no effect.)", annotation->name), annotation); } @@ -1802,8 +1759,8 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() { List<StringName> binds; branch->patterns[0]->binds.get_key_list(&binds); - for (List<StringName>::Element *E = binds.front(); E != nullptr; E = E->next()) { - SuiteNode::Local local(branch->patterns[0]->binds[E->get()], current_function); + for (const StringName &E : binds) { + SuiteNode::Local local(branch->patterns[0]->binds[E], current_function); suite->add_local(local); } } @@ -2129,10 +2086,10 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_builtin_constant(Expressio constant->value = Math_TAU; break; case GDScriptTokenizer::Token::CONST_INF: - constant->value = Math_INF; + constant->value = INFINITY; break; case GDScriptTokenizer::Token::CONST_NAN: - constant->value = Math_NAN; + constant->value = NAN; break; default: return nullptr; // Unreachable. @@ -2487,7 +2444,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode switch (dictionary->style) { case DictionaryNode::LUA_TABLE: if (key != nullptr && key->type != Node::IDENTIFIER) { - push_error("Expected identifier as dictionary key."); + push_error("Expected identifier as LUA-style dictionary key."); + advance(); + break; } if (!match(GDScriptTokenizer::Token::EQUAL)) { if (match(GDScriptTokenizer::Token::COLON)) { @@ -2991,7 +2950,7 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String & } else { /* Syntax: - @tutorial ( The Title Here ) : http://the.url/ + @tutorial ( The Title Here ) : https://the.url/ ^ open ^ close ^ colon ^ url */ int open_bracket_pos = begin_scan, close_bracket_pos = 0; @@ -3368,10 +3327,10 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node variable->export_info.hint_string = Variant::get_type_name(export_type.builtin_type); break; case GDScriptParser::DataType::NATIVE: - if (ClassDB::is_parent_class(get_real_class_name(export_type.native_type), "Resource")) { + if (ClassDB::is_parent_class(export_type.native_type, "Resource")) { variable->export_info.type = Variant::OBJECT; variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE; - variable->export_info.hint_string = get_real_class_name(export_type.native_type); + variable->export_info.hint_string = export_type.native_type; } else { push_error(R"(Export type can only be built-in, a resource, or an enum.)", variable); return false; @@ -3431,27 +3390,60 @@ template <MultiplayerAPI::RPCMode t_mode> bool GDScriptParser::network_annotations(const AnnotationNode *p_annotation, Node *p_node) { ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE && p_node->type != Node::FUNCTION, false, vformat(R"("%s" annotation can only be applied to variables and functions.)", p_annotation->name)); - switch (p_node->type) { - case Node::VARIABLE: { - VariableNode *variable = static_cast<VariableNode *>(p_node); - if (variable->rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) { - push_error(R"(RPC annotations can only be used once per variable.)", p_annotation); + MultiplayerAPI::RPCConfig rpc_config; + rpc_config.rpc_mode = t_mode; + for (int i = 0; i < p_annotation->resolved_arguments.size(); i++) { + if (i == 0) { + String mode = p_annotation->resolved_arguments[i].operator String(); + if (mode == "any") { + rpc_config.rpc_mode = MultiplayerAPI::RPC_MODE_REMOTE; + } else if (mode == "master") { + rpc_config.rpc_mode = MultiplayerAPI::RPC_MODE_MASTER; + } else if (mode == "puppet") { + rpc_config.rpc_mode = MultiplayerAPI::RPC_MODE_PUPPET; + } else { + push_error(R"(Invalid RPC mode. Must be one of: 'any', 'master', or 'puppet')", p_annotation); + return false; } - variable->rpc_mode = t_mode; - break; + } else if (i == 1) { + String sync = p_annotation->resolved_arguments[i].operator String(); + if (sync == "sync") { + rpc_config.sync = true; + } else if (sync == "nosync") { + rpc_config.sync = false; + } else { + push_error(R"(Invalid RPC sync mode. Must be one of: 'sync' or 'nosync')", p_annotation); + return false; + } + } else if (i == 2) { + String mode = p_annotation->resolved_arguments[i].operator String(); + if (mode == "reliable") { + rpc_config.transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE; + } else if (mode == "unreliable") { + rpc_config.transfer_mode = MultiplayerPeer::TRANSFER_MODE_UNRELIABLE; + } else if (mode == "ordered") { + rpc_config.transfer_mode = MultiplayerPeer::TRANSFER_MODE_UNRELIABLE_ORDERED; + } else { + push_error(R"(Invalid RPC transfer mode. Must be one of: 'reliable', 'unreliable', 'ordered')", p_annotation); + return false; + } + } else if (i == 3) { + rpc_config.channel = p_annotation->resolved_arguments[i].operator int(); } + } + switch (p_node->type) { case Node::FUNCTION: { FunctionNode *function = static_cast<FunctionNode *>(p_node); - if (function->rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) { + if (function->rpc_config.rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) { push_error(R"(RPC annotations can only be used once per function.)", p_annotation); + return false; } - function->rpc_mode = t_mode; + function->rpc_config = rpc_config; break; } default: return false; // Unreachable. } - return true; } @@ -3591,7 +3583,7 @@ void GDScriptParser::TreePrinter::push_text(const String &p_text) { printed += p_text; } -void GDScriptParser::TreePrinter::print_annotation(AnnotationNode *p_annotation) { +void GDScriptParser::TreePrinter::print_annotation(const AnnotationNode *p_annotation) { push_text(p_annotation->name); push_text(" ("); for (int i = 0; i < p_annotation->arguments.size(); i++) { @@ -3966,8 +3958,8 @@ void GDScriptParser::TreePrinter::print_for(ForNode *p_for) { } void GDScriptParser::TreePrinter::print_function(FunctionNode *p_function, const String &p_context) { - for (const List<AnnotationNode *>::Element *E = p_function->annotations.front(); E != nullptr; E = E->next()) { - print_annotation(E->get()); + for (const AnnotationNode *E : p_function->annotations) { + print_annotation(E); } push_text(p_context); push_text(" "); @@ -4306,8 +4298,8 @@ void GDScriptParser::TreePrinter::print_unary_op(UnaryOpNode *p_unary_op) { } void GDScriptParser::TreePrinter::print_variable(VariableNode *p_variable) { - for (const List<AnnotationNode *>::Element *E = p_variable->annotations.front(); E != nullptr; E = E->next()) { - print_annotation(E->get()); + for (const AnnotationNode *E : p_variable->annotations) { + print_annotation(E); } push_text("Variable "); diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 9e0b60a407..0bce8d7ddd 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -729,7 +729,7 @@ public: SuiteNode *body = nullptr; bool is_static = false; bool is_coroutine = false; - MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; + MultiplayerAPI::RPCConfig rpc_config; MethodInfo info; LambdaNode *source_lambda = nullptr; #ifdef TOOLS_ENABLED @@ -1117,7 +1117,6 @@ public: bool exported = false; bool onready = false; PropertyInfo export_info; - MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; int assignments = 0; int usages = 0; bool use_conversion_assign = false; @@ -1400,7 +1399,6 @@ public: ClassNode *get_tree() const { return head; } bool is_tool() const { return _is_tool; } static Variant::Type get_builtin_type(const StringName &p_type); - static StringName get_real_class_name(const StringName &p_source); CompletionContext get_completion_context() const { return completion_context; } CompletionCall get_completion_call() const { return completion_call; } @@ -1432,7 +1430,7 @@ public: void push_line(const String &p_line = String()); void push_text(const String &p_text); - void print_annotation(AnnotationNode *p_annotation); + void print_annotation(const AnnotationNode *p_annotation); void print_array(ArrayNode *p_array); void print_assert(AssertNode *p_assert); void print_assignment(AssignmentNode *p_assignment); diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index 3f14156dfa..d4a098811a 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -1440,7 +1440,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() { GDScriptTokenizer::GDScriptTokenizer() { #ifdef TOOLS_ENABLED if (EditorSettings::get_singleton()) { - tab_size = EditorSettings::get_singleton()->get_setting("text_editor/indent/size"); + tab_size = EditorSettings::get_singleton()->get_setting("text_editor/behavior/indent/size"); } #endif // TOOLS_ENABLED } diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp index 64c629662c..62531473c3 100644 --- a/modules/gdscript/gdscript_utility_functions.cpp +++ b/modules/gdscript/gdscript_utility_functions.cpp @@ -706,8 +706,8 @@ bool GDScriptUtilityFunctions::function_exists(const StringName &p_function) { } void GDScriptUtilityFunctions::get_function_list(List<StringName> *r_functions) { - for (const List<StringName>::Element *E = utility_function_name_table.front(); E; E = E->next()) { - r_functions->push_back(E->get()); + for (const StringName &E : utility_function_name_table) { + r_functions->push_back(E); } } diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 8a261a88e3..882256b7e3 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -174,7 +174,7 @@ void (*type_init_function_table[])(Variant *) = { &VariantInitializer<StringName>::init, // STRING_NAME. &VariantInitializer<NodePath>::init, // NODE_PATH. &VariantInitializer<RID>::init, // RID. - &VariantTypeAdjust<Object *>::adjust, // OBJECT. + &VariantInitializer<Object *>::init, // OBJECT. &VariantInitializer<Callable>::init, // CALLABLE. &VariantInitializer<Signal>::init, // SIGNAL. &VariantInitializer<Dictionary>::init, // DICTIONARY. diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 15236d900d..d106b3b541 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -32,7 +32,6 @@ #include "../gdscript.h" #include "../gdscript_analyzer.h" -#include "core/io/json.h" #include "gdscript_language_protocol.h" #include "gdscript_workspace.h" @@ -40,8 +39,7 @@ void ExtendGDScriptParser::update_diagnostics() { diagnostics.clear(); const List<ParserError> &errors = get_errors(); - for (const List<ParserError>::Element *E = errors.front(); E != nullptr; E = E->next()) { - const ParserError &error = E->get(); + for (const ParserError &error : errors) { lsp::Diagnostic diagnostic; diagnostic.severity = lsp::DiagnosticSeverity::Error; diagnostic.message = error.message; @@ -62,8 +60,7 @@ void ExtendGDScriptParser::update_diagnostics() { } const List<GDScriptWarning> &warnings = get_warnings(); - for (const List<GDScriptWarning>::Element *E = warnings.front(); E; E = E->next()) { - const GDScriptWarning &warning = E->get(); + for (const GDScriptWarning &warning : warnings) { lsp::Diagnostic diagnostic; diagnostic.severity = lsp::DiagnosticSeverity::Warning; diagnostic.message = "(" + warning.get_name() + "): " + warning.get_message(); @@ -153,9 +150,9 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p } r_symbol.kind = lsp::SymbolKind::Class; r_symbol.deprecated = false; - r_symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_class->start_line); - r_symbol.range.start.character = LINE_NUMBER_TO_INDEX(p_class->start_column); - r_symbol.range.end.line = LINE_NUMBER_TO_INDEX(p_class->end_line); + r_symbol.range.start.line = p_class->start_line; + r_symbol.range.start.character = p_class->start_column; + r_symbol.range.end.line = lines.size(); r_symbol.selectionRange.start.line = r_symbol.range.start.line; r_symbol.detail = "class " + r_symbol.name; bool is_root_class = &r_symbol == &class_symbol; @@ -168,7 +165,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p case ClassNode::Member::VARIABLE: { lsp::DocumentSymbol symbol; symbol.name = m.variable->identifier->name; - symbol.kind = lsp::SymbolKind::Variable; + symbol.kind = m.variable->property == VariableNode::PropertyStyle::PROP_NONE ? lsp::SymbolKind::Variable : lsp::SymbolKind::Property; symbol.deprecated = false; symbol.range.start.line = LINE_NUMBER_TO_INDEX(m.variable->start_line); symbol.range.start.character = LINE_NUMBER_TO_INDEX(m.variable->start_column); @@ -183,7 +180,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p symbol.detail += ": " + m.get_datatype().to_string(); } if (m.variable->initializer != nullptr && m.variable->initializer->is_constant) { - symbol.detail += " = " + JSON::print(m.variable->initializer->reduced_value); + symbol.detail += " = " + m.variable->initializer->reduced_value.to_json_string(); } symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(m.variable->start_line)); @@ -224,10 +221,10 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p } } } else { - value_text = JSON::print(default_value); + value_text = default_value.to_json_string(); } } else { - value_text = JSON::print(default_value); + value_text = default_value.to_json_string(); } if (!value_text.is_empty()) { symbol.detail += " = " + value_text; @@ -320,7 +317,7 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN const String uri = get_uri(); r_symbol.name = p_func->identifier->name; - r_symbol.kind = lsp::SymbolKind::Function; + r_symbol.kind = p_func->is_static ? lsp::SymbolKind::Function : lsp::SymbolKind::Method; r_symbol.detail = "func " + String(p_func->identifier->name) + "("; r_symbol.deprecated = false; r_symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_func->start_line); @@ -353,8 +350,7 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN parameters += ": " + parameter->get_datatype().to_string(); } if (parameter->default_value != nullptr) { - String value = JSON::print(parameter->default_value->reduced_value); - parameters += " = " + value; + parameters += " = " + parameter->default_value->reduced_value.to_json_string(); } } r_symbol.detail += parameters + ")"; @@ -469,8 +465,8 @@ String ExtendGDScriptParser::parse_documentation(int p_line, bool p_docs_down) { } String doc; - for (List<String>::Element *E = doc_lines.front(); E; E = E->next()) { - doc += E->get() + "\n"; + for (const String &E : doc_lines) { + doc += E + "\n"; } return doc; } @@ -697,7 +693,9 @@ Dictionary ExtendGDScriptParser::dump_function_api(const GDScriptParser::Functio ERR_FAIL_NULL_V(p_func, func); func["name"] = p_func->identifier->name; func["return_type"] = p_func->get_datatype().to_string(); - func["rpc_mode"] = p_func->rpc_mode; + func["rpc_mode"] = p_func->rpc_config.rpc_mode; + func["rpc_transfer_mode"] = p_func->rpc_config.transfer_mode; + func["rpc_transfer_channel"] = p_func->rpc_config.channel; Array parameters; for (int i = 0; i < p_func->parameters.size(); i++) { Dictionary arg; diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp index c16a7fa889..b6c48468f5 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.cpp +++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp @@ -31,7 +31,6 @@ #include "gdscript_language_protocol.h" #include "core/config/project_settings.h" -#include "core/io/json.h" #include "editor/doc_tools.h" #include "editor/editor_log.h" #include "editor/editor_node.h" @@ -129,13 +128,13 @@ Error GDScriptLanguageProtocol::on_client_connected() { peer->connection = tcp_peer; clients.set(next_client_id, peer); next_client_id++; - EditorNode::get_log()->add_message("Connection Taken", EditorLog::MSG_TYPE_EDITOR); + EditorNode::get_log()->add_message("[LSP] Connection Taken", EditorLog::MSG_TYPE_EDITOR); return OK; } void GDScriptLanguageProtocol::on_client_disconnected(const int &p_client_id) { clients.erase(p_client_id); - EditorNode::get_log()->add_message("Disconnected", EditorLog::MSG_TYPE_EDITOR); + EditorNode::get_log()->add_message("[LSP] Disconnected", EditorLog::MSG_TYPE_EDITOR); } String GDScriptLanguageProtocol::process_message(const String &p_text) { @@ -194,7 +193,7 @@ Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) { vformat("GDScriptLanguageProtocol: Can't initialize invalid peer '%d'.", latest_client_id)); Ref<LSPeer> peer = clients.get(latest_client_id); if (peer != nullptr) { - String msg = JSON::print(request); + String msg = Variant(request).to_json_string(); msg = format_output(msg); (*peer)->res_queue.push_back(msg.utf8()); } @@ -280,7 +279,7 @@ void GDScriptLanguageProtocol::notify_client(const String &p_method, const Varia ERR_FAIL_COND(peer == nullptr); Dictionary message = make_notification(p_method, p_params); - String msg = JSON::print(message); + String msg = Variant(message).to_json_string(); msg = format_output(msg); peer->res_queue.push_back(msg.utf8()); } @@ -294,10 +293,10 @@ bool GDScriptLanguageProtocol::is_goto_native_symbols_enabled() const { } GDScriptLanguageProtocol::GDScriptLanguageProtocol() { - server.instance(); + server.instantiate(); singleton = this; - workspace.instance(); - text_document.instance(); + workspace.instantiate(); + text_document.instantiate(); set_scope("textDocument", text_document.ptr()); set_scope("completionItem", text_document.ptr()); set_scope("workspace", workspace.ptr()); diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h index 969c38eab6..5a2dd55c46 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.h +++ b/modules/gdscript/language_server/gdscript_language_protocol.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GDSCRIPT_PROTOCAL_SERVER_H -#define GDSCRIPT_PROTOCAL_SERVER_H +#ifndef GDSCRIPT_LANGUAGE_PROTOCOL_H +#define GDSCRIPT_LANGUAGE_PROTOCOL_H #include "core/io/stream_peer.h" #include "core/io/stream_peer_tcp.h" @@ -37,7 +37,13 @@ #include "gdscript_text_document.h" #include "gdscript_workspace.h" #include "lsp.hpp" + +#include "modules/modules_enabled.gen.h" +#ifdef MODULE_JSONRPC_ENABLED #include "modules/jsonrpc/jsonrpc.h" +#else +#error "Can't build GDScript LSP without JSONRPC module." +#endif #define LSP_MAX_BUFFER_SIZE 4194304 #define LSP_MAX_CLIENTS 8 @@ -108,4 +114,4 @@ public: GDScriptLanguageProtocol(); }; -#endif +#endif // GDSCRIPT_LANGUAGE_PROTOCOL_H diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp index 33597c286f..c47164d95b 100644 --- a/modules/gdscript/language_server/gdscript_language_server.cpp +++ b/modules/gdscript/language_server/gdscript_language_server.cpp @@ -101,7 +101,7 @@ void GDScriptLanguageServer::stop() { } void register_lsp_types() { - ClassDB::register_class<GDScriptLanguageProtocol>(); - ClassDB::register_class<GDScriptTextDocument>(); - ClassDB::register_class<GDScriptWorkspace>(); + GDREGISTER_CLASS(GDScriptLanguageProtocol); + GDREGISTER_CLASS(GDScriptTextDocument); + GDREGISTER_CLASS(GDScriptWorkspace); } diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index 030633274c..03b1e3fa44 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -40,11 +40,14 @@ void GDScriptTextDocument::_bind_methods() { ClassDB::bind_method(D_METHOD("didOpen"), &GDScriptTextDocument::didOpen); + ClassDB::bind_method(D_METHOD("didClose"), &GDScriptTextDocument::didClose); ClassDB::bind_method(D_METHOD("didChange"), &GDScriptTextDocument::didChange); + ClassDB::bind_method(D_METHOD("didSave"), &GDScriptTextDocument::didSave); ClassDB::bind_method(D_METHOD("nativeSymbol"), &GDScriptTextDocument::nativeSymbol); ClassDB::bind_method(D_METHOD("documentSymbol"), &GDScriptTextDocument::documentSymbol); ClassDB::bind_method(D_METHOD("completion"), &GDScriptTextDocument::completion); ClassDB::bind_method(D_METHOD("resolve"), &GDScriptTextDocument::resolve); + ClassDB::bind_method(D_METHOD("rename"), &GDScriptTextDocument::rename); ClassDB::bind_method(D_METHOD("foldingRange"), &GDScriptTextDocument::foldingRange); ClassDB::bind_method(D_METHOD("codeLens"), &GDScriptTextDocument::codeLens); ClassDB::bind_method(D_METHOD("documentLink"), &GDScriptTextDocument::documentLink); @@ -61,6 +64,11 @@ void GDScriptTextDocument::didOpen(const Variant &p_param) { sync_script_content(doc.uri, doc.text); } +void GDScriptTextDocument::didClose(const Variant &p_param) { + // Left empty on purpose. Godot does nothing special on closing a document, + // but it satisfies LSP clients that require didClose be implemented. +} + void GDScriptTextDocument::didChange(const Variant &p_param) { lsp::TextDocumentItem doc = load_document_item(p_param); Dictionary dict = p_param; @@ -73,6 +81,20 @@ void GDScriptTextDocument::didChange(const Variant &p_param) { sync_script_content(doc.uri, doc.text); } +void GDScriptTextDocument::didSave(const Variant &p_param) { + lsp::TextDocumentItem doc = load_document_item(p_param); + Dictionary dict = p_param; + String text = dict["text"]; + + sync_script_content(doc.uri, text); + + /*String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(doc.uri); + + Ref<GDScript> script = ResourceLoader::load(path); + script->load_source_code(path); + script->reload(true);*/ +} + lsp::TextDocumentItem GDScriptTextDocument::load_document_item(const Variant &p_param) { lsp::TextDocumentItem doc; Dictionary params = p_param; @@ -151,8 +173,7 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) { int i = 0; arr.resize(options.size()); - for (const List<ScriptCodeCompletionOption>::Element *E = options.front(); E; E = E->next()) { - const ScriptCodeCompletionOption &option = E->get(); + for (const ScriptCodeCompletionOption &option : options) { lsp::CompletionItem item; item.label = option.display; item.data = request_data; @@ -210,6 +231,14 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) { return arr; } +Dictionary GDScriptTextDocument::rename(const Dictionary &p_params) { + lsp::TextDocumentPositionParams params; + params.load(p_params); + String new_name = p_params["newName"]; + + return GDScriptLanguageProtocol::get_singleton()->get_workspace()->rename(params, new_name); +} + Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) { lsp::CompletionItem item; item.load(p_params); @@ -262,8 +291,8 @@ Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) { } } else if (item.kind == lsp::CompletionItemKind::Event) { if (params.context.triggerKind == lsp::CompletionTriggerKind::TriggerCharacter && (params.context.triggerCharacter == "(")) { - const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; - item.insertText = quote_style + item.label + quote_style; + const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; + item.insertText = item.label.quote(quote_style); } } @@ -288,8 +317,8 @@ Array GDScriptTextDocument::documentLink(const Dictionary &p_params) { List<lsp::DocumentLink> links; GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_document_links(params.textDocument.uri, links); - for (const List<lsp::DocumentLink>::Element *E = links.front(); E; E = E->next()) { - ret.push_back(E->get().to_json()); + for (const lsp::DocumentLink &E : links) { + ret.push_back(E.to_json()); } return ret; } @@ -316,8 +345,8 @@ Variant GDScriptTextDocument::hover(const Dictionary &p_params) { Array contents; List<const lsp::DocumentSymbol *> list; GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_related_symbols(params, list); - for (List<const lsp::DocumentSymbol *>::Element *E = list.front(); E; E = E->next()) { - if (const lsp::DocumentSymbol *s = E->get()) { + for (const lsp::DocumentSymbol *&E : list) { + if (const lsp::DocumentSymbol *s = E) { contents.push_back(s->render().value); } } @@ -367,7 +396,7 @@ Variant GDScriptTextDocument::declaration(const Dictionary &p_params) { id = "class_global:" + symbol->native_class + ":" + symbol->name; break; } - call_deferred("show_native_symbol_in_editor", id); + call_deferred(SNAME("show_native_symbol_in_editor"), id); } else { notify_client_show_symbol(symbol); } @@ -400,11 +429,19 @@ 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); GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content); + EditorFileSystem::get_singleton()->update_file(path); + Error error; + Ref<GDScript> script = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &error); + if (error == OK) { + if (script->load_source_code(path) == OK) { + script->reload(true); + } + } } void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) { - ScriptEditor::get_singleton()->call_deferred("_help_class_goto", p_symbol_id); + ScriptEditor::get_singleton()->call_deferred(SNAME("_help_class_goto"), p_symbol_id); DisplayServer::get_singleton()->window_move_to_foreground(); } @@ -424,8 +461,8 @@ Array GDScriptTextDocument::find_symbols(const lsp::TextDocumentPositionParams & } else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) { List<const lsp::DocumentSymbol *> list; GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_related_symbols(p_location, list); - for (List<const lsp::DocumentSymbol *>::Element *E = list.front(); E; E = E->next()) { - if (const lsp::DocumentSymbol *s = E->get()) { + for (const lsp::DocumentSymbol *&E : list) { + if (const lsp::DocumentSymbol *s = E) { if (!s->uri.is_empty()) { lsp::Location location; location.uri = s->uri; diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h index 17f1d5d5e3..9021c84a3f 100644 --- a/modules/gdscript/language_server/gdscript_text_document.h +++ b/modules/gdscript/language_server/gdscript_text_document.h @@ -43,7 +43,9 @@ protected: FileAccess *file_checker; void didOpen(const Variant &p_param); + void didClose(const Variant &p_param); void didChange(const Variant &p_param); + void didSave(const Variant &p_param); void sync_script_content(const String &p_path, const String &p_content); void show_native_symbol_in_editor(const String &p_symbol_id); @@ -60,6 +62,7 @@ public: Array documentSymbol(const Dictionary &p_params); Array completion(const Dictionary &p_params); Dictionary resolve(const Dictionary &p_params); + Dictionary rename(const Dictionary &p_params); Array foldingRange(const Dictionary &p_params); Array codeLens(const Dictionary &p_params); Array documentLink(const Dictionary &p_params); diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index d83f77ed82..1512b4bb89 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -116,11 +116,40 @@ const lsp::DocumentSymbol *GDScriptWorkspace::get_script_symbol(const String &p_ return nullptr; } +const lsp::DocumentSymbol *GDScriptWorkspace::get_parameter_symbol(const lsp::DocumentSymbol *p_parent, const String &symbol_identifier) { + for (int i = 0; i < p_parent->children.size(); ++i) { + const lsp::DocumentSymbol *parameter_symbol = &p_parent->children[i]; + if (!parameter_symbol->detail.is_empty() && parameter_symbol->name == symbol_identifier) { + return parameter_symbol; + } + } + + return nullptr; +} + +const lsp::DocumentSymbol *GDScriptWorkspace::get_local_symbol(const ExtendGDScriptParser *p_parser, const String &p_symbol_identifier) { + const lsp::DocumentSymbol *class_symbol = &p_parser->get_symbols(); + + for (int i = 0; i < class_symbol->children.size(); ++i) { + if (class_symbol->children[i].kind == lsp::SymbolKind::Function || class_symbol->children[i].kind == lsp::SymbolKind::Class) { + const lsp::DocumentSymbol *function_symbol = &class_symbol->children[i]; + + for (int l = 0; l < function_symbol->children.size(); ++l) { + const lsp::DocumentSymbol *local = &function_symbol->children[l]; + if (!local->detail.is_empty() && local->name == p_symbol_identifier) { + return local; + } + } + } + } + + return nullptr; +} + void GDScriptWorkspace::reload_all_workspace_scripts() { List<String> paths; list_script_files("res://", paths); - for (List<String>::Element *E = paths.front(); E; E = E->next()) { - const String &path = E->get(); + for (const String &path : paths) { Error err; String content = FileAccess::get_file_as_string(path, &err); ERR_CONTINUE(err != OK); @@ -232,18 +261,13 @@ Error GDScriptWorkspace::initialize() { class_symbol.children.push_back(symbol); } - Vector<DocData::PropertyDoc> properties; - properties.append_array(class_data.properties); - const int theme_prop_start_idx = properties.size(); - properties.append_array(class_data.theme_properties); - for (int i = 0; i < class_data.properties.size(); i++) { const DocData::PropertyDoc &data = class_data.properties[i]; lsp::DocumentSymbol symbol; symbol.name = data.name; symbol.native_class = class_name; symbol.kind = lsp::SymbolKind::Property; - symbol.detail = String(i >= theme_prop_start_idx ? "<Theme> var" : "var") + " " + class_name + "." + data.name; + symbol.detail = "var " + class_name + "." + data.name; if (data.enumeration.length()) { symbol.detail += ": " + data.enumeration; } else { @@ -253,6 +277,17 @@ Error GDScriptWorkspace::initialize() { class_symbol.children.push_back(symbol); } + for (int i = 0; i < class_data.theme_properties.size(); i++) { + const DocData::ThemeItemDoc &data = class_data.theme_properties[i]; + lsp::DocumentSymbol symbol; + symbol.name = data.name; + symbol.native_class = class_name; + symbol.kind = lsp::SymbolKind::Property; + symbol.detail = "<Theme> var " + class_name + "." + data.name + ": " + data.type; + symbol.documentation = data.description; + class_symbol.children.push_back(symbol); + } + Vector<DocData::MethodDoc> methods_signals; methods_signals.append_array(class_data.methods); const int signal_start_idx = methods_signals.size(); @@ -351,6 +386,50 @@ Error GDScriptWorkspace::parse_script(const String &p_path, const String &p_cont return err; } +Dictionary GDScriptWorkspace::rename(const lsp::TextDocumentPositionParams &p_doc_pos, const String &new_name) { + Error err; + String path = get_file_path(p_doc_pos.textDocument.uri); + + lsp::WorkspaceEdit edit; + + List<String> paths; + list_script_files("res://", paths); + + const lsp::DocumentSymbol *reference_symbol = resolve_symbol(p_doc_pos); + if (reference_symbol) { + String identifier = reference_symbol->name; + + for (List<String>::Element *PE = paths.front(); PE; PE = PE->next()) { + PackedStringArray content = FileAccess::get_file_as_string(PE->get(), &err).split("\n"); + for (int i = 0; i < content.size(); ++i) { + String line = content[i]; + + int character = line.find(identifier); + while (character > -1) { + lsp::TextDocumentPositionParams params; + + lsp::TextDocumentIdentifier text_doc; + text_doc.uri = get_file_uri(PE->get()); + + params.textDocument = text_doc; + params.position.line = i; + params.position.character = character; + + const lsp::DocumentSymbol *other_symbol = resolve_symbol(params); + + if (other_symbol == reference_symbol) { + edit.add_change(text_doc.uri, i, character, character + identifier.length(), new_name); + } + + character = line.find(identifier, character + 1); + } + } + } + } + + return edit.to_json(); +} + Error GDScriptWorkspace::parse_local_script(const String &p_path) { Error err; String content = FileAccess::get_file_as_string(p_path, &err); @@ -426,7 +505,7 @@ Node *GDScriptWorkspace::_get_owner_scene_node(String p_path) { RES owner_res = ResourceLoader::load(owner_path); if (Object::cast_to<PackedScene>(owner_res.ptr())) { Ref<PackedScene> owner_packed_scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*owner_res)); - owner_scene_node = owner_packed_scene->instance(); + owner_scene_node = owner_packed_scene->instantiate(); break; } } @@ -441,8 +520,31 @@ void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<S if (const ExtendGDScriptParser *parser = get_parse_result(path)) { Node *owner_scene_node = _get_owner_scene_node(path); + + Array stack; + Node *current = nullptr; + if (owner_scene_node != nullptr) { + stack.push_back(owner_scene_node); + + while (!stack.is_empty()) { + current = stack.pop_back(); + Ref<GDScript> script = current->get_script(); + if (script.is_valid() && script->get_path() == path) { + break; + } + for (int i = 0; i < current->get_child_count(); ++i) { + stack.push_back(current->get_child(i)); + } + } + + Ref<GDScript> script = current->get_script(); + if (!script.is_valid() || script->get_path() != path) { + current = owner_scene_node; + } + } + String code = parser->get_text_for_completion(p_params.position); - GDScriptLanguage::get_singleton()->complete_code(code, path, owner_scene_node, r_options, forced, call_hint); + GDScriptLanguage::get_singleton()->complete_code(code, path, current, r_options, forced, call_hint); if (owner_scene_node) { memdelete(owner_scene_node); } @@ -479,10 +581,16 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu String target_script_path = path; if (!ret.script.is_null()) { target_script_path = ret.script->get_path(); + } else if (!ret.class_path.is_empty()) { + target_script_path = ret.class_path; } if (const ExtendGDScriptParser *target_parser = get_parse_result(target_script_path)) { symbol = target_parser->get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(ret.location)); + + if (symbol && symbol->kind == lsp::SymbolKind::Function && symbol->name != symbol_identifier) { + symbol = get_parameter_symbol(symbol, symbol_identifier); + } } } else { @@ -494,6 +602,10 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu } } else { symbol = parser->get_member_symbol(symbol_identifier); + + if (!symbol) { + symbol = get_local_symbol(parser, symbol_identifier); + } } } } @@ -559,8 +671,8 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_native_symbol(const lsp::N void GDScriptWorkspace::resolve_document_links(const String &p_uri, List<lsp::DocumentLink> &r_list) { if (const ExtendGDScriptParser *parser = get_parse_successed_script(get_file_path(p_uri))) { const List<lsp::DocumentLink> &links = parser->get_document_links(); - for (const List<lsp::DocumentLink>::Element *E = links.front(); E; E = E->next()) { - r_list.push_back(E->get()); + for (const lsp::DocumentLink &E : links) { + r_list.push_back(E); } } } @@ -587,8 +699,7 @@ Error GDScriptWorkspace::resolve_signature(const lsp::TextDocumentPositionParams GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_related_symbols(text_pos, symbols); } - for (List<const lsp::DocumentSymbol *>::Element *E = symbols.front(); E; E = E->next()) { - const lsp::DocumentSymbol *symbol = E->get(); + for (const lsp::DocumentSymbol *const &symbol : symbols) { if (symbol->kind == lsp::SymbolKind::Method || symbol->kind == lsp::SymbolKind::Function) { lsp::SignatureInformation signature_info; signature_info.label = symbol->detail; diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h index 8b166a873c..9496677449 100644 --- a/modules/gdscript/language_server/gdscript_workspace.h +++ b/modules/gdscript/language_server/gdscript_workspace.h @@ -52,6 +52,8 @@ protected: const lsp::DocumentSymbol *get_native_symbol(const String &p_class, const String &p_member = "") const; const lsp::DocumentSymbol *get_script_symbol(const String &p_path) const; + const lsp::DocumentSymbol *get_parameter_symbol(const lsp::DocumentSymbol *p_parent, const String &symbol_identifier); + const lsp::DocumentSymbol *get_local_symbol(const ExtendGDScriptParser *p_parser, const String &p_symbol_identifier); void reload_all_workspace_scripts(); @@ -90,6 +92,7 @@ public: Dictionary generate_script_api(const String &p_path); Error resolve_signature(const lsp::TextDocumentPositionParams &p_doc_pos, lsp::SignatureHelp &r_signature); void did_delete_files(const Dictionary &p_params); + Dictionary rename(const lsp::TextDocumentPositionParams &p_doc_pos, const String &new_name); GDScriptWorkspace(); ~GDScriptWorkspace(); diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp index a7dcfdb22d..9ac6c6bd4e 100644 --- a/modules/gdscript/language_server/lsp.hpp +++ b/modules/gdscript/language_server/lsp.hpp @@ -255,6 +255,62 @@ struct TextEdit { }; /** + * The edits to be applied. + */ +struct WorkspaceEdit { + /** + * Holds changes to existing resources. + */ + Map<String, Vector<TextEdit>> changes; + + _FORCE_INLINE_ Dictionary to_json() const { + Dictionary dict; + + Dictionary out_changes; + for (Map<String, Vector<TextEdit>>::Element *E = changes.front(); E; E = E->next()) { + Array edits; + for (int i = 0; i < E->get().size(); ++i) { + Dictionary text_edit; + text_edit["range"] = E->get()[i].range.to_json(); + text_edit["newText"] = E->get()[i].newText; + edits.push_back(text_edit); + } + out_changes[E->key()] = edits; + } + dict["changes"] = out_changes; + + return dict; + } + + _FORCE_INLINE_ void add_change(const String &uri, const int &line, const int &start_character, const int &end_character, const String &new_text) { + if (Map<String, Vector<TextEdit>>::Element *E = changes.find(uri)) { + Vector<TextEdit> edit_list = E->value(); + for (int i = 0; i < edit_list.size(); ++i) { + TextEdit edit = edit_list[i]; + if (edit.range.start.character == start_character) { + return; + } + } + } + + TextEdit new_edit; + new_edit.newText = new_text; + new_edit.range.start.line = line; + new_edit.range.start.character = start_character; + new_edit.range.end.line = line; + new_edit.range.end.character = end_character; + + if (Map<String, Vector<TextEdit>>::Element *E = changes.find(uri)) { + E->value().push_back(new_edit); + } else { + Vector<TextEdit> edit_list; + edit_list.push_back(new_edit); + changes.insert(uri, edit_list); + } + } +}; + +/** * Represents a reference to a command. * Provides a title which will be used to represent a command in the UI. * Commands are identified by a string identifier. @@ -486,7 +542,7 @@ struct TextDocumentSyncOptions { * If present save notifications are sent to the server. If omitted the notification should not be * sent. */ - bool save = false; + SaveOptions save; Dictionary to_json() { Dictionary dict; @@ -494,7 +550,7 @@ struct TextDocumentSyncOptions { dict["willSave"] = willSave; dict["openClose"] = openClose; dict["change"] = change; - dict["save"] = save; + dict["save"] = save.to_json(); return dict; } }; @@ -1018,32 +1074,32 @@ struct CompletionList { * A symbol kind. */ namespace SymbolKind { -static const int File = 0; -static const int Module = 1; -static const int Namespace = 2; -static const int Package = 3; -static const int Class = 4; -static const int Method = 5; -static const int Property = 6; -static const int Field = 7; -static const int Constructor = 8; -static const int Enum = 9; -static const int Interface = 10; -static const int Function = 11; -static const int Variable = 12; -static const int Constant = 13; -static const int String = 14; -static const int Number = 15; -static const int Boolean = 16; -static const int Array = 17; -static const int Object = 18; -static const int Key = 19; -static const int Null = 20; -static const int EnumMember = 21; -static const int Struct = 22; -static const int Event = 23; -static const int Operator = 24; -static const int TypeParameter = 25; +static const int File = 1; +static const int Module = 2; +static const int Namespace = 3; +static const int Package = 4; +static const int Class = 5; +static const int Method = 6; +static const int Property = 7; +static const int Field = 8; +static const int Constructor = 9; +static const int Enum = 10; +static const int Interface = 11; +static const int Function = 12; +static const int Variable = 13; +static const int Constant = 14; +static const int String = 15; +static const int Number = 16; +static const int Boolean = 17; +static const int Array = 18; +static const int Object = 19; +static const int Key = 20; +static const int Null = 21; +static const int EnumMember = 22; +static const int Struct = 23; +static const int Event = 24; +static const int Operator = 25; +static const int TypeParameter = 26; }; // namespace SymbolKind /** diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index 867142019f..c2b1981f31 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -92,12 +92,12 @@ public: static void _editor_init() { Ref<EditorExportGDScript> gd_export; - gd_export.instance(); + gd_export.instantiate(); EditorExport::get_singleton()->add_export_plugin(gd_export); #ifdef TOOLS_ENABLED Ref<GDScriptSyntaxHighlighter> gdscript_syntax_highlighter; - gdscript_syntax_highlighter.instance(); + gdscript_syntax_highlighter.instantiate(); ScriptEditor::get_singleton()->register_syntax_highlighter(gdscript_syntax_highlighter); #endif @@ -112,15 +112,15 @@ static void _editor_init() { #endif // TOOLS_ENABLED void register_gdscript_types() { - ClassDB::register_class<GDScript>(); + GDREGISTER_CLASS(GDScript); script_language_gd = memnew(GDScriptLanguage); ScriptServer::register_language(script_language_gd); - resource_loader_gd.instance(); + resource_loader_gd.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_gd); - resource_saver_gd.instance(); + resource_saver_gd.instantiate(); ResourceSaver::add_resource_format_saver(resource_saver_gd); gdscript_cache = memnew(GDScriptCache); @@ -128,7 +128,7 @@ void register_gdscript_types() { #ifdef TOOLS_ENABLED EditorNode::add_init_callback(_editor_init); - gdscript_translation_parser_plugin.instance(); + gdscript_translation_parser_plugin.instantiate(); EditorTranslationParser::get_singleton()->add_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD); #endif // TOOLS_ENABLED diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index 67bc927517..03a48bf071 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -75,14 +75,14 @@ void init_autoloads() { Node *n = nullptr; if (res->is_class("PackedScene")) { Ref<PackedScene> ps = res; - n = ps->instance(); + n = ps->instantiate(); } else if (res->is_class("Script")) { Ref<Script> script_res = res; StringName ibt = script_res->get_instance_base_type(); bool valid_type = ClassDB::is_parent_class(ibt, "Node"); ERR_CONTINUE_MSG(!valid_type, "Script does not inherit a Node: " + info.path); - Object *obj = ClassDB::instance(ibt); + Object *obj = ClassDB::instantiate(ibt); ERR_CONTINUE_MSG(obj == nullptr, "Cannot instance script for autoload, expected 'Node' inheritance, got: " + @@ -295,7 +295,7 @@ void GDScriptTestRunner::handle_cmdline() { String test_cmd = "--gdscript-test"; String gen_cmd = "--gdscript-generate-tests"; - for (List<String>::Element *E = cmdline_args.front(); E != nullptr; E = E->next()) { + for (List<String>::Element *E = cmdline_args.front(); E; E = E->next()) { String &cmd = E->get(); if (cmd == test_cmd || cmd == gen_cmd) { if (E->next() == nullptr) { @@ -420,7 +420,7 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { // Create script. Ref<GDScript> script; - script.instance(); + script.instantiate(); script->set_path(source_file); script->set_script_path(source_file); err = script->load_source_code(source_file); @@ -440,8 +440,8 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { result.output = get_text_for_status(result.status) + "\n"; const List<GDScriptParser::ParserError> &errors = parser.get_errors(); - for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E; E = E->next()) { - result.output += E->get().message + "\n"; // TODO: line, column? + for (const GDScriptParser::ParserError &E : errors) { + result.output += E.message + "\n"; // TODO: line, column? break; // Only the first error since the following might be cascading. } if (!p_is_generating) { @@ -459,8 +459,8 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { result.output = get_text_for_status(result.status) + "\n"; const List<GDScriptParser::ParserError> &errors = parser.get_errors(); - for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E; E = E->next()) { - result.output += E->get().message + "\n"; // TODO: line, column? + for (const GDScriptParser::ParserError &E : errors) { + result.output += E.message + "\n"; // TODO: line, column? break; // Only the first error since the following might be cascading. } if (!p_is_generating) { @@ -470,8 +470,8 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { } StringBuilder warning_string; - for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E != nullptr; E = E->next()) { - const GDScriptWarning warning = E->get(); + for (const GDScriptWarning &E : parser.get_warnings()) { + const GDScriptWarning warning = E; warning_string.append(">> WARNING"); warning_string.append("\n>> Line: "); warning_string.append(itos(warning.start_line)); @@ -510,7 +510,7 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { script->reload(); // Create object instance for test. - Object *obj = ClassDB::instance(script->get_native()->get_name()); + Object *obj = ClassDB::instantiate(script->get_native()->get_name()); Ref<RefCounted> obj_ref; if (obj->is_ref_counted()) { obj_ref = Ref<RefCounted>(Object::cast_to<RefCounted>(obj)); diff --git a/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.gd b/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.gd new file mode 100644 index 0000000000..ac66b78220 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.gd @@ -0,0 +1,3 @@ +func test(): + print(Color.html_is_valid("00ffff")) + print("OK") diff --git a/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.out b/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.out new file mode 100644 index 0000000000..75b002aa62 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.out @@ -0,0 +1,3 @@ +GDTEST_OK +True +OK diff --git a/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd b/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd new file mode 100644 index 0000000000..fb0ace6a90 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd @@ -0,0 +1,5 @@ +func test(): + pass + +func something(): + return "OK" diff --git a/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.out b/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.gd b/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.gd new file mode 100644 index 0000000000..4f4b7a4897 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.gd @@ -0,0 +1,11 @@ +class InnerClass: + var val := "OK" + static func create_instance() -> InnerClass: + return new() + +func create_inner_instance() -> InnerClass: + return InnerClass.create_instance() + +func test(): + var instance = create_inner_instance() + print(instance.val) diff --git a/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.out b/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.out new file mode 100644 index 0000000000..1ccb591560 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.out @@ -0,0 +1,2 @@ +GDTEST_OK +OK diff --git a/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.gd b/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.gd new file mode 100644 index 0000000000..5f73064cc0 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.gd @@ -0,0 +1,5 @@ +const preloaded : GDScript = preload("gdscript_to_preload.gd") + +func test(): + var preloaded_instance: preloaded = preloaded.new() + print(preloaded_instance.something()) diff --git a/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.out b/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.out new file mode 100644 index 0000000000..1ccb591560 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.out @@ -0,0 +1,2 @@ +GDTEST_OK +OK diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp index c37d52febd..e54f055f2b 100644 --- a/modules/gdscript/tests/test_gdscript.cpp +++ b/modules/gdscript/tests/test_gdscript.cpp @@ -56,7 +56,7 @@ static void test_tokenizer(const String &p_code, const Vector<String> &p_lines) int tab_size = 4; #ifdef TOOLS_ENABLED if (EditorSettings::get_singleton()) { - tab_size = EditorSettings::get_singleton()->get_setting("text_editor/indent/size"); + tab_size = EditorSettings::get_singleton()->get_setting("text_editor/behavior/indent/size"); } #endif // TOOLS_ENABLED String tab = String(" ").repeat(tab_size); @@ -113,8 +113,7 @@ static void test_parser(const String &p_code, const String &p_script_path, const if (err != OK) { const List<GDScriptParser::ParserError> &errors = parser.get_errors(); - for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E != nullptr; E = E->next()) { - const GDScriptParser::ParserError &error = E->get(); + for (const GDScriptParser::ParserError &error : errors) { print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message)); } } @@ -124,8 +123,7 @@ static void test_parser(const String &p_code, const String &p_script_path, const if (err != OK) { const List<GDScriptParser::ParserError> &errors = parser.get_errors(); - for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E != nullptr; E = E->next()) { - const GDScriptParser::ParserError &error = E->get(); + for (const GDScriptParser::ParserError &error : errors) { print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message)); } } @@ -143,8 +141,7 @@ static void test_compiler(const String &p_code, const String &p_script_path, con if (err != OK) { print_line("Error in parser:"); const List<GDScriptParser::ParserError> &errors = parser.get_errors(); - for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E != nullptr; E = E->next()) { - const GDScriptParser::ParserError &error = E->get(); + for (const GDScriptParser::ParserError &error : errors) { print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message)); } return; @@ -156,8 +153,7 @@ static void test_compiler(const String &p_code, const String &p_script_path, con if (err != OK) { print_line("Error in analyzer:"); const List<GDScriptParser::ParserError> &errors = parser.get_errors(); - for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E != nullptr; E = E->next()) { - const GDScriptParser::ParserError &error = E->get(); + for (const GDScriptParser::ParserError &error : errors) { print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message)); } return; @@ -165,7 +161,7 @@ static void test_compiler(const String &p_code, const String &p_script_path, con GDScriptCompiler compiler; Ref<GDScript> script; - script.instance(); + script.instantiate(); script->set_path(p_script_path); err = compiler.compile(&parser, script.ptr(), false); |