1
0
Fork 0

Use structed data for "deprecated" in `gdextension_interface.json`

This commit is contained in:
David Snopek 2025-12-06 21:01:30 -06:00
parent 2ecefada8d
commit b15f9deffb
5 changed files with 207 additions and 51 deletions

View File

@ -1116,7 +1116,10 @@
"type": "int32_t"
}
],
"deprecated": "Deprecated. Use GDExtensionClassNotification2 instead."
"deprecated": {
"since": "4.2",
"replace_with": "GDExtensionClassNotification2"
}
},
{
"name": "GDExtensionClassNotification2",
@ -1461,7 +1464,10 @@
]
}
],
"deprecated": "Deprecated. Use GDExtensionClassCreationInfo4 instead."
"deprecated": {
"since": "4.2",
"replace_with": "GDExtensionClassCreationInfo4"
}
},
{
"name": "GDExtensionClassCreationInfo2",
@ -1579,7 +1585,10 @@
]
}
],
"deprecated": "Deprecated. Use GDExtensionClassCreationInfo4 instead."
"deprecated": {
"since": "4.3",
"replace_with": "GDExtensionClassCreationInfo4"
}
},
{
"name": "GDExtensionClassCreationInfo3",
@ -1701,7 +1710,10 @@
]
}
],
"deprecated": "Deprecated. Use GDExtensionClassCreationInfo4 instead."
"deprecated": {
"since": "4.4",
"replace_with": "GDExtensionClassCreationInfo4"
}
},
{
"name": "GDExtensionClassCreationInfo4",
@ -2344,7 +2356,10 @@
"",
"`free_func` is necessary if `callable_userdata` needs to be cleaned up when the callable is freed."
],
"deprecated": "Deprecated. Use GDExtensionCallableCustomInfo2 instead."
"deprecated": {
"since": "4.3",
"replace_with": "GDExtensionCallableCustomInfo2"
}
},
{
"name": "GDExtensionCallableCustomInfo2",
@ -2493,7 +2508,10 @@
"type": "const GDExtensionPropertyInfo*"
}
],
"deprecated": "Deprecated. Use GDExtensionScriptInstanceFreePropertyList2 instead."
"deprecated": {
"since": "4.3",
"replace_with": "GDExtensionScriptInstanceFreePropertyList2"
}
},
{
"name": "GDExtensionScriptInstanceFreePropertyList2",
@ -2697,7 +2715,10 @@
"type": "const GDExtensionMethodInfo*"
}
],
"deprecated": "Deprecated. Use GDExtensionScriptInstanceFreeMethodList2 instead."
"deprecated": {
"since": "4.3",
"replace_with": "GDExtensionScriptInstanceFreeMethodList2"
}
},
{
"name": "GDExtensionScriptInstanceFreeMethodList2",
@ -2807,7 +2828,10 @@
"type": "int32_t"
}
],
"deprecated": "Deprecated. Use GDExtensionScriptInstanceNotification2 instead."
"deprecated": {
"since": "4.2",
"replace_with": "GDExtensionScriptInstanceNotification2"
}
},
{
"name": "GDExtensionScriptInstanceNotification2",
@ -3037,7 +3061,10 @@
"type": "GDExtensionScriptInstanceFree"
}
],
"deprecated": "Deprecated. Use GDExtensionScriptInstanceInfo3 instead."
"deprecated": {
"since": "4.2",
"replace_with": "GDExtensionScriptInstanceInfo3"
}
},
{
"name": "GDExtensionScriptInstanceInfo2",
@ -3147,7 +3174,10 @@
"type": "GDExtensionScriptInstanceFree"
}
],
"deprecated": "Deprecated. Use GDExtensionScriptInstanceInfo3 instead."
"deprecated": {
"since": "4.3",
"replace_with": "GDExtensionScriptInstanceInfo3"
}
},
{
"name": "GDExtensionScriptInstanceInfo3",
@ -3622,7 +3652,10 @@
"Gets the Godot version that the GDExtension was loaded into."
],
"since": "4.1",
"deprecated": "Deprecated in Godot 4.5. Use `get_godot_version2` instead."
"deprecated": {
"since": "4.5",
"replace_with": "get_godot_version2"
}
},
{
"name": "get_godot_version2",
@ -3664,7 +3697,11 @@
"Allocates memory."
],
"since": "4.1",
"deprecated": "Deprecated in Godot 4.6. Use `mem_alloc2` instead."
"deprecated": {
"since": "4.6",
"message": "Does not allow explicitly requesting padding.",
"replace_with": "mem_alloc2"
}
},
{
"name": "mem_realloc",
@ -3694,7 +3731,11 @@
"Reallocates memory."
],
"since": "4.1",
"deprecated": "Deprecated in Godot 4.6. Use `mem_realloc2` instead."
"deprecated": {
"since": "4.6",
"message": "Does not allow explicitly requesting padding.",
"replace_with": "mem_realloc2"
}
},
{
"name": "mem_free",
@ -3714,7 +3755,11 @@
"Frees memory."
],
"since": "4.1",
"deprecated": "Deprecated in Godot 4.6. Use `mem_free2` instead."
"deprecated": {
"since": "4.6",
"message": "Does not allow explicitly requesting padding.",
"replace_with": "mem_free2"
}
},
{
"name": "mem_alloc2",
@ -5885,7 +5930,10 @@
"Creates a String from a UTF-8 encoded C string with the given length."
],
"since": "4.1",
"deprecated": "Deprecated in Godot 4.3. Use `string_new_with_utf8_chars_and_len2` instead."
"deprecated": {
"since": "4.3",
"replace_with": "string_new_with_utf8_chars_and_len2"
}
},
{
"name": "string_new_with_utf8_chars_and_len2",
@ -5955,7 +6003,10 @@
"Creates a String from a UTF-16 encoded C string with the given length."
],
"since": "4.1",
"deprecated": "Deprecated in Godot 4.3. Use `string_new_with_utf16_chars_and_len2` instead."
"deprecated": {
"since": "4.3",
"replace_with": "string_new_with_utf16_chars_and_len2"
}
},
{
"name": "string_new_with_utf16_chars_and_len2",
@ -7512,7 +7563,10 @@
"Sets an Array to be a reference to another Array object."
],
"since": "4.1",
"deprecated": "Deprecated in Godot 4.5. use `Array::operator=` instead."
"deprecated": {
"since": "4.5",
"message": "Removed from interface. Use copy constructor instead."
}
},
{
"name": "array_set_typed",
@ -8214,7 +8268,10 @@
"Creates a script instance that contains the given info and instance data."
],
"since": "4.1",
"deprecated": "Deprecated in Godot 4.2. Use `script_instance_create3` instead."
"deprecated": {
"since": "4.2",
"replace_with": "script_instance_create3"
}
},
{
"name": "script_instance_create2",
@ -8244,7 +8301,10 @@
"Creates a script instance that contains the given info and instance data."
],
"since": "4.2",
"deprecated": "Deprecated in Godot 4.3. Use `script_instance_create3` instead."
"deprecated": {
"since": "4.3",
"replace_with": "script_instance_create3"
}
},
{
"name": "script_instance_create3",
@ -8430,7 +8490,10 @@
"Provided struct can be safely freed once the function returns."
],
"since": "4.2",
"deprecated": "Deprecated in Godot 4.3. Use `callable_custom_create2` instead."
"deprecated": {
"since": "4.3",
"replace_with": "callable_custom_create2"
}
},
{
"name": "callable_custom_create2",
@ -8512,7 +8575,10 @@
"The passed class must be a built-in godot class, or an already-registered extension class. In both cases, object_set_instance() should be called to fully initialize the object."
],
"since": "4.1",
"deprecated": "Deprecated in Godot 4.4. Use `classdb_construct_object2` instead."
"deprecated": {
"since": "4.4",
"replace_with": "classdb_construct_object2"
}
},
{
"name": "classdb_construct_object2",
@ -8637,7 +8703,10 @@
"Provided struct can be safely freed once the function returns."
],
"since": "4.1",
"deprecated": "Deprecated in Godot 4.2. Use `classdb_register_extension_class4` instead."
"deprecated": {
"since": "4.2",
"replace_with": "classdb_register_extension_class5"
}
},
{
"name": "classdb_register_extension_class2",
@ -8679,7 +8748,10 @@
"Provided struct can be safely freed once the function returns."
],
"since": "4.2",
"deprecated": "Deprecated in Godot 4.3. Use `classdb_register_extension_class4` instead."
"deprecated": {
"since": "4.3",
"replace_with": "classdb_register_extension_class5"
}
},
{
"name": "classdb_register_extension_class3",
@ -8721,7 +8793,10 @@
"Provided struct can be safely freed once the function returns."
],
"since": "4.3",
"deprecated": "Deprecated in Godot 4.4. Use `classdb_register_extension_class4` instead."
"deprecated": {
"since": "4.4",
"replace_with": "classdb_register_extension_class5"
}
},
{
"name": "classdb_register_extension_class4",
@ -8763,7 +8838,10 @@
"Provided struct can be safely freed once the function returns."
],
"since": "4.4",
"deprecated": "Deprecated in Godot 4.5. Use `classdb_register_extension_class5` instead."
"deprecated": {
"since": "4.5",
"replace_with": "classdb_register_extension_class5"
}
},
{
"name": "classdb_register_extension_class5",

View File

@ -37,7 +37,22 @@
}
},
"deprecated": {
"type": "string"
"type": "object",
"properties": {
"since": {
"type": "string",
"pattern": "4\\.[0-9]+"
},
"message": {
"type": "string",
"pattern": "\\.$"
},
"replace_with": {
"type": "string"
}
},
"required": ["since"],
"additionalProperties": false
}
},
"required": [
@ -256,7 +271,22 @@
"pattern": "4\\.[0-9]+"
},
"deprecated": {
"type": "string"
"type": "object",
"properties": {
"since": {
"type": "string",
"pattern": "4\\.[0-9]+"
},
"message": {
"type": "string",
"pattern": "\\.$"
},
"replace_with": {
"type": "string"
}
},
"required": ["since"],
"additionalProperties": false
},
"see": {
"type": "array",

View File

@ -145,7 +145,7 @@ void GDExtensionInterfaceHeaderGenerator::write_doc(const Ref<FileAccess> &p_fa,
void GDExtensionInterfaceHeaderGenerator::write_simple_type(const Ref<FileAccess> &p_fa, const Dictionary &p_type) {
String type_and_name = format_type_and_name(p_type["type"], p_type["name"]);
p_fa->store_string(vformat("typedef %s;%s\n", type_and_name, make_deprecated_note(p_type)));
p_fa->store_string(vformat("typedef %s;%s\n", type_and_name, make_deprecated_comment_for_type(p_type)));
}
void GDExtensionInterfaceHeaderGenerator::write_enum_type(const Ref<FileAccess> &p_fa, const Dictionary &p_enum) {
@ -157,14 +157,14 @@ void GDExtensionInterfaceHeaderGenerator::write_enum_type(const Ref<FileAccess>
}
p_fa->store_string(vformat("\t%s = %s,\n", value_dict["name"], (int)value_dict["value"]));
}
p_fa->store_string(vformat("} %s;%s\n\n", p_enum["name"], make_deprecated_note(p_enum)));
p_fa->store_string(vformat("} %s;%s\n\n", p_enum["name"], make_deprecated_comment_for_type(p_enum)));
}
void GDExtensionInterfaceHeaderGenerator::write_function_type(const Ref<FileAccess> &p_fa, const Dictionary &p_func) {
String args_text = p_func.has("arguments") ? make_args_text(p_func["arguments"]) : "";
String name_and_args = vformat("(*%s)(%s)", p_func["name"], args_text);
Dictionary ret = p_func["return_value"];
p_fa->store_string(vformat("typedef %s;%s\n", format_type_and_name(ret["type"], name_and_args), make_deprecated_note(p_func)));
p_fa->store_string(vformat("typedef %s;%s\n", format_type_and_name(ret["type"], name_and_args), make_deprecated_comment_for_type(p_func)));
}
void GDExtensionInterfaceHeaderGenerator::write_struct_type(const Ref<FileAccess> &p_fa, const Dictionary &p_struct) {
@ -176,7 +176,7 @@ void GDExtensionInterfaceHeaderGenerator::write_struct_type(const Ref<FileAccess
}
p_fa->store_string(vformat("\t%s;\n", format_type_and_name(member_dict["type"], member_dict["name"])));
}
p_fa->store_string(vformat("} %s;%s\n\n", p_struct["name"], make_deprecated_note(p_struct)));
p_fa->store_string(vformat("} %s;%s\n\n", p_struct["name"], make_deprecated_comment_for_type(p_struct)));
}
String GDExtensionInterfaceHeaderGenerator::format_type_and_name(const String &p_type, const String &p_name) {
@ -196,11 +196,23 @@ String GDExtensionInterfaceHeaderGenerator::format_type_and_name(const String &p
return ret;
}
String GDExtensionInterfaceHeaderGenerator::make_deprecated_note(const Dictionary &p_type) {
String GDExtensionInterfaceHeaderGenerator::make_deprecated_message(const Dictionary &p_data) {
PackedStringArray parts;
parts.push_back(vformat("Deprecated in Godot %s.", p_data["since"]));
if (p_data.has("message")) {
parts.push_back(p_data["message"]);
}
if (p_data.has("replace_with")) {
parts.push_back(vformat("Use `%s` instead.", p_data["replace_with"]));
}
return String(" ").join(parts);
}
String GDExtensionInterfaceHeaderGenerator::make_deprecated_comment_for_type(const Dictionary &p_type) {
if (!p_type.has("deprecated")) {
return "";
}
return vformat(" /* %s */", p_type["deprecated"]);
return vformat(" /* %s */", make_deprecated_message(p_type["deprecated"]));
}
String GDExtensionInterfaceHeaderGenerator::make_args_text(const Array &p_args) {
@ -218,12 +230,7 @@ void GDExtensionInterfaceHeaderGenerator::write_interface(const Ref<FileAccess>
doc.push_back(String("@since ") + (String)p_interface["since"]);
if (p_interface.has("deprecated")) {
String deprecated = p_interface["deprecated"];
if (deprecated.to_lower().begins_with("deprecated")) {
Vector<String> parts = deprecated.split_spaces(1);
deprecated = parts[1];
}
doc.push_back(String("@deprecated ") + deprecated);
doc.push_back(String("@deprecated ") + make_deprecated_message(p_interface["deprecated"]));
}
Array orig_doc = p_interface["description"];

View File

@ -46,7 +46,8 @@ private:
static void write_struct_type(const Ref<FileAccess> &p_fa, const Dictionary &p_struct);
static String format_type_and_name(const String &p_type, const String &p_name);
static String make_deprecated_note(const Dictionary &p_type);
static String make_deprecated_message(const Dictionary &p_data);
static String make_deprecated_comment_for_type(const Dictionary &p_type);
static String make_args_text(const Array &p_args);
static void write_interface(const Ref<FileAccess> &p_fa, const Dictionary &p_interface);

View File

@ -54,11 +54,17 @@ extern "C" {
""")
handles = []
type_replacements = []
for type in data["types"]:
kind = type["kind"]
check_type(kind, type, valid_data_types)
valid_data_types[type["name"]] = True
valid_data_types[type["name"]] = type
if "deprecated" in type:
check_allowed_keys(type["deprecated"], ["since"], ["message", "replace_with"])
if "replace_with" in type["deprecated"]:
type_replacements.append((type["name"], type["deprecated"]["replace_with"]))
if "description" in type:
write_doc(file, type["description"])
@ -86,6 +92,17 @@ extern "C" {
else:
raise Exception(f"Unknown kind of type: {kind}")
for type_name, replace_with in type_replacements:
if replace_with not in valid_data_types:
raise Exception(f"Unknown type '{replace_with}' used as replacement for '{type_name}'")
replacement = valid_data_types[replace_with]
if isinstance(replacement, dict) and "deprecated" in replacement:
raise Exception(
f"Cannot use '{replace_with}' as replacement for '{type_name}' because it's deprecated too"
)
interface_replacements = []
valid_interfaces = {}
for interface in data["interface"]:
check_type("function", interface, valid_data_types)
check_allowed_keys(
@ -93,8 +110,24 @@ extern "C" {
["name", "return_value", "arguments", "since", "description"],
["see", "legacy_type_name", "deprecated"],
)
valid_interfaces[interface["name"]] = interface
if "deprecated" in interface:
check_allowed_keys(interface["deprecated"], ["since"], ["message", "replace_with"])
if "replace_with" in interface["deprecated"]:
interface_replacements.append((interface["name"], interface["deprecated"]["replace_with"]))
write_interface(file, interface)
for function_name, replace_with in interface_replacements:
if replace_with not in valid_interfaces:
raise Exception(
f"Unknown interface function '{replace_with}' used as replacement for '{function_name}'"
)
replacement = valid_interfaces[replace_with]
if "deprecated" in replacement:
raise Exception(
f"Cannot use '{replace_with}' as replacement for '{function_name}' because it's deprecated too"
)
file.write("""\
#ifdef __cplusplus
}
@ -202,14 +235,24 @@ def write_doc(file, doc, indent=""):
file.write(indent + " */\n")
def make_deprecated_note(type):
def make_deprecated_message(data):
parts = [
f"Deprecated in Godot {data['since']}.",
data["message"] if "message" in data else "",
f"Use `{data['replace_with']}` instead." if "replace_with" in data else "",
]
return " ".join([x for x in parts if x.strip() != ""])
def make_deprecated_comment_for_type(type):
if "deprecated" not in type:
return ""
return f" /* {type['deprecated']} */"
message = make_deprecated_message(type["deprecated"])
return f" /* {message} */"
def write_simple_type(file, type):
file.write(f"typedef {format_type_and_name(type['type'], type['name'])};{make_deprecated_note(type)}\n")
file.write(f"typedef {format_type_and_name(type['type'], type['name'])};{make_deprecated_comment_for_type(type)}\n")
def write_enum_type(file, enum):
@ -219,7 +262,7 @@ def write_enum_type(file, enum):
if "description" in value:
write_doc(file, value["description"], "\t")
file.write(f"\t{value['name']} = {value['value']},\n")
file.write(f"}} {enum['name']};{make_deprecated_note(enum)}\n\n")
file.write(f"}} {enum['name']};{make_deprecated_comment_for_type(enum)}\n\n")
def make_args_text(args):
@ -234,7 +277,7 @@ def write_function_type(file, fn):
args_text = make_args_text(fn["arguments"]) if ("arguments" in fn) else ""
name_and_args = f"(*{fn['name']})({args_text})"
file.write(
f"typedef {format_type_and_name(fn['return_value']['type'], name_and_args)};{make_deprecated_note(fn)}\n"
f"typedef {format_type_and_name(fn['return_value']['type'], name_and_args)};{make_deprecated_comment_for_type(fn)}\n"
)
@ -245,7 +288,7 @@ def write_struct_type(file, struct):
if "description" in member:
write_doc(file, member["description"], "\t")
file.write(f"\t{format_type_and_name(member['type'], member['name'])};\n")
file.write(f"}} {struct['name']};{make_deprecated_note(struct)}\n\n")
file.write(f"}} {struct['name']};{make_deprecated_comment_for_type(struct)}\n\n")
def write_interface(file, interface):
@ -255,10 +298,7 @@ def write_interface(file, interface):
]
if "deprecated" in interface:
if interface["deprecated"].lower().startswith("deprecated "):
parts = interface["deprecated"].split(" ", 1)
interface["deprecated"] = parts[1]
doc.append(f"@deprecated {interface['deprecated']}")
doc.append(f"@deprecated {make_deprecated_message(interface['deprecated'])}")
doc += [
"",