X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1e702ab351f24530b90709025ac52a3a1c96b3d8..66c2bf7b1d9326fb650acfaae22ec50528cfbf7c:/include/wx/debug.h diff --git a/include/wx/debug.h b/include/wx/debug.h index 93f394a60b..f80f7be680 100644 --- a/include/wx/debug.h +++ b/include/wx/debug.h @@ -2,42 +2,64 @@ // Name: wx/debug.h // Purpose: Misc debug functions and macros // Author: Vadim Zeitlin -// Modified by: // Created: 29/01/98 -// RCS-ID: $Id$ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows license +// Copyright: (c) 1998-2009 Vadim Zeitlin +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifndef _WX_DEBUG_H_ -#define _WX_DEBUG_H_ +#ifndef _WX_DEBUG_H_ +#define _WX_DEBUG_H_ -#ifndef __WXWINCE__ -#include -#endif -#include // for CHAR_BIT used below +#if !defined(__WXWINCE__) + #include +#endif // systems without assert.h + +#include // for CHAR_BIT used below + +#include "wx/chartype.h" // for __TFILE__ and wxChar +#include "wx/cpp.h" // for __WXFUNCTION__ +#include "wx/dlimpexp.h" // for WXDLLIMPEXP_FWD_BASE -#include "wx/wxchar.h" // for __TFILE__ and wxChar +class WXDLLIMPEXP_FWD_BASE wxString; +class WXDLLIMPEXP_FWD_BASE wxCStrData; // ---------------------------------------------------------------------------- // Defines controlling the debugging macros // ---------------------------------------------------------------------------- -// if _DEBUG is defined (MS VC++ and others use it in debug builds), define -// __WXDEBUG__ too -#ifdef _DEBUG +/* + wxWidgets can be built with several different levels of debug support + specified by the value of wxDEBUG_LEVEL constant: + + 0: No assertion macros at all, this should only be used when optimizing + for resource-constrained systems (typically embedded ones). + 1: Default level, most of the assertions are enabled. + 2: Maximal (at least for now): asserts which are "expensive" + (performance-wise) or only make sense for finding errors in wxWidgets + itself, as opposed to bugs in applications using it, are also enabled. + */ + +// unless wxDEBUG_LEVEL is predefined (by configure or via wx/setup.h under +// Windows), use the default +#if !defined(wxDEBUG_LEVEL) + #define wxDEBUG_LEVEL 1 +#endif // !defined(wxDEBUG_LEVEL) + +/* + __WXDEBUG__ is defined when wxDEBUG_LEVEL != 0. This is done mostly for + compatibility but it also provides a simpler way to check if asserts and + debug logging is enabled at all. + */ +#if wxDEBUG_LEVEL > 0 #ifndef __WXDEBUG__ #define __WXDEBUG__ - #endif // !__WXDEBUG__ -#endif // _DEBUG - -// if NDEBUG is defined ( uses it), undef __WXDEBUG__ and WXDEBUG -#ifdef NDEBUG + #endif +#else #undef __WXDEBUG__ - #undef WXDEBUG -#endif // NDEBUG +#endif -// if __WXDEBUG__ is defined, make sure that WXDEBUG is defined and >= 1 +// Finally there is also a very old WXDEBUG macro not used anywhere at all, it +// is only defined for compatibility. #ifdef __WXDEBUG__ #if !defined(WXDEBUG) || !WXDEBUG #undef WXDEBUG @@ -46,113 +68,301 @@ #endif // __WXDEBUG__ // ---------------------------------------------------------------------------- -// Debugging macros -// -// All debugging macros rely on ASSERT() which in turn calls user-defined -// OnAssert() function. To keep things simple, it's called even when the -// expression is TRUE (i.e. everything is ok) and by default does nothing: just -// returns the same value back. But if you redefine it to do something more sexy -// (popping up a message box in your favourite GUI, sending you e-mail or -// whatever) it will affect all ASSERTs, FAILs and CHECKs in your code. -// -// Warning: if you don't like advices on programming style, don't read -// further! ;-) -// -// Extensive use of these macros is recommended! Remember that ASSERTs are -// disabled in final (without __WXDEBUG__ defined) build, so they add strictly -// nothing to your program's code. On the other hand, CHECK macros do stay -// even in release builds, but in general are not much of a burden, while -// a judicious use of them might increase your program's stability. +// Handling assertion failures // ---------------------------------------------------------------------------- -// Macros which are completely disabled in 'release' mode +/* + Type for the function called in case of assert failure, see + wxSetAssertHandler(). + */ +typedef void (*wxAssertHandler_t)(const wxString& file, + int line, + const wxString& func, + const wxString& cond, + const wxString& msg); + +#if wxDEBUG_LEVEL + +// the global assert handler function, if it is NULL asserts don't check their +// conditions +extern WXDLLIMPEXP_DATA_BASE(wxAssertHandler_t) wxTheAssertHandler; + +/* + Sets the function to be called in case of assertion failure. + + The default assert handler forwards to wxApp::OnAssertFailure() whose + default behaviour is, in turn, to show the standard assertion failure + dialog if a wxApp object exists or shows the same dialog itself directly + otherwise. + + While usually it is enough -- and more convenient -- to just override + OnAssertFailure(), to handle all assertion failures, including those + occurring even before wxApp object creation or after its destruction you + need to provide your assertion handler function. + + This function also provides a simple way to disable all asserts: simply + pass NULL pointer to it. Doing this will result in not even evaluating + assert conditions at all, avoiding almost all run-time cost of asserts. + + Notice that this function is not MT-safe, so you should call it before + starting any other threads. + + The return value of this function is the previous assertion handler. It can + be called after any pre-processing by your handler and can also be restored + later if you uninstall your handler. + */ +inline wxAssertHandler_t wxSetAssertHandler(wxAssertHandler_t handler) +{ + const wxAssertHandler_t old = wxTheAssertHandler; + wxTheAssertHandler = handler; + return old; +} + +/* + Reset the default assert handler. + + This may be used to enable asserts, which are disabled by default in this + case, for programs built in release build (NDEBUG defined). + */ +extern void WXDLLIMPEXP_BASE wxSetDefaultAssertHandler(); + +#else // !wxDEBUG_LEVEL + +// provide empty stubs in case assertions are completely disabled // -// NB: these functions are implemented in src/common/appcmn.cpp -#ifdef __WXDEBUG__ - /* - this function may be redefined to do something non trivial and is called - whenever one of debugging macros fails (i.e. condition is false in an - assertion) - - parameters: - szFile and nLine - file name and line number of the ASSERT - szMsg - optional message explaining the reason - */ - extern void WXDLLEXPORT wxOnAssert(const wxChar *szFile, - int nLine, - const wxChar *szCond, - const wxChar *szMsg = NULL); - - // call this function to break into the debugger uncodnitionally (assuming - // the program is running under debugger, of course) - extern void WXDLLEXPORT wxTrap(); - - // helper function used to implement wxASSERT and wxASSERT_MSG - // - // note using "int" and not "bool" for cond to avoid VC++ warnings about - // implicit conversions when doing "wxAssert( pointer )" and also use of - // "!!cond" below to ensure that everything is converted to int - extern void WXDLLEXPORT wxAssert(int cond, - const wxChar *szFile, - int nLine, - const wxChar *szCond, - const wxChar *szMsg = NULL) ; - - // generic assert macro - #define wxASSERT(cond) wxAssert(!!(cond), __TFILE__, __LINE__, _T(#cond)) - - // assert with additional message explaining it's cause - #define wxASSERT_MSG(cond, msg) \ - wxAssert(!!(cond), __TFILE__, __LINE__, _T(#cond), msg) - - // an assert helper used to avoid warning when testing constant expressions, - // i.e. wxASSERT( sizeof(int) == 4 ) can generate a compiler warning about - // expression being always true, but not using - // wxASSERT( wxAssertIsEqual(sizeof(int), 4) ) - // - // NB: this is made obsolete by wxCOMPILE_TIME_ASSERT() and shouldn't be - // used any longer - extern bool WXDLLEXPORT wxAssertIsEqual(int x, int y); +// NB: can't use WXUNUSED() here as we're included from wx/defs.h before it is +// defined +inline wxAssertHandler_t wxSetAssertHandler(wxAssertHandler_t /* handler */) +{ + return NULL; +} + +inline void wxSetDefaultAssertHandler() { } + +#endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL + +// simply a synonym for wxSetAssertHandler(NULL) +inline void wxDisableAsserts() { wxSetAssertHandler(NULL); } + +/* + A macro which disables asserts for applications compiled in release build. + + By default, wxIMPLEMENT_APP (or rather wxIMPLEMENT_WXWIN_MAIN) disable the + asserts in the applications compiled in the release build by calling this. + It does nothing if NDEBUG is not defined. + */ +#ifdef NDEBUG + #define wxDISABLE_ASSERTS_IN_RELEASE_BUILD() wxDisableAsserts() #else - #define wxTrap() + #define wxDISABLE_ASSERTS_IN_RELEASE_BUILD() +#endif - // nothing to do in release modes (hopefully at this moment there are - // no more bugs ;-) - #define wxASSERT(cond) - #define wxASSERT_MSG(x, m) -#endif //__WXDEBUG__ +#if wxDEBUG_LEVEL -// Use of wxFalse instead of FALSE suppresses compiler warnings about testing -// constant expression -WXDLLEXPORT_DATA(extern const bool) wxFalse; -#define wxAssertFailure wxFalse +/* + wxOnAssert() is used by the debugging macros defined below. Different + overloads are needed because these macros can be used with or without wxT(). + + All of them are implemented in src/common/appcmn.cpp and unconditionally + call wxTheAssertHandler so the caller must check that it is non-NULL + (assert macros do it). + */ -// special form of assert: always triggers it (in debug mode) -#define wxFAIL wxASSERT(wxAssertFailure) +#if wxUSE_UNICODE + +// these overloads are the ones typically used by debugging macros: we have to +// provide wxChar* msg version because it's common to use wxT() in the macros +// and finally, we can't use const wx(char)* msg = NULL, because that would +// be ambiguous +// +// also notice that these functions can't be inline as wxString is not defined +// yet (and can't be as wxString code itself may use assertions) +extern WXDLLIMPEXP_BASE void wxOnAssert(const char *file, + int line, + const char *func, + const char *cond); + +extern WXDLLIMPEXP_BASE void wxOnAssert(const char *file, + int line, + const char *func, + const char *cond, + const char *msg); + +extern WXDLLIMPEXP_BASE void wxOnAssert(const char *file, + int line, + const char *func, + const char *cond, + const wxChar *msg) ; +#endif /* wxUSE_UNICODE */ + +// this version is for compatibility with wx 2.8 Unicode build only, we don't +// use it ourselves any more except in ANSI-only build in which case it is all +// we need +extern WXDLLIMPEXP_BASE void wxOnAssert(const wxChar *file, + int line, + const char *func, + const wxChar *cond, + const wxChar *msg = NULL); + +// these overloads work when msg passed to debug macro is a string and we +// also have to provide wxCStrData overload to resolve ambiguity which would +// otherwise arise from wxASSERT( s.c_str() ) +extern WXDLLIMPEXP_BASE void wxOnAssert(const wxString& file, + int line, + const wxString& func, + const wxString& cond, + const wxString& msg); + +extern WXDLLIMPEXP_BASE void wxOnAssert(const wxString& file, + int line, + const wxString& func, + const wxString& cond); + +extern WXDLLIMPEXP_BASE void wxOnAssert(const char *file, + int line, + const char *func, + const char *cond, + const wxCStrData& msg); + +extern WXDLLIMPEXP_BASE void wxOnAssert(const char *file, + int line, + const char *func, + const char *cond, + const wxString& msg); + +#endif // wxDEBUG_LEVEL -// FAIL with some message -#define wxFAIL_MSG(msg) wxASSERT_MSG(wxAssertFailure, msg) -// NB: the following macros work also in release mode! +// ---------------------------------------------------------------------------- +// Debugging macros +// ---------------------------------------------------------------------------- /* - These macros must be used only in invalid situation: for example, an - invalid parameter (NULL pointer) is passed to a function. Instead of - dereferencing it and causing core dump the function might try using - CHECK( p != NULL ) or CHECK( p != NULL, return LogError("p is NULL!!") ) + Assertion macros: check if the condition is true and call assert handler + (which will by default notify the user about failure) if it isn't. + + wxASSERT and wxFAIL macros as well as wxTrap() function do nothing at all + if wxDEBUG_LEVEL is 0 however they do check their conditions at default + debug level 1, unlike the previous wxWidgets versions. + + wxASSERT_LEVEL_2 is meant to be used for "expensive" asserts which should + normally be disabled because they have a big impact on performance and so + this macro only does anything if wxDEBUG_LEVEL >= 2. + */ +#if wxDEBUG_LEVEL + // wxTrap() can be used to break into the debugger unconditionally + // (assuming the program is running under debugger, of course). + // + // If possible, we prefer to define it as a macro rather than as a function + // to open the debugger at the position where we trapped and not inside the + // trap function itself which is not very useful. + #if wxCHECK_VISUALC_VERSION(7) + #define wxTrap() __debugbreak() + #else + extern WXDLLIMPEXP_BASE void wxTrap(); + #endif // Win VisualC + + // Global flag used to indicate that assert macros should call wxTrap(): it + // is set by the default assert handler if the user answers yes to the + // question of whether to trap. + extern WXDLLIMPEXP_DATA_BASE(bool) wxTrapInAssert; + + // This macro checks if the condition is true and calls the assert handler + // with the provided message if it isn't and finally traps if the special + // flag indicating that it should do it was set by the handler. + // + // Notice that we don't use the handler return value for compatibility + // reasons (if we changed its return type, we'd need to change wxApp:: + // OnAssertFailure() too which would break user code overriding it), hence + // the need for the ugly global flag. + #define wxASSERT_MSG(cond, msg) \ + wxSTATEMENT_MACRO_BEGIN \ + if ( wxTheAssertHandler && !(cond) && \ + (wxOnAssert(__FILE__, __LINE__, __WXFUNCTION__, \ + #cond, msg), wxTrapInAssert) ) \ + { \ + wxTrapInAssert = false; \ + wxTrap(); \ + } \ + wxSTATEMENT_MACRO_END + + // a version without any additional message, don't use unless condition + // itself is fully self-explanatory + #define wxASSERT(cond) wxASSERT_MSG(cond, (const char*)NULL) + + // wxFAIL is a special form of assert: it always triggers (and so is + // usually used in normally unreachable code) + #define wxFAIL_COND_MSG(cond, msg) \ + wxSTATEMENT_MACRO_BEGIN \ + if ( wxTheAssertHandler && \ + (wxOnAssert(__FILE__, __LINE__, __WXFUNCTION__, \ + cond, msg), wxTrapInAssert) ) \ + { \ + wxTrapInAssert = false; \ + wxTrap(); \ + } \ + wxSTATEMENT_MACRO_END + + #define wxFAIL_MSG(msg) wxFAIL_COND_MSG("Assert failure", msg) + #define wxFAIL wxFAIL_MSG((const char*)NULL) +#else // !wxDEBUG_LEVEL + #define wxTrap() + + #define wxASSERT(cond) + #define wxASSERT_MSG(cond, msg) + #define wxFAIL + #define wxFAIL_MSG(msg) + #define wxFAIL_COND_MSG(cond, msg) +#endif // wxDEBUG_LEVEL + +#if wxDEBUG_LEVEL >= 2 + #define wxASSERT_LEVEL_2_MSG(cond, msg) wxASSERT_MSG(cond, msg) + #define wxASSERT_LEVEL_2(cond) wxASSERT(cond) +#else // wxDEBUG_LEVEL < 2 + #define wxASSERT_LEVEL_2_MSG(cond, msg) + #define wxASSERT_LEVEL_2(cond) +#endif + +// This is simply a wrapper for the standard abort() which is not available +// under all platforms. +// +// It isn't really debug-related but there doesn't seem to be any better place +// for it, so declare it here and define it in appbase.cpp, together with +// wxTrap(). +extern void WXDLLIMPEXP_BASE wxAbort(); + +/* + wxCHECK macros always check their conditions, setting debug level to 0 only + makes them silent in case of failure, otherwise -- including at default + debug level 1 -- they call the assert handler if the condition is false + + They are supposed to be used only in invalid situation: for example, an + invalid parameter (e.g. a NULL pointer) is passed to a function. Instead of + dereferencing it and causing core dump the function might use + + wxCHECK_RET( p != NULL, "pointer can't be NULL" ) */ -// check that expression is true, "return" if not (also FAILs in debug mode) -#define wxCHECK(x, rc) if (!(x)) {wxFAIL; return rc; } +// the generic macro: takes the condition to check, the statement to be executed +// in case the condition is false and the message to pass to the assert handler +#define wxCHECK2_MSG(cond, op, msg) \ + if ( cond ) \ + {} \ + else \ + { \ + wxFAIL_COND_MSG(#cond, msg); \ + op; \ + } \ + struct wxDummyCheckStruct /* just to force a semicolon */ + +// check which returns with the specified return code if the condition fails +#define wxCHECK_MSG(cond, rc, msg) wxCHECK2_MSG(cond, return rc, msg) -// as wxCHECK but with a message explaining why we fail -#define wxCHECK_MSG(x, rc, msg) if (!(x)) {wxFAIL_MSG(msg); return rc; } +// check that expression is true, "return" if not (also FAILs in debug mode) +#define wxCHECK(cond, rc) wxCHECK_MSG(cond, rc, (const char*)NULL) // check that expression is true, perform op if not -#define wxCHECK2(x, op) if (!(x)) {wxFAIL; op; } - -// as wxCHECK2 but with a message explaining why we fail -#define wxCHECK2_MSG(x, op, msg) if (!(x)) {wxFAIL_MSG(msg); op; } +#define wxCHECK2(cond, op) wxCHECK2_MSG(cond, op, (const char*)NULL) // special form of wxCHECK2: as wxCHECK, but for use in void functions // @@ -160,13 +370,14 @@ WXDLLEXPORT_DATA(extern const bool) wxFalse; // there is no other way to tell the caller what exactly went wrong // from the void function (of course, the function shouldn't be void // to begin with...) -#define wxCHECK_RET(x, msg) if (!(x)) {wxFAIL_MSG(msg); return; } +#define wxCHECK_RET(cond, msg) wxCHECK2_MSG(cond, return, msg) + // ---------------------------------------------------------------------------- // Compile time asserts // // Unlike the normal assert and related macros above which are checked during -// the program tun-time the macros below will result in a compilation error if +// the program run-time the macros below will result in a compilation error if // the condition they check is false. This is usually used to check the // expressions containing sizeof()s which cannot be tested with the // preprocessor. If you can use the #if's, do use them as you can give a more @@ -181,19 +392,9 @@ WXDLLEXPORT_DATA(extern const bool) wxFalse; particular, this is why we define a struct and not an object (which would result in a warning about unused variable) and a named struct (otherwise we'd get a warning about an unnamed struct not used to define an object!). - The _n__ part is to stop VC++ 7 being confused since it encloses __LINE++ in - parentheses. Unfortunately this does not work with MetroWerks CW so this fix - is being limited to VC++. */ -#define wxMAKE_ASSERT_NAME_HELPER(line) wxAssert_ ## line -#define wxMAKE_ASSERT_NAME(line) wxMAKE_ASSERT_NAME_HELPER(line) -#ifdef __VISUALC__ -#define wxMAKE_UNIQUE_ASSERT_NAME wxMAKE_ASSERT_NAME(_n___ ## __LINE__) -#else -#define wxMAKE_UNIQUE_ASSERT_NAME wxMAKE_ASSERT_NAME(__LINE__) -#endif -#define wxMAKE_UNIQUE_ASSERT_NAME2(text) wxMAKE_ASSERT_NAME(text) +#define wxMAKE_UNIQUE_ASSERT_NAME wxMAKE_UNIQUE_NAME(wxAssert_) /* The second argument of this macro must be a valid C++ identifier and not a @@ -203,8 +404,42 @@ WXDLLEXPORT_DATA(extern const bool) wxFalse; It may be used both within a function and in the global scope. */ -#define wxCOMPILE_TIME_ASSERT(expr, msg) \ - struct wxMAKE_UNIQUE_ASSERT_NAME { unsigned int msg: expr; } +#if defined(__WATCOMC__) + /* avoid "unused symbol" warning */ + #define wxCOMPILE_TIME_ASSERT(expr, msg) \ + class wxMAKE_UNIQUE_ASSERT_NAME { \ + unsigned int msg: expr; \ + wxMAKE_UNIQUE_ASSERT_NAME() { wxUnusedVar(msg); } \ + } +#elif defined( __VMS ) +namespace wxdebug{ + +// HP aCC cannot deal with missing names for template value parameters +template struct STATIC_ASSERTION_FAILURE; + +template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; + +// HP aCC cannot deal with missing names for template value parameters +template struct static_assert_test{}; + +} + #define WX_JOIN( X, Y ) X##Y + #define WX_STATIC_ASSERT_BOOL_CAST(x) (bool)(x) + #define wxCOMPILE_TIME_ASSERT(expr, msg) \ + typedef ::wxdebug::static_assert_test<\ + sizeof(::wxdebug::STATIC_ASSERTION_FAILURE< WX_STATIC_ASSERT_BOOL_CAST( expr ) >)>\ + WX_JOIN(wx_static_assert_typedef_, __LINE__) +#else + #define wxCOMPILE_TIME_ASSERT(expr, msg) \ + struct wxMAKE_UNIQUE_ASSERT_NAME { unsigned int msg: expr; } +#endif + +/* + When using VC++ 6 with "Edit and Continue" on, the compiler completely + mishandles __LINE__ and so wxCOMPILE_TIME_ASSERT() doesn't work, provide a + way to make "unique" assert names by specifying a unique prefix explicitly + */ +#define wxMAKE_UNIQUE_ASSERT_NAME2(text) wxCONCAT(wxAssert_, text) #define wxCOMPILE_TIME_ASSERT2(expr, msg, text) \ struct wxMAKE_UNIQUE_ASSERT_NAME2(text) { unsigned int msg: expr; } @@ -218,5 +453,44 @@ WXDLLEXPORT_DATA(extern const bool) wxFalse; wxCOMPILE_TIME_ASSERT(sizeof(type) * CHAR_BIT >= size, \ wxMAKE_BITSIZE_MSG(type, size)) -#endif // _WX_DEBUG_H_ +// ---------------------------------------------------------------------------- +// other miscellaneous debugger-related functions +// ---------------------------------------------------------------------------- + +/* + Return true if we're running under debugger. + + Currently only really works under Win32 and just returns false elsewhere. + */ +#if defined(__WIN32__) + extern bool WXDLLIMPEXP_BASE wxIsDebuggerRunning(); +#else // !Mac + inline bool wxIsDebuggerRunning() { return false; } +#endif // Mac/!Mac + +// An assert helper used to avoid warning when testing constant expressions, +// i.e. wxASSERT( sizeof(int) == 4 ) can generate a compiler warning about +// expression being always true, but not using +// wxASSERT( wxAssertIsEqual(sizeof(int), 4) ) +// +// NB: this is made obsolete by wxCOMPILE_TIME_ASSERT() and should no +// longer be used. +extern bool WXDLLIMPEXP_BASE wxAssertIsEqual(int x, int y); + +// Use of wxFalse instead of false suppresses compiler warnings about testing +// constant expression +extern WXDLLIMPEXP_DATA_BASE(const bool) wxFalse; + +#define wxAssertFailure wxFalse + +// This is similar to WXUNUSED() and useful for parameters which are only used +// in assertions. +#if wxDEBUG_LEVEL + #define WXUNUSED_UNLESS_DEBUG(param) param +#else + #define WXUNUSED_UNLESS_DEBUG(param) WXUNUSED(param) +#endif + + +#endif // _WX_DEBUG_H_