Annotate pointer parameters and returned pointers to help with language bindings
This PR adds annotations to the documentation of the functions' parameters and return value, since C pointers do not convey information about ownership, among other things. The annotations are written next to \params and \returns inside square brackets (eg. \params[out,own] only for relevant pointer values, with the supported annotations being:
in - Parameters that the function reads from. out - Parameters that the function writes to, no matter the initial value (ie. output parameters). inout - Parameters that the function modifies according to their value. Different from out parameters, these need to be initialized beforehand.
opt - Parameters that can be null. own - Parameters that need to be disposed of with SDL_free/other deallocation function after being used.
own can also be applied to pointers returned by functions, with the same meaning that it carries for parameters.
The possible combinations are as following: [in], [out], [inout], [in, opt], [out, opt], [inout, opt], [out, own] . Notice there can be at most two annotations per value, to make the parsing process as simple as possible (which is the reason for having inout instead of in, out).
The wiki parser can skip the [] in \params and \returns (if present) to keep the output the same as before this PR, or you can parse the annotations if that is of interest.
With the annotations accepted, we should now have more information when parsing the headers to generate bindings.
If there are more annotations that should be considered, I'm open to implementing them.
What language binding are you working on and how will this be consumed?
Is the \param[stuff] format unique to this pull request, or is this something Doxygen knows how to parse?
wikiheaders would also need to parse it, too, but if this isn't a Doxygen thing either, I'd rather we find some other way to publish this information.
Would adding an extra section (e.g. \binding) be ok?
Probably not since clang complains about unknown commands (-Wdocumentation-unknown-command).
In that command, we could document the function with some DSL (e.g. this one).
What language binding are you working on and how will this be consumed?
My current goal is a C# binding but the PR should help with other languages as well.
The in/out/inout tags tie in with C#'s in/out and ref params. opt helps with making values null safe at compile time instead of causing an error at runtime. Finally, own tells which pointers the caller is responsible for, which can further be combined with RAII/GC languages so that they automatically free these pointers for the user.
Is the \param[stuff] format unique to this pull request, or is this something Doxygen knows how to parse?
Doxygen can parse \param[in], \param[out], \param[in,out] and \param[inout], but it doesn't know anything about opt and own. If the syntax is not optimal, Doxygen can parse custom tags (described here, in which case we can have a \binding section as suggested.
I was considering another alternative to the comment annotations: instead of annotating the documentation, the parameters and return can instead be annotated. This way the wiki parsing code doesn't need to change at all and tools can parse the annotations as needed. Here's a comparison of the two ways to do it:
// annotations in documentation
/**
* Send a joystick specific effect packet.
*
* \param[self] joystick the joystick to affect.
* \param[in, array(size)] data the data to send to the joystick.
* \param size the size of the data to send to the joystick.
* \returns 0 on success or a negative error code on failure; call
* SDL_GetError() for more information.
*
* \since This function is available since SDL 3.0.0.
*/
extern SDL_DECLSPEC int SDLCALL SDL_SendJoystickEffect(SDL_Joystick *joystick, const void *data, int size);
// annotations in parameters
/**
* Send a joystick specific effect packet.
*
* \param joystick the joystick to affect.
* \param data the data to send to the joystick.
* \param size the size of the data to send to the joystick.
* \returns 0 on success or a negative error code on failure; call
* SDL_GetError() for more information.
*
* \since This function is available since SDL 3.0.0.
*/
extern SDL_DECLSPEC int SDLCALL SDL_SendJoystickEffect(
[[self]] SDL_Joystick *joystick, // `self` means that this function should be considered to be a method of `SDL_Joystick`
[[in, array(size)]] const void *data, // format `array(<size-variable> | return)`
int size
);
The only issue of this approach is that SDL has to provide pragmas on begin_code/close_code that disable "unkown attribute" warnings which should be harmless.
Here's a list of attributes that I have considered, note they apply ONLY to pointer parameters and pointer returns:
in - Const parameters.
out - Mutable parameters, not read by the function.
inout - Mutable parameters that are also read by the function.
self - Only for first parameter, used to denote a "method" of the type. Only useful if the type is defined in the same file.
array(<size-variable>) and array(return) - The parameter is an array with the given size.
free(function) - The pointer needs to be freed with the given function.
Feedback appreciated.
I'm not a fan of adding this to the headers. If we need this information, I'd rather it be annotated somewhere in src/dynapi. @icculus, thoughts?
Let me think about it. That might not be a bad idea.
Yup, this would be useful for Ada too, as Ada uses in, out and in out as well as access for sub-program parameter passing conventions.
Another annotation which would be useful is for pointers and pointers to pointers and pointers to pointers to pointers, etc. to annotate the meaning, is the pointed to object an array for example. This is because other languages can bind to these things differently depending on what is meant.