diff --git a/src/catch2/internal/catch_result_type.hpp b/src/catch2/internal/catch_result_type.hpp index 69a6ef1413..2ae7dcebc3 100644 --- a/src/catch2/internal/catch_result_type.hpp +++ b/src/catch2/internal/catch_result_type.hpp @@ -57,6 +57,9 @@ namespace Catch { constexpr bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + constexpr bool shouldTerminateOnFailure( int flags ) { + return ( flags & ResultDisposition::Normal ) != 0; + } constexpr bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } diff --git a/src/catch2/internal/catch_test_macro_impl.hpp b/src/catch2/internal/catch_test_macro_impl.hpp index f38ec6066c..fafd5be36f 100644 --- a/src/catch2/internal/catch_test_macro_impl.hpp +++ b/src/catch2/internal/catch_test_macro_impl.hpp @@ -10,9 +10,12 @@ #include #include +#include #include +#include #include #include +#include namespace Catch { namespace Detail { @@ -44,6 +47,8 @@ namespace Catch { #endif +#if !defined( CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) + /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ do { /* NOLINT(bugprone-infinite-loop) */ \ @@ -60,6 +65,25 @@ namespace Catch { } while( (void)0, (false) && static_cast( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. +#else // ^^ !CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT | vv CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT + +/////////////////////////////////////////////////////////////////////////////// +# define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ + do { \ + const bool catchInternalAssertionResult = static_cast( __VA_ARGS__ ); \ + if ( Catch::shouldTerminateOnFailure( resultDisposition ) ) { \ + if ( Catch::isFalseTest( resultDisposition ) ) { \ + if ( catchInternalAssertionResult ) { Catch::Detail::Unreachable(); } \ + } else { \ + if ( !catchInternalAssertionResult ) { Catch::Detail::Unreachable(); } \ + } \ + } \ + } while ( false ) + +#endif // CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT + +#if !defined( CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) + /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ @@ -70,6 +94,20 @@ namespace Catch { INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ if( !Catch::Detail::lastAssertionPassed() ) +#else // ^^ !CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT | vv CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT + +/////////////////////////////////////////////////////////////////////////////// +# define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ + if ( __VA_ARGS__ ) + +/////////////////////////////////////////////////////////////////////////////// +# define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ + if ( !( __VA_ARGS__ ) ) + +#endif // CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT + +#if !defined( CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) + /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ do { \ @@ -87,6 +125,27 @@ namespace Catch { catchAssertionHandler.complete(); \ } while( false ) +#else // ^^ !CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT | vv CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT + +/////////////////////////////////////////////////////////////////////////////// +# define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ + do { \ + try { \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ + static_cast(__VA_ARGS__); \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + } catch ( ... ) { \ + if ( Catch::shouldTerminateOnFailure( resultDisposition ) ) { \ + Catch::Detail::Unreachable(); \ + } \ + } \ + } while ( false ) + +#endif // CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT + +#if !defined( CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) + /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ do { \ @@ -108,6 +167,31 @@ namespace Catch { catchAssertionHandler.complete(); \ } while( false ) +#else // ^^ !CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT | vv CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT + +/////////////////////////////////////////////////////////////////////////////// +# define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ + do { \ + bool catchInternalThrew = false; \ + try { \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \ + CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ + static_cast(__VA_ARGS__); \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + } catch ( ... ) { \ + catchInternalThrew = true; \ + } \ + if ( !catchInternalThrew && \ + Catch::shouldTerminateOnFailure( resultDisposition ) ) { \ + Catch::Detail::Unreachable(); \ + } \ + } while ( false ) + +#endif // CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT + +#if !defined( CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) + /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ do { \ @@ -132,6 +216,30 @@ namespace Catch { catchAssertionHandler.complete(); \ } while( false ) +#else // ^^ !CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT | vv CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT + +/////////////////////////////////////////////////////////////////////////////// +# define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ + do { \ + bool catchInternalCaughtExpected = false; \ + try { \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \ + CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ + static_cast(expr); \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + } catch ( exceptionType const& ) { \ + catchInternalCaughtExpected = true; \ + } catch ( ... ) { \ + } \ + if ( !catchInternalCaughtExpected && \ + Catch::shouldTerminateOnFailure( resultDisposition ) ) { \ + Catch::Detail::Unreachable(); \ + } \ + } while ( false ) + +#endif // CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT + ///////////////////////////////////////////////////////////////////////////////