Skip to content

Commit 76b2d85

Browse files
committed
GDScript: Fix some export annotation issues
1 parent bdc0316 commit 76b2d85

File tree

13 files changed

+249
-150
lines changed

13 files changed

+249
-150
lines changed

editor/editor_help.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1967,7 +1967,7 @@ void EditorHelp::_update_doc() {
19671967

19681968
class_desc->add_text(argument.name);
19691969
class_desc->add_text(": ");
1970-
_add_type(argument.type);
1970+
_add_type(argument.type, argument.enumeration, argument.is_bitfield);
19711971

19721972
if (!argument.default_value.is_empty()) {
19731973
class_desc->push_color(theme_cache.symbol_color);

modules/gdscript/doc_classes/@GDScript.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,10 +349,11 @@
349349
<param index="1" name="hint_string" type="String" />
350350
<param index="2" name="usage" type="int" enum="PropertyUsageFlags" is_bitfield="true" default="6" />
351351
<description>
352-
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.
352+
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 parameters to the editor.
353353
[codeblock]
354354
@export_custom(PROPERTY_HINT_NONE, "suffix:m") var suffix: Vector3
355355
[/codeblock]
356+
[b]Note:[/b] Regardless of the [param usage] value, the [constant PROPERTY_USAGE_SCRIPT_VARIABLE] flag is always added, as with any explicitly declared script variable.
356357
</description>
357358
</annotation>
358359
<annotation name="@export_dir">

modules/gdscript/gdscript_editor.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,29 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a
911911
option.insert_text = option.display.quote(p_quote_style);
912912
r_result.insert(option.display, option);
913913
}
914+
} else if (p_annotation->name == SNAME("@export_custom")) {
915+
switch (p_argument) {
916+
case 0: {
917+
static HashMap<StringName, int64_t> items;
918+
if (unlikely(items.is_empty())) {
919+
CoreConstants::get_enum_values(SNAME("PropertyHint"), &items);
920+
}
921+
for (const KeyValue<StringName, int64_t> &item : items) {
922+
ScriptLanguage::CodeCompletionOption option(item.key, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
923+
r_result.insert(option.display, option);
924+
}
925+
} break;
926+
case 2: {
927+
static HashMap<StringName, int64_t> items;
928+
if (unlikely(items.is_empty())) {
929+
CoreConstants::get_enum_values(SNAME("PropertyUsageFlags"), &items);
930+
}
931+
for (const KeyValue<StringName, int64_t> &item : items) {
932+
ScriptLanguage::CodeCompletionOption option(item.key, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
933+
r_result.insert(option.display, option);
934+
}
935+
} break;
936+
}
914937
} else if (p_annotation->name == SNAME("@warning_ignore")) {
915938
for (int warning_code = 0; warning_code < GDScriptWarning::WARNING_MAX; warning_code++) {
916939
ScriptLanguage::CodeCompletionOption warning(GDScriptWarning::get_name_from_code((GDScriptWarning::Code)warning_code).to_lower(), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);

modules/gdscript/gdscript_parser.cpp

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ GDScriptParser::GDScriptParser() {
101101
register_annotation(MethodInfo("@onready"), AnnotationInfo::VARIABLE, &GDScriptParser::onready_annotation);
102102
// Export annotations.
103103
register_annotation(MethodInfo("@export"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>);
104-
register_annotation(MethodInfo("@export_storage"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>);
105104
register_annotation(MethodInfo("@export_enum", PropertyInfo(Variant::STRING, "names")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_ENUM, Variant::NIL>, varray(), true);
106105
register_annotation(MethodInfo("@export_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FILE, Variant::STRING>, varray(""), true);
107106
register_annotation(MethodInfo("@export_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_DIR, Variant::STRING>);
@@ -121,6 +120,7 @@ GDScriptParser::GDScriptParser() {
121120
register_annotation(MethodInfo("@export_flags_3d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_PHYSICS, Variant::INT>);
122121
register_annotation(MethodInfo("@export_flags_3d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_NAVIGATION, Variant::INT>);
123122
register_annotation(MethodInfo("@export_flags_avoidance"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_AVOIDANCE, Variant::INT>);
123+
register_annotation(MethodInfo("@export_storage"), AnnotationInfo::VARIABLE, &GDScriptParser::export_storage_annotation);
124124
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));
125125
// Export grouping annotations.
126126
register_annotation(MethodInfo("@export_category", PropertyInfo(Variant::STRING, "name")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_CATEGORY>);
@@ -4295,7 +4295,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
42954295
case GDScriptParser::DataType::BUILTIN:
42964296
variable->export_info.type = export_type.builtin_type;
42974297
variable->export_info.hint = PROPERTY_HINT_NONE;
4298-
variable->export_info.hint_string = Variant::get_type_name(export_type.builtin_type);
4298+
variable->export_info.hint_string = String();
42994299
break;
43004300
case GDScriptParser::DataType::NATIVE:
43014301
if (ClassDB::is_parent_class(export_type.native_type, SNAME("Resource"))) {
@@ -4396,12 +4396,6 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
43964396
push_error(_get_annotation_error_string(p_annotation->name, expected_types, variable->get_datatype()), p_annotation);
43974397
return false;
43984398
}
4399-
} else if (p_annotation->name == SNAME("@export_storage")) {
4400-
use_default_variable_type_check = false; // Can be applied to a variable of any type.
4401-
4402-
// Save the info because the compiler uses export info for overwriting member info.
4403-
variable->export_info = export_type.to_property_info(variable->identifier->name);
4404-
variable->export_info.usage |= PROPERTY_USAGE_STORAGE;
44054399
}
44064400

44074401
if (use_default_variable_type_check) {
@@ -4421,11 +4415,38 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
44214415
if (variable->export_info.hint) {
44224416
hint_prefix += "/" + itos(variable->export_info.hint);
44234417
}
4418+
variable->export_info.type = original_export_type_builtin;
44244419
variable->export_info.hint = PROPERTY_HINT_TYPE_STRING;
44254420
variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string;
4426-
variable->export_info.type = original_export_type_builtin;
4421+
variable->export_info.usage = PROPERTY_USAGE_DEFAULT;
4422+
variable->export_info.class_name = StringName();
4423+
}
4424+
4425+
return true;
4426+
}
4427+
4428+
// For `@export_storage` and `@export_custom`, there is no need to check the variable type, argument values,
4429+
// or handle array exports in a special way, so they are implemented as separate methods.
4430+
4431+
bool GDScriptParser::export_storage_annotation(const AnnotationNode *p_annotation, Node *p_node, ClassNode *p_class) {
4432+
ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name));
4433+
4434+
VariableNode *variable = static_cast<VariableNode *>(p_node);
4435+
if (variable->is_static) {
4436+
push_error(vformat(R"(Annotation "%s" cannot be applied to a static variable.)", p_annotation->name), p_annotation);
4437+
return false;
4438+
}
4439+
if (variable->exported) {
4440+
push_error(vformat(R"(Annotation "%s" cannot be used with another "@export" annotation.)", p_annotation->name), p_annotation);
4441+
return false;
44274442
}
44284443

4444+
variable->exported = true;
4445+
4446+
// Save the info because the compiler uses export info for overwriting member info.
4447+
variable->export_info = variable->get_datatype().to_property_info(variable->identifier->name);
4448+
variable->export_info.usage |= PROPERTY_USAGE_STORAGE;
4449+
44294450
return true;
44304451
}
44314452

@@ -4434,6 +4455,10 @@ bool GDScriptParser::export_custom_annotation(const AnnotationNode *p_annotation
44344455
ERR_FAIL_COND_V_MSG(p_annotation->resolved_arguments.size() < 2, false, R"(Annotation "@export_custom" requires 2 arguments.)");
44354456

44364457
VariableNode *variable = static_cast<VariableNode *>(p_node);
4458+
if (variable->is_static) {
4459+
push_error(vformat(R"(Annotation "%s" cannot be applied to a static variable.)", p_annotation->name), p_annotation);
4460+
return false;
4461+
}
44374462
if (variable->exported) {
44384463
push_error(vformat(R"(Annotation "%s" cannot be used with another "@export" annotation.)", p_annotation->name), p_annotation);
44394464
return false;

modules/gdscript/gdscript_parser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,6 +1499,7 @@ class GDScriptParser {
14991499
bool onready_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
15001500
template <PropertyHint t_hint, Variant::Type t_type>
15011501
bool export_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
1502+
bool export_storage_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
15021503
bool export_custom_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
15031504
template <PropertyUsageFlags t_usage>
15041505
bool export_group_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
GDTEST_OK
22
var test_1: Dictionary
3-
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE
3+
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
44
var test_2: TestExportEnumAsDictionary.MyEnum
5-
hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM
5+
hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"TestExportEnumAsDictionary.MyEnum"
66
var test_3: Dictionary
7-
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE
7+
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
88
var test_4: TestExportEnumAsDictionary.MyEnum
9-
hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM
9+
hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"TestExportEnumAsDictionary.MyEnum"
1010
var test_5: TestExportEnumAsDictionary.MyEnum
11-
hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM
11+
hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"TestExportEnumAsDictionary.MyEnum"
Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
GDTEST_OK
22
var test_1: int = null
3-
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE
3+
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
44
var test_2: int = null
5-
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE
5+
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
66
var test_3: int = null
7-
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE
7+
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
88
var test_4: int = null
9-
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE
9+
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
1010
var test_5: int = 0
11-
hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE
11+
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
1212
var test_6: int = 0
13-
hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE
13+
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
1414
var test_7: int = 42
15-
hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE
15+
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
1616
var test_8: int = 0
17-
hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE
17+
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
1818
var test_9: int = 0
19-
hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE
19+
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
2020
var test_10: int = 0
21-
hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE
21+
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
2222
var test_11: int = 0
23-
hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE
23+
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
2424
var test_12: int = 0
25-
hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE
25+
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""

0 commit comments

Comments
 (0)