Merge pull request #1011 from mihe/error-macros

Update error macros to match core
pull/975/head
Rémi Verschelde 2023-02-07 13:47:51 +01:00
commit fccceb8736
No known key found for this signature in database
GPG Key ID: C3336907360768E1
4 changed files with 362 additions and 173 deletions

View File

@ -415,9 +415,12 @@ typedef struct {
void *(*mem_realloc)(void *p_ptr, size_t p_bytes); void *(*mem_realloc)(void *p_ptr, size_t p_bytes);
void (*mem_free)(void *p_ptr); void (*mem_free)(void *p_ptr);
void (*print_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line); void (*print_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line, bool p_editor_notify);
void (*print_warning)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line); void (*print_error_with_message)(const char *p_description, const char *p_message, const char *p_function, const char *p_file, int32_t p_line, bool p_editor_notify);
void (*print_script_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line); void (*print_warning)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line, bool p_editor_notify);
void (*print_warning_with_message)(const char *p_description, const char *p_message, const char *p_function, const char *p_file, int32_t p_line, bool p_editor_notify);
void (*print_script_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line, bool p_editor_notify);
void (*print_script_error_with_message)(const char *p_description, const char *p_message, const char *p_function, const char *p_file, int32_t p_line, bool p_editor_notify);
uint64_t (*get_native_struct_size)(GDExtensionConstStringNamePtr p_name); uint64_t (*get_native_struct_size)(GDExtensionConstStringNamePtr p_name);

View File

@ -32,32 +32,26 @@
#define GODOT_ERROR_MACROS_HPP #define GODOT_ERROR_MACROS_HPP
#include <godot_cpp/core/defs.hpp> #include <godot_cpp/core/defs.hpp>
#include <godot_cpp/variant/string.hpp>
#include <cstdint> #include <atomic>
namespace godot { namespace godot {
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_is_warning = false); class String;
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_is_warning = false);
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_is_warning = false); void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify = false, bool p_is_warning = false);
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_is_warning = false); void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify = false, bool p_is_warning = false);
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_is_warning = false); void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify = false, bool p_is_warning = false);
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_is_warning = false); void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify = false, bool p_is_warning = false);
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message = "", bool fatal = false); void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify = false, bool p_is_warning = false);
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool fatal = false); void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify = false, bool p_is_warning = false);
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message = "", bool p_editor_notify = false, bool p_fatal = false);
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify = false, bool p_fatal = false);
void _err_flush_stdout();
} // namespace godot } // namespace godot
// Used to strip debug messages in release mode
#ifdef DEBUG_ENABLED
#define DEBUG_STR(m_msg) m_msg
#else
#define DEBUG_STR(m_msg) ""
#endif
#ifdef __GNUC__ #ifdef __GNUC__
//#define FUNCTION_STR __PRETTY_FUNCTION__ - too annoying
#define FUNCTION_STR __FUNCTION__ #define FUNCTION_STR __FUNCTION__
#else #else
#define FUNCTION_STR __FUNCTION__ #define FUNCTION_STR __FUNCTION__
@ -75,6 +69,34 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
#define GENERATE_TRAP() __builtin_trap() #define GENERATE_TRAP() __builtin_trap()
#endif #endif
/**
* Error macros.
* WARNING: These macros work in the opposite way to assert().
*
* Unlike exceptions and asserts, these macros try to maintain consistency and stability.
* In most cases, bugs and/or invalid data are not fatal. They should never allow a perfectly
* running application to fail or crash.
* Always try to return processable data, so the engine can keep running well.
* Use the _MSG versions to print a meaningful message to help with debugging.
*
* The `((void)0)` no-op statement is used as a trick to force us to put a semicolon after
* those macros, making them look like proper statements.
* The if wrappers are used to ensure that the macro replacement does not trigger unexpected
* issues when expanded e.g. after an `if (cond) ERR_FAIL();` without braces.
*/
// Index out of bounds error macros.
// These macros should be used instead of `ERR_FAIL_COND` for bounds checking.
// Integer index out of bounds error macros.
/**
* Try using `ERR_FAIL_INDEX_MSG`.
* Only use this macro if there is no sensible error message.
*
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, the current function returns.
*/
#define ERR_FAIL_INDEX(m_index, m_size) \ #define ERR_FAIL_INDEX(m_index, m_size) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ ::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
@ -86,11 +108,21 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, prints `m_msg` and the current function returns. * If not, prints `m_msg` and the current function returns.
*/ */
#define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg) \ #define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ ::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
return; \ return; \
} else \ } else \
((void)0)
/**
* Same as `ERR_FAIL_INDEX_MSG` but also notifies the editor.
*/
#define ERR_FAIL_INDEX_EDMSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
return; \
} else \
((void)0) ((void)0)
/** /**
@ -111,11 +143,21 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, prints `m_msg` and the current function returns `m_retval`. * If not, prints `m_msg` and the current function returns `m_retval`.
*/ */
#define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \ #define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ ::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
return m_retval; \ return m_retval; \
} else \ } else \
((void)0)
/**
* Same as `ERR_FAIL_INDEX_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
return m_retval; \
} else \
((void)0) ((void)0)
/** /**
@ -126,11 +168,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, the application crashes. * If not, the application crashes.
*/ */
#define CRASH_BAD_INDEX(m_index, m_size) \ #define CRASH_BAD_INDEX(m_index, m_size) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", true); \ ::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
GENERATE_TRAP(); \ ::godot::_err_flush_stdout(); \
} else \ GENERATE_TRAP(); \
} else \
((void)0) ((void)0)
/** /**
@ -140,11 +183,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, prints `m_msg` and the application crashes. * If not, prints `m_msg` and the application crashes.
*/ */
#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \ #define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg), true); \ ::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
GENERATE_TRAP(); \ ::godot::_err_flush_stdout(); \
} else \ GENERATE_TRAP(); \
} else \
((void)0) ((void)0)
// Unsigned integer index out of bounds error macros. // Unsigned integer index out of bounds error macros.
@ -167,11 +211,21 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Ensures an unsigned integer index `m_index` is less than `m_size`. * Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, prints `m_msg` and the current function returns. * If not, prints `m_msg` and the current function returns.
*/ */
#define ERR_FAIL_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \ #define ERR_FAIL_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \ if (unlikely((m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ ::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
return; \ return; \
} else \ } else \
((void)0)
/**
* Same as `ERR_FAIL_UNSIGNED_INDEX_MSG` but also notifies the editor.
*/
#define ERR_FAIL_UNSIGNED_INDEX_EDMSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
return; \
} else \
((void)0) ((void)0)
/** /**
@ -192,11 +246,21 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Ensures an unsigned integer index `m_index` is less than `m_size`. * Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, prints `m_msg` and the current function returns `m_retval`. * If not, prints `m_msg` and the current function returns `m_retval`.
*/ */
#define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \ #define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) >= (m_size))) { \ if (unlikely((m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ ::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
return m_retval; \ return m_retval; \
} else \ } else \
((void)0)
/**
* Same as `ERR_FAIL_UNSIGNED_INDEX_V_EDMSG` but also notifies the editor.
*/
#define ERR_FAIL_UNSIGNED_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
return m_retval; \
} else \
((void)0) ((void)0)
/** /**
@ -207,11 +271,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Ensures an unsigned integer index `m_index` is less than `m_size`. * Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, the application crashes. * If not, the application crashes.
*/ */
#define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \ #define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \
if (unlikely((m_index) >= (m_size))) { \ if (unlikely((m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", true); \ ::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
GENERATE_TRAP(); \ ::godot::_err_flush_stdout(); \
} else \ GENERATE_TRAP(); \
} else \
((void)0) ((void)0)
/** /**
@ -221,11 +286,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Ensures an unsigned integer index `m_index` is less than `m_size`. * Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, prints `m_msg` and the application crashes. * If not, prints `m_msg` and the application crashes.
*/ */
#define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \ #define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \ if (unlikely((m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg), true); \ ::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
GENERATE_TRAP(); \ ::godot::_err_flush_stdout(); \
} else \ GENERATE_TRAP(); \
} else \
((void)0) ((void)0)
// Null reference error macros. // Null reference error macros.
@ -248,11 +314,21 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Ensures a pointer `m_param` is not null. * Ensures a pointer `m_param` is not null.
* If it is null, prints `m_msg` and the current function returns. * If it is null, prints `m_msg` and the current function returns.
*/ */
#define ERR_FAIL_NULL_MSG(m_param, m_msg) \ #define ERR_FAIL_NULL_MSG(m_param, m_msg) \
if (unlikely(m_param == nullptr)) { \ if (unlikely(m_param == nullptr)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", DEBUG_STR(m_msg)); \ ::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \
return; \ return; \
} else \ } else \
((void)0)
/**
* Same as `ERR_FAIL_NULL_MSG` but also notifies the editor.
*/
#define ERR_FAIL_NULL_EDMSG(m_param, m_msg) \
if (unlikely(m_param == nullptr)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \
return; \
} else \
((void)0) ((void)0)
/** /**
@ -273,11 +349,21 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Ensures a pointer `m_param` is not null. * Ensures a pointer `m_param` is not null.
* If it is null, prints `m_msg` and the current function returns `m_retval`. * If it is null, prints `m_msg` and the current function returns `m_retval`.
*/ */
#define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \ #define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \
if (unlikely(m_param == nullptr)) { \ if (unlikely(m_param == nullptr)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", DEBUG_STR(m_msg)); \ ::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \
return m_retval; \ return m_retval; \
} else \ } else \
((void)0)
/**
* Same as `ERR_FAIL_NULL_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_NULL_V_EDMSG(m_param, m_retval, m_msg) \
if (unlikely(m_param == nullptr)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \
return m_retval; \
} else \
((void)0) ((void)0)
/** /**
@ -303,11 +389,21 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* If checking for null use ERR_FAIL_NULL_MSG instead. * If checking for null use ERR_FAIL_NULL_MSG instead.
* If checking index bounds use ERR_FAIL_INDEX_MSG instead. * If checking index bounds use ERR_FAIL_INDEX_MSG instead.
*/ */
#define ERR_FAIL_COND_MSG(m_cond, m_msg) \ #define ERR_FAIL_COND_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \ if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", DEBUG_STR(m_msg)); \ ::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg); \
return; \ return; \
} else \ } else \
((void)0)
/**
* Same as `ERR_FAIL_COND_MSG` but also notifies the editor.
*/
#define ERR_FAIL_COND_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg, true); \
return; \
} else \
((void)0) ((void)0)
/** /**
@ -333,11 +429,21 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* If checking for null use ERR_FAIL_NULL_V_MSG instead. * If checking for null use ERR_FAIL_NULL_V_MSG instead.
* If checking index bounds use ERR_FAIL_INDEX_V_MSG instead. * If checking index bounds use ERR_FAIL_INDEX_V_MSG instead.
*/ */
#define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \ #define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \
if (unlikely(m_cond)) { \ if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), DEBUG_STR(m_msg)); \ ::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg); \
return m_retval; \ return m_retval; \
} else \ } else \
((void)0)
/**
* Same as `ERR_FAIL_COND_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_COND_V_EDMSG(m_cond, m_retval, m_msg) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg, true); \
return m_retval; \
} else \
((void)0) ((void)0)
/** /**
@ -358,11 +464,21 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Ensures `m_cond` is false. * Ensures `m_cond` is false.
* If `m_cond` is true, prints `m_msg` and the current loop continues. * If `m_cond` is true, prints `m_msg` and the current loop continues.
*/ */
#define ERR_CONTINUE_MSG(m_cond, m_msg) \ #define ERR_CONTINUE_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \ if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", DEBUG_STR(m_msg)); \ ::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg); \
continue; \ continue; \
} else \ } else \
((void)0)
/**
* Same as `ERR_CONTINUE_MSG` but also notifies the editor.
*/
#define ERR_CONTINUE_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg, true); \
continue; \
} else \
((void)0) ((void)0)
/** /**
@ -383,11 +499,21 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Ensures `m_cond` is false. * Ensures `m_cond` is false.
* If `m_cond` is true, prints `m_msg` and the current loop breaks. * If `m_cond` is true, prints `m_msg` and the current loop breaks.
*/ */
#define ERR_BREAK_MSG(m_cond, m_msg) \ #define ERR_BREAK_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \ if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", DEBUG_STR(m_msg)); \ ::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg); \
break; \ break; \
} else \ } else \
((void)0)
/**
* Same as `ERR_BREAK_MSG` but also notifies the editor.
*/
#define ERR_BREAK_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg, true); \
break; \
} else \
((void)0) ((void)0)
/** /**
@ -401,6 +527,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
#define CRASH_COND(m_cond) \ #define CRASH_COND(m_cond) \
if (unlikely(m_cond)) { \ if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true."); \ ::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true."); \
::godot::_err_flush_stdout(); \
GENERATE_TRAP(); \ GENERATE_TRAP(); \
} else \ } else \
((void)0) ((void)0)
@ -412,11 +539,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Ensures `m_cond` is false. * Ensures `m_cond` is false.
* If `m_cond` is true, prints `m_msg` and the application crashes. * If `m_cond` is true, prints `m_msg` and the application crashes.
*/ */
#define CRASH_COND_MSG(m_cond, m_msg) \ #define CRASH_COND_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \ if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true.", DEBUG_STR(m_msg)); \ ::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true.", m_msg); \
GENERATE_TRAP(); \ ::godot::_err_flush_stdout(); \
} else \ GENERATE_TRAP(); \
} else \
((void)0) ((void)0)
// Generic error macros. // Generic error macros.
@ -441,11 +569,21 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* *
* Prints `m_msg`, and the current function returns. * Prints `m_msg`, and the current function returns.
*/ */
#define ERR_FAIL_MSG(m_msg) \ #define ERR_FAIL_MSG(m_msg) \
if (true) { \ if (true) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", DEBUG_STR(m_msg)); \ ::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg); \
return; \ return; \
} else \ } else \
((void)0)
/**
* Same as `ERR_FAIL_MSG` but also notifies the editor.
*/
#define ERR_FAIL_EDMSG(m_msg) \
if (true) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg, true); \
return; \
} else \
((void)0) ((void)0)
/** /**
@ -468,15 +606,25 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* *
* Prints `m_msg`, and the current function returns `m_retval`. * Prints `m_msg`, and the current function returns `m_retval`.
*/ */
#define ERR_FAIL_V_MSG(m_retval, m_msg) \ #define ERR_FAIL_V_MSG(m_retval, m_msg) \
if (true) { \ if (true) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), DEBUG_STR(m_msg)); \ ::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg); \
return m_retval; \ return m_retval; \
} else \ } else \
((void)0) ((void)0)
/** /**
* Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or ERR_BREAK_MSG. * Same as `ERR_FAIL_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_V_EDMSG(m_retval, m_msg) \
if (true) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg, true); \
return m_retval; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or `ERR_BREAK_MSG`.
* Only use this macro at the start of a function that has not been implemented yet, or * Only use this macro at the start of a function that has not been implemented yet, or
* if more complex error detection or recovery is required. * if more complex error detection or recovery is required.
* *
@ -485,6 +633,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
#define ERR_PRINT(m_msg) \ #define ERR_PRINT(m_msg) \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg) ::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg)
/**
* Same as `ERR_PRINT` but also notifies the editor.
*/
#define ERR_PRINT_ED(m_msg) \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true)
/** /**
* Prints `m_msg` once during the application lifetime. * Prints `m_msg` once during the application lifetime.
*/ */
@ -498,22 +652,10 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
} else \ } else \
((void)0) ((void)0)
// Print warning message macros.
/** /**
* Prints `m_msg`. * Same as `ERR_PRINT_ONCE` but also notifies the editor.
*
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
*/ */
#define WARN_PRINT(m_msg) \ #define ERR_PRINT_ONCE_ED(m_msg) \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true)
/**
* Prints `m_msg` once during the application lifetime.
*
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
*/
#define WARN_PRINT_ONCE(m_msg) \
if (true) { \ if (true) { \
static bool first_print = true; \ static bool first_print = true; \
if (first_print) { \ if (first_print) { \
@ -523,32 +665,76 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
} else \ } else \
((void)0) ((void)0)
// Print warning message macros.
/**
* Prints `m_msg`.
*
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
*/
#define WARN_PRINT(m_msg) \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, true)
/**
* Same as `WARN_PRINT` but also notifies the editor.
*/
#define WARN_PRINT_ED(m_msg) \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, true)
/**
* Prints `m_msg` once during the application lifetime.
*
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
*/
#define WARN_PRINT_ONCE(m_msg) \
if (true) { \
static bool first_print = true; \
if (first_print) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, true); \
first_print = false; \
} \
} else \
((void)0)
/**
* Same as `WARN_PRINT_ONCE` but also notifies the editor.
*/
#define WARN_PRINT_ONCE_ED(m_msg) \
if (true) { \
static bool first_print = true; \
if (first_print) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, true); \
first_print = false; \
} \
} else \
((void)0)
// Print deprecated warning message macros. // Print deprecated warning message macros.
/** /**
* Warns that the current function is deprecated. * Warns that the current function is deprecated.
*/ */
#define WARN_DEPRECATED \ #define WARN_DEPRECATED \
if (true) { \ if (true) { \
static SafeFlag warning_shown; \ static std::atomic<bool> warning_shown; \
if (!warning_shown.is_set()) { \ if (!warning_shown.load()) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", true); \ ::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", false, true); \
warning_shown.set(); \ warning_shown.store(true); \
} \ } \
} else \ } else \
((void)0) ((void)0)
/** /**
* Warns that the current function is deprecated and prints `m_msg`. * Warns that the current function is deprecated and prints `m_msg`.
*/ */
#define WARN_DEPRECATED_MSG(m_msg) \ #define WARN_DEPRECATED_MSG(m_msg) \
if (true) { \ if (true) { \
static SafeFlag warning_shown; \ static std::atomic<bool> warning_shown; \
if (!warning_shown.is_set()) { \ if (!warning_shown.load()) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", DEBUG_STR(m_msg), true); \ ::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", m_msg, false, true); \
warning_shown.set(); \ warning_shown.store(true); \
} \ } \
} else \ } else \
((void)0) ((void)0)
/** /**
@ -560,6 +746,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
#define CRASH_NOW() \ #define CRASH_NOW() \
if (true) { \ if (true) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed."); \ ::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed."); \
::godot::_err_flush_stdout(); \
GENERATE_TRAP(); \ GENERATE_TRAP(); \
} else \ } else \
((void)0) ((void)0)
@ -569,11 +756,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* *
* Prints `m_msg`, and then the application crashes. * Prints `m_msg`, and then the application crashes.
*/ */
#define CRASH_NOW_MSG(m_msg) \ #define CRASH_NOW_MSG(m_msg) \
if (true) { \ if (true) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed.", DEBUG_STR(m_msg)); \ ::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed.", m_msg); \
GENERATE_TRAP(); \ ::godot::_err_flush_stdout(); \
} else \ GENERATE_TRAP(); \
} else \
((void)0) ((void)0)
/** /**
@ -584,6 +772,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
#define DEV_ASSERT(m_cond) \ #define DEV_ASSERT(m_cond) \
if (unlikely(!(m_cond))) { \ if (unlikely(!(m_cond))) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: DEV_ASSERT failed \"" _STR(m_cond) "\" is false."); \ ::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: DEV_ASSERT failed \"" _STR(m_cond) "\" is false."); \
::godot::_err_flush_stdout(); \
GENERATE_TRAP(); \ GENERATE_TRAP(); \
} else \ } else \
((void)0) ((void)0)

View File

@ -31,61 +31,56 @@
#include <godot_cpp/core/error_macros.hpp> #include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/godot.hpp> #include <godot_cpp/godot.hpp>
#include <godot_cpp/variant/string.hpp>
#include <string> #include <cstdio>
namespace godot { namespace godot {
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_is_warning) { void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify, bool p_is_warning) {
if (p_is_warning) { if (p_is_warning) {
internal::gde_interface->print_warning(p_message, p_function, p_file, p_line); internal::gde_interface->print_warning(p_error, p_function, p_file, p_line, p_editor_notify);
} else { } else {
internal::gde_interface->print_error(p_message, p_function, p_file, p_line); internal::gde_interface->print_error(p_error, p_function, p_file, p_line, p_editor_notify);
} }
} }
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_is_warning) { void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify, bool p_is_warning) {
_err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), p_editor_notify, p_is_warning);
}
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify, bool p_is_warning) {
if (p_is_warning) { if (p_is_warning) {
internal::gde_interface->print_warning(p_message, p_function, p_file, p_line); internal::gde_interface->print_warning_with_message(p_error, p_message, p_function, p_file, p_line, p_editor_notify);
} else { } else {
internal::gde_interface->print_error(p_message, p_function, p_file, p_line); internal::gde_interface->print_error_with_message(p_error, p_message, p_function, p_file, p_line, p_editor_notify);
} }
} }
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_is_warning) { void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify, bool p_is_warning) {
if (p_is_warning) { _err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), p_message, p_editor_notify, p_is_warning);
internal::gde_interface->print_warning(p_message.utf8().get_data(), p_function, p_file, p_line);
} else {
internal::gde_interface->print_error(p_message.utf8().get_data(), p_function, p_file, p_line);
}
} }
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_is_warning) { void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify, bool p_is_warning) {
if (p_is_warning) { _err_print_error(p_function, p_file, p_line, p_error, p_message.utf8().get_data(), p_editor_notify, p_is_warning);
internal::gde_interface->print_warning(p_message.utf8().get_data(), p_function, p_file, p_line);
} else {
internal::gde_interface->print_error(p_message.utf8().get_data(), p_function, p_file, p_line);
}
} }
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_is_warning) { void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify, bool p_is_warning) {
_err_print_error(p_function, p_file, p_line, "", p_error, p_is_warning); _err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), p_message.utf8().get_data(), p_editor_notify, p_is_warning);
} }
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_is_warning) { void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message, bool p_editor_notify, bool p_fatal) {
_err_print_error(p_function, p_file, p_line, "", p_error, p_is_warning); String fstr(p_fatal ? "FATAL: " : "");
String err(fstr + "Index " + p_index_str + " = " + itos(p_index) + " is out of bounds (" + p_size_str + " = " + itos(p_size) + ").");
_err_print_error(p_function, p_file, p_line, err.utf8().get_data(), p_message, p_editor_notify, false);
} }
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message, bool fatal) { void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify, bool p_fatal) {
std::string fstr(fatal ? "FATAL: " : ""); _err_print_index_error(p_function, p_file, p_line, p_index, p_size, p_index_str, p_size_str, p_message.utf8().get_data(), p_editor_notify, p_fatal);
std::string err(fstr + "Index " + p_index_str + " = " + std::to_string(p_index) + " is out of bounds (" + p_size_str + " = " + std::to_string(p_size) + ").");
_err_print_error(p_function, p_file, p_line, err.c_str(), p_message);
} }
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool fatal) { void _err_flush_stdout() {
std::string fstr(fatal ? "FATAL: " : ""); fflush(stdout);
std::string err(fstr + "Index " + p_index_str + " = " + std::to_string(p_index) + " is out of bounds (" + p_size_str + " = " + std::to_string(p_size) + ").");
_err_print_error(p_function, p_file, p_line, err.c_str(), p_message);
} }
} // namespace godot } // namespace godot

View File

@ -30,6 +30,8 @@
#include <godot_cpp/variant/transform2d.hpp> #include <godot_cpp/variant/transform2d.hpp>
#include <godot_cpp/variant/string.hpp>
namespace godot { namespace godot {
void Transform2D::invert() { void Transform2D::invert() {