diff options
Diffstat (limited to 'modules')
129 files changed, 1453 insertions, 104 deletions
diff --git a/modules/SCsub b/modules/SCsub index 7c9946170f..87c59c3bcc 100644 --- a/modules/SCsub +++ b/modules/SCsub @@ -19,7 +19,6 @@ env.CommandNoCache( Value(env.module_list), env.Run( modules_builders.generate_modules_enabled, - "Generating enabled modules header.", # NOTE: No need to run in subprocess since this is still executed serially. subprocess=False, ), @@ -58,7 +57,6 @@ if env["tests"]: test_headers, env.Run( modules_builders.generate_modules_tests, - "Generating modules tests header.", # NOTE: No need to run in subprocess since this is still executed serially. subprocess=False, ), diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 7ececce613..a68d65e8d3 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -333,20 +333,34 @@ <annotation name="@export_color_no_alpha"> <return type="void" /> <description> - Export a [Color] property without allowing its transparency ([member Color.a]) to be edited. + Export a [Color], [Array][lb][Color][rb], or [PackedColorArray] property without allowing its transparency ([member Color.a]) to be edited. See also [constant PROPERTY_HINT_COLOR_NO_ALPHA]. [codeblock] @export_color_no_alpha var dye_color: Color + @export_color_no_alpha var dye_colors: Array[Color] + [/codeblock] + </description> + </annotation> + <annotation name="@export_custom"> + <return type="void" /> + <param index="0" name="hint" type="int" enum="PropertyHint" /> + <param index="1" name="hint_string" type="String" /> + <param index="2" name="usage" type="int" enum="PropertyUsageFlags" is_bitfield="true" default="6" /> + <description> + Allows you to set a custom hint, hint string, and usage flags for the exported property. Note that there's no validation done in GDScript, it will just pass the hint along to the editor. + [codeblock] + @export_custom(PROPERTY_HINT_NONE, "suffix:m") var suffix: Vector3 [/codeblock] </description> </annotation> <annotation name="@export_dir"> <return type="void" /> <description> - Export a [String] property as a path to a directory. The path will be limited to the project folder and its subfolders. See [annotation @export_global_dir] to allow picking from the entire filesystem. + Export a [String], [Array][lb][String][rb], or [PackedStringArray] property as a path to a directory. The path will be limited to the project folder and its subfolders. See [annotation @export_global_dir] to allow picking from the entire filesystem. See also [constant PROPERTY_HINT_DIR]. [codeblock] @export_dir var sprite_folder_path: String + @export_dir var sprite_folder_paths: Array[String] [/codeblock] </description> </annotation> @@ -354,12 +368,15 @@ <return type="void" /> <param index="0" name="names" type="String" /> <description> - Export an [int] or [String] property as an enumerated list of options. If the property is an [int], then the index of the value is stored, in the same order the values are provided. You can add explicit values using a colon. If the property is a [String], then the value is stored. + Export an [int], [String], [Array][lb][int][rb], [Array][lb][String][rb], [PackedByteArray], [PackedInt32Array], [PackedInt64Array], or [PackedStringArray] property as an enumerated list of options (or an array of options). If the property is an [int], then the index of the value is stored, in the same order the values are provided. You can add explicit values using a colon. If the property is a [String], then the value is stored. See also [constant PROPERTY_HINT_ENUM]. [codeblock] @export_enum("Warrior", "Magician", "Thief") var character_class: int @export_enum("Slow:30", "Average:60", "Very Fast:200") var character_speed: int @export_enum("Rebecca", "Mary", "Leah") var character_name: String + + @export_enum("Sword", "Spear", "Mace") var character_items: Array[int] + @export_enum("double_jump", "climb", "dash") var character_skills: Array[String] [/codeblock] If you want to set an initial value, you must specify it explicitly: [codeblock] @@ -369,6 +386,9 @@ [codeblock] enum CharacterName {REBECCA, MARY, LEAH} @export var character_name: CharacterName + + enum CharacterItem {SWORD, SPEAR, MACE} + @export var character_items: Array[CharacterItem] [/codeblock] </description> </annotation> @@ -382,6 +402,7 @@ @export_exp_easing var transition_speed @export_exp_easing("attenuation") var fading_attenuation @export_exp_easing("positive_only") var effect_power + @export_exp_easing var speeds: Array[float] [/codeblock] </description> </annotation> @@ -389,12 +410,13 @@ <return type="void" /> <param index="0" name="filter" type="String" default="""" /> <description> - Export a [String] property as a path to a file. The path will be limited to the project folder and its subfolders. See [annotation @export_global_file] to allow picking from the entire filesystem. + Export a [String], [Array][lb][String][rb], or [PackedStringArray] property as a path to a file. The path will be limited to the project folder and its subfolders. See [annotation @export_global_file] to allow picking from the entire filesystem. If [param filter] is provided, only matching files will be available for picking. See also [constant PROPERTY_HINT_FILE]. [codeblock] @export_file var sound_effect_path: String @export_file("*.txt") var notes_path: String + @export_file var level_paths: Array[String] [/codeblock] </description> </annotation> @@ -421,6 +443,10 @@ [codeblock] @export_flags("A:16", "B", "C") var x [/codeblock] + You can also use the annotation on [Array][lb][int][rb], [PackedByteArray], [PackedInt32Array], and [PackedInt64Array] + [codeblock] + @export_flags("Fire", "Water", "Earth", "Wind") var phase_elements: Array[int] + [/codeblock] </description> </annotation> <annotation name="@export_flags_2d_navigation"> @@ -430,6 +456,7 @@ See also [constant PROPERTY_HINT_LAYERS_2D_NAVIGATION]. [codeblock] @export_flags_2d_navigation var navigation_layers: int + @export_flags_2d_navigation var navigation_layers_array: Array[int] [/codeblock] </description> </annotation> @@ -440,6 +467,7 @@ See also [constant PROPERTY_HINT_LAYERS_2D_PHYSICS]. [codeblock] @export_flags_2d_physics var physics_layers: int + @export_flags_2d_physics var physics_layers_array: Array[int] [/codeblock] </description> </annotation> @@ -450,6 +478,7 @@ See also [constant PROPERTY_HINT_LAYERS_2D_RENDER]. [codeblock] @export_flags_2d_render var render_layers: int + @export_flags_2d_render var render_layers_array: Array[int] [/codeblock] </description> </annotation> @@ -460,6 +489,7 @@ See also [constant PROPERTY_HINT_LAYERS_3D_NAVIGATION]. [codeblock] @export_flags_3d_navigation var navigation_layers: int + @export_flags_3d_navigation var navigation_layers_array: Array[int] [/codeblock] </description> </annotation> @@ -470,6 +500,7 @@ See also [constant PROPERTY_HINT_LAYERS_3D_PHYSICS]. [codeblock] @export_flags_3d_physics var physics_layers: int + @export_flags_3d_physics var physics_layers_array: Array[int] [/codeblock] </description> </annotation> @@ -480,6 +511,7 @@ See also [constant PROPERTY_HINT_LAYERS_3D_RENDER]. [codeblock] @export_flags_3d_render var render_layers: int + @export_flags_3d_render var render_layers_array: Array[int] [/codeblock] </description> </annotation> @@ -490,16 +522,18 @@ See also [constant PROPERTY_HINT_LAYERS_AVOIDANCE]. [codeblock] @export_flags_avoidance var avoidance_layers: int + @export_flags_avoidance var avoidance_layers_array: Array[int] [/codeblock] </description> </annotation> <annotation name="@export_global_dir"> <return type="void" /> <description> - Export a [String] property as an absolute path to a directory. The path can be picked from the entire filesystem. See [annotation @export_dir] to limit it to the project folder and its subfolders. + Export a [String], [Array][lb][String][rb], or [PackedStringArray] property as an absolute path to a directory. The path can be picked from the entire filesystem. See [annotation @export_dir] to limit it to the project folder and its subfolders. See also [constant PROPERTY_HINT_GLOBAL_DIR]. [codeblock] @export_global_dir var sprite_folder_path: String + @export_global_dir var sprite_folder_paths: Array[String] [/codeblock] </description> </annotation> @@ -507,12 +541,13 @@ <return type="void" /> <param index="0" name="filter" type="String" default="""" /> <description> - Export a [String] property as an absolute path to a file. The path can be picked from the entire filesystem. See [annotation @export_file] to limit it to the project folder and its subfolders. + Export a [String], [Array][lb][String][rb], or [PackedStringArray] property as an absolute path to a file. The path can be picked from the entire filesystem. See [annotation @export_file] to limit it to the project folder and its subfolders. If [param filter] is provided, only matching files will be available for picking. See also [constant PROPERTY_HINT_GLOBAL_FILE]. [codeblock] @export_global_file var sound_effect_path: String @export_global_file("*.txt") var notes_path: String + @export_global_file var multiple_paths: Array[String] [/codeblock] </description> </annotation> @@ -542,10 +577,11 @@ <annotation name="@export_multiline"> <return type="void" /> <description> - Export a [String] property with a large [TextEdit] widget instead of a [LineEdit]. This adds support for multiline content and makes it easier to edit large amount of text stored in the property. + Export a [String], [Array][lb][String][rb], [PackedStringArray], [Dictionary] or [Array][lb][Dictionary][rb] property with a large [TextEdit] widget instead of a [LineEdit]. This adds support for multiline content and makes it easier to edit large amount of text stored in the property. See also [constant PROPERTY_HINT_MULTILINE_TEXT]. [codeblock] @export_multiline var character_biography + @export_multiline var npc_dialogs: Array[String] [/codeblock] </description> </annotation> @@ -553,10 +589,11 @@ <return type="void" /> <param index="0" name="type" type="String" default="""" /> <description> - Export a [NodePath] property with a filter for allowed node types. + Export a [NodePath] or [Array][lb][NodePath][rb] property with a filter for allowed node types. See also [constant PROPERTY_HINT_NODE_PATH_VALID_TYPES]. [codeblock] @export_node_path("Button", "TouchScreenButton") var some_button + @export_node_path("Button", "TouchScreenButton") var many_buttons: Array[NodePath] [/codeblock] [b]Note:[/b] The type must be a native class or a globally registered script (using the [code]class_name[/code] keyword) that inherits [Node]. </description> @@ -565,10 +602,11 @@ <return type="void" /> <param index="0" name="placeholder" type="String" /> <description> - Export a [String] property with a placeholder text displayed in the editor widget when no value is present. + Export a [String], [Array][lb][String][rb], or [PackedStringArray] property with a placeholder text displayed in the editor widget when no value is present. See also [constant PROPERTY_HINT_PLACEHOLDER_TEXT]. [codeblock] @export_placeholder("Name in lowercase") var character_id: String + @export_placeholder("Name in lowercase") var friend_ids: Array[String] [/codeblock] </description> </annotation> @@ -579,7 +617,7 @@ <param index="2" name="step" type="float" default="1.0" /> <param index="3" name="extra_hints" type="String" default="""" /> <description> - Export an [int] or [float] property as a range value. The range must be defined by [param min] and [param max], as well as an optional [param step] and a variety of extra hints. The [param step] defaults to [code]1[/code] for integer properties. For floating-point numbers this value depends on your [member EditorSettings.interface/inspector/default_float_step] setting. + Export an [int], [float], [Array][lb][int][rb], [Array][lb][float][rb], [PackedByteArray], [PackedInt32Array], [PackedInt64Array], [PackedFloat32Array], or [PackedFloat64Array] property as a range value. The range must be defined by [param min] and [param max], as well as an optional [param step] and a variety of extra hints. The [param step] defaults to [code]1[/code] for integer properties. For floating-point numbers this value depends on your [member EditorSettings.interface/inspector/default_float_step] setting. If hints [code]"or_greater"[/code] and [code]"or_less"[/code] are provided, the editor widget will not cap the value at range boundaries. The [code]"exp"[/code] hint will make the edited values on range to change exponentially. The [code]"hide_slider"[/code] hint will hide the slider element of the editor widget. Hints also allow to indicate the units for the edited value. Using [code]"radians_as_degrees"[/code] you can specify that the actual value is in radians, but should be displayed in degrees in the Inspector dock (the range values are also in degrees). [code]"degrees"[/code] allows to add a degree sign as a unit suffix (the value is unchanged). Finally, a custom suffix can be provided using [code]"suffix:unit"[/code], where "unit" can be any string. See also [constant PROPERTY_HINT_RANGE]. @@ -587,6 +625,7 @@ @export_range(0, 20) var number @export_range(-10, 20) var number @export_range(-10, 20, 0.2) var number: float + @export_range(0, 20) var numbers: Array[float] @export_range(0, 100, 1, "or_greater") var power_percent @export_range(0, 100, 1, "or_greater", "or_less") var health_delta diff --git a/modules/gdscript/editor/script_templates/SCsub b/modules/gdscript/editor/script_templates/SCsub index 2266ef2d01..5db7e3fc3b 100644 --- a/modules/gdscript/editor/script_templates/SCsub +++ b/modules/gdscript/editor/script_templates/SCsub @@ -5,7 +5,7 @@ Import("env") import editor.template_builders as build_template_gd env["BUILDERS"]["MakeGDTemplateBuilder"] = Builder( - action=env.Run(build_template_gd.make_templates, "Generating GDScript templates header."), + action=env.Run(build_template_gd.make_templates), suffix=".h", src_suffix=".gd", ) diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 98d4a19a87..3ec5098c21 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -3360,12 +3360,8 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a parser->push_warning(p_call, GDScriptWarning::RETURN_VALUE_DISCARDED, p_call->function_name); } - if (method_flags.has_flag(METHOD_FLAG_STATIC) && !is_constructor && !base_type.is_meta_type && !(is_self && static_context)) { - String caller_type = String(base_type.native_type); - - if (caller_type.is_empty()) { - caller_type = base_type.to_string(); - } + if (method_flags.has_flag(METHOD_FLAG_STATIC) && !is_constructor && !base_type.is_meta_type && !is_self) { + String caller_type = base_type.to_string(); parser->push_warning(p_call, GDScriptWarning::STATIC_CALLED_ON_INSTANCE, p_call->function_name, caller_type); } diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index babd2c1772..12ff22c878 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -828,17 +828,21 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio return arghint; } -static void _get_directory_contents(EditorFileSystemDirectory *p_dir, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_list) { +static void _get_directory_contents(EditorFileSystemDirectory *p_dir, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_list, const StringName &p_required_type = StringName()) { const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; + const bool requires_type = p_required_type; for (int i = 0; i < p_dir->get_file_count(); i++) { + if (requires_type && !ClassDB::is_parent_class(p_dir->get_file_type(i), p_required_type)) { + continue; + } ScriptLanguage::CodeCompletionOption option(p_dir->get_file_path(i), ScriptLanguage::CODE_COMPLETION_KIND_FILE_PATH); option.insert_text = option.display.quote(quote_style); r_list.insert(option.display, option); } for (int i = 0; i < p_dir->get_subdir_count(); i++) { - _get_directory_contents(p_dir->get_subdir(i), r_list); + _get_directory_contents(p_dir->get_subdir(i), r_list, p_required_type); } } @@ -2803,6 +2807,16 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c r_result.insert(option.display, option); } } + if (EDITOR_GET("text_editor/completion/complete_file_paths")) { + if (p_argidx == 0 && p_method == SNAME("change_scene_to_file") && ClassDB::is_parent_class(class_name, SNAME("SceneTree"))) { + HashMap<String, ScriptLanguage::CodeCompletionOption> list; + _get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), list, SNAME("PackedScene")); + for (const KeyValue<String, ScriptLanguage::CodeCompletionOption> &key_value_pair : list) { + ScriptLanguage::CodeCompletionOption option = key_value_pair.value; + r_result.insert(option.display, option); + } + } + } base_type.kind = GDScriptParser::DataType::UNRESOLVED; } break; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 4d4eadf0fa..aae45274e0 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -121,6 +121,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>); register_annotation(MethodInfo("@export_flags_avoidance"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_AVOIDANCE, Variant::INT>); + register_annotation(MethodInfo("@export_custom", PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CLASS_IS_ENUM, "PropertyHint"), PropertyInfo(Variant::STRING, "hint_string"), PropertyInfo(Variant::INT, "usage", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CLASS_IS_BITFIELD, "PropertyUsageFlags")), AnnotationInfo::VARIABLE, &GDScriptParser::export_custom_annotation, varray(PROPERTY_USAGE_DEFAULT)); // Export grouping annotations. register_annotation(MethodInfo("@export_category", PropertyInfo(Variant::STRING, "name")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_CATEGORY>); register_annotation(MethodInfo("@export_group", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "prefix")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_GROUP>, varray("")); @@ -4006,6 +4007,55 @@ bool GDScriptParser::onready_annotation(const AnnotationNode *p_annotation, Node return true; } +static String _get_annotation_error_string(const StringName &p_annotation_name, const Vector<Variant::Type> &p_expected_types, const GDScriptParser::DataType &p_provided_type) { + Vector<String> types; + for (int i = 0; i < p_expected_types.size(); i++) { + const Variant::Type &type = p_expected_types[i]; + types.push_back(Variant::get_type_name(type)); + types.push_back("Array[" + Variant::get_type_name(type) + "]"); + switch (type) { + case Variant::INT: + types.push_back("PackedByteArray"); + types.push_back("PackedInt32Array"); + types.push_back("PackedInt64Array"); + break; + case Variant::FLOAT: + types.push_back("PackedFloat32Array"); + types.push_back("PackedFloat64Array"); + break; + case Variant::STRING: + types.push_back("PackedStringArray"); + break; + case Variant::VECTOR2: + types.push_back("PackedVector2Array"); + break; + case Variant::VECTOR3: + types.push_back("PackedVector3Array"); + break; + case Variant::COLOR: + types.push_back("PackedColorArray"); + break; + default: + break; + } + } + + String string; + if (types.size() == 1) { + string = types[0].quote(); + } else if (types.size() == 2) { + string = types[0].quote() + " or " + types[1].quote(); + } else if (types.size() >= 3) { + string = types[0].quote(); + for (int i = 1; i < types.size() - 1; i++) { + string += ", " + types[i].quote(); + } + string += ", or " + types[types.size() - 1].quote(); + } + + return vformat(R"("%s" annotation requires a variable of type %s, but type "%s" was given instead.)", p_annotation_name, string, p_provided_type.to_string()); +} + template <PropertyHint t_hint, Variant::Type t_type> bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) { ERR_FAIL_COND_V_MSG(p_target->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name)); @@ -4090,6 +4140,26 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node // This is called after the analyzer is done finding the type, so this should be set here. DataType export_type = variable->get_datatype(); + + // Use initializer type if specified type is `Variant`. + if (export_type.is_variant() && variable->initializer != nullptr && variable->initializer->datatype.is_set()) { + export_type = variable->initializer->get_datatype(); + export_type.type_source = DataType::INFERRED; + } + + const Variant::Type original_export_type_builtin = export_type.builtin_type; + + // Process array and packed array annotations on the element type. + bool is_array = false; + if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type(0)) { + is_array = true; + export_type = export_type.get_container_element_type(0); + } else if (export_type.is_typed_container_type()) { + is_array = true; + export_type = export_type.get_typed_container_type(); + export_type.type_source = variable->datatype.type_source; + } + bool use_default_variable_type_check = true; if (p_annotation->name == SNAME("@export_range")) { @@ -4097,30 +4167,16 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node variable->export_info.type = Variant::INT; } } else if (p_annotation->name == SNAME("@export_multiline")) { - if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type(0)) { - DataType inner_type = export_type.get_container_element_type(0); - if (inner_type.builtin_type != Variant::STRING) { - push_error(vformat(R"("%s" annotation on arrays requires a string type but type "%s" was given instead.)", p_annotation->name.operator String(), inner_type.to_string()), variable); - return false; - } + use_default_variable_type_check = false; - String hint_prefix = itos(inner_type.builtin_type) + "/" + itos(variable->export_info.hint); - variable->export_info.hint = PROPERTY_HINT_TYPE_STRING; - variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string; - variable->export_info.type = Variant::ARRAY; + if (export_type.builtin_type != Variant::STRING && export_type.builtin_type != Variant::DICTIONARY) { + Vector<Variant::Type> expected_types = { Variant::STRING, Variant::DICTIONARY }; + push_error(_get_annotation_error_string(p_annotation->name, expected_types, variable->get_datatype()), p_annotation); + return false; + } - return true; - } else if (export_type.builtin_type == Variant::DICTIONARY) { + if (export_type.builtin_type == Variant::DICTIONARY) { variable->export_info.type = Variant::DICTIONARY; - - return true; - } else if (export_type.builtin_type == Variant::PACKED_STRING_ARRAY) { - String hint_prefix = itos(Variant::STRING) + "/" + itos(variable->export_info.hint); - variable->export_info.hint = PROPERTY_HINT_TYPE_STRING; - variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string; - variable->export_info.type = Variant::PACKED_STRING_ARRAY; - - return true; } } else if (p_annotation->name == SNAME("@export")) { use_default_variable_type_check = false; @@ -4130,13 +4186,6 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node return false; } - bool is_array = false; - - if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type(0)) { - export_type = export_type.get_container_element_type(0); // Use inner type for. - is_array = true; - } - if (export_type.is_variant() || export_type.has_no_type()) { push_error(R"(Cannot use simple "@export" annotation because the type of the initialized value can't be inferred.)", p_annotation); return false; @@ -4158,7 +4207,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node variable->export_info.hint = PROPERTY_HINT_NODE_TYPE; variable->export_info.hint_string = export_type.native_type; } else { - push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", variable); + push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", p_annotation); return false; } break; @@ -4172,7 +4221,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node variable->export_info.hint = PROPERTY_HINT_NODE_TYPE; variable->export_info.hint_string = export_type.to_string(); } else { - push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", variable); + push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", p_annotation); return false; } @@ -4223,24 +4272,14 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node } } break; default: - push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", variable); + push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", p_annotation); return false; } if (variable->export_info.hint == PROPERTY_HINT_NODE_TYPE && !ClassDB::is_parent_class(p_class->base_type.native_type, SNAME("Node"))) { - push_error(vformat(R"(Node export is only supported in Node-derived classes, but the current class inherits "%s".)", p_class->base_type.to_string()), variable); + push_error(vformat(R"(Node export is only supported in Node-derived classes, but the current class inherits "%s".)", p_class->base_type.to_string()), p_annotation); return false; } - - if (is_array) { - String hint_prefix = itos(variable->export_info.type); - if (variable->export_info.hint) { - hint_prefix += "/" + itos(variable->export_info.hint); - } - variable->export_info.hint = PROPERTY_HINT_TYPE_STRING; - variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string; - variable->export_info.type = Variant::ARRAY; - } } else if (p_annotation->name == SNAME("@export_enum")) { use_default_variable_type_check = false; @@ -4248,17 +4287,13 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node if (export_type.kind == DataType::BUILTIN && export_type.builtin_type == Variant::STRING) { enum_type = Variant::STRING; - } else if (export_type.is_variant() && variable->initializer != nullptr) { - DataType initializer_type = variable->initializer->get_datatype(); - if (initializer_type.kind == DataType::BUILTIN && initializer_type.builtin_type == Variant::STRING) { - enum_type = Variant::STRING; - } } variable->export_info.type = enum_type; if (!export_type.is_variant() && (export_type.kind != DataType::BUILTIN || export_type.builtin_type != enum_type)) { - push_error(vformat(R"("@export_enum" annotation requires a variable of type "int" or "String" but type "%s" was given instead.)", export_type.to_string()), variable); + Vector<Variant::Type> expected_types = { Variant::INT, Variant::STRING }; + push_error(_get_annotation_error_string(p_annotation->name, expected_types, variable->get_datatype()), p_annotation); return false; } } else if (p_annotation->name == SNAME("@export_storage")) { @@ -4274,12 +4309,47 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node if (!export_type.is_variant() && (export_type.kind != DataType::BUILTIN || export_type.builtin_type != t_type)) { // Allow float/int conversion. if ((t_type != Variant::FLOAT || export_type.builtin_type != Variant::INT) && (t_type != Variant::INT || export_type.builtin_type != Variant::FLOAT)) { - push_error(vformat(R"("%s" annotation requires a variable of type "%s" but type "%s" was given instead.)", p_annotation->name.operator String(), Variant::get_type_name(t_type), export_type.to_string()), variable); + Vector<Variant::Type> expected_types = { t_type }; + push_error(_get_annotation_error_string(p_annotation->name, expected_types, variable->get_datatype()), p_annotation); return false; } } } + if (is_array) { + String hint_prefix = itos(variable->export_info.type); + if (variable->export_info.hint) { + hint_prefix += "/" + itos(variable->export_info.hint); + } + variable->export_info.hint = PROPERTY_HINT_TYPE_STRING; + variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string; + variable->export_info.type = original_export_type_builtin; + } + + return true; +} + +bool GDScriptParser::export_custom_annotation(const AnnotationNode *p_annotation, Node *p_node, ClassNode *p_class) { + ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name)); + ERR_FAIL_COND_V_MSG(p_annotation->resolved_arguments.size() < 2, false, R"(Annotation "@export_custom" requires 2 arguments.)"); + + VariableNode *variable = static_cast<VariableNode *>(p_node); + if (variable->exported) { + push_error(vformat(R"(Annotation "%s" cannot be used with another "@export" annotation.)", p_annotation->name), p_annotation); + return false; + } + + variable->exported = true; + + DataType export_type = variable->get_datatype(); + + variable->export_info.type = export_type.builtin_type; + variable->export_info.hint = static_cast<PropertyHint>(p_annotation->resolved_arguments[0].operator int64_t()); + variable->export_info.hint_string = p_annotation->resolved_arguments[1]; + + if (p_annotation->resolved_arguments.size() >= 3) { + variable->export_info.usage = p_annotation->resolved_arguments[2].operator int64_t(); + } return true; } diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 6664e6df04..45ab3f3e38 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -1482,6 +1482,7 @@ private: bool onready_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); template <PropertyHint t_hint, Variant::Type t_type> bool export_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); + bool export_custom_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); template <PropertyUsageFlags t_usage> bool export_group_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); bool warning_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); diff --git a/modules/gdscript/tests/scripts/completion/class_a.notest.gd b/modules/gdscript/tests/scripts/completion/class_a.notest.gd new file mode 100644 index 0000000000..47c64dc674 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/class_a.notest.gd @@ -0,0 +1,8 @@ +extends Node + +signal signal_of_a + +var property_of_a + +func func_of_a(): + pass diff --git a/modules/gdscript/tests/scripts/completion/get_node/get_node.tscn b/modules/gdscript/tests/scripts/completion/get_node/get_node.tscn new file mode 100644 index 0000000000..35ac666941 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/get_node.tscn @@ -0,0 +1,19 @@ +[gd_scene load_steps=2 format=3 uid="uid://c8wekfd5ql7bc"] + +[ext_resource type="Script" path="res://completion/class_a.notest.gd" id="1_ldc4g"] + +[node name="GetNode" type="Node"] + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] + +[node name="UniqueNames" type="Node" parent="."] + +[node name="UniqueAnimationPlayer" type="AnimationPlayer" parent="UniqueNames"] +unique_name_in_owner = true + +[node name="UniqueA" type="Node" parent="UniqueNames"] +unique_name_in_owner = true +script = ExtResource("1_ldc4g") + +[node name="A" type="Node" parent="."] +script = ExtResource("1_ldc4g") diff --git a/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg b/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg deleted file mode 100644 index 27e695d245..0000000000 --- a/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[output] -include=[ - {"display": "autoplay"}, -] diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg new file mode 100644 index 0000000000..ae7d34d87d --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg @@ -0,0 +1,7 @@ +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.gd b/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.gd new file mode 100644 index 0000000000..df458a9435 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.gd @@ -0,0 +1,4 @@ +extends Node + +func a(): + %AnimationPlayer.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg new file mode 100644 index 0000000000..ae7d34d87d --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg @@ -0,0 +1,7 @@ +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal/percent.gd b/modules/gdscript/tests/scripts/completion/get_node/literal/percent.gd new file mode 100644 index 0000000000..7050761b86 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/literal/percent.gd @@ -0,0 +1,4 @@ +extends Node + +func a(): + $UniqueAnimationPlayer.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg new file mode 100644 index 0000000000..009ab9f9ce --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; GDScript: class_a.notest.gd + {"display": "property_of_a"}, + {"display": "func_of_a"}, + {"display": "signal_of_a"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.gd new file mode 100644 index 0000000000..a84283a1de --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.gd @@ -0,0 +1,4 @@ +extends Node + +func a(): + $A.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg new file mode 100644 index 0000000000..0fb46a4704 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; AnimationPlayer + {"display": "autoplay"}, + {"display": "play"}, + {"display": "animation_changed"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.gd new file mode 100644 index 0000000000..6e3fee1696 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.gd @@ -0,0 +1,4 @@ +extends Node + +func a(): + $AnimationPlayer.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg new file mode 100644 index 0000000000..009ab9f9ce --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; GDScript: class_a.notest.gd + {"display": "property_of_a"}, + {"display": "func_of_a"}, + {"display": "signal_of_a"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.gd new file mode 100644 index 0000000000..27f059c944 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.gd @@ -0,0 +1,4 @@ +extends Node + +func a(): + %UniqueA.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg new file mode 100644 index 0000000000..0fb46a4704 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; AnimationPlayer + {"display": "autoplay"}, + {"display": "play"}, + {"display": "animation_changed"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.gd new file mode 100644 index 0000000000..07068fc5a4 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.gd @@ -0,0 +1,4 @@ +extends Node + +func a(): + %UniqueAnimationPlayer.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg b/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg new file mode 100644 index 0000000000..ae7d34d87d --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg @@ -0,0 +1,7 @@ +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/local/local.gd b/modules/gdscript/tests/scripts/completion/get_node/local/local.gd new file mode 100644 index 0000000000..596ad80ef2 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local/local.gd @@ -0,0 +1,5 @@ +extends Node + +func a(): + var test = $AnimationPlayer + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.cfg new file mode 100644 index 0000000000..ae7d34d87d --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.cfg @@ -0,0 +1,7 @@ +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.gd b/modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.gd new file mode 100644 index 0000000000..6f87af3c85 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.gd @@ -0,0 +1,5 @@ +extends Node + +func a(): + var test := $AnimationPlayer + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.cfg new file mode 100644 index 0000000000..009ab9f9ce --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; GDScript: class_a.notest.gd + {"display": "property_of_a"}, + {"display": "func_of_a"}, + {"display": "signal_of_a"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.gd new file mode 100644 index 0000000000..a710c8bbd7 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.gd @@ -0,0 +1,5 @@ +extends Node + +func a(): + var test := $A + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.cfg new file mode 100644 index 0000000000..0fb46a4704 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; AnimationPlayer + {"display": "autoplay"}, + {"display": "play"}, + {"display": "animation_changed"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.gd new file mode 100644 index 0000000000..6f87af3c85 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.gd @@ -0,0 +1,5 @@ +extends Node + +func a(): + var test := $AnimationPlayer + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg new file mode 100644 index 0000000000..009ab9f9ce --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; GDScript: class_a.notest.gd + {"display": "property_of_a"}, + {"display": "func_of_a"}, + {"display": "signal_of_a"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.gd new file mode 100644 index 0000000000..2fc88f93dd --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.gd @@ -0,0 +1,5 @@ +extends Node + +func a(): + var test = $A + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg new file mode 100644 index 0000000000..0fb46a4704 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; AnimationPlayer + {"display": "autoplay"}, + {"display": "play"}, + {"display": "animation_changed"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.gd new file mode 100644 index 0000000000..596ad80ef2 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.gd @@ -0,0 +1,5 @@ +extends Node + +func a(): + var test = $AnimationPlayer + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg new file mode 100644 index 0000000000..a72b489be6 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg @@ -0,0 +1,12 @@ +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; GDScript: class_a.notest.gd + {"display": "property_of_a"}, + {"display": "func_of_a"}, + {"display": "signal_of_a"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.gd new file mode 100644 index 0000000000..b6d2074939 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.gd @@ -0,0 +1,7 @@ +extends Node + +const A := preload("res://completion/class_a.notest.gd") + +func a(): + var test: A = $A + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg new file mode 100644 index 0000000000..adf06c8707 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg @@ -0,0 +1,12 @@ +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; AnimationPlayer + {"display": "autoplay"}, + {"display": "play"}, + {"display": "animation_changed"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.gd new file mode 100644 index 0000000000..13b541a35d --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.gd @@ -0,0 +1,5 @@ +extends Node + +func a(): + var test: AnimationPlayer = $AnimationPlayer + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg new file mode 100644 index 0000000000..9c580b711d --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; GDScript: class_a.notest.gd + {"display": "property_of_a"}, + {"display": "func_of_a"}, + {"display": "signal_of_a"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.gd new file mode 100644 index 0000000000..b6d2074939 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.gd @@ -0,0 +1,7 @@ +extends Node + +const A := preload("res://completion/class_a.notest.gd") + +func a(): + var test: A = $A + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg new file mode 100644 index 0000000000..446198dd35 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; AnimationPlayer + {"display": "autoplay"}, + {"display": "play"}, + {"display": "animation_changed"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.gd new file mode 100644 index 0000000000..13b541a35d --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.gd @@ -0,0 +1,5 @@ +extends Node + +func a(): + var test: AnimationPlayer = $AnimationPlayer + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg new file mode 100644 index 0000000000..9c580b711d --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; GDScript: class_a.notest.gd + {"display": "property_of_a"}, + {"display": "func_of_a"}, + {"display": "signal_of_a"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.notest.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.notest.gd new file mode 100644 index 0000000000..5c785b3ddc --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.notest.gd @@ -0,0 +1,6 @@ +# TODO +extends Node + +func a(): + var test: Node = $A + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg new file mode 100644 index 0000000000..446198dd35 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; AnimationPlayer + {"display": "autoplay"}, + {"display": "play"}, + {"display": "animation_changed"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.notest.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.notest.gd new file mode 100644 index 0000000000..57f4e16e3c --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.notest.gd @@ -0,0 +1,6 @@ +# TODO +extends Node + +func a(): + var test: Node = $AnimationPlayer + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg new file mode 100644 index 0000000000..1894e72c65 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg @@ -0,0 +1,20 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; Area2D + {"display": "get_overlapping_areas"}, + {"display": "linear_damp"}, + {"display": "area_entered"}, +] +exclude=[ + ; GDScript: class_a.notest.gd + {"display": "property_of_a"}, + {"display": "func_of_a"}, + {"display": "signal_of_a"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.gd new file mode 100644 index 0000000000..c6adfe0dd3 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.gd @@ -0,0 +1,5 @@ +extends Node + +func a(): + var test: Area2D = $A + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg new file mode 100644 index 0000000000..c8ab63f6d6 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg @@ -0,0 +1,20 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; Area2D + {"display": "get_overlapping_areas"}, + {"display": "linear_damp"}, + {"display": "area_entered"}, +] +exclude=[ + ; AnimationPlayer + {"display": "autoplay"}, + {"display": "play"}, + {"display": "animation_changed"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.gd new file mode 100644 index 0000000000..f53fce9bfe --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.gd @@ -0,0 +1,5 @@ +extends Node + +func a(): + var test: Area2D = $AnimationPlayer + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg b/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg new file mode 100644 index 0000000000..ae7d34d87d --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg @@ -0,0 +1,7 @@ +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/member/member.gd b/modules/gdscript/tests/scripts/completion/get_node/member/member.gd new file mode 100644 index 0000000000..6bcc0a0298 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member/member.gd @@ -0,0 +1,6 @@ +extends Node + +var test = $AnimationPlayer + +func a(): + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.cfg new file mode 100644 index 0000000000..ae7d34d87d --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.cfg @@ -0,0 +1,7 @@ +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.gd b/modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.gd new file mode 100644 index 0000000000..542197e643 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.gd @@ -0,0 +1,6 @@ +extends Node + +var test := $AnimationPlayer + +func a(): + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.cfg new file mode 100644 index 0000000000..009ab9f9ce --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; GDScript: class_a.notest.gd + {"display": "property_of_a"}, + {"display": "func_of_a"}, + {"display": "signal_of_a"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.gd new file mode 100644 index 0000000000..da0b1b11d4 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.gd @@ -0,0 +1,6 @@ +extends Node + +var test := $A + +func a(): + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.cfg new file mode 100644 index 0000000000..0fb46a4704 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; AnimationPlayer + {"display": "autoplay"}, + {"display": "play"}, + {"display": "animation_changed"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.gd new file mode 100644 index 0000000000..542197e643 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.gd @@ -0,0 +1,6 @@ +extends Node + +var test := $AnimationPlayer + +func a(): + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg new file mode 100644 index 0000000000..009ab9f9ce --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; GDScript: class_a.notest.gd + {"display": "property_of_a"}, + {"display": "func_of_a"}, + {"display": "signal_of_a"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.gd new file mode 100644 index 0000000000..4a35661e94 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.gd @@ -0,0 +1,6 @@ +extends Node + +var test = $A + +func a(): + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg new file mode 100644 index 0000000000..0fb46a4704 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; AnimationPlayer + {"display": "autoplay"}, + {"display": "play"}, + {"display": "animation_changed"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.gd new file mode 100644 index 0000000000..6bcc0a0298 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.gd @@ -0,0 +1,6 @@ +extends Node + +var test = $AnimationPlayer + +func a(): + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg new file mode 100644 index 0000000000..a72b489be6 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg @@ -0,0 +1,12 @@ +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; GDScript: class_a.notest.gd + {"display": "property_of_a"}, + {"display": "func_of_a"}, + {"display": "signal_of_a"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.gd new file mode 100644 index 0000000000..e4edc3a4e4 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.gd @@ -0,0 +1,8 @@ +extends Node + +const A := preload("res://completion/class_a.notest.gd") + +var test: A = $A + +func a(): + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg new file mode 100644 index 0000000000..adf06c8707 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg @@ -0,0 +1,12 @@ +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; AnimationPlayer + {"display": "autoplay"}, + {"display": "play"}, + {"display": "animation_changed"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.gd index d41bbb970c..eda94ae34d 100644 --- a/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.gd +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.gd @@ -2,5 +2,5 @@ extends Node var test: AnimationPlayer = $AnimationPlayer -func _ready(): +func a(): test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg new file mode 100644 index 0000000000..9c580b711d --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; GDScript: class_a.notest.gd + {"display": "property_of_a"}, + {"display": "func_of_a"}, + {"display": "signal_of_a"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.gd new file mode 100644 index 0000000000..8f68f54072 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.gd @@ -0,0 +1,8 @@ +extends Node + +const A := preload("res://completion/class_a.notest.gd") + +@onready var test: A = $A + +func a(): + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg new file mode 100644 index 0000000000..446198dd35 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg @@ -0,0 +1,14 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; AnimationPlayer + {"display": "autoplay"}, + {"display": "play"}, + {"display": "animation_changed"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.gd new file mode 100644 index 0000000000..eda94ae34d --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.gd @@ -0,0 +1,6 @@ +extends Node + +var test: AnimationPlayer = $AnimationPlayer + +func a(): + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg new file mode 100644 index 0000000000..502038bef7 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg @@ -0,0 +1,16 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + +] +exclude=[ + ; GDScript: class_a.notest.gd + {"display": "property_of_a"}, + {"display": "func_of_a"}, + {"display": "signal_of_a"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.gd new file mode 100644 index 0000000000..7b0ed4ecd8 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.gd @@ -0,0 +1,6 @@ +extends Node + +var test: Node = $A + +func a(): + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg new file mode 100644 index 0000000000..1810e9fe5f --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg @@ -0,0 +1,16 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + +] +exclude=[ + ; AnimationPlayer + {"display": "autoplay"}, + {"display": "play"}, + {"display": "animation_changed"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.gd new file mode 100644 index 0000000000..87342f9a21 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.gd @@ -0,0 +1,6 @@ +extends Node + +var test: Node = $AnimationPlayer + +func a(): + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg new file mode 100644 index 0000000000..1894e72c65 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg @@ -0,0 +1,20 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; Area2D + {"display": "get_overlapping_areas"}, + {"display": "linear_damp"}, + {"display": "area_entered"}, +] +exclude=[ + ; GDScript: class_a.notest.gd + {"display": "property_of_a"}, + {"display": "func_of_a"}, + {"display": "signal_of_a"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.gd new file mode 100644 index 0000000000..5f78bcdf04 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.gd @@ -0,0 +1,6 @@ +extends Node + +var test: Area2D = $A + +func a(): + test.➡ diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg new file mode 100644 index 0000000000..c8ab63f6d6 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg @@ -0,0 +1,20 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + ; Node + {"display": "add_child"}, + {"display": "owner"}, + {"display": "child_entered_tree"}, + + ; Area2D + {"display": "get_overlapping_areas"}, + {"display": "linear_damp"}, + {"display": "area_entered"}, +] +exclude=[ + ; AnimationPlayer + {"display": "autoplay"}, + {"display": "play"}, + {"display": "animation_changed"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.gd new file mode 100644 index 0000000000..c14df5cd1b --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.gd @@ -0,0 +1,6 @@ +extends Node + +var test: Area2D = $AnimationPlayer + +func a(): + test.➡ diff --git a/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.gd b/modules/gdscript/tests/scripts/parser/errors/dollar_assignment_bug_53696.gd index e9690ee93d..e9690ee93d 100644 --- a/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.gd +++ b/modules/gdscript/tests/scripts/parser/errors/dollar_assignment_bug_53696.gd diff --git a/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.out b/modules/gdscript/tests/scripts/parser/errors/dollar_assignment_bug_53696.out index 9fafcb5a64..9fafcb5a64 100644 --- a/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.out +++ b/modules/gdscript/tests/scripts/parser/errors/dollar_assignment_bug_53696.out diff --git a/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_array_type.gd b/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_array_type.gd new file mode 100644 index 0000000000..9f1a52856d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_array_type.gd @@ -0,0 +1,4 @@ +@export_enum("A", "B", "C") var x: Array[Color] + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_array_type.out b/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_array_type.out new file mode 100644 index 0000000000..1e0455b96d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_array_type.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +"@export_enum" annotation requires a variable of type "int", "Array[int]", "PackedByteArray", "PackedInt32Array", "PackedInt64Array", "String", "Array[String]", or "PackedStringArray", but type "Array[Color]" was given instead. diff --git a/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_type.gd b/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_type.gd new file mode 100644 index 0000000000..5fe66e7cce --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_type.gd @@ -0,0 +1,4 @@ +@export_enum("A", "B", "C") var x: Color + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_type.out b/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_type.out new file mode 100644 index 0000000000..43a08acc0a --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_type.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +"@export_enum" annotation requires a variable of type "int", "Array[int]", "PackedByteArray", "PackedInt32Array", "PackedInt64Array", "String", "Array[String]", or "PackedStringArray", but type "Color" was given instead. diff --git a/modules/gdscript/tests/scripts/parser/features/export_arrays.gd b/modules/gdscript/tests/scripts/parser/features/export_arrays.gd new file mode 100644 index 0000000000..ddfb186aa4 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/export_arrays.gd @@ -0,0 +1,86 @@ +const Utils = preload("../../utils.notest.gd") + +@export_dir var test_dir: Array[String] +@export_dir var test_dir_packed: PackedStringArray +@export_file var test_file: Array[String] +@export_file var test_file_packed: PackedStringArray +@export_global_dir var test_global_dir: Array[String] +@export_global_dir var test_global_dir_packed: PackedStringArray +@export_global_file var test_global_file: Array[String] +@export_global_file var test_global_file_packed: PackedStringArray +@export_flags("A", "B", "C") var test_bit_flag: Array[int] +@export_flags("A", "B", "C") var test_bit_flag_packed_byte: PackedByteArray +@export_flags("A", "B", "C") var test_bit_flag_packed32: PackedInt32Array +@export_flags("A", "B", "C") var test_bit_flag_packed64: PackedInt64Array +@export_flags_2d_navigation var test_bit_flag_2d_nav: Array[int] +@export_flags_2d_navigation var test_bit_flag_2d_nav_packed_byte: PackedByteArray +@export_flags_2d_navigation var test_bit_flag_2d_nav_packed32: PackedInt32Array +@export_flags_2d_navigation var test_bit_flag_2d_nav_packed64: PackedInt64Array +@export_flags_2d_physics var test_bit_flag_2d_phys: Array[int] +@export_flags_2d_physics var test_bit_flag_2d_phys_packed_byte: PackedByteArray +@export_flags_2d_physics var test_bit_flag_2d_phys_packed32: PackedInt32Array +@export_flags_2d_physics var test_bit_flag_2d_phys_packed64: PackedInt64Array +@export_flags_2d_render var test_bit_flag_2d_render: Array[int] +@export_flags_2d_render var test_bit_flag_2d_render_packed_byte: PackedByteArray +@export_flags_2d_render var test_bit_flag_2d_render_packed32: PackedInt32Array +@export_flags_2d_render var test_bit_flag_2d_render_packed64: PackedInt64Array +@export_flags_3d_navigation var test_bit_flag_3d_nav: Array[int] +@export_flags_3d_navigation var test_bit_flag_3d_nav_packed_byte: PackedByteArray +@export_flags_3d_navigation var test_bit_flag_3d_nav_packed32: PackedInt32Array +@export_flags_3d_navigation var test_bit_flag_3d_nav_packed64: PackedInt64Array +@export_flags_3d_physics var test_bit_flag_3d_phys: Array[int] +@export_flags_3d_physics var test_bit_flag_3d_phys_packed_byte: PackedByteArray +@export_flags_3d_physics var test_bit_flag_3d_phys_packed32: PackedInt32Array +@export_flags_3d_physics var test_bit_flag_3d_phys_packed64: PackedInt64Array +@export_flags_3d_render var test_bit_flag_3d_render: Array[int] +@export_flags_3d_render var test_bit_flag_3d_render_packed_byte: PackedByteArray +@export_flags_3d_render var test_bit_flag_3d_render_packed32: PackedInt32Array +@export_flags_3d_render var test_bit_flag_3d_render_packed64: PackedInt64Array +@export_multiline var test_multiline: Array[String] +@export_multiline var test_multiline_packed: PackedStringArray +@export_placeholder("Placeholder") var test_placeholder: Array[String] +@export_placeholder("Placeholder") var test_placeholder_packed: PackedStringArray +@export_range(1, 10) var test_range_int: Array[int] +@export_range(1, 10) var test_range_int_packed_byte: PackedByteArray +@export_range(1, 10) var test_range_int_packed32: PackedInt32Array +@export_range(1, 10) var test_range_int_packed64: PackedInt64Array +@export_range(1, 10, 0.01) var test_range_int_float_step: Array[int] +@export_range(1.0, 10.0) var test_range_float: Array[float] +@export_range(1.0, 10.0) var test_range_float_packed32: PackedFloat32Array +@export_range(1.0, 10.0) var test_range_float_packed64: PackedFloat64Array +@export_exp_easing var test_exp_easing: Array[float] +@export_exp_easing var test_exp_easing_packed32: PackedFloat32Array +@export_exp_easing var test_exp_easing_packed64: PackedFloat64Array +@export_node_path var test_node_path: Array[NodePath] +@export_color_no_alpha var test_color: Array[Color] +@export_color_no_alpha var test_color_packed: PackedColorArray + +var temp_packed_byte_array: PackedByteArray +var temp_packed_int32_array: PackedInt32Array +var temp_packed_int64_array: PackedInt64Array +var temp_packed_float32_array: PackedFloat32Array +var temp_packed_float64_array: PackedFloat64Array +var temp_packed_color_array: PackedColorArray +var temp_packed_vector2_array: PackedVector2Array +var temp_packed_vector3_array: PackedVector3Array + +@export var test_weak_packed_byte_array = temp_packed_byte_array +@export var test_weak_packed_int32_array = temp_packed_int32_array +@export var test_weak_packed_int64_array = temp_packed_int64_array +@export var test_weak_packed_float32_array = temp_packed_float32_array +@export var test_weak_packed_float64_array = temp_packed_float64_array +@export var test_weak_packed_color_array = temp_packed_color_array +@export var test_weak_packed_vector2_array = temp_packed_vector2_array +@export var test_weak_packed_vector3_array = temp_packed_vector3_array + +@export_range(1, 10) var test_range_weak_packed_byte_array = temp_packed_byte_array +@export_range(1, 10) var test_range_weak_packed_int32_array = temp_packed_int32_array +@export_range(1, 10) var test_range_weak_packed_int64_array = temp_packed_int64_array +@export_range(1, 10) var test_range_weak_packed_float32_array = temp_packed_float32_array +@export_range(1, 10) var test_range_weak_packed_float64_array = temp_packed_float64_array +@export_color_no_alpha var test_noalpha_weak_packed_color_array = temp_packed_color_array + +func test(): + for property in get_property_list(): + if str(property.name).begins_with("test_"): + Utils.print_property_extended_info(property) diff --git a/modules/gdscript/tests/scripts/parser/features/export_arrays.out b/modules/gdscript/tests/scripts/parser/features/export_arrays.out new file mode 100644 index 0000000000..00e75fcc43 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/export_arrays.out @@ -0,0 +1,137 @@ +GDTEST_OK +var test_dir: Array + hint=TYPE_STRING hint_string="String/DIR:" usage=DEFAULT|SCRIPT_VARIABLE +var test_dir_packed: PackedStringArray + hint=TYPE_STRING hint_string="String/DIR:" usage=DEFAULT|SCRIPT_VARIABLE +var test_file: Array + hint=TYPE_STRING hint_string="String/FILE:" usage=DEFAULT|SCRIPT_VARIABLE +var test_file_packed: PackedStringArray + hint=TYPE_STRING hint_string="String/FILE:" usage=DEFAULT|SCRIPT_VARIABLE +var test_global_dir: Array + hint=TYPE_STRING hint_string="String/GLOBAL_DIR:" usage=DEFAULT|SCRIPT_VARIABLE +var test_global_dir_packed: PackedStringArray + hint=TYPE_STRING hint_string="String/GLOBAL_DIR:" usage=DEFAULT|SCRIPT_VARIABLE +var test_global_file: Array + hint=TYPE_STRING hint_string="String/GLOBAL_FILE:" usage=DEFAULT|SCRIPT_VARIABLE +var test_global_file_packed: PackedStringArray + hint=TYPE_STRING hint_string="String/GLOBAL_FILE:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag: Array + hint=TYPE_STRING hint_string="int/FLAGS:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_packed_byte: PackedByteArray + hint=TYPE_STRING hint_string="int/FLAGS:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_packed32: PackedInt32Array + hint=TYPE_STRING hint_string="int/FLAGS:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_packed64: PackedInt64Array + hint=TYPE_STRING hint_string="int/FLAGS:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_2d_nav: Array + hint=TYPE_STRING hint_string="int/LAYERS_2D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_2d_nav_packed_byte: PackedByteArray + hint=TYPE_STRING hint_string="int/LAYERS_2D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_2d_nav_packed32: PackedInt32Array + hint=TYPE_STRING hint_string="int/LAYERS_2D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_2d_nav_packed64: PackedInt64Array + hint=TYPE_STRING hint_string="int/LAYERS_2D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_2d_phys: Array + hint=TYPE_STRING hint_string="int/LAYERS_2D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_2d_phys_packed_byte: PackedByteArray + hint=TYPE_STRING hint_string="int/LAYERS_2D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_2d_phys_packed32: PackedInt32Array + hint=TYPE_STRING hint_string="int/LAYERS_2D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_2d_phys_packed64: PackedInt64Array + hint=TYPE_STRING hint_string="int/LAYERS_2D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_2d_render: Array + hint=TYPE_STRING hint_string="int/LAYERS_2D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_2d_render_packed_byte: PackedByteArray + hint=TYPE_STRING hint_string="int/LAYERS_2D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_2d_render_packed32: PackedInt32Array + hint=TYPE_STRING hint_string="int/LAYERS_2D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_2d_render_packed64: PackedInt64Array + hint=TYPE_STRING hint_string="int/LAYERS_2D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_3d_nav: Array + hint=TYPE_STRING hint_string="int/LAYERS_3D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_3d_nav_packed_byte: PackedByteArray + hint=TYPE_STRING hint_string="int/LAYERS_3D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_3d_nav_packed32: PackedInt32Array + hint=TYPE_STRING hint_string="int/LAYERS_3D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_3d_nav_packed64: PackedInt64Array + hint=TYPE_STRING hint_string="int/LAYERS_3D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_3d_phys: Array + hint=TYPE_STRING hint_string="int/LAYERS_3D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_3d_phys_packed_byte: PackedByteArray + hint=TYPE_STRING hint_string="int/LAYERS_3D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_3d_phys_packed32: PackedInt32Array + hint=TYPE_STRING hint_string="int/LAYERS_3D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_3d_phys_packed64: PackedInt64Array + hint=TYPE_STRING hint_string="int/LAYERS_3D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_3d_render: Array + hint=TYPE_STRING hint_string="int/LAYERS_3D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_3d_render_packed_byte: PackedByteArray + hint=TYPE_STRING hint_string="int/LAYERS_3D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_3d_render_packed32: PackedInt32Array + hint=TYPE_STRING hint_string="int/LAYERS_3D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE +var test_bit_flag_3d_render_packed64: PackedInt64Array + hint=TYPE_STRING hint_string="int/LAYERS_3D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE +var test_multiline: Array + hint=TYPE_STRING hint_string="String/MULTILINE_TEXT:" usage=DEFAULT|SCRIPT_VARIABLE +var test_multiline_packed: PackedStringArray + hint=TYPE_STRING hint_string="String/MULTILINE_TEXT:" usage=DEFAULT|SCRIPT_VARIABLE +var test_placeholder: Array + hint=TYPE_STRING hint_string="String/PLACEHOLDER_TEXT:Placeholder" usage=DEFAULT|SCRIPT_VARIABLE +var test_placeholder_packed: PackedStringArray + hint=TYPE_STRING hint_string="String/PLACEHOLDER_TEXT:Placeholder" usage=DEFAULT|SCRIPT_VARIABLE +var test_range_int: Array + hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE +var test_range_int_packed_byte: PackedByteArray + hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE +var test_range_int_packed32: PackedInt32Array + hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE +var test_range_int_packed64: PackedInt64Array + hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE +var test_range_int_float_step: Array + hint=TYPE_STRING hint_string="int/RANGE:1,10,0.01" usage=DEFAULT|SCRIPT_VARIABLE +var test_range_float: Array + hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE +var test_range_float_packed32: PackedFloat32Array + hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE +var test_range_float_packed64: PackedFloat64Array + hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE +var test_exp_easing: Array + hint=TYPE_STRING hint_string="float/EXP_EASING:" usage=DEFAULT|SCRIPT_VARIABLE +var test_exp_easing_packed32: PackedFloat32Array + hint=TYPE_STRING hint_string="float/EXP_EASING:" usage=DEFAULT|SCRIPT_VARIABLE +var test_exp_easing_packed64: PackedFloat64Array + hint=TYPE_STRING hint_string="float/EXP_EASING:" usage=DEFAULT|SCRIPT_VARIABLE +var test_node_path: Array + hint=TYPE_STRING hint_string="NodePath/NODE_PATH_VALID_TYPES:" usage=DEFAULT|SCRIPT_VARIABLE +var test_color: Array + hint=TYPE_STRING hint_string="Color/COLOR_NO_ALPHA:" usage=DEFAULT|SCRIPT_VARIABLE +var test_color_packed: PackedColorArray + hint=TYPE_STRING hint_string="Color/COLOR_NO_ALPHA:" usage=DEFAULT|SCRIPT_VARIABLE +var test_weak_packed_byte_array: PackedByteArray + hint=TYPE_STRING hint_string="int:int" usage=DEFAULT|SCRIPT_VARIABLE +var test_weak_packed_int32_array: PackedInt32Array + hint=TYPE_STRING hint_string="int:int" usage=DEFAULT|SCRIPT_VARIABLE +var test_weak_packed_int64_array: PackedInt64Array + hint=TYPE_STRING hint_string="int:int" usage=DEFAULT|SCRIPT_VARIABLE +var test_weak_packed_float32_array: PackedFloat32Array + hint=TYPE_STRING hint_string="float:float" usage=DEFAULT|SCRIPT_VARIABLE +var test_weak_packed_float64_array: PackedFloat64Array + hint=TYPE_STRING hint_string="float:float" usage=DEFAULT|SCRIPT_VARIABLE +var test_weak_packed_color_array: PackedColorArray + hint=TYPE_STRING hint_string="Color:Color" usage=DEFAULT|SCRIPT_VARIABLE +var test_weak_packed_vector2_array: PackedVector2Array + hint=TYPE_STRING hint_string="Vector2:Vector2" usage=DEFAULT|SCRIPT_VARIABLE +var test_weak_packed_vector3_array: PackedVector3Array + hint=TYPE_STRING hint_string="Vector3:Vector3" usage=DEFAULT|SCRIPT_VARIABLE +var test_range_weak_packed_byte_array: PackedByteArray + hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE +var test_range_weak_packed_int32_array: PackedInt32Array + hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE +var test_range_weak_packed_int64_array: PackedInt64Array + hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE +var test_range_weak_packed_float32_array: PackedFloat32Array + hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE +var test_range_weak_packed_float64_array: PackedFloat64Array + hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE +var test_noalpha_weak_packed_color_array: PackedColorArray + hint=TYPE_STRING hint_string="Color/COLOR_NO_ALPHA:" usage=DEFAULT|SCRIPT_VARIABLE diff --git a/modules/gdscript/tests/scripts/parser/features/export_enum.gd b/modules/gdscript/tests/scripts/parser/features/export_enum.gd index 4f2a43f4fe..7f0737f4db 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_enum.gd +++ b/modules/gdscript/tests/scripts/parser/features/export_enum.gd @@ -1,14 +1,35 @@ const Utils = preload("../../utils.notest.gd") @export_enum("Red", "Green", "Blue") var test_untyped +@export_enum("Red:10", "Green:20", "Blue:30") var test_with_values + +var temp_array_int: Array[int] +var temp_array_string: Array[String] +var temp_packed_byte_array: PackedByteArray +var temp_packed_int32_array: PackedInt32Array +var temp_packed_int64_array: PackedInt64Array +var temp_packed_string_array: PackedStringArray +@export_enum("Red", "Green", "Blue") var test_weak_variant @export_enum("Red", "Green", "Blue") var test_weak_int = 0 @export_enum("Red", "Green", "Blue") var test_weak_string = "" +@export_enum("Red", "Green", "Blue") var test_weak_array_int = temp_array_int +@export_enum("Red", "Green", "Blue") var test_weak_array_string = temp_array_string +@export_enum("Red", "Green", "Blue") var test_weak_packed_byte_array = temp_packed_byte_array +@export_enum("Red", "Green", "Blue") var test_weak_packed_int32_array = temp_packed_int32_array +@export_enum("Red", "Green", "Blue") var test_weak_packed_int64_array = temp_packed_int64_array +@export_enum("Red", "Green", "Blue") var test_weak_packed_string_array = temp_packed_string_array +@export_enum("Red", "Green", "Blue") var test_hard_variant: Variant @export_enum("Red", "Green", "Blue") var test_hard_int: int @export_enum("Red", "Green", "Blue") var test_hard_string: String +@export_enum("Red", "Green", "Blue") var test_hard_array_int: Array[int] +@export_enum("Red", "Green", "Blue") var test_hard_array_string: Array[String] -@export_enum("Red:10", "Green:20", "Blue:30") var test_with_values +@export_enum("Red", "Green", "Blue") var test_variant_array_int: Variant = temp_array_int +@export_enum("Red", "Green", "Blue") var test_variant_packed_int32_array: Variant = temp_packed_int32_array +@export_enum("Red", "Green", "Blue") var test_variant_array_string: Variant = temp_array_string +@export_enum("Red", "Green", "Blue") var test_variant_packed_string_array: Variant = temp_packed_string_array func test(): for property in get_property_list(): diff --git a/modules/gdscript/tests/scripts/parser/features/export_enum.out b/modules/gdscript/tests/scripts/parser/features/export_enum.out index 43f5e197ad..c87f9b17f0 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_enum.out +++ b/modules/gdscript/tests/scripts/parser/features/export_enum.out @@ -1,13 +1,41 @@ GDTEST_OK var test_untyped: int = null hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_with_values: int = null + hint=ENUM hint_string="Red:10,Green:20,Blue:30" usage=DEFAULT|SCRIPT_VARIABLE +var test_weak_variant: int = null + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE var test_weak_int: int = 0 hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE var test_weak_string: String = "" hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_weak_array_int: Array = Array[int]([]) + hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_weak_array_string: Array = Array[String]([]) + hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_weak_packed_byte_array: PackedByteArray = PackedByteArray() + hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_weak_packed_int32_array: PackedInt32Array = PackedInt32Array() + hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_weak_packed_int64_array: PackedInt64Array = PackedInt64Array() + hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_weak_packed_string_array: PackedStringArray = PackedStringArray() + hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_hard_variant: int = null + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE var test_hard_int: int = 0 hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE var test_hard_string: String = "" hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE -var test_with_values: int = null - hint=ENUM hint_string="Red:10,Green:20,Blue:30" usage=DEFAULT|SCRIPT_VARIABLE +var test_hard_array_int: Array = Array[int]([]) + hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_hard_array_string: Array = Array[String]([]) + hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_variant_array_int: Array = Array[int]([]) + hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_variant_packed_int32_array: PackedInt32Array = PackedInt32Array() + hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_variant_array_string: Array = Array[String]([]) + hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_variant_packed_string_array: PackedStringArray = PackedStringArray() + hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.out b/modules/gdscript/tests/scripts/parser/features/export_variable.out index baadcd4ee8..b3f9d0ca9c 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_variable.out +++ b/modules/gdscript/tests/scripts/parser/features/export_variable.out @@ -24,4 +24,4 @@ var test_node_path: NodePath = NodePath("hello") var test_node: Node = null hint=NODE_TYPE hint_string="Node" usage=DEFAULT|SCRIPT_VARIABLE var test_node_array: Array = Array[Node]([]) - hint=TYPE_STRING hint_string="24/34:Node" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="Object/NODE_TYPE:Node" usage=DEFAULT|SCRIPT_VARIABLE diff --git a/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.gd b/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.gd index 29d8501b78..193faab5d0 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.gd +++ b/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.gd @@ -1,11 +1,23 @@ -class Player: - var x = 3 +class_name TestStaticCalledOnInstance + +class Inner: + static func static_func(): + pass + +static func static_func(): + pass func test(): - # These should not emit a warning. - var _player = Player.new() - print(String.num_uint64(8589934592)) # 2 ^ 33 + print(String.num_uint64(8589934592)) + var some_string := String() + print(some_string.num_uint64(8589934592)) # Warning. + + TestStaticCalledOnInstance.static_func() + static_func() + self.static_func() + var other := TestStaticCalledOnInstance.new() + other.static_func() # Warning. - # This should emit a warning. - var some_string = String() - print(some_string.num_uint64(8589934592)) # 2 ^ 33 + Inner.static_func() + var inner := Inner.new() + inner.static_func() # Warning. diff --git a/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.out b/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.out index 77994ce9ba..c00f3d093a 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.out +++ b/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.out @@ -1,7 +1,15 @@ GDTEST_OK >> WARNING ->> Line: 11 +>> Line: 13 >> STATIC_CALLED_ON_INSTANCE >> The function "num_uint64()" is a static function but was called from an instance. Instead, it should be directly called from the type: "String.num_uint64()". +>> WARNING +>> Line: 19 +>> STATIC_CALLED_ON_INSTANCE +>> The function "static_func()" is a static function but was called from an instance. Instead, it should be directly called from the type: "TestStaticCalledOnInstance.static_func()". +>> WARNING +>> Line: 23 +>> STATIC_CALLED_ON_INSTANCE +>> The function "static_func()" is a static function but was called from an instance. Instead, it should be directly called from the type: "Inner.static_func()". 8589934592 8589934592 diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.gd b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.gd index 809d0d28a9..809d0d28a9 100644 --- a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.gd +++ b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.gd diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.out b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.out index 27423ab8e7..27423ab8e7 100644 --- a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.out +++ b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.out diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.gd b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.gd index f46afb0f18..f46afb0f18 100644 --- a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.gd +++ b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.gd diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.out b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.out index a11c47854a..a11c47854a 100644 --- a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.out +++ b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.out diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.gd b/modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.gd index 7649062fda..7649062fda 100644 --- a/modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.gd +++ b/modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.gd diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.out b/modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.out index 639f6027b9..639f6027b9 100644 --- a/modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.out +++ b/modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.out diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.gd b/modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.gd index 8d5f9df1b8..8d5f9df1b8 100644 --- a/modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.gd +++ b/modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.gd diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.out b/modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.out index d1e332afba..d1e332afba 100644 --- a/modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.out +++ b/modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.out diff --git a/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on exit_block.gd b/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.gd index c774ebf83c..c774ebf83c 100644 --- a/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on exit_block.gd +++ b/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.gd diff --git a/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on exit_block.out b/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.out index 04b4638adf..04b4638adf 100644 --- a/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on exit_block.out +++ b/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.out diff --git a/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd b/modules/gdscript/tests/scripts/runtime/features/standalone_calls_do_not_write_to_nil.gd index 691b611574..691b611574 100644 --- a/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd +++ b/modules/gdscript/tests/scripts/runtime/features/standalone_calls_do_not_write_to_nil.gd diff --git a/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.out b/modules/gdscript/tests/scripts/runtime/features/standalone_calls_do_not_write_to_nil.out index 5bc3dcf2db..5bc3dcf2db 100644 --- a/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.out +++ b/modules/gdscript/tests/scripts/runtime/features/standalone_calls_do_not_write_to_nil.out diff --git a/modules/gdscript/tests/scripts/utils.notest.gd b/modules/gdscript/tests/scripts/utils.notest.gd index 31818c9d01..1cf46c179e 100644 --- a/modules/gdscript/tests/scripts/utils.notest.gd +++ b/modules/gdscript/tests/scripts/utils.notest.gd @@ -39,11 +39,46 @@ static func get_property_signature(property: Dictionary, base: Object = null, is return result +static func get_human_readable_hint_string(property: Dictionary) -> String: + if property.type >= TYPE_ARRAY and property.hint == PROPERTY_HINT_TYPE_STRING: + var type_hint_prefixes: String = "" + var hint_string: String = property.hint_string + + while true: + if not hint_string.contains(":"): + push_error("Invalid PROPERTY_HINT_TYPE_STRING format.") + var elem_type_hint: String = hint_string.get_slice(":", 0) + hint_string = hint_string.substr(elem_type_hint.length() + 1) + + var elem_type: int + var elem_hint: int + + if elem_type_hint.is_valid_int(): + elem_type = elem_type_hint.to_int() + type_hint_prefixes += type_string(elem_type) + ":" + else: + if elem_type_hint.count("/") != 1: + push_error("Invalid PROPERTY_HINT_TYPE_STRING format.") + elem_type = elem_type_hint.get_slice("/", 0).to_int() + elem_hint = elem_type_hint.get_slice("/", 1).to_int() + type_hint_prefixes += "%s/%s:" % [ + type_string(elem_type), + get_property_hint_name(elem_hint).trim_prefix("PROPERTY_HINT_"), + ] + + if elem_type < TYPE_ARRAY: + break + + return type_hint_prefixes + hint_string + + return property.hint_string + + static func print_property_extended_info(property: Dictionary, base: Object = null, is_static: bool = false) -> void: print(get_property_signature(property, base, is_static)) print(' hint=%s hint_string="%s" usage=%s' % [ get_property_hint_name(property.hint).trim_prefix("PROPERTY_HINT_"), - str(property.hint_string).c_escape(), + get_human_readable_hint_string(property), get_property_usage_string(property.usage).replace("PROPERTY_USAGE_", ""), ]) diff --git a/modules/gdscript/tests/test_completion.h b/modules/gdscript/tests/test_completion.h index fd6b5321e6..ac9ffcd915 100644 --- a/modules/gdscript/tests/test_completion.h +++ b/modules/gdscript/tests/test_completion.h @@ -139,7 +139,7 @@ static void test_directory(const String &p_dir) { Node *owner = nullptr; if (conf.has_section_key("input", "scene")) { - Ref<PackedScene> scene = ResourceLoader::load(conf.get_value("input", "scene"), "PackedScene"); + Ref<PackedScene> scene = ResourceLoader::load(conf.get_value("input", "scene"), "PackedScene", ResourceFormatLoader::CACHE_MODE_IGNORE_DEEP); if (scene.is_valid()) { owner = scene->instantiate(); } diff --git a/modules/mbedtls/SCsub b/modules/mbedtls/SCsub index 7c1204d2b7..4b8f65d8ff 100644 --- a/modules/mbedtls/SCsub +++ b/modules/mbedtls/SCsub @@ -121,6 +121,9 @@ if env["tests"]: env_mbed_tls.Append(CPPDEFINES=["TESTS_ENABLED"]) env_mbed_tls.add_source_files(module_obj, "./tests/*.cpp") + if env["disable_exceptions"]: + env_mbed_tls.Append(CPPDEFINES=["DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS"]) + env.modules_sources += module_obj # Needed to force rebuilding the module files when the thirdparty library is updated. diff --git a/modules/mbedtls/tests/test_crypto_mbedtls.cpp b/modules/mbedtls/tests/test_crypto_mbedtls.cpp index 22d79b79f9..b96a072146 100644 --- a/modules/mbedtls/tests/test_crypto_mbedtls.cpp +++ b/modules/mbedtls/tests/test_crypto_mbedtls.cpp @@ -33,6 +33,7 @@ #include "../crypto_mbedtls.h" #include "tests/test_macros.h" +#include "tests/test_utils.h" namespace TestCryptoMbedTLS { @@ -60,4 +61,42 @@ void hmac_context_digest_test(HashingContext::HashType ht, String expected_hex) String hex = String::hex_encode_buffer(digest.ptr(), digest.size()); CHECK(hex == expected_hex); } + +Ref<CryptoKey> create_crypto_key(const String &p_key_path, bool p_public_only) { + Ref<CryptoKey> crypto_key = Ref<CryptoKey>(CryptoKey::create()); + crypto_key->load(p_key_path, p_public_only); + return crypto_key; +} + +String read_file_s(const String &p_file_path) { + Ref<FileAccess> file_access = FileAccess::open(p_file_path, FileAccess::READ); + REQUIRE(file_access.is_valid()); + return file_access->get_as_utf8_string(); +} + +bool files_equal(const String &p_in_path, const String &p_out_path) { + const String s_in = read_file_s(p_in_path); + const String s_out = read_file_s(p_out_path); + return s_in == s_out; +} + +void crypto_key_public_only_test(const String &p_key_path, bool p_public_only) { + Ref<CryptoKey> crypto_key = create_crypto_key(p_key_path, p_public_only); + bool is_equal = crypto_key->is_public_only() == p_public_only; + CHECK(is_equal); +} + +void crypto_key_save_test(const String &p_in_path, const String &p_out_path, bool p_public_only) { + Ref<CryptoKey> crypto_key = create_crypto_key(p_in_path, p_public_only); + crypto_key->save(p_out_path, p_public_only); + bool is_equal = files_equal(p_in_path, p_out_path); + CHECK(is_equal); +} + +void crypto_key_save_public_only_test(const String &p_in_priv_path, const String &p_in_pub_path, const String &p_out_path) { + Ref<CryptoKey> crypto_key = create_crypto_key(p_in_priv_path, false); + crypto_key->save(p_out_path, true); + bool is_equal = files_equal(p_in_pub_path, p_out_path); + CHECK(is_equal); +} } // namespace TestCryptoMbedTLS diff --git a/modules/mbedtls/tests/test_crypto_mbedtls.h b/modules/mbedtls/tests/test_crypto_mbedtls.h index 0b24925d6b..5ec78d18a3 100644 --- a/modules/mbedtls/tests/test_crypto_mbedtls.h +++ b/modules/mbedtls/tests/test_crypto_mbedtls.h @@ -31,9 +31,11 @@ #ifndef TEST_CRYPTO_MBEDTLS_H #define TEST_CRYPTO_MBEDTLS_H +#include "core/crypto/crypto.h" #include "core/crypto/hashing_context.h" #include "tests/test_macros.h" +#include "tests/test_utils.h" namespace TestCryptoMbedTLS { @@ -56,6 +58,35 @@ TEST_CASE("[HMACContext] HMAC digest") { // SHA-1 hmac_context_digest_test(HashingContext::HashType::HASH_SHA1, "a0ac4cd68a2f4812c355983d94e8d025afe7dddf"); } + +void crypto_key_public_only_test(const String &p_key_path, bool public_only); + +TEST_CASE("[Crypto] CryptoKey is_public_only") { + crypto_key_public_only_test(TestUtils::get_data_path("crypto/in.key"), false); + crypto_key_public_only_test(TestUtils::get_data_path("crypto/in.pub"), true); +} + +void crypto_key_save_test(const String &p_in_path, const String &p_out_path, bool public_only); + +TEST_CASE("[Crypto] CryptoKey save") { + const String in_priv_path = TestUtils::get_data_path("crypto/in.key"); + const String out_priv_path = TestUtils::get_data_path("crypto/out.key"); + crypto_key_save_test(in_priv_path, out_priv_path, false); + + const String in_pub_path = TestUtils::get_data_path("crypto/in.pub"); + const String out_pub_path = TestUtils::get_data_path("crypto/out.pub"); + crypto_key_save_test(in_pub_path, out_pub_path, true); +} + +void crypto_key_save_public_only_test(const String &p_in_priv_path, const String &p_in_pub_path, const String &p_out_path); + +TEST_CASE("[Crypto] CryptoKey save public_only") { + const String in_priv_path = TestUtils::get_data_path("crypto/in.key"); + const String in_pub_path = TestUtils::get_data_path("crypto/in.pub"); + const String out_path = TestUtils::get_data_path("crypto/out_public_only.pub"); + crypto_key_save_public_only_test(in_priv_path, in_pub_path, out_path); +} + } // namespace TestCryptoMbedTLS #endif // TEST_CRYPTO_MBEDTLS_H diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 9ccaa27e84..93fb5f1dc6 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -405,6 +405,10 @@ bool CSharpLanguage::supports_builtin_mode() const { return false; } +ScriptLanguage::ScriptNameCasing CSharpLanguage::preferred_file_name_casing() const { + return SCRIPT_NAME_CASING_PASCAL_CASE; +} + #ifdef TOOLS_ENABLED struct VariantCsName { Variant::Type variant_type; diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 99e6ebf2e3..7821420620 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -518,6 +518,7 @@ public: virtual String _get_indentation() const; /* TODO? */ void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const override {} /* TODO */ void add_global_constant(const StringName &p_variable, const Variant &p_value) override {} + virtual ScriptNameCasing preferred_file_name_casing() const override; /* SCRIPT GLOBAL CLASS FUNCTIONS */ virtual bool handles_global_class_type(const String &p_type) const override; diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedComplexStrings.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedComplexStrings.cs new file mode 100644 index 0000000000..907257b125 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedComplexStrings.cs @@ -0,0 +1,26 @@ +using Godot; + +namespace Godot.SourceGenerators.Sample +{ + public partial class ExportedComplexStrings : Node + { + [Export] + private string _fieldInterpolated1 = $"The quick brown fox jumps over ({Engine.GetVersionInfo()})"; + + [Export] + private string _fieldInterpolated2 = $"The quick brown fox jumps over ({Engine.GetVersionInfo()["major"],0:G}) the lazy dog."; + + [Export] + private string _fieldInterpolated3 = $"{((int)Engine.GetVersionInfo()["major"]) * -1 * -1:G} the lazy dog."; + + [Export] + private string _fieldInterpolated4 = $"{":::fff,,}<,<}},,}]"}"; + + [Export] + public string PropertyInterpolated1 + { + get; + private set; + } = $"The quick brown fox jumps over {GD.VarToStr($"the lazy {Engine.GetVersionInfo()} do")}g."; + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertyDefValGeneratorTests.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertyDefValGeneratorTests.cs index ae5fb86d77..7711bce1c7 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertyDefValGeneratorTests.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertyDefValGeneratorTests.cs @@ -21,4 +21,13 @@ public class ScriptPropertyDefValGeneratorTests "ExportedProperties_ScriptPropertyDefVal.generated.cs" ); } + + [Fact] + public async void ExportedComplexStrings() + { + await CSharpSourceGeneratorVerifier<ScriptPropertyDefValGenerator>.Verify( + "ExportedComplexStrings.cs", + "ExportedComplexStrings_ScriptPropertyDefVal.generated.cs" + ); + } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedComplexStrings_ScriptPropertyDefVal.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedComplexStrings_ScriptPropertyDefVal.generated.cs new file mode 100644 index 0000000000..69e85b4467 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedComplexStrings_ScriptPropertyDefVal.generated.cs @@ -0,0 +1,29 @@ +partial class ExportedComplexStrings +{ +#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword +#if TOOLS + /// <summary> + /// Get the default values for all properties declared in this class. + /// This method is used by Godot to determine the value that will be + /// used by the inspector when resetting properties. + /// Do not call this method. + /// </summary> + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + internal new static global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant> GetGodotPropertyDefaultValues() + { + var values = new global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant>(5); + string __PropertyInterpolated1_default_value = $"The quick brown fox jumps over {(global::Godot.GD.VarToStr($"the lazy {(global::Godot.Engine.GetVersionInfo())} do"))}g."; + values.Add(PropertyName.PropertyInterpolated1, global::Godot.Variant.From<string>(__PropertyInterpolated1_default_value)); + string ___fieldInterpolated1_default_value = $"The quick brown fox jumps over ({(global::Godot.Engine.GetVersionInfo())})"; + values.Add(PropertyName._fieldInterpolated1, global::Godot.Variant.From<string>(___fieldInterpolated1_default_value)); + string ___fieldInterpolated2_default_value = $"The quick brown fox jumps over ({(global::Godot.Engine.GetVersionInfo()["major"]),0:G}) the lazy dog."; + values.Add(PropertyName._fieldInterpolated2, global::Godot.Variant.From<string>(___fieldInterpolated2_default_value)); + string ___fieldInterpolated3_default_value = $"{(((int)global::Godot.Engine.GetVersionInfo()["major"]) * -1 * -1):G} the lazy dog."; + values.Add(PropertyName._fieldInterpolated3, global::Godot.Variant.From<string>(___fieldInterpolated3_default_value)); + string ___fieldInterpolated4_default_value = $"{(":::fff,,}<,<}},,}]")}"; + values.Add(PropertyName._fieldInterpolated4, global::Godot.Variant.From<string>(___fieldInterpolated4_default_value)); + return values; + } +#endif // TOOLS +#pragma warning restore CS0109 +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedComplexStrings.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedComplexStrings.cs new file mode 100644 index 0000000000..06a34bdc4a --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedComplexStrings.cs @@ -0,0 +1,23 @@ +using Godot; + +public partial class ExportedComplexStrings : Node +{ + [Export] + private string _fieldInterpolated1 = $"The quick brown fox jumps over ({Engine.GetVersionInfo()})"; + + [Export] + private string _fieldInterpolated2 = $"The quick brown fox jumps over ({Engine.GetVersionInfo()["major"],0:G}) the lazy dog."; + + [Export] + private string _fieldInterpolated3 = $"{((int)Engine.GetVersionInfo()["major"]) * -1 * -1:G} the lazy dog."; + + [Export] + private string _fieldInterpolated4 = $"{":::fff,,}<,<}},,}]"}"; + + [Export] + public string PropertyInterpolated1 + { + get; + private set; + } = $"The quick brown fox jumps over {GD.VarToStr($"the lazy {Engine.GetVersionInfo()} do")}g."; +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs index 9784bd0b78..957d5789df 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs @@ -208,7 +208,17 @@ namespace Godot.SourceGenerators if (child.IsNode) { - FullQualifiedSyntax(child.AsNode()!, sm, sb, isFirstNode: innerIsFirstNode); + var childNode = child.AsNode()!; + + if (node is InterpolationSyntax && childNode is ExpressionSyntax) + { + ParenEnclosedFullQualifiedSyntax(childNode, sm, sb, isFirstNode: innerIsFirstNode); + } + else + { + FullQualifiedSyntax(childNode, sm, sb, isFirstNode: innerIsFirstNode); + } + innerIsFirstNode = false; } else @@ -221,6 +231,13 @@ namespace Godot.SourceGenerators sb.Append(child.GetTrailingTrivia()); } } + + static void ParenEnclosedFullQualifiedSyntax(SyntaxNode node, SemanticModel sm, StringBuilder sb, bool isFirstNode) + { + sb.Append(SyntaxFactory.Token(SyntaxKind.OpenParenToken)); + FullQualifiedSyntax(node, sm, sb, isFirstNode); + sb.Append(SyntaxFactory.Token(SyntaxKind.CloseParenToken)); + } } public static string SanitizeQualifiedNameForUniqueHint(this string qualifiedName) diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 0a9162bd28..5cb177676c 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -121,6 +121,10 @@ StringBuilder &operator<<(StringBuilder &r_sb, const char *p_cstring) { // This must be kept in sync with `ignored_types` in csharp_script.cpp const Vector<String> ignored_types = {}; +// Special [code] keywords to wrap with <see langword="code"/> instead of <c>code</c>. +// Don't check against all C# reserved words, as many cases are GDScript-specific. +const Vector<String> langword_check = { "true", "false", "null" }; + void BindingsGenerator::TypeInterface::postsetup_enum_type(BindingsGenerator::TypeInterface &r_enum_itype) { // C interface for enums is the same as that of 'uint32_t'. Remember to apply // any of the changes done here to the 'uint32_t' type interface as well. @@ -670,11 +674,24 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag == "code" || tag.begins_with("code ")) { - xml_output.append("<c>"); + int end = bbcode.find("[", brk_end); + if (end == -1) { + end = bbcode.length(); + } + String code = bbcode.substr(brk_end + 1, end - brk_end - 1); + if (langword_check.has(code)) { + xml_output.append("<see langword=\""); + xml_output.append(code); + xml_output.append("\"/>"); - code_tag = true; - pos = brk_end + 1; - tag_stack.push_front("code"); + pos = brk_end + code.length() + 8; + } else { + xml_output.append("<c>"); + + code_tag = true; + pos = brk_end + 1; + tag_stack.push_front("code"); + } } else if (tag == "codeblock" || tag.begins_with("codeblock ")) { xml_output.append("<code>"); diff --git a/modules/mono/editor/script_templates/SCsub b/modules/mono/editor/script_templates/SCsub index 39f6cb5c01..01c293c25d 100644 --- a/modules/mono/editor/script_templates/SCsub +++ b/modules/mono/editor/script_templates/SCsub @@ -5,7 +5,7 @@ Import("env") import editor.template_builders as build_template_cs env["BUILDERS"]["MakeCSharpTemplateBuilder"] = Builder( - action=env.Run(build_template_cs.make_templates, "Generating C# templates header."), + action=env.Run(build_template_cs.make_templates), suffix=".h", src_suffix=".cs", ) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index 72a3fe3ed0..a1f1ade9b8 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -336,7 +336,7 @@ namespace Godot /// by the specified ratio (on the range of 0 to 1). /// </summary> /// <param name="amount">The ratio to lighten by.</param> - /// <returns>The darkened color.</returns> + /// <returns>The lightened color.</returns> public readonly Color Lightened(float amount) { Color res = this; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj index db16b1fe1d..d54942e654 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -142,5 +142,5 @@ We can't use wildcards as there may be undesired old files still hanging around. Fortunately code completion, go to definition and such still work. --> - <Import Project="Generated\GeneratedIncludes.props" /> + <Import Condition=" '$(GodotSkipGenerated)' == '' " Project="Generated\GeneratedIncludes.props" /> </Project> diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj index 31e20e4ecd..c32cbcd3d1 100644 --- a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj @@ -44,5 +44,5 @@ We can't use wildcards as there may be undesired old files still hanging around. Fortunately code completion, go to definition and such still work. --> - <Import Project="Generated\GeneratedIncludes.props" /> + <Import Condition=" '$(GodotSkipGenerated)' == '' " Project="Generated\GeneratedIncludes.props" /> </Project> diff --git a/modules/multiplayer/editor/multiplayer_editor_plugin.cpp b/modules/multiplayer/editor/multiplayer_editor_plugin.cpp index e8dfc3379c..599926ec99 100644 --- a/modules/multiplayer/editor/multiplayer_editor_plugin.cpp +++ b/modules/multiplayer/editor/multiplayer_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "editor_network_profiler.h" #include "replication_editor.h" +#include "editor/editor_command_palette.h" #include "editor/editor_interface.h" #include "editor/editor_node.h" #include "editor/gui/editor_bottom_panel.h" @@ -113,7 +114,7 @@ void MultiplayerEditorDebugger::setup_session(int p_session_id) { MultiplayerEditorPlugin::MultiplayerEditorPlugin() { repl_editor = memnew(ReplicationEditor); - button = EditorNode::get_bottom_panel()->add_item(TTR("Replication"), repl_editor); + button = EditorNode::get_bottom_panel()->add_item(TTR("Replication"), repl_editor, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_replication_bottom_panel", TTR("Toggle Replication Bottom Panel"))); button->hide(); repl_editor->get_pin()->connect("pressed", callable_mp(this, &MultiplayerEditorPlugin::_pinned)); debugger.instantiate(); diff --git a/modules/multiplayer/scene_replication_config.cpp b/modules/multiplayer/scene_replication_config.cpp index 836fa1014d..733540a0e4 100644 --- a/modules/multiplayer/scene_replication_config.cpp +++ b/modules/multiplayer/scene_replication_config.cpp @@ -103,6 +103,14 @@ void SceneReplicationConfig::_get_property_list(List<PropertyInfo> *p_list) cons } } +void SceneReplicationConfig::reset_state() { + dirty = false; + properties.clear(); + sync_props.clear(); + spawn_props.clear(); + watch_props.clear(); +} + TypedArray<NodePath> SceneReplicationConfig::get_properties() const { TypedArray<NodePath> paths; for (const ReplicationProperty &prop : properties) { diff --git a/modules/multiplayer/scene_replication_config.h b/modules/multiplayer/scene_replication_config.h index 3f870ba2d8..969a23d788 100644 --- a/modules/multiplayer/scene_replication_config.h +++ b/modules/multiplayer/scene_replication_config.h @@ -79,6 +79,8 @@ protected: void _get_property_list(List<PropertyInfo> *p_list) const; public: + virtual void reset_state() override; // Required since we use variable amount of properties. + TypedArray<NodePath> get_properties() const; void add_property(const NodePath &p_path, int p_index = -1); diff --git a/modules/openxr/doc_classes/OpenXRAction.xml b/modules/openxr/doc_classes/OpenXRAction.xml index 6a3529e43e..2a9f255f2f 100644 --- a/modules/openxr/doc_classes/OpenXRAction.xml +++ b/modules/openxr/doc_classes/OpenXRAction.xml @@ -4,7 +4,7 @@ An OpenXR action. </brief_description> <description> - This resource defines an OpenXR action. Actions can be used both for inputs (buttons/joystick/trigger/etc) and outputs (haptics). + This resource defines an OpenXR action. Actions can be used both for inputs (buttons, joysticks, triggers, etc.) and outputs (haptics). OpenXR performs automatic conversion between action type and input type whenever possible. An analog trigger bound to a boolean action will thus return [code]false[/code] if the trigger is depressed and [code]true[/code] if pressed fully. Actions are not directly bound to specific devices, instead OpenXR recognizes a limited number of top level paths that identify devices by usage. We can restrict which devices an action can be bound to by these top level paths. For instance an action that should only be used for hand held controllers can have the top level paths "/user/hand/left" and "/user/hand/right" associated with them. See the [url=https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#semantic-path-reserved]reserved path section in the OpenXR specification[/url] for more info on the top level paths. Note that the name of the resource is used to register the action with. diff --git a/modules/openxr/editor/openxr_editor_plugin.cpp b/modules/openxr/editor/openxr_editor_plugin.cpp index f545e31073..f6b7f2dd0c 100644 --- a/modules/openxr/editor/openxr_editor_plugin.cpp +++ b/modules/openxr/editor/openxr_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "../action_map/openxr_action_map.h" +#include "editor/editor_command_palette.h" #include "editor/editor_node.h" #include "editor/gui/editor_bottom_panel.h" @@ -53,7 +54,7 @@ void OpenXREditorPlugin::make_visible(bool p_visible) { OpenXREditorPlugin::OpenXREditorPlugin() { action_map_editor = memnew(OpenXRActionMapEditor); - EditorNode::get_bottom_panel()->add_item(TTR("OpenXR Action Map"), action_map_editor); + EditorNode::get_bottom_panel()->add_item(TTR("OpenXR Action Map"), action_map_editor, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_openxr_action_map_bottom_panel", TTR("Toggle OpenXR Action Map Bottom Panel"))); #ifndef ANDROID_ENABLED select_runtime = memnew(OpenXRSelectRuntime); diff --git a/modules/text_server_adv/gdextension_build/methods.py b/modules/text_server_adv/gdextension_build/methods.py index e58bc3abec..327097a3df 100644 --- a/modules/text_server_adv/gdextension_build/methods.py +++ b/modules/text_server_adv/gdextension_build/methods.py @@ -42,6 +42,12 @@ def no_verbose(sys, env): java_library_message = "{}Creating Java Archive {}$TARGET{} ...{}".format( colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] ) + compiled_resource_message = "{}Creating Compiled Resource {}$TARGET{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + generated_file_message = "{}Generating {}$TARGET{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) env.Append(CXXCOMSTR=[compile_source_message]) env.Append(CCCOMSTR=[compile_source_message]) @@ -53,6 +59,8 @@ def no_verbose(sys, env): env.Append(LINKCOMSTR=[link_program_message]) env.Append(JARCOMSTR=[java_library_message]) env.Append(JAVACCOMSTR=[java_compile_source_message]) + env.Append(RCCOMSTR=[compiled_resource_message]) + env.Append(GENCOMSTR=[generated_file_message]) def disable_warnings(self): diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index ea88278a17..3da19aaee8 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -5360,11 +5360,14 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) { // No data loaded - use fallback. for (int j = r_start; j < r_end; j++) { char32_t c = sd->text[j - sd->start]; + char32_t c_next = (j < r_end) ? sd->text[j - sd->start + 1] : 0x0000; if (is_whitespace(c)) { sd->breaks[j + 1] = false; } if (is_linebreak(c)) { - sd->breaks[j + 1] = true; + if (c != 0x000D || c_next != 0x000A) { // Skip first hard break in CR-LF pair. + sd->breaks[j + 1] = true; + } } } } else { diff --git a/modules/text_server_fb/gdextension_build/methods.py b/modules/text_server_fb/gdextension_build/methods.py index e58bc3abec..327097a3df 100644 --- a/modules/text_server_fb/gdextension_build/methods.py +++ b/modules/text_server_fb/gdextension_build/methods.py @@ -42,6 +42,12 @@ def no_verbose(sys, env): java_library_message = "{}Creating Java Archive {}$TARGET{} ...{}".format( colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] ) + compiled_resource_message = "{}Creating Compiled Resource {}$TARGET{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + generated_file_message = "{}Generating {}$TARGET{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) env.Append(CXXCOMSTR=[compile_source_message]) env.Append(CCCOMSTR=[compile_source_message]) @@ -53,6 +59,8 @@ def no_verbose(sys, env): env.Append(LINKCOMSTR=[link_program_message]) env.Append(JARCOMSTR=[java_library_message]) env.Append(JAVACCOMSTR=[java_compile_source_message]) + env.Append(RCCOMSTR=[compiled_resource_message]) + env.Append(GENCOMSTR=[generated_file_message]) def disable_warnings(self): diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index f2d70db7a4..7e34de0bbc 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -3617,6 +3617,7 @@ bool TextServerFallback::_shaped_text_update_breaks(const RID &p_shaped) { for (int i = 0; i < sd_size; i++) { if (sd_glyphs[i].count > 0) { char32_t c = sd->text[sd_glyphs[i].start - sd->start]; + char32_t c_next = i < sd_size ? sd->text[sd_glyphs[i].start - sd->start + 1] : 0x0000; if (c_punct_size == 0) { if (is_punct(c) && c != 0x005F && c != ' ') { sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; @@ -3640,7 +3641,9 @@ bool TextServerFallback::_shaped_text_update_breaks(const RID &p_shaped) { } if (is_linebreak(c)) { sd_glyphs[i].flags |= GRAPHEME_IS_SPACE; - sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD; + if (c != 0x000D || c_next != 0x000A) { // Skip first hard break in CR-LF pair. + sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD; + } } if (c == 0x0009 || c == 0x000b) { sd_glyphs[i].flags |= GRAPHEME_IS_TAB; |