Add clang-tidy integration and fix all warnings (#659)
* Add clang-tidy job
* Install ninja
* Remove duplicate path
* Remove compiler specification??
* Remove linebreak
* Readd compiler specification
* Remove check specification
* Install clang-tidy
* Enable default checks
* Add .clang-tidy
* Start fixing tidy
* Require tidy >=14
* Bump Ubuntu version
* Bump clang-tidy invocation to 14
* Next set of fixes
* Fix set :D
* maybe this does the trick
* ??
* ????
* Surely this is it
* Close to just giving up
* Mark operator* with noexcept
* NOLINT
* Bump clang-tidy version
* Revert "Bump clang-tidy version"
This reverts commit 3173050e17359eacd62899f284128ec2e0b4f5db.
* More NOLINT test
* Does this do the trick?
* Else suppression
* More fixes!
* Specify error
* Root cause
* Readd at one location
* Cleanup and more fixes
* Huh!
* More eradication
* fuchsia
* More fuchsia
* More
* definitions-in-headers
* definitions-in-headers 2
* Does this do the trick?
* Sussy lambda cast
* Mem
* Try default move const
* Improve declaration
* A lot more fixes!
* -
* +
* *
* Getting somewhere
* Woo
* More
* Fix process
* Update main.yml
* Update main.yml
* Update main.yml
* Update main.yml
* Wrap up and add all CI
* Accomodate weird DLL bug?
* Update main.yml
* Test reintroduce error
* Finishing touches
* Final finishing touches
diff --git a/examples/all_features/CMakeLists.txt b/examples/all_features/CMakeLists.txt
index 5b752e0..ebc75c2 100644
--- a/examples/all_features/CMakeLists.txt
+++ b/examples/all_features/CMakeLists.txt
@@ -23,7 +23,7 @@
set(files_all
${files_with_output}
concurrency.cpp
- ../../scripts/coverage_maxout.cpp
+ coverage_maxout.cpp
namespace1.cpp
namespace2.cpp
namespace3.cpp
diff --git a/examples/all_features/assert_returns_disabled.cpp b/examples/all_features/assert_returns_disabled.cpp
index 8dd5997..da5a701 100644
--- a/examples/all_features/assert_returns_disabled.cpp
+++ b/examples/all_features/assert_returns_disabled.cpp
@@ -1,17 +1,18 @@
#define DOCTEST_CONFIG_ASSERTS_RETURN_VALUES
#include <doctest/doctest.h>
-#include <cstdio>
-
+DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN
+#include <iostream>
+DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END
#ifndef TEST_FLIP
#define TEST_FLIP 0
#endif
-#define TEST_FAIL() printf("FAILED ON: %d (%s)\n", \
- __LINE__, TEST_FLIP ? "EVALUATED" : "DISABLED")
+#define TEST_FAIL() std::cout << "FAILED ON: " << __LINE__ \
+ << "(" << (TEST_FLIP ? "EVALUATED" : "DISABLED") << ")" << std::endl
-static int test_disabled_var_ = [] {
+static int test_disabled_var_ = [] { // NOLINT
// none may return true
if (TEST_FLIP ^ CHECK(0 == 0)) { TEST_FAIL(); }
if (TEST_FLIP ^ CHECK_FALSE(0 != 0)) { TEST_FAIL(); }
diff --git a/examples/all_features/assertion_macros.cpp b/examples/all_features/assertion_macros.cpp
index 959a9c3..193a2e9 100644
--- a/examples/all_features/assertion_macros.cpp
+++ b/examples/all_features/assertion_macros.cpp
@@ -205,7 +205,8 @@
someAssertsInFunction();
}
-inline DOCTEST_NOINLINE void comp(int a, int b) {
+// TODO: Remove NOLINT (if (false && (__VA_ARGS__));)?
+inline DOCTEST_NOINLINE void comp(int a, int b) { // NOLINT(misc-unused-parameters)
if (CHECK(a == b)) { MESSAGE(":D"); }
if (CHECK_FALSE(a != b)) { MESSAGE(":D"); }
if (CHECK_EQ(a, b)) { MESSAGE(":D"); }
diff --git a/examples/all_features/coverage_maxout.cpp b/examples/all_features/coverage_maxout.cpp
new file mode 100644
index 0000000..34489da
--- /dev/null
+++ b/examples/all_features/coverage_maxout.cpp
@@ -0,0 +1,127 @@
+#include <doctest/doctest.h>
+
+#include "header.h"
+
+DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN
+#include <ostream>
+#include <sstream>
+#include <stdexcept>
+DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END
+
+#ifndef DOCTEST_CONFIG_DISABLE
+
+// =================================================================================================
+// !!! THESE ARE NOT PROPER EXAMPLES OF LIBRARY USAGE !!! THESE ARE MEANT FOR CODE COVERAGE ONLY !!!
+// =================================================================================================
+
+TEST_CASE("exercising tricky code paths of doctest") {
+ using namespace doctest;
+
+ // trigger code path for comparing the file in "operator<" of SubcaseSignature
+ CHECK(SubcaseSignature{"", "a.cpp", 0} < SubcaseSignature{"", "b.cpp", 0});
+ // same for String
+ CHECK(String("a.cpp") < String("b.cpp"));
+
+ // trigger code path for string with nullptr
+ String str;
+ const String const_str("omgomgomg");
+ str = const_str.c_str();
+ CHECK(const_str[0] == 'o');
+ CHECK(str.capacity() == 24);
+ CHECK(str.size() == const_str.size());
+ CHECK_MESSAGE(str.compare(const_str, true) != 0, "should fail");
+ CHECK_MESSAGE(str.compare("omgomgomg", false) != 0, "should fail");
+
+ String heap_str("012345678901234567890123456789");
+ CHECK(heap_str.capacity() == heap_str.size() + 1); // on heap with maxed capacity
+ heap_str += "0123456789";
+ CHECK(heap_str.capacity() > heap_str.size() + 1);
+ heap_str += "0123456789"; // triggers path in +=
+ CHECK(heap_str[heap_str.size() - 1] == '9');
+ heap_str = "";
+
+ CHECK(String("abc") == "abc");
+ CHECK(String("abc") > "aaa");
+ CHECK(String("abc") >= "aaa");
+ CHECK(String("abc") < "bbb");
+ CHECK(String("abc") <= "bbb");
+ CHECK(String("abc")[0] == 'a');
+
+ // toString
+ str += toString("aaa") //
+ + toString(nullptr) //
+ + toString(true) //
+ + toString(0u) //
+ + toString('c') //
+ + toString(static_cast<signed char>('c')) //
+ + toString(static_cast<unsigned char>(1)) //
+ + toString(static_cast<short>(1)) //
+ + toString(1L) //
+ + toString(1UL) //
+ + toString(static_cast<unsigned short>(1)) //
+ + toString(1LL) //
+ + toString(1ULL);
+
+ std::ostringstream oss;
+
+ // trigger code path for String to ostream through operator<<
+ oss << str;
+ // trigger code path for assert string of a non-existent assert type
+#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
+ try {
+ assertString(static_cast<assertType::Enum>(3));
+ } catch (const std::logic_error&) { }
+#endif
+ str += oss.str().c_str();
+ str += failureString(assertType::is_normal);
+ CHECK(str == "omgomgomgaaanullptrtrue099991111111"
+ "omgomgomgaaanullptrtrue099991111111");
+ // trigger code path for rawMemoryToString
+ bool isThereAnything = str.size() > 0u;
+ String unknown = toString(skip()); // trigger code path for "{?}"
+ str = unknown; // trigger code path for deleting memory in operator=
+ CHECK_FALSE_MESSAGE(isThereAnything, "should fail");
+
+ Approx a(5);
+ a.scale(4);
+ Approx b = a(7);
+
+ CHECK(b == 7);
+ CHECK(b != 6);
+ CHECK(b > 6);
+ CHECK(b < 8);
+ CHECK(b >= 7);
+ CHECK(b <= 7);
+
+ CHECK(5 == a);
+ CHECK(6 != a);
+ CHECK(6 > a);
+ CHECK(4 < a);
+ CHECK(5 >= a);
+ CHECK(5 <= a);
+
+ // trigger another single line of code... lol
+ // NOLINTBEGIN(cppcoreguidelines-pro-type-const-cast)
+ auto oldVal = const_cast<ContextOptions*>(getContextOptions())->no_path_in_filenames;
+ const_cast<ContextOptions*>(getContextOptions())->no_path_in_filenames = false;
+ CHECK(String(skipPathFromFilename("")) == "");
+ const_cast<ContextOptions*>(getContextOptions())->no_path_in_filenames = oldVal;
+ // NOLINTEND(cppcoreguidelines-pro-type-const-cast)
+
+ // a hack to trigger a bug in doctest: currently a 0 cannot be successfully parsed for an int option!
+ Context().setOption("last", 0);
+}
+
+TEST_SUITE("will be overridden by a decorator" * doctest::test_suite("exception related")) {
+ TEST_CASE("will end from a std::string exception") {
+ throw_if(true, std::string("std::string!"));
+ }
+
+ TEST_CASE("will end from a const char* exception") { throw_if(true, "const char*!"); }
+
+ TEST_CASE("will end from an unknown exception") {
+ throw_if(true, doctest::String("unknown :("));
+ }
+}
+
+#endif // DOCTEST_CONFIG_DISABLE
diff --git a/examples/all_features/decomposition.cpp b/examples/all_features/decomposition.cpp
index d610cc7..c48f8a4 100644
--- a/examples/all_features/decomposition.cpp
+++ b/examples/all_features/decomposition.cpp
@@ -7,6 +7,8 @@
MoveOnly(const MoveOnly&) = delete;
MoveOnly& operator=(MoveOnly&&) = default;
MoveOnly& operator=(const MoveOnly&) = default;
+ ~MoveOnly() = default;
+ // NOLINTNEXTLINE(readability-make-member-function-const)
operator bool() { // NOT const!
return i == 42;
}
@@ -16,7 +18,7 @@
};
static MoveOnly genType(bool b) {
- return MoveOnly(b ? 42 : 0);
+ return { b ? 42 : 0 };
}
TEST_CASE("Move Only Type") {
diff --git a/examples/all_features/enums.cpp b/examples/all_features/enums.cpp
index e58c3a9..d92127d 100644
--- a/examples/all_features/enums.cpp
+++ b/examples/all_features/enums.cpp
@@ -67,7 +67,7 @@
template<class E, class T = typename std::underlying_type<E>::type>
T printable(E val)
{
- return T(val);
+ return static_cast<T>(val);
}
}
diff --git a/examples/all_features/header.h b/examples/all_features/header.h
index 6a46aec..5c5fed4 100644
--- a/examples/all_features/header.h
+++ b/examples/all_features/header.h
@@ -7,7 +7,7 @@
int throw_if(bool in, const T& ex) {
if(in)
#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
- throw ex;
+ throw ex; // NOLINT
#else // DOCTEST_CONFIG_NO_EXCEPTIONS
((void)ex);
#endif // DOCTEST_CONFIG_NO_EXCEPTIONS
@@ -47,6 +47,7 @@
DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow")
#endif // gcc 5
+// NOLINTBEGIN
struct SomeFixture
{
int data;
@@ -59,6 +60,7 @@
// teardown here
}
};
+// NOLINTEND
TEST_CASE_FIXTURE(SomeFixture, "fixtured test") {
data /= 2;
diff --git a/examples/all_features/logging.cpp b/examples/all_features/logging.cpp
index ddc95d3..5182b16 100644
--- a/examples/all_features/logging.cpp
+++ b/examples/all_features/logging.cpp
@@ -51,9 +51,11 @@
throw_if(true, 0);
}
+// TODO: Also remove
+// NOLINTNEXTLINE(misc-unused-parameters)
static void thirdPartyAssert(bool result, bool is_fatal, const char* file, int line) {
- if(result == false) {
- if(is_fatal)
+ if(!result) {
+ if(is_fatal) // NOLINT(bugprone-branch-clone)
ADD_FAIL_AT(file, line, "MY_ASSERT_FATAL(" << result << ")");
else
ADD_FAIL_CHECK_AT(file, line, "MY_ASSERT(" << result << ")");
diff --git a/examples/all_features/main.cpp b/examples/all_features/main.cpp
index 76086c7..e51542b 100644
--- a/examples/all_features/main.cpp
+++ b/examples/all_features/main.cpp
@@ -46,6 +46,6 @@
}
int program() {
- printf("Program code.\n");
+ std::cout << "Program code." << std::endl;
return EXIT_SUCCESS;
}
diff --git a/examples/all_features/stringification.cpp b/examples/all_features/stringification.cpp
index 57e654a..a9518a3 100644
--- a/examples/all_features/stringification.cpp
+++ b/examples/all_features/stringification.cpp
@@ -4,7 +4,7 @@
namespace std {
template <typename> struct char_traits;
template <typename, typename> class basic_ostream;
- typedef basic_ostream<char, char_traits<char>> ostream;
+ typedef basic_ostream<char, char_traits<char>> ostream; // NOLINT(modernize-use-using)
template<class TRAITS>
basic_ostream<char, TRAITS>& operator<<(basic_ostream<char, TRAITS>&, const char*);
}
@@ -44,16 +44,16 @@
#endif
TEST_CASE("no headers") {
- char chs[] = { '1', 'a', 's' };
+ char chs[] = { '1', 'a', 's' }; // NOLINT(*-avoid-c-arrays)
MESSAGE(chs); CHECK(chs == nullptr);
MESSAGE("1as"); CHECK("1as" == nullptr);
- int ints[] = { 0, 1, 1, 2, 3, 5, 8, 13 };
+ int ints[] = { 0, 1, 1, 2, 3, 5, 8, 13 }; // NOLINT(*-avoid-c-arrays)
MESSAGE(ints); CHECK(ints == nullptr);
- MESSAGE(MOVE(ints));
+ MESSAGE(MOVE(ints)); // NOLINT(*-move-const-arg)
- char* cptr = reinterpret_cast<char*>(ints + 4);
- const char* ccptr = const_cast<const char*>(cptr);
+ char* cptr = reinterpret_cast<char*>(ints + 4); // NOLINT
+ const char* ccptr = cptr;
void* vptr = reinterpret_cast<void*>(cptr);
CHECK(doctest::toString(cptr) == doctest::toString(ccptr));
CHECK(doctest::toString(ccptr) == doctest::toString(vptr));
@@ -80,7 +80,7 @@
DOCTEST_MSVC_SUPPRESS_WARNING(5045) // Spectre mitigation diagnostics
// the standard forbids writing in the std namespace but it works on all compilers
-namespace std
+namespace std // NOLINT(cert-dcl58-cpp)
{
template <typename T>
ostream& operator<<(ostream& stream, const vector<T>& in) {
@@ -104,6 +104,7 @@
std::ostringstream oss;
oss << "[";
+ // NOLINTNEXTLINE(*-use-auto)
for (typename std::list<T>::const_iterator it = in.begin(); it != in.end();) {
oss << *it;
if (++it != in.end()) { oss << ", "; }
diff --git a/examples/all_features/subcases.cpp b/examples/all_features/subcases.cpp
index 3fad25f..558baa0 100644
--- a/examples/all_features/subcases.cpp
+++ b/examples/all_features/subcases.cpp
@@ -135,7 +135,7 @@
}
}
-static void checks(int data)
+static void checks(int data) // NOLINT(misc-unused-parameters)
{
DOCTEST_SUBCASE("check data 1") { REQUIRE(data % 2 == 0); }
DOCTEST_SUBCASE("check data 2") { REQUIRE(data % 4 == 0); }
diff --git a/examples/all_features/templated_test_cases.cpp b/examples/all_features/templated_test_cases.cpp
index 7c45f13..dafb32e 100644
--- a/examples/all_features/templated_test_cases.cpp
+++ b/examples/all_features/templated_test_cases.cpp
@@ -45,8 +45,8 @@
template <typename first, typename second>
struct TypePair
{
- typedef first A;
- typedef second B;
+ using A = first;
+ using B = second;
};
TYPE_TO_STRING_AS("Custom name test", TypePair<int, char>);
@@ -54,8 +54,8 @@
TYPE_TO_STRING(TypePair<bool, int>);
TEST_CASE_TEMPLATE("multiple types", T, TypePair<int, char>, TypePair<char, int>, TypePair<bool, int>) {
- typedef typename T::A T1;
- typedef typename T::B T2;
+ using T1 = typename T::A;
+ using T2 = typename T::B;
T1 t1 = T1();
T2 t2 = T2();
// use T1 and T2 types
@@ -64,12 +64,12 @@
}
// currently the string result will be "int_pair" instead of "TypePair<int, int>" because of the way the type stringification works
-typedef TypePair<int, int> int_pair;
+using int_pair = TypePair<int, int>;
TYPE_TO_STRING(int_pair);
TEST_CASE_TEMPLATE("bad stringification of type pair", T, int_pair) {
- typedef typename T::A T1;
- typedef typename T::B T2;
+ using T1 = typename T::A;
+ using T2 = typename T::B;
T1 t1 = T1();
T2 t2 = T2();
// use T1 and T2 types