Prevent clang tidy to report warnings on Boost Test headers - c++

Note December 2022: it seems that this problem is solved in clang-tidy 14. Just by experimentation I can reproduce the problem with clang-tidy 11, 12 and 13 but not with 14.
I have a Cmake project that uses Boost.UnitTest for testing.
When I do static analysis with clang-tidy it reports some warnings from the Boost.UnitTest headers. I would like to filter those.
As an example (disregard detaisl)
/usr/include/boost/test/tools/old/interface.hpp:84:45: note: expanded from macro 'BOOST_REQUIRE'
#define BOOST_REQUIRE( P ) BOOST_TEST_TOOL_IMPL( 2, \
^
/usr/include/boost/test/tools/old/interface.hpp:65:5: note: expanded from macro 'BOOST_TEST_TOOL_IMPL'
BOOST_TEST_PASSPOINT(); \
^
/usr/include/boost/test/unit_test_log.hpp:261:5: note: expanded from macro 'BOOST_TEST_PASSPOINT'
::boost::unit_test::unit_test_log.set_checkpoint( \
^
/usr/include/boost/test/unit_test_log.hpp:209:82: note: default parameter was declared here
void set_checkpoint( const_string file, std::size_t line_num, const_string msg = const_string() );
^
/home/user/prj/alf/boost/multi/test/zero_dimensionality.cpp:23:3: error: calling a function that uses a default argument is disallowed [fuchsia-default-arguments-calls,-warnings-as-errors]
BOOST_REQUIRE( num_elements(m1) == 3 );
So far, I add the dependency on Boost.UnitTest with these lines
target_link_libraries(${TEST_EXE} PRIVATE Boost::unit_test_framework Boost::serialization)
I tried with this, to make Boost.UnitTest a "system" library but I still get the same warnings
target_include_directories(${TEST_EXE} SYSTEM PRIVATE ${Boost_INCLUDE_DIRS})
target_link_libraries(${TEST_EXE} PRIVATE ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
target_link_libraries(${TEST_EXE} PRIVATE ${Boost_SERIALIZATION_LIBRARY})
but I still get the same results.
How can I prevent clang-tidy to check or report errors in the Boost headers?
(I accept answers changing the configuration of clang-tidy itself (I used a .clang-tidy configuration file); although it seems more elegant to change CMakeLists.txt instead.)
ADDED NOTE:
Following one of the recommendations in the comments I disabled these warnings that were "incompatible" with Boost.Test.
I would still prefer to leave them on and make clang-tidy filter somehow the headers of Boost.Test:
# -altera-unroll-loops, // BOOST_REQUIRE macro requires this
# -cert-err58-cpp, // BOOST_AUTO_TEST_CASE macro requires this
# -cppcoreguidelines-avoid-non-const-global-variables, // BOOST_AUTO_TEST_CASE macros require this
# -cppcoreguidelines-macro-usage, // BOOST_TEST_MODULE macro requires this
# -cppcoreguidelines-pro-type-vararg, // BOOST_REQUIRE macros require this
# -fuchsia-default-arguments-declarations // BOOST_AUTO_TEST_CASE_TEMPLATE
# -fuchsia-default-arguments-calls, // BOOST_REQUIRE macros require this
# -fuchsia-statically-constructed-objects, // BOOST_AUTO_TEST_CASE creates these
# -hicpp-vararg, // all BOOST_TEST_REQUIRE macros require this

Okay, I't not entirely clear (to me) from this:
I do CXX=clang++ cmake .. -DCMAKE_CXX_CLANG_TIDY="clang-tidy" (plus a configuration file for clang-tidy)
how or when clang-tidy is actually invoked. Apparently that uses some CMake magic I'm not familiar with. I do remember once seeing such a thing, and there were reasons why I didn't end up using it.
Instead, I use CMAKE_EXPORT_COMPILE_COMMANDS=On (very handy for all tooling based on libclang and then some, like IDEs and LSP servers). Having the compile_commands.json makes it so you can invoke the run-clang-tidy tool with -p pointing to it.
In my experience it does filter system includes as it ought to (and it gives a count of diagnostics suppressed in verbose modes).

If you use macros from a library which incur clang-tidy warnings, I don't think there's a good way to avoid it today. Even if you include the library as a system library (e.g., via -isystem) my understanding is the warnings will still trigger because the macro is used in your code, even if it is declared in the library.
Here's a proposal to fix it, unfortunately it seems stalled since 2021.

Solution: use clang-tidy 14 or newer.

Related

ClangTidy + CMake - ignore third party headers from Conan

I am trying to use ClangTidy on some working source code but I cannot get it to ignore / bypass lib{fmt} and see lots of noise such as:
~/.conan/data/fmt/9.1.0///package/2c09c8f84c016041549fcee94e4caae5d89424b6/
include/fmt/core.h:2955:15: warning: 5 uninitialized fields at the end of
the constructor call [clang-analyzer-optin.cplusplus.UninitializedObject]
types_{
^
~/.conan/data/fmt/9.1.0///package/2c09c8f84c016041549fcee94e4caae5d89424b6/
include/fmt/core.h:732:7: note: uninitialized field
'this->context_.num_args_'
int num_args_;
^~~~~~~~~
I am using CMake + Conan and the diagnostic messages I have come from lib{fmt}.
How can I silence them? For CppCheck it was simply a case of specifying that all files under ~/.conan/ should be ignored.
How do I tell Clang-tidy to ignore all files under ~/.conan/
Note I have seen clang-tidy - ignore third party headers code which does not answer my question

How can I make compiler version specific ifdef?

I've got the problem that my program will compile with g++10.2 and c++11 activated through cmake. but it will not compile with arduino dues arm-none-eabi-g++.exe compiler which also has c++11. The failure occurs because of one line that needs to be added for the arm compiler, but when I add that line to g++10.2 it won't compile.
So I need an #ifdef or some alternative to activate and deactivate the line specific for the compiler.
Like Deumaudit said in the comments:
Try to use __arm__, __aarch64__ or __ARM_ARCH macro
You'll probably be ok if you use #ifdef __arm__ or even #if defined(__arm__) || defined(__aarch64__)
If you're planning to add more supported platforms to your program, it might be a good idea to define some macros when building for a specific platform. I have my own _MY_APP_ARM macro defined in my CMakeLists.txt:
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm")
add_definitions(-D_MY_APP_ARM)
endif()
Which I can then use as #ifdef _MY_APP_ARM

How to enable _LIBCPP_DEBUG_LEVEL>=2 in xcode

When reading the std library implementation I could see lots of checks enabled by #if _LIBCPP_DEBUG_LEVEL >= 2 conditions. I tried to add _LIBCPP_DEBUG_LEVEL = 3 in xcode preprocessor options, but <iterator> doesn't compile anymore:
#if _LIBCPP_DEBUG_LEVEL >= 2
__get_db()->__insert_i(this); <----- the error is on this line
#endif
Is there something else I'm missing here to use a higher debug level for the standard library?
According to the libc++ documentation:
Debug mode is currently not functional. Defining _LIBCPP_DEBUG will result in fairly nasty compile errors.
So that is probably the source of that.
Baum mit Augen's answer that _LIBCPP_DEBUG_LEVEL >= 2 standard library code for lower level iterator debugging is basically unusable, appears to still be the case with the out-of-the-box Xcode 11.6. But if you're up for extra work or just want more specifics, read on...
Enabling _LIBCPP_DEBUG_LEVEL code is enabling LLVM's Debug Mode. According to that documentation, enabling this debug mode is done by defining the _LIBCPP_DEBUG to a value of 0 (that "enables most of libc++’s assertions") or 1 (that "enables 'iterator debugging' which provides additional assertions about the validity of iterators used by the program").
In XCode 11.6, I've found that adding _LIBCPP_DEBUG=0 to a project's Debug Preprocessor Macros setting, compiles and links and indeed adds additional checks - at least checking against out of range references to std::vector elements via its [] operator. Enabling the _LIBCPP_DEBUG_LEVEL >= 2 code is done by instead setting _LIBCPP_DEBUG=1. That alone however won't fully link as not all the necessary symbols are found. Specifically, the std::__1::__libcpp_db::__insert_c(void*, std::__1::__c_node* (*)(void*, void*, std::__1::__c_node*)) symbol is reported as undefined and maybe others as well. Presumably, XCode 11.6 did not ship with this built into the standard C++ library it provides. If anybody knows better or could corroborate this, I'd appreciate hearing from them.
With the following extra work, I've been able to enable libc++'s assertions plus the additional iterator debugging capabilities:
Install a recent LLVM package somewhere that doesn't interfere with Xcode's included LLVM package. I installed LLVM 10.0.1 using Homebrew and I was able to access it then under /usr/local/Cellar/llvm/10.0.1.
Have Xcode recognize the Xcode tool chain support that this new LLVM package provides. I added a symbolic link to /usr/local/Cellar/llvm/10.0.1/Toolchains/LLVM10.0.1.xctoolchain into Xcode's /Applications/Xcode.app/Contents/Developer/Toolchains directory. I'd done that while Xcode was running and it immediately saw the new tool chain but I had to restart Xcode to get it to compile with it.
Under Xcode's "Xcode" -> "Toolchains" submenu, select the new tool chain. My setup showed "Xcode 11.7" and "org.llvm.10.0.1" and I selected the latter to accomplish this.
Add the path to the new tool chain's usr/lib directory to the LIBRARY_SEARCH_PATHS declaration for resulting executable Targets. I did this by adding /usr/local/Cellar/llvm/10.0.1/Toolchains/LLVM10.0.1.xctoolchain/usr/lib to a project's executable target "Library Search Paths" "Debug" setting.
Have the path to the new tool chain's include directory override the normal standard library's include directory. I haven't confirmed that this is necessary but did this by adding to my library and executable targets' OTHER_CPLUSPLUSFLAGS declaration the value of -nostdinc++ -I/usr/local/Cellar/llvm/10.0.1/Toolchains/LLVM10.0.1.xctoolchain/usr/include/c++/v1. From within Xcode, I'd achieved that by setting the "Other C++ Flags" setting to include this value for the targets of interest. I suspect it's probably safer to make this change at the project level than target level.
Set the COMPILER_INDEX_STORE_ENABLE declaration to NO. This prevented "Unknown argument: '-index-store-path'" errors that stopped builds right from the beginning. I used Xcode's "Enable Index-While-Building Functionality" setting and set it to "No" for this.
Add _LIBCPP_DEBUG=1 to the GCC_PREPROCESSOR_DEFINITIONS declaration for the project. Did this by adding it to Xcode's "Preprocessor Macros" "Debug" setting.
For related Q&A about this, see Is it possible to enable _LIBCPP_DEBUG2 in the current Xcode 4.6.1 toolchain on Mountain Lion?.

error messages in BOOST's has_binary_operator.hpp on OSX 10.9 Xcode6

So, I built boost with the following script conveniently posted by toma
and it compiles and I can add the respective frameworks in Xcode6 to my iOS target and my OSX target.
It runs properly on iOS, but when I try compiling on OSX I get errors in has_binary_operator.hpp in the following lines:
template < typename Lhs, typename Rhs >
struct operator_exists {
static ::boost::type_traits::yes_type check(has_operator); // this version is preferred when operator exists
static ::boost::type_traits::no_type check(no_operator); // this version is used otherwise
BOOST_STATIC_CONSTANT(bool, value = (sizeof(check(((make<Lhs>() BOOST_TT_TRAIT_OP make<Rhs>()),make<has_operator>())))==sizeof(::boost::type_traits::yes_type)));
};
Error messages:
.../boost.framework/Headers/type_traits/detail/has_binary_operator.hpp:155:42: Expected member name or ';' after declaration specifiers
.../boost.framework/Headers/type_traits/detail/has_binary_operator.hpp:156:41: Expected member name or ';' after declaration specifiers
Screenshot:
PS: My stdlib is libc++ and I want to use C++11 and Clang in both iOS and MacOSX. I mean it works perfectly for iOS, so why is it not working with the MacOSX target?!?
Quickfix:
Undefining 'check' seems to solve the error, as this seems to be a keyword reserved on MacOSX. Still it seems a weird solution to just undefine an OSX keyword, wouldn't this cause problems later?
#undef check
#include <boost/multi_array.hpp>
check is not a keyword, but an unfortunately named macro in a file supplied by Apple.
This has been an ongoing problem for boost (and other library vendors) for many years.
The header file <AssertMacros.h> is where this macros is defined.
See https://svn.boost.org/trac/boost/ticket/2115 for some history on this.
The latest version of this file (that Apple ships with the 10.9 SDK) contains the following text:
Prior to Mac OS X 10.6 the macro names used in this file conflicted with some
user code, including libraries in boost and the proposed C++ standards efforts,
and there was no way for a client of this header to resolve this conflict. Because
of this, most of the macros have been changed so that they are prefixed with
__ and contain at least one capital letter, which should alleviate the current
and future conflicts. However, to allow current sources to continue to compile,
compatibility macros are defined at the end with the old names. A tops script
at the end of this file will convert all of the old macro names used in a directory
to the new names. Clients are recommended to migrate over to these new macros as
they update their sources because a future release of Mac OS X will remove the
old macro definitions ( without the double-underscore prefix ). Clients who
want to compile without the old macro definitions can define the macro
__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES to 0 before this file is
included.
So, you could add -D__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES=0 to your build commands to fix this problem.
Alternately, you could get a newer version of boost, where those calls have been renamed from check to s_check.

Error "token is not a valid binary operator in a preprocessor subexpression"

if I build and run a project, basically a stub generated by the Qt framework on Mac OS 10.6, I get this error output:
/Users/home/Qt5.0.1/5.0.1/clang_64/include/QtCore/qisenum.h:53: Error:token is not a valid binary operator in a preprocessor subexpression
# if __has_extension(is_enum)
~~~~~~~~~~~~~~~^
I can´t find a solution to this, although I read that other Mac users seem to have the same problem. Anyone knows how to solve this?
I have found the solution. Just copy the latest qisenum.h file from here and replace it in clang_64/include/QtCore folder in your Qt creator installation, it will work fine.
This issue is resolved in this forum post.
It is basically an issue with your version of clang
# if __has_extension(is_enum)
~~~~~~~~~~~~~~~^
That's a Clang language extension called feature checking macros. They've been around a long time for Clang. GCC provided them starting at GCC 5.0, IIRC.
__has_extension can be tested as a preprocessor macro. So you test for the presence of the macro first, and then you test for the feature:
#if defined(__has_extension)
# if __has_extension(is_enum)
...
# endif
#endif
__has_extension(is_enum) must be on a separate line.
It works for include files, too. From the Crypto++ project an rdrand.cpp file:
# include <immintrin.h> // rdrand, MSC, ICC, and GCC
# if defined(__has_include)
# if __has_include(<x86intrin.h>)
# include <x86intrin.h> // rdseed for some compilers, like GCC
# endif
# endif
In my case the reason of the same error was that Preprocessor macro name in Target Build Settings contained hyphen sign '-', something like that TEST-DEBUG=1.
Xcode build configuration names with hyphens ('-') cause pods build failures
My case is:
#define USE_LIBICONV 1 # xxxxxx
Error
Token is not a valid binary operator in a preprocessor subexpression
Solution:
remove typo comments after #define
=> change # to //
#define USE_LIBICONV 1 // xxxxxx
then can use macro normally:
#if USE_LIBICONV
...
#endif