Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/src/catch2
diff options
context:
space:
mode:
authorMartin Hořeňovský2023-05-15 14:33:24 +0200
committerMartin Hořeňovský2023-05-29 21:45:28 +0200
commitbf5aa7b383b143ba9939fad289d1f7a41f07f8cd (patch)
tree9633cdce4da112807f21ee644707315029b31373 /src/catch2
parentdba9197ec71ed64c6f08c7ce73f1af5bc3331f3c (diff)
downloadcatch3-bf5aa7b383b143ba9939fad289d1f7a41f07f8cd.tar.gz
Experimental static analysis support in TEST_CASE and SECTION
Closes #2681
Diffstat (limited to 'src/catch2')
-rw-r--r--src/catch2/internal/catch_section.hpp69
-rw-r--r--src/catch2/internal/catch_test_registry.hpp67
2 files changed, 112 insertions, 24 deletions
diff --git a/src/catch2/internal/catch_section.hpp b/src/catch2/internal/catch_section.hpp
index 8c1a882b..bd92bdf4 100644
--- a/src/catch2/internal/catch_section.hpp
+++ b/src/catch2/internal/catch_section.hpp
@@ -9,6 +9,7 @@
#define CATCH_SECTION_HPP_INCLUDED
#include <catch2/internal/catch_compiler_capabilities.hpp>
+#include <catch2/internal/catch_config_static_analysis_support.hpp>
#include <catch2/internal/catch_noncopyable.hpp>
#include <catch2/catch_section_info.hpp>
#include <catch2/catch_timer.hpp>
@@ -38,16 +39,62 @@ namespace Catch {
} // end namespace Catch
-#define INTERNAL_CATCH_SECTION( ... ) \
- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
- if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
-
-#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
- if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \
- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+#if !defined(CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT)
+# define INTERNAL_CATCH_SECTION( ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ if ( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( \
+ catch_internal_Section ) = \
+ Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+# define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ if ( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( \
+ catch_internal_Section ) = \
+ Catch::SectionInfo( \
+ CATCH_INTERNAL_LINEINFO, \
+ ( Catch::ReusableStringStream() << __VA_ARGS__ ) \
+ .str() ) ) \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+#else
+
+// These section definitions imply that at most one section at one level
+// will be intered (because only one section's __LINE__ can be equal to
+// the dummy `catchInternalSectionHint` variable from `TEST_CASE`).
+
+namespace Catch {
+ namespace Detail {
+ // Intentionally without linkage, as it should only be used as a dummy
+ // symbol for static analysis.
+ int GetNewSectionHint();
+ } // namespace Detail
+} // namespace Catch
+
+
+# define INTERNAL_CATCH_SECTION( ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
+ if ( [[maybe_unused]] int catchInternalPreviousSectionHint = \
+ catchInternalSectionHint, \
+ catchInternalSectionHint = Catch::Detail::GetNewSectionHint(); \
+ catchInternalPreviousSectionHint == __LINE__ ) \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+# define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
+ if ( [[maybe_unused]] int catchInternalPreviousSectionHint = \
+ catchInternalSectionHint, \
+ catchInternalSectionHint = Catch::Detail::GetNewSectionHint(); \
+ catchInternalPreviousSectionHint == __LINE__ ) \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+#endif
+
#endif // CATCH_SECTION_HPP_INCLUDED
diff --git a/src/catch2/internal/catch_test_registry.hpp b/src/catch2/internal/catch_test_registry.hpp
index 5cb73067..d248d3cf 100644
--- a/src/catch2/internal/catch_test_registry.hpp
+++ b/src/catch2/internal/catch_test_registry.hpp
@@ -8,6 +8,7 @@
#ifndef CATCH_TEST_REGISTRY_HPP_INCLUDED
#define CATCH_TEST_REGISTRY_HPP_INCLUDED
+#include <catch2/internal/catch_config_static_analysis_support.hpp>
#include <catch2/internal/catch_source_line_info.hpp>
#include <catch2/internal/catch_noncopyable.hpp>
#include <catch2/interfaces/catch_interfaces_test_invoker.hpp>
@@ -72,6 +73,9 @@ struct AutoReg : Detail::NonCopyable {
void TestName::test()
#endif
+
+#if !defined(CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT)
+
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
static void TestName(); \
@@ -84,19 +88,40 @@ struct AutoReg : Detail::NonCopyable {
#define INTERNAL_CATCH_TESTCASE( ... ) \
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__ )
- ///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
- namespace { \
- const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
- Catch::makeTestInvoker( &QualifiedMethod ), \
- CATCH_INTERNAL_LINEINFO, \
- "&" #QualifiedMethod##_catch_sr, \
- Catch::NameAndTags{ __VA_ARGS__ } ); \
- } /* NOLINT */ \
- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+#else // ^^ !CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT | vv CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
+
+
+// Dummy registrator for the dumy test case macros
+namespace Catch {
+ namespace Detail {
+ struct DummyUse {
+ DummyUse( void ( * )( int ) );
+ };
+ } // namespace Detail
+} // namespace Catch
+
+// Note that both the presence of the argument and its exact name are
+// necessary for the section support.
+
+// We provide a shadowed variable so that a `SECTION` inside non-`TEST_CASE`
+// tests can compile. The redefined `TEST_CASE` shadows this with param.
+static int catchInternalSectionHint = 0;
+
+# define INTERNAL_CATCH_TESTCASE2( fname ) \
+ static void fname( int ); \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ static const Catch::Detail::DummyUse INTERNAL_CATCH_UNIQUE_NAME( \
+ dummyUser )( &fname ); \
+ CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
+ static void fname( [[maybe_unused]] int catchInternalSectionHint ) \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+# define INTERNAL_CATCH_TESTCASE( ... ) \
+ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( dummyFunction ) )
+
+
+#endif // CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
@@ -118,6 +143,22 @@ struct AutoReg : Detail::NonCopyable {
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), ClassName, __VA_ARGS__ )
+
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ namespace { \
+ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
+ Catch::makeTestInvoker( &QualifiedMethod ), \
+ CATCH_INTERNAL_LINEINFO, \
+ "&" #QualifiedMethod##_catch_sr, \
+ Catch::NameAndTags{ __VA_ARGS__ } ); \
+ } /* NOLINT */ \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
do { \