diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000000000000000000000000000000000000..2e81039e16142d0498198397067b2dba8b0c9ebd --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,16 @@ +# SPDX-FileCopyrightText: 2024 Arm Limited and/or its affiliates +# +# SPDX-License-Identifier: Apache-2.0 + +--- +Checks: >- + -*, + cert-*, + clang-analyzer-core*, + clang-analyzer-cplusplus*, + clang-analyzer-unix.MismatchedDeallocator, + misc-new-delete-overloads +WarningsAsErrors: '*' +HeaderFilterRegex: '(intrinsiccv|test)/.*' +FormatStyle: google +... diff --git a/intrinsiccv/include/utils.h b/intrinsiccv/include/utils.h index 74f2f2d11fcc1719ae4dfe251239795e6f8026de..cdb7b8695caf0c2ee2acb0f47874f7fd78506ecd 100644 --- a/intrinsiccv/include/utils.h +++ b/intrinsiccv/include/utils.h @@ -80,6 +80,7 @@ class LoopUnroll final { size_t step) INTRINSICCV_STREAMING_COMPATIBLE : length_(length), step_(step), + index_(0), can_avoid_tail_(length >= step) {} // Loop unrolled four times. @@ -172,7 +173,11 @@ class LoopUnroll final { LoopUnroll &unroll_n_times(CallbackType callback) INTRINSICCV_STREAMING_COMPATIBLE { const size_t step = UnrollFactor * step_; + // In practice step will never be zero and we don't want to spend + // instructions on checking that. + // NOLINTBEGIN(clang-analyzer-core.DivideZero) const size_t max_index = remaining_length() / step; + // NOLINTEND(clang-analyzer-core.DivideZero) for (index_ = 0; index_ < max_index; ++index_) { callback(step); diff --git a/scripts/ci.sh b/scripts/ci.sh index 1fbb28faafabcadb6ae580b4356ac87a9f647fb4..bd2bb544d0f3619a41ed584f5f682d02aaf3c840 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -20,8 +20,12 @@ reuse lint # Build and run tests cmake -S . -B build -G Ninja \ + -DCMAKE_CXX_CLANG_TIDY=clang-tidy \ -DCMAKE_CXX_FLAGS="--coverage -g -O0" +# Workaround to avoid applying clang-tidy to files in build directory +echo '{"Checks": "-*,cppcoreguidelines-avoid-goto"}'>build/.clang-tidy + GTEST_OUTPUT=xml:$(pwd)/build/test-results/ \ ninja -C build check-intrinsiccv diff --git a/test/api/test_yuv_to_rgb.cpp b/test/api/test_yuv_to_rgb.cpp index 03de4d4bfd227f8f0288e5139a5d0fae3f8427e3..876e4dce59171780a48e65a24cdcf33d9ff06934 100644 --- a/test/api/test_yuv_to_rgb.cpp +++ b/test/api/test_yuv_to_rgb.cpp @@ -58,7 +58,9 @@ class YuvTest final { for (size_t vindex = 0; vindex < exp_arr.height(); vindex++) { for (size_t hindex = 0; hindex < exp_arr.width() / channel_number_; hindex++) { + // NOLINTBEGIN(clang-analyzer-core.uninitialized.Assign) int32_t y = *y_arr.at(vindex, hindex); + // NOLINTEND(clang-analyzer-core.uninitialized.Assign) y = std::max(0, y - 16); int32_t u = *uv_arr.at(vindex / 2, (hindex - hindex % 2) + (is_nv21 ? 1 : 0)); diff --git a/test/framework/array.h b/test/framework/array.h index e5f9e4bd9fc15000aad99644359e6871441c2c45..1b392ad652ad1c700c85b6673d34d52537519da2 100644 --- a/test/framework/array.h +++ b/test/framework/array.h @@ -57,6 +57,7 @@ class Array2D : public TwoDimensional { /// Copy assignment operator. Array2D &operator=(const Array2D &other) { + if (this == &other) return *this; width_ = other.width_; height_ = other.height_; channels_ = other.channels_; @@ -74,6 +75,7 @@ class Array2D : public TwoDimensional { /// Move assignment operator. Array2D &operator=(Array2D &&other) { + if (this == &other) return *this; data_ = std::move(other.data_); width_ = other.width_; height_ = other.height_; diff --git a/test/framework/generator.h b/test/framework/generator.h index 34c56af532b9eaf4dfd1aefc04d8710c0c192b13..42eb5c9df1e07ac77566755f646dc8dcb9d11de7 100644 --- a/test/framework/generator.h +++ b/test/framework/generator.h @@ -16,7 +16,7 @@ namespace test { template class PseudoRandomNumberGenerator : public Generator { public: - PseudoRandomNumberGenerator() : seed_{Options::seed()} { reset(); } + PseudoRandomNumberGenerator() : seed_{Options::seed()}, rng_{seed_} {} /// Resets the generator to the initial state. void reset() override { rng_.seed(seed_); } diff --git a/test/framework/test_array2d.cpp b/test/framework/test_array2d.cpp index 7aed9667ad24ea82a3407e7e3a1ac64140d4a24f..a26c25bd19de5b0c651cd2a0a34b76303df2c6a9 100644 --- a/test/framework/test_array2d.cpp +++ b/test/framework/test_array2d.cpp @@ -75,11 +75,15 @@ TEST(Array2D, MoveAssignment) { EXPECT_EQ(array_2.stride(), width * sizeof(uint32_t)); EXPECT_TRUE(array_2.valid()); + // This test is specifically to find out what happens to an object after it is + // moved so disable this static analysis check. + // NOLINTBEGIN(clang-analyzer-cplusplus.Move) EXPECT_EQ(array_1.width(), 0); EXPECT_EQ(array_1.height(), 0); EXPECT_EQ(array_1.channels(), 0); EXPECT_EQ(array_1.stride(), 0); EXPECT_FALSE(array_1.valid()); + // NOLINTEND(clang-analyzer-cplusplus.Move) } /// Tests that test::Array2D.at() works for set/get. diff --git a/test/framework/test_kernel.cpp b/test/framework/test_kernel.cpp index 2818859a712aa610ebc64c6cad95a7b34db084d3..30b5f5018a2f8bd7df4756af4b3f40c25f02f54a 100644 --- a/test/framework/test_kernel.cpp +++ b/test/framework/test_kernel.cpp @@ -150,6 +150,9 @@ class ExampleKernelTest : public test::KernelTest { size_t border_count_{0}; }; // end of class class ExampleKernelTest +// Disable check for possible exceptions thrown outside main. +// The check isn't important in a test program. +// NOLINTBEGIN(cert-err58-cpp) template const std::array, 2> ExampleKernelTest::kKernels = { @@ -158,6 +161,7 @@ const std::array, 2> test::Kernel{ test::Array2D{4, 4}}, }; +// NOLINTEND(cert-err58-cpp) /// Tests that KernelTest::test() works. TEST(KernelTest, Test) {