Skip to content

Commit

Permalink
Merge pull request #90716 from dalexeev/gds-fix-export-annotation-issues
Browse files Browse the repository at this point in the history
GDScript: Fix some export annotation issues
  • Loading branch information
akien-mga committed May 19, 2024
2 parents f58a96c + 76b2d85 commit 6761923
Show file tree
Hide file tree
Showing 13 changed files with 249 additions and 150 deletions.
2 changes: 1 addition & 1 deletion editor/editor_help.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1967,7 +1967,7 @@ void EditorHelp::_update_doc() {

class_desc->add_text(argument.name);
class_desc->add_text(": ");
_add_type(argument.type);
_add_type(argument.type, argument.enumeration, argument.is_bitfield);

if (!argument.default_value.is_empty()) {
class_desc->push_color(theme_cache.symbol_color);
Expand Down
3 changes: 2 additions & 1 deletion modules/gdscript/doc_classes/@GDScript.xml
Original file line number Diff line number Diff line change
Expand Up @@ -349,10 +349,11 @@
<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.
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.
[codeblock]
@export_custom(PROPERTY_HINT_NONE, "suffix:m") var suffix: Vector3
[/codeblock]
[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.
</description>
</annotation>
<annotation name="@export_dir">
Expand Down
23 changes: 23 additions & 0 deletions modules/gdscript/gdscript_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,29 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a
option.insert_text = option.display.quote(p_quote_style);
r_result.insert(option.display, option);
}
} else if (p_annotation->name == SNAME("@export_custom")) {
switch (p_argument) {
case 0: {
static HashMap<StringName, int64_t> items;
if (unlikely(items.is_empty())) {
CoreConstants::get_enum_values(SNAME("PropertyHint"), &items);
}
for (const KeyValue<StringName, int64_t> &item : items) {
ScriptLanguage::CodeCompletionOption option(item.key, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
r_result.insert(option.display, option);
}
} break;
case 2: {
static HashMap<StringName, int64_t> items;
if (unlikely(items.is_empty())) {
CoreConstants::get_enum_values(SNAME("PropertyUsageFlags"), &items);
}
for (const KeyValue<StringName, int64_t> &item : items) {
ScriptLanguage::CodeCompletionOption option(item.key, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
r_result.insert(option.display, option);
}
} break;
}
} else if (p_annotation->name == SNAME("@warning_ignore")) {
for (int warning_code = 0; warning_code < GDScriptWarning::WARNING_MAX; warning_code++) {
ScriptLanguage::CodeCompletionOption warning(GDScriptWarning::get_name_from_code((GDScriptWarning::Code)warning_code).to_lower(), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
Expand Down
43 changes: 34 additions & 9 deletions modules/gdscript/gdscript_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ GDScriptParser::GDScriptParser() {
register_annotation(MethodInfo("@onready"), AnnotationInfo::VARIABLE, &GDScriptParser::onready_annotation);
// Export annotations.
register_annotation(MethodInfo("@export"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>);
register_annotation(MethodInfo("@export_storage"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>);
register_annotation(MethodInfo("@export_enum", PropertyInfo(Variant::STRING, "names")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_ENUM, Variant::NIL>, varray(), true);
register_annotation(MethodInfo("@export_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FILE, Variant::STRING>, varray(""), true);
register_annotation(MethodInfo("@export_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_DIR, Variant::STRING>);
Expand All @@ -121,6 +120,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_storage"), AnnotationInfo::VARIABLE, &GDScriptParser::export_storage_annotation);
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>);
Expand Down Expand Up @@ -4299,7 +4299,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
case GDScriptParser::DataType::BUILTIN:
variable->export_info.type = export_type.builtin_type;
variable->export_info.hint = PROPERTY_HINT_NONE;
variable->export_info.hint_string = Variant::get_type_name(export_type.builtin_type);
variable->export_info.hint_string = String();
break;
case GDScriptParser::DataType::NATIVE:
if (ClassDB::is_parent_class(export_type.native_type, SNAME("Resource"))) {
Expand Down Expand Up @@ -4400,12 +4400,6 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
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")) {
use_default_variable_type_check = false; // Can be applied to a variable of any type.

// Save the info because the compiler uses export info for overwriting member info.
variable->export_info = export_type.to_property_info(variable->identifier->name);
variable->export_info.usage |= PROPERTY_USAGE_STORAGE;
}

if (use_default_variable_type_check) {
Expand All @@ -4425,11 +4419,38 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
if (variable->export_info.hint) {
hint_prefix += "/" + itos(variable->export_info.hint);
}
variable->export_info.type = original_export_type_builtin;
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;
variable->export_info.usage = PROPERTY_USAGE_DEFAULT;
variable->export_info.class_name = StringName();
}

return true;
}

// For `@export_storage` and `@export_custom`, there is no need to check the variable type, argument values,
// or handle array exports in a special way, so they are implemented as separate methods.

bool GDScriptParser::export_storage_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));

VariableNode *variable = static_cast<VariableNode *>(p_node);
if (variable->is_static) {
push_error(vformat(R"(Annotation "%s" cannot be applied to a static variable.)", p_annotation->name), p_annotation);
return false;
}
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;

// Save the info because the compiler uses export info for overwriting member info.
variable->export_info = variable->get_datatype().to_property_info(variable->identifier->name);
variable->export_info.usage |= PROPERTY_USAGE_STORAGE;

return true;
}

Expand All @@ -4438,6 +4459,10 @@ bool GDScriptParser::export_custom_annotation(const AnnotationNode *p_annotation
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->is_static) {
push_error(vformat(R"(Annotation "%s" cannot be applied to a static variable.)", p_annotation->name), p_annotation);
return false;
}
if (variable->exported) {
push_error(vformat(R"(Annotation "%s" cannot be used with another "@export" annotation.)", p_annotation->name), p_annotation);
return false;
Expand Down
1 change: 1 addition & 0 deletions modules/gdscript/gdscript_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1497,6 +1497,7 @@ class GDScriptParser {
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_storage_annotation(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);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
GDTEST_OK
var test_1: Dictionary
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
var test_2: TestExportEnumAsDictionary.MyEnum
hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM
hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"TestExportEnumAsDictionary.MyEnum"
var test_3: Dictionary
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
var test_4: TestExportEnumAsDictionary.MyEnum
hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM
hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"TestExportEnumAsDictionary.MyEnum"
var test_5: TestExportEnumAsDictionary.MyEnum
hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM
hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"TestExportEnumAsDictionary.MyEnum"
24 changes: 12 additions & 12 deletions modules/gdscript/tests/scripts/parser/features/annotations.out
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
GDTEST_OK
var test_1: int = null
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
var test_2: int = null
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
var test_3: int = null
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
var test_4: int = null
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
var test_5: int = 0
hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
var test_6: int = 0
hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
var test_7: int = 42
hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
var test_8: int = 0
hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
var test_9: int = 0
hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
var test_10: int = 0
hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
var test_11: int = 0
hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
var test_12: int = 0
hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
Loading

0 comments on commit 6761923

Please sign in to comment.