feat: add clang-format, clang-tidy, pre-commit hooks and CI lint workflow#12
feat: add clang-format, clang-tidy, pre-commit hooks and CI lint workflow#12deku2026 wants to merge 4 commits into
Conversation
…flow - Add .clang-format (Google-based, C++20, 120 col, 4-space indent) - Add .clang-tidy with comprehensive checks (bugprone, cert, modernize, performance, readability) - Add .pre-commit-config.yaml with trailing-whitespace, line-ending, codespell, clang-format, clang-tidy hooks - Add GitHub Actions lint.yml workflow (ubuntu-24.04, LLVM 20, pre-commit/action) - Add compile_commands.json auto-copy to build/ in CMakeLists.txt - Apply clang-format to all source files - Fix all clang-tidy warnings (narrowing conversions, deprecated headers, modernize suggestions) - Normalize line endings to LF across all files Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds repository-wide C++ linting/formatting infrastructure (clang-format/clang-tidy via pre-commit) and a GitHub Actions lint workflow, alongside codebase reformatting and minor modernization to satisfy the new tooling.
Changes:
- Introduce
.clang-format,.clang-tidy,.pre-commit-config.yaml, and CI lint workflow to run these checks automatically. - Update CMake to provide
compile_commands.jsonat a stable location for tooling. - Apply formatting/modernization changes across source, headers, and docs (including LF normalization).
Reviewed changes
Copilot reviewed 30 out of 39 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
src/util/value.cpp |
Namespace formatting cleanup. |
src/util/timerange.cpp |
Reformat + minor modernizations (brace-init, moves, casts). |
src/util/timecodefunctions.cpp |
Reformat + minor modernizations/casts. |
src/util/tests.cpp |
Switch to C++ header <cstdarg> + reformat. |
src/util/stringutils.cpp |
Switch to <cstdarg> + reformat/modernize returns. |
src/util/rational.cpp |
Switch to <cmath> + reformat/modernize operator=. |
src/util/color.cpp |
Header modernization (<cstdint>, <cmath>) + reformat. |
src/util/bezier.cpp |
Reformat/condense trivial constructors and expressions. |
src/render/samplebuffer.cpp |
Header modernization (<cstring>, <utility>) + reformat/move usage. |
src/render/audioparams.cpp |
Reformat + cast changes to satisfy tidy. |
include/arcvideo/foundation/util/value.h |
Header modernization + reformat constructors. |
include/arcvideo/foundation/util/timerange.h |
Reformat + API tweaks (iterator ctor takes list by value). |
include/arcvideo/foundation/util/timecodefunctions.h |
Reformat + line wrapping for declarations. |
include/arcvideo/foundation/util/tests.h |
Reformat + minor type spacing changes. |
include/arcvideo/foundation/util/stringutils.h |
Reformat + minor signature/inline formatting changes. |
include/arcvideo/foundation/util/rational.h |
Reformat + make assignment operator return rational&. |
include/arcvideo/foundation/util/math.h |
Simplify empty namespace formatting. |
include/arcvideo/foundation/util/log.h |
Reformat and condense trivial methods. |
include/arcvideo/foundation/util/cpuoptimize.h |
Comment spacing normalization. |
include/arcvideo/foundation/util/color.h |
Reformat; keep operators inline; preserve API. |
include/arcvideo/foundation/util/bezier.h |
Reformat and wrap long signatures. |
include/arcvideo/foundation/render/sampleformat.h |
Reformat + add [[nodiscard]] to some accessors. |
include/arcvideo/foundation/render/samplebuffer.h |
Reformat + constructors now take AudioParams by value. |
include/arcvideo/foundation/render/pixelformat.h |
Reformat and condense enum/utility methods. |
include/arcvideo/foundation/render/audioparams.h |
Reformat and inline many trivial getters/setters. |
include/arcvideo/foundation/foundation.h |
Header guard comment spacing normalization. |
docs/BUILD_GUIDE.md |
LF normalization + Markdown separator normalization. |
SECURITY.md |
Trailing whitespace fix. |
README.md |
LF normalization + Markdown separator normalization. |
CMakePresets.json |
LF normalization (no functional changes apparent). |
CMakeLists.txt |
Add compile_commands copy target + LF normalization. |
.pre-commit-config.yaml |
Add pre-commit hooks for whitespace/codespell/clang-format/clang-tidy. |
.gitignore |
LF normalization. |
.github/workflows/lint.yml |
Add CI workflow that installs LLVM/vcpkg deps and runs pre-commit. |
.github/dependabot.yml |
Trailing newline cleanup. |
.clang-tidy |
Add clang-tidy check configuration. |
.clang-format |
Add clang-format style configuration. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Copy compile_commands.json to project root for clangd / clang-tidy | ||
| if(CMAKE_EXPORT_COMPILE_COMMANDS) | ||
| add_custom_target(copy-compile-commands ALL | ||
| COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_SOURCE_DIR}/build" | ||
| COMMAND ${CMAKE_COMMAND} -E copy_if_different | ||
| "${CMAKE_BINARY_DIR}/compile_commands.json" | ||
| "${CMAKE_SOURCE_DIR}/build/compile_commands.json" | ||
| COMMENT "Copying compile_commands.json to build/" | ||
| ) | ||
| endif() |
There was a problem hiding this comment.
copy-compile-commands unconditionally copies ${CMAKE_BINARY_DIR}/compile_commands.json whenever CMAKE_EXPORT_COMPILE_COMMANDS is ON. Some generators (notably Visual Studio) don't generate compile_commands.json, so this target can fail the build by trying to copy a non-existent file. Consider guarding on generator support and/or performing the copy via a small cmake -P script that checks file existence before copying.
| - name: Install LLVM 20 and build tools | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y nasm pkg-config | ||
| wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - | ||
| echo "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-20 main" | sudo tee /etc/apt/sources.list.d/llvm-20.list |
There was a problem hiding this comment.
This workflow uses apt-key to add the LLVM APT signing key. apt-key is deprecated on Ubuntu and may stop working in future runner images; prefer installing the key into /etc/apt/keyrings and using signed-by= in the deb entry (and consider using https://apt.llvm.org/...).
| **Pure C++20 Core Library for AI-Powered Video Editing** | ||
|
|
||
| [](https://isocpp.org/) | ||
| [](https://cmake.org/) |
There was a problem hiding this comment.
README claims the project is C++20 (badge/text), but the build config sets CMAKE_CXX_STANDARD 23 and uses cxx_std_23 in CMakeLists.txt. This is confusing for users and tool configuration (e.g., .clang-format sets Standard: c++20). Please align the documentation and tooling with the actual language standard (either update docs to C++23 or switch the project/tooling back to C++20).
| if (fDelta > 0) { | ||
| if (fCMax == red()) { | ||
| *hue = static_cast<DataType>(60 * (fmod(((green() - blue()) / fDelta), 6))); | ||
| } else if (fCMax == green()) { |
There was a problem hiding this comment.
After switching to <cmath>, fmod isn't guaranteed to be available in the global namespace. This can cause portability/compile issues; use std::fmod (or using std::fmod;) here.
| rational rational::fromDouble(const double &flt, bool *ok) { | ||
| if (isnan(flt)) { | ||
| // Return NaN rational | ||
| if (ok) *ok = false; | ||
| return NaN; |
There was a problem hiding this comment.
<cmath> doesn't guarantee isnan is available in the global namespace; this can break compilation on some standard libraries. Use std::isnan (or using std::isnan;) here after switching from <math.h> to <cmath>.
| Value(int64_t v) : type_(INT) { | ||
| data_.resize(sizeof(int64_t)); | ||
| memcpy(data_.data(), &v, sizeof(int64_t)); | ||
| } | ||
|
|
||
| Value(double v) : type_(FLOAT) { | ||
| data_.resize(sizeof(double)); | ||
| memcpy(data_.data(), &v, sizeof(double)); | ||
| } | ||
|
|
||
| Value(const char *s) { | ||
| if (!s) { | ||
| type_ = NONE; | ||
| return; | ||
| } | ||
| size_t sz = strlen(s); | ||
| data_.resize(sz); | ||
| memcpy(data_.data(), s, sz); | ||
| type_ = STRING; |
There was a problem hiding this comment.
After switching to <cstring>, relying on unqualified memcpy/strlen is non-portable (these functions are only guaranteed in std::). Please qualify them (std::memcpy, std::strlen) or include the corresponding C headers if you intentionally want the global versions.
| for (int i = 0; i < audio_params().channel_count(); i++) { | ||
| memset(reinterpret_cast<char *>(data_[i].data()) + start_byte, 0, end_byte - start_byte); | ||
| } | ||
| } | ||
|
|
||
| void SampleBuffer::set(int channel, const float *data, size_t sample_offset, size_t sample_length) | ||
| { | ||
| if (!is_allocated()) { | ||
| Log::Warning() << "Tried to fill an unallocated sample buffer"; | ||
| return; | ||
| } | ||
| void SampleBuffer::set(int channel, const float *data, size_t sample_offset, size_t sample_length) { | ||
| if (!is_allocated()) { | ||
| Log::Warning() << "Tried to fill an unallocated sample buffer"; | ||
| return; | ||
| } | ||
|
|
||
| if (channel < 0 || channel >= audio_params_.channel_count()) { | ||
| Log::Warning() << "Tried to set data on out-of-range channel"; | ||
| return; | ||
| } | ||
| if (channel < 0 || channel >= audio_params_.channel_count()) { | ||
| Log::Warning() << "Tried to set data on out-of-range channel"; | ||
| return; | ||
| } | ||
|
|
||
| if (sample_offset + sample_length > static_cast<size_t>(sample_count_per_channel_)) { | ||
| Log::Warning() << "Tried to set data beyond sample buffer bounds"; | ||
| return; | ||
| } | ||
| if (sample_offset + sample_length > static_cast<size_t>(sample_count_per_channel_)) { | ||
| Log::Warning() << "Tried to set data beyond sample buffer bounds"; | ||
| return; | ||
| } | ||
|
|
||
| memcpy(&data_[channel].data()[sample_offset], data, sizeof(float) * sample_length); | ||
| memcpy(&data_[channel].data()[sample_offset], data, sizeof(float) * sample_length); | ||
| } |
There was a problem hiding this comment.
memset/memcpy are used unqualified after switching to <cstring>. These are only guaranteed to be available as std::memset/std::memcpy, so this can fail to compile on some platforms/standard libraries.
| rational AudioParams::samples_to_time(const int64_t &samples) const { | ||
| return sample_rate_as_time_base() * static_cast<int>(samples); | ||
| } |
There was a problem hiding this comment.
This narrows int64_t samples to int before converting to rational, which will truncate/overflow for long durations. If rational is limited to int, consider clamping/validating (assert(samples <= INT_MAX)) or computing the time via a representation that can handle int64_t (e.g., rational::fromDouble(static_cast<double>(samples) / sample_rate())).
- Use std::isnan, std::fmod, std::memcpy, std::memset, std::strlen - Fix samples_to_time int64_t overflow via rational::fromDouble - Delete standalone lint.yml, add pre-commit step to linux-ci.yml - Add [[nodiscard]] to sampleformat.h member functions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The CMake configure step generates compile_commands.json in build/linux-ci/ but pre-commit clang-tidy expects it at build/. Add explicit copy step between configure and lint. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
Local Setup
\\�ash
pip install pre-commit
pre-commit install
\\
Tools