feat: add clang tooling, lint infrastructure, Linux debug/release presets#13
Conversation
…presets - Replace .clang-format with modern C++20 style (4-space indent, 120 col, Google-based) - Add .clang-tidy with comprehensive check set (bugprone, modernize, performance, readability) - Add .gitattributes for language detection, LF normalization, binary file handling - Add .pre-commit-config.yaml (clang-format v22.1.0, clang-tidy v22.1.0, codespell) - Update .github/workflows/linux-ci.yml: add pre-commit lint step between configure and build - Add linux-debug and linux-release configure+build presets to CMakePresets.json - Add sync-compile-commands CMake target to copy compile_commands.json to build/ for clangd - Update .vscode/settings.json: clangd points to build/, tabSize=4, clangd as C++ formatter - Apply clang-format to all source files - Fix all clang-tidy warnings (nodiscard, narrowing casts, braced-init-list, unconventional assign-operator, simd NOLINT, ranges::any_of, inconsistent param names, std::isnan) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces a full C++ lint/format toolchain (clang-format/clang-tidy via pre-commit), wires it into Linux CI, adds Linux CMake presets, and applies formatting/tidy-driven refactors across the codebase to align with the new tooling.
Changes:
- Add repository-wide lint/format infrastructure:
.clang-format,.clang-tidy,.pre-commit-config.yaml, and.gitattributes - Add Linux
debug/releasepresets and CI lint step; update VS Code to point clangd at a unifiedbuild/compile_commands.json - Apply clang-format + clang-tidy cleanups across util/render code (API annotations, include modernization, small refactors)
Reviewed changes
Copilot reviewed 33 out of 40 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| src/util/value.cpp | Collapse empty namespace definition to single-line form. |
| src/util/timerange.cpp | Reformat + tidy refactors (ranges algorithms, move-based iterator ctor, casts). |
| src/util/timecodefunctions.cpp | Reformat + tidy refactors (casts, switch formatting, std qualifiers). |
| src/util/tests.cpp | Replace deprecated C headers and reformat test harness helpers. |
| src/util/stringutils.cpp | Replace deprecated C headers and reformat; minor return-style tweaks. |
| src/util/rational.cpp | Replace deprecated math header and update NaN handling/formatting. |
| src/util/color.cpp | Include modernization + formatting + explicit casts in conversions. |
| src/util/bezier.cpp | Reformat + minor arithmetic formatting/cleanup. |
| src/render/samplebuffer.cpp | Include modernization + formatting; SIMD lint suppressions added; API signature adjustments. |
| src/render/audioparams.cpp | Formatting + minor logic change for samples_to_time multiplication/cast. |
| include/arcvideo/foundation/util/value.h | Reformat Value container; include ordering adjustments. |
| include/arcvideo/foundation/util/timerange.h | Add [[nodiscard]], ranges-based helpers, iterator API adjustments, and formatting. |
| include/arcvideo/foundation/util/timecodefunctions.h | Reformat enums and function declarations; minor signature formatting. |
| include/arcvideo/foundation/util/tests.h | Reformat test runner API. |
| include/arcvideo/foundation/util/stringutils.h | Reformat + inline helper restructuring and signature formatting. |
| include/arcvideo/foundation/util/rational.h | Add [[nodiscard]], modernize operators/defaults, and reformat. |
| include/arcvideo/foundation/util/math.h | Simplify to empty namespace + header guard formatting. |
| include/arcvideo/foundation/util/log.h | Reformat and modernize small returns/constructors. |
| include/arcvideo/foundation/util/cpuoptimize.h | Header guard comment formatting only. |
| include/arcvideo/foundation/util/color.h | Add [[nodiscard]], reformat, and small API/inline modernization. |
| include/arcvideo/foundation/util/bezier.h | Add [[nodiscard]], reformat, and inline return braced-init updates. |
| include/arcvideo/foundation/render/sampleformat.h | Reformat + add [[nodiscard]] on accessors; tidy-style refactors. |
| include/arcvideo/foundation/render/samplebuffer.h | API tweaks (AudioParams by value), add [[nodiscard]], and reformat. |
| include/arcvideo/foundation/render/pixelformat.h | Reformat + add [[nodiscard]] on accessors. |
| include/arcvideo/foundation/render/audioparams.h | Reformat + add [[nodiscard]] on many APIs; member default init cleanup. |
| include/arcvideo/foundation/foundation.h | Header guard comment formatting only. |
| docs/BUILD_GUIDE.md | Normalize line endings/markdown separators; no functional change. |
| SECURITY.md | Trailing whitespace cleanup. |
| README.md | Normalize line endings/markdown separators; no functional change. |
| CMakePresets.json | Add linux-debug / linux-release presets and matching build presets; formatting normalization. |
| CMakeLists.txt | Add sync-compile-commands ALL target; formatting normalization. |
| .vscode/settings.json | Point clangd to build/ compile commands; set tab size to 4; switch formatter to clangd. |
| .pre-commit-config.yaml | Add pre-commit hooks for formatting/tidy/codespell and hygiene checks. |
| .gitignore | Normalize line endings; no rule logic change. |
| .github/workflows/linux-ci.yml | Add lint step (copy compile_commands + run pre-commit) before build. |
| .github/dependabot.yml | Trailing newline cleanup. |
| .gitattributes | Enforce LF normalization; mark binaries; improve GitHub linguist language detection. |
| .clang-tidy | Add comprehensive clang-tidy configuration/check set. |
| .clang-format | Add modern Google-based C++20 style (4-space indent, 120 cols, regrouped includes). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| __m128 mult = _mm_load1_ps(&volume); | ||
| unopt_start = (sample_count_per_channel_ / 4) * 4; | ||
| for (size_t j = 0; j < unopt_start; j += 4) { | ||
| float* here = cdat + j; | ||
| __m128 samples = _mm_loadu_ps(here); | ||
| __m128 multiplied = _mm_mul_ps(samples, mult); // NOLINT(portability-simd-intrinsics) | ||
| _mm_storeu_ps(here, multiplied); | ||
| } |
There was a problem hiding this comment.
portability-simd-intrinsics is enabled in the repo’s .clang-tidy, but only _mm_mul_ps is annotated with NOLINT. The other intrinsics in this block (_mm_load1_ps, _mm_loadu_ps, _mm_storeu_ps) are likely to be flagged too; consider annotating the whole block (e.g., NOLINTBEGIN/NOLINTEND) or each intrinsic call consistently.
| __m128 min_sse = _mm_load1_ps(&min); | ||
| __m128 max_sse = _mm_load1_ps(&max); | ||
|
|
||
| unopt_start = (sample_count_per_channel_ / 4) * 4; | ||
| for (size_t j=0; j<unopt_start; j+=4) { | ||
| float *here = cdat + j; | ||
| __m128 samples = _mm_loadu_ps(here); | ||
| unopt_start = (sample_count_per_channel_ / 4) * 4; | ||
| for (size_t j = 0; j < unopt_start; j += 4) { | ||
| float* here = cdat + j; | ||
| __m128 samples = _mm_loadu_ps(here); | ||
|
|
||
| samples = _mm_max_ps(samples, min_sse); | ||
| samples = _mm_min_ps(samples, max_sse); | ||
| samples = _mm_max_ps(samples, min_sse); // NOLINT(portability-simd-intrinsics) | ||
| samples = _mm_min_ps(samples, max_sse); // NOLINT(portability-simd-intrinsics) | ||
|
|
||
| _mm_storeu_ps(here, samples); | ||
| } | ||
| _mm_storeu_ps(here, samples); | ||
| } |
There was a problem hiding this comment.
Same as above: the SSE clamp loop uses multiple _mm_* intrinsics but only some lines have NOLINT(portability-simd-intrinsics). To keep clang-tidy clean, annotate the full intrinsic sequence consistently (block-level suppression is usually less error-prone).
| AudioParams(const int& sample_rate, const uint64_t& channel_layout, const SampleFormat& format) | ||
| : sample_rate_(sample_rate), channel_layout_(channel_layout), format_(format) { | ||
| set_default_footage_parameters(); | ||
| timebase_ = sample_rate_as_time_base(); |
There was a problem hiding this comment.
The constructor takes sample_rate/channel_layout by const& even though they’re fundamental types. This typically triggers readability-avoid-const-params-in-decls; consider passing these by value to simplify the API and avoid needless references.
| [[nodiscard]] int64_t time_to_bytes(const double& time) const; | ||
| [[nodiscard]] int64_t time_to_bytes(const rational& time) const; | ||
| [[nodiscard]] int64_t time_to_bytes_per_channel(const double& time) const; | ||
| [[nodiscard]] int64_t time_to_bytes_per_channel(const rational& time) const; | ||
| [[nodiscard]] int64_t time_to_samples(const double& time) const; | ||
| [[nodiscard]] int64_t time_to_samples(const rational& time) const; | ||
| [[nodiscard]] int64_t samples_to_bytes(const int64_t& samples) const; | ||
| [[nodiscard]] int64_t samples_to_bytes_per_channel(const int64_t& samples) const; | ||
| [[nodiscard]] rational samples_to_time(const int64_t& samples) const; |
There was a problem hiding this comment.
Several APIs here take fundamental types by const& (e.g., const double&, const int64_t&). With readability-avoid-const-params-in-decls enabled, these should generally be passed by value to avoid lint warnings and make call sites simpler.
| SampleBuffer::SampleBuffer(AudioParams audio_params, const rational& length) : audio_params_(audio_params) { | ||
| sample_count_per_channel_ = audio_params_.time_to_samples(length); | ||
| allocate(); |
There was a problem hiding this comment.
The constructors now take AudioParams by value, but the member initializer copies it (audio_params_(audio_params)), which adds an extra copy for lvalue callers. Either move into the member (std::move(audio_params)) or revert the parameter back to const AudioParams& if copying is intended.
| #include <stdint.h> | ||
| #include <string> | ||
| #include <string.h> | ||
|
|
||
| #include <map> | ||
| #include <string> |
There was a problem hiding this comment.
This header still includes deprecated C headers (<stdint.h>, <string.h>) while other files were migrated to C++ headers. With modernize-deprecated-headers enabled in .clang-tidy, consider switching these to <cstdint> / <cstring> and using std::memcpy / std::strlen for consistency.
| const TimeRange& operator-=(const rational& rhs); | ||
|
|
||
| std::list<TimeRange> Split(const int &chunk_size) const; | ||
| [[nodiscard]] std::list<TimeRange> Split(const int& chunk_size) const; |
There was a problem hiding this comment.
Split takes const int&, but .clang-tidy enables readability-avoid-const-params-in-decls, which recommends passing small trivially-copyable types by value. Consider changing this parameter to plain int (and matching the definition) to avoid unnecessary references and lint noise.
| [[nodiscard]] const size_t& sample_count() const { return sample_count_per_channel_; } | ||
| void set_sample_count(const size_t& sample_count); | ||
| void set_sample_count(const rational& length) { set_sample_count(audio_params_.time_to_samples(length)); } |
There was a problem hiding this comment.
set_sample_count takes const size_t& even though size_t is cheap to copy. Given readability-avoid-const-params-in-decls is enabled, consider taking size_t by value (and update the .cpp definition accordingly).
| SampleBuffer::SampleBuffer(AudioParams audio_params, size_t samples_per_channel) | ||
| : audio_params_(audio_params), sample_count_per_channel_(samples_per_channel) { | ||
| allocate(); |
There was a problem hiding this comment.
This overload also takes AudioParams by value but copies it into audio_params_. Consider moving the parameter into the member to avoid an extra copy.
Summary
This PR adds comprehensive C++ lint infrastructure and code quality tooling.
0. CMake & VSCode changes
linux-debugandlinux-releaseconfigure+build presets (symmetric withwindows-debug/windows-release)sync-compile-commandsALL target — copiescompile_commands.jsonfrom the preset's binary dir tobuild/so clangd and lint tools always find it--compile-commands-dir→build/;editor.tabSize→ 4 (matches new style); C++ formatter → clangd1. New tooling files
clang-format v22.1.0,clang-tidy v22.1.0,codespell, standard file hygiene hooks2. GitHub CI
compile_commands.jsontobuild/, sets up Python 3.11, runspre-commit/action@v3.0.1(all hooks)3. Code quality fixes
Applied clang-format to all source/header files and fixed all clang-tidy warnings:
[[nodiscard]]annotations on all const query methodsstatic_cast<int>,static_cast<float>, etc.)misc-unconventional-assign-operator:operator=now returnsrational&std::isnanqualified name (fixes clang diagnostic error)std::ranges::any_ofreplaces manual loops inTimeRangeList// NOLINT(portability-simd-intrinsics)for intentional SSE intrinsics in guarded blocksAll pre-commit hooks pass locally (clang-format, clang-tidy, codespell, file hygiene).