diff --git a/include/wx/log.h b/include/wx/log.h index 514dc84b6b..a5973762d9 100644 --- a/include/wx/log.h +++ b/include/wx/log.h @@ -1241,11 +1241,14 @@ WXDLLIMPEXP_BASE wxString wxSysErrorMsgStr(unsigned long nErrCode = 0); // this macro generates the expression which logs whatever follows it in // parentheses at the level specified as argument -#define wxDO_LOG(level) wxMAKE_LOGGER(level).Log +#define wxDO_LOG_WITH_FUNC(level, func) wxMAKE_LOGGER(level).func +#define wxDO_LOG(level) wxDO_LOG_WITH_FUNC(level, Log) // this is the non-vararg equivalent #define wxDO_LOGV(level, format, argptr) \ wxMAKE_LOGGER(level).LogV(format, argptr) +#define wxDO_LOGV_WITH_FUNC(level, format, argptr, func) \ + wxMAKE_LOGGER(level).func(format, argptr) // this macro declares wxLog() macro which logs whatever follows it if // logging at specified level is enabled (notice that if it is false, the @@ -1264,14 +1267,51 @@ WXDLLIMPEXP_BASE wxString wxSysErrorMsgStr(unsigned long nErrCode = 0); // // See also #11829 for the problems with other simpler approaches, // notably the need for two macros due to buggy __LINE__ in MSVC. -#define wxDO_LOG_IF_ENABLED_HELPER(level, loopvar) \ +#define wxDO_LOG_IF_ENABLED_HELPER(level, loopvar, extraCond, func) \ for ( bool loopvar = false; \ - !loopvar && wxLog::IsLevelEnabled(wxLOG_##level, wxLOG_COMPONENT); \ + !loopvar && wxLog::IsLevelEnabled(wxLOG_##level, wxLOG_COMPONENT) &&\ + extraCond ; \ loopvar = true ) \ - wxDO_LOG(level) + wxDO_LOG_WITH_FUNC(level, func) + +#define wxDO_LOGV_IF_ENABLED_HELPER(level, format, argptr, loopvar, extraCond)\ + for ( bool loopvar = false; \ + !loopvar && wxLog::IsLevelEnabled(wxLOG_##level, wxLOG_COMPONENT) &&\ + extraCond ; \ + loopvar = true ) \ + wxDO_LOGV(level, format, argptr) + +#define wxDO_LOGV_IF_ENABLED_HELPER_WITH_FUNC(level, format, argptr, loopvar, \ + extraCond, func) \ + for ( bool loopvar = false; \ + !loopvar && wxLog::IsLevelEnabled(wxLOG_##level, wxLOG_COMPONENT) &&\ + extraCond ; \ + loopvar = true ) \ + wxDO_LOGV_WITH_FUNC(level, format, argptr, func) + +#define wxDO_LOG_IF_ENABLED_WITH_FUNC(level, func) \ + wxDO_LOG_IF_ENABLED_HELPER(level, wxMAKE_UNIQUE_NAME(wxlogcheck), true, \ + func) #define wxDO_LOG_IF_ENABLED(level) \ - wxDO_LOG_IF_ENABLED_HELPER(level, wxMAKE_UNIQUE_NAME(wxlogcheck)) + wxDO_LOG_IF_ENABLED_HELPER(level, wxMAKE_UNIQUE_NAME(wxlogcheck), true, \ + Log) + +#define wxDO_LOGV_IF_ENABLED_WITH_FUNC(level, func) \ + wxDO_LOGV_IF_ENABLED_HELPER_WITH_FUNC(level, \ + wxMAKE_UNIQUE_NAME(wxlogcheck), true, func) + +#define wxDO_LOGV_IF_ENABLED(level, format, argptr) \ + wxDO_LOGV_IF_ENABLED_HELPER_WITH_FUNC(level, format, argptr, \ + wxMAKE_UNIQUE_NAME(wxlogcheck), true, LogV) + +#define wxDO_LOG_IF_ENABLED_WITH_COND(level, extraCond) \ + wxDO_LOG_IF_ENABLED_HELPER(level, wxMAKE_UNIQUE_NAME(wxlogcheck), \ + extraCond, Log) + +#define wxDO_LOGV_IF_ENABLED_WITH_COND(level, format, argptr, extraCond) \ + wxDO_LOGV_IF_ENABLED_HELPER(level, format, argptr, \ + wxMAKE_UNIQUE_NAME(wxlogcheck), extraCond) // wxLogFatalError() is special as it can't be disabled #define wxLogFatalError wxDO_LOG(FatalError) @@ -1291,18 +1331,9 @@ WXDLLIMPEXP_BASE wxString wxSysErrorMsgStr(unsigned long nErrCode = 0); // this one is special as it only logs if we're in verbose mode -#define wxLogVerbose \ - if ( !(wxLog::IsLevelEnabled(wxLOG_Info, wxLOG_COMPONENT) && \ - wxLog::GetVerbose()) ) \ - {} \ - else \ - wxDO_LOG(Info) +#define wxLogVerbose wxDO_LOG_IF_ENABLED_WITH_COND(Info, wxLog::GetVerbose()) #define wxVLogVerbose(format, argptr) \ - if ( !(wxLog::IsLevelEnabled(wxLOG_Info, wxLOG_COMPONENT) && \ - wxLog::GetVerbose()) ) \ - {} \ - else \ - wxDO_LOGV(Info, format, argptr) + wxDO_LOGV_IF_ENABLED_WITH_COND(Info, format, argptr, wxLog::GetVerbose()) // another special case: the level is passed as first argument of the function // and so is not available to the macro @@ -1311,10 +1342,7 @@ WXDLLIMPEXP_BASE wxString wxSysErrorMsgStr(unsigned long nErrCode = 0); // always evaluated, unlike for the other log functions #define wxLogGeneric wxMAKE_LOGGER(Max).LogAtLevel #define wxVLogGeneric(level, format, argptr) \ - if ( !wxLog::IsLevelEnabled(wxLOG_##level, wxLOG_COMPONENT) ) \ - {} \ - else \ - wxDO_LOGV(level, format, argptr) + wxDO_LOGV_IF_ENABLED(level, format, argptr) // wxLogSysError() needs to stash the error code value in the log record info @@ -1331,12 +1359,8 @@ WXDLLIMPEXP_BASE wxString wxSysErrorMsgStr(unsigned long nErrCode = 0); // change even much sooner) #define wxLOG_KEY_SYS_ERROR_CODE "wx.sys_error" -#define wxLogSysError \ - if ( !wxLog::IsLevelEnabled(wxLOG_Error, wxLOG_COMPONENT) ) \ - {} \ - else \ - wxMAKE_LOGGER(Error).MaybeStore(wxLOG_KEY_SYS_ERROR_CODE, \ - wxSysErrorCode()).Log +#define wxLogSysError wxDO_LOG_IF_ENABLED_WITH_FUNC(Error, \ + MaybeStore(wxLOG_KEY_SYS_ERROR_CODE, wxSysErrorCode()).Log) // unfortunately we can't have overloaded macros so we can't define versions // both with and without error code argument and have to rely on LogV() @@ -1350,11 +1374,8 @@ WXDLLIMPEXP_BASE wxString wxSysErrorMsgStr(unsigned long nErrCode = 0); // specify the frame to which the message should go #define wxLOG_KEY_FRAME "wx.frame" - #define wxLogStatus \ - if ( !wxLog::IsLevelEnabled(wxLOG_Status, wxLOG_COMPONENT) ) \ - {} \ - else \ - wxMAKE_LOGGER(Status).MaybeStore(wxLOG_KEY_FRAME).Log + #define wxLogStatus wxDO_LOG_IF_ENABLED_WITH_FUNC(Status, \ + MaybeStore(wxLOG_KEY_FRAME).Log) #define wxVLogStatus \ wxMAKE_LOGGER(Status).MaybeStore(wxLOG_KEY_FRAME).LogV @@ -1451,16 +1472,8 @@ public: #endif // wxUSE_LOG_DEBUG/!wxUSE_LOG_DEBUG #if wxUSE_LOG_TRACE - #define wxLogTrace \ - if ( !wxLog::IsLevelEnabled(wxLOG_Trace, wxLOG_COMPONENT) ) \ - {} \ - else \ - wxMAKE_LOGGER(Trace).LogTrace - #define wxVLogTrace \ - if ( !wxLog::IsLevelEnabled(wxLOG_Trace, wxLOG_COMPONENT) ) \ - {} \ - else \ - wxMAKE_LOGGER(Trace).LogVTrace + #define wxLogTrace wxDO_LOG_IF_ENABLED_WITH_FUNC(Trace, LogTrace) + #define wxVLogTrace wxDO_LOG_IF_ENABLED_WITH_FUNC(Trace, LogVTrace) #else // !wxUSE_LOG_TRACE #define wxVLogTrace(mask, fmt, valist) wxLogNop() diff --git a/tests/log/logtest.cpp b/tests/log/logtest.cpp index 5529fe1d40..c6f47c080b 100644 --- a/tests/log/logtest.cpp +++ b/tests/log/logtest.cpp @@ -394,4 +394,66 @@ void LogTestCase::NoWarnings() CPPUNIT_ASSERT_EQUAL( "If", m_log->GetLog(wxLOG_Error) ); } +// The following two functions (v, macroCompilabilityTest) are not run by +// any test, and their purpose is merely to guarantee that the wx(V)LogXXX +// macros compile without 'dangling else' warnings. +#pragma GCC diagnostic error "-Wdangling-else" + +static void v(int x, ...) { + va_list list; + va_start(list, x); + + if (true) + wxVLogGeneric(Info, "vhello generic %d", list); + if (true) + wxVLogTrace(wxTRACE_Messages, "vhello trace %d", list); + if (true) + wxVLogError("vhello error %d", list); + if (true) + wxVLogMessage("vhello message %d", list); + if (true) + wxVLogVerbose("vhello verbose %d", list); + if (true) + wxVLogWarning("vhello warning %d", list); + if (true) + wxVLogFatalError("vhello fatal %d", list); + if (true) + wxVLogSysError("vhello syserror %d", list); +#if wxUSE_GUI + if (true) + wxVLogStatus("vhello status %d", list); +#endif + if (true) + wxVLogDebug("vhello debug %d", list); + + va_end(list); +} + +void macroCompilabilityTest() +{ + v(123, 456); + if (true) + wxLogGeneric(wxLOG_Info, "hello generic %d", 42); + if (true) + wxLogTrace(wxTRACE_Messages, "hello trace %d", 42); + if (true) + wxLogError("hello error %d", 42); + if (true) + wxLogMessage("hello message %d", 42); + if (true) + wxLogVerbose("hello verbose %d", 42); + if (true) + wxLogWarning("hello warning %d", 42); + if (true) + wxLogFatalError("hello fatal %d", 42); + if (true) + wxLogSysError("hello syserror %d", 42); +#if wxUSE_GUI + if (true) + wxLogStatus("hello status %d", 42); +#endif + if (true) + wxLogDebug("hello debug %d", 42); +} + #endif // wxUSE_LOG