SonarQube:
- Developer Edition
- Version 9.2.4 (build 50792)
We are using googletest, which has a feature where you can use the macro SCOPED_TRACE
to add a trace to the output from a test if any test checks fail in the same scope.
Building on that, we have written this macro
//Use this to see line numbers of calling code when calling a subroutine with
// assert/expect statements
#define SCOPE_TRACE(statement) \
do { \
SCOPED_TRACE("in " #statement); \
statement; \
} while (false)
Which can be used like this from the top level test scope:
SCOPE_TRACE(someFunctionThatDoesSomeChecks());
SCOPE_TRACE(anotherFunctionThatDoesSomeChecks());
Which will make it so that if any check inside either of those functions fail, then the test report will document in which function call the failure(s) happened. An element that is probably relevant to the discussion, these functions return void
, which means this is definitively not a function macro in the sense of being a pure function.
Also, the implementation of SCOPED_TRACE
looks like this
#define SCOPED_TRACE(message) \
::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\
__FILE__, __LINE__, (message))
Now the point is that this define is triggering “Function-like macros should not be used” (cpp:S960).
My understanding is that this macro can’t be rewritten as a C++ function, constexpr
or otherwise, because the entire purpose of this macro is to wrap a call to a function while reporting both the line number and doing a textual replacement of the line. Even with the existence of std::source_location
from C++20, I don’t think this can be rewritten.
Considering that the underlying macro from googletest is using the magic “LINE” and “FILE” macros internally, this is also speaking in favor of not being able to rewrite the wrapping macro as a function.
Also, I suspect that this rule is triggered in general for all macro definitions, while the references at the bottom of the issue description only suggest that macros should be avoided as constants and “functions”. I guess this wording is indicating that it is possible to write macros that aren’t considered either constants or functions. I would argue that the example I’ve provided falls outside of the definition of a function-like macro, because it’s using features that can’t be implemented with functions.
I guess a function macro would be one that evaluates to an expression. Unless there’s some esoteric grammatical property of C++ I’m not aware of, a do-while loop is not an expression syntactically.