Enable clang-tidy tooling - #372
colin-higgins wants to merge 6 commits into
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
BenchmarksBenchmark execution time: 2026-09-24 17:32:53 Comparing candidate commit 70b56c4 in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 8 metrics, 0 unstable metrics.
|
|
I you don't pin the clang-tidy version, it's going to be very difficult to get reproductible results. What's gonna happen is that the checks are gonna pass on the dev's machine and fail on ci. This is also a problem with clang-format, but a bit less so because you can work around the problem by running clang-format directly from some docker container. This doesn't work for clang-tidy because compile_commands.json is going to have references to system headers, perhaps you're running on mac os, etc. For that, you need to run everything inside a container with cmake/compilers/etc, run cmake build dir initialization to generate compile_commands.json inside, and run clang-tidy there. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2cfeebf708
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| # Collect first-party translation units. Headers are analyzed through them. | ||
| # Compiler flags from the database may include -Werror. Tidy findings are the | ||
| # gate; unknown-to-this-tidy compiler flags should not fail the job. | ||
| find binding/ examples/ fuzz/ include/ src/ test/ \ |
There was a problem hiding this comment.
Restrict tidy to configured translation units
The ci-clang preset enables tests and tools only; it leaves the C binding, examples, and fuzzers disabled, so their files have no entries in .build/compile_commands.json. This command still passes all of those files to clang-tidy. For example, binding/c/src/tracer.cpp is analyzed without the binding include path and fails to find datadog/c/tracer.h, causing the new verify job to fail on every PR before downstream jobs can run. Enumerate compilation-database entries instead, or enable every directory being scanned in the CI preset.
Useful? React with 👍 / 👎.
| readability-redundant-member-init, | ||
| readability-redundant-string-cstr, | ||
| readability-simplify-boolean-expr | ||
| WarningsAsErrors: '*' |
There was a problem hiding this comment.
Make the new hard-error baseline pass
This setting turns existing diagnostics in configured translation units into CI failures. Running the configured checks against src/datadog/tracer.cpp reports readability-redundant-member-init and performance-move-const-arg, while src/datadog/remote_config/product.cpp reports two misc-static-assert diagnostics; therefore the new check cannot pass even after its input list is limited to compilation-database entries. Fix or suppress the baseline findings before making all warnings fatal.
Useful? React with 👍 / 👎.
| readability-redundant-string-cstr, | ||
| readability-simplify-boolean-expr | ||
| WarningsAsErrors: '*' | ||
| HeaderFilterRegex: '(src|include|binding|test|fuzz|examples)/' |
There was a problem hiding this comment.
Match full paths in the header filter
This pattern does not match full header paths such as include/datadog/clock.h, so clang-tidy suppresses their diagnostics rather than gating them. With the current config, clang-tidy reports the clock header's readability-redundant-member-init diagnostics only when invoked with --header-filter=.*; the normal filter emits no diagnostic and exits successfully. Prefix the directory alternatives with a full-path match (for example, .*(src|include|binding|test|fuzz|examples)/) so first-party header findings fail the check as documented.
Useful? React with 👍 / 👎.
| # Collect first-party translation units. Headers are analyzed through them. | ||
| # Compiler flags from the database may include -Werror. Tidy findings are the | ||
| # gate; unknown-to-this-tidy compiler flags should not fail the job. | ||
| find binding/ examples/ fuzz/ include/ src/ test/ \ |
There was a problem hiding this comment.
Include configured tool sources in the tidy scan
This source-root list omits tools/, even though ci-clang enables DD_TRACE_BUILD_TOOLS and therefore creates a compilation-database entry for tools/config-inversion/main.cpp. The Development workflow builds and runs that executable after this check, but changes to its first-party C++ source will never be analyzed by clang-tidy despite the script and documentation promising coverage of first-party sources. Include tools/ here, or derive the input list from the compilation database.
Useful? React with 👍 / 👎.
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
xlamorlette-datadog
left a comment
There was a problem hiding this comment.
Thanks a lot for this, this will definitely help a lot!…
Please consider alternative proposed solution to run Clang Tidy “on its own”.
| @@ -0,0 +1,95 @@ | |||
| #!/bin/sh | |||
| # Run the pinned clang-tidy through CMake in the CI container. | |||
There was a problem hiding this comment.
nit: I find this comment a bit complicated. I suggest:
# Run clang-tidy through CMake in the CI container.
#
# This builds dd-trace-cpp-objects with DD_TRACE_ENABLE_CLANG_TIDY=ON.
# CMakeLists.txt sets CXX_CLANG_TIDY on that target, so tidy runs with
# the real compile line.
#
# Usage: bin/check-tidy
| REPO_ROOT=$(cd "$SCRIPT_DIR/.." && pwd) | ||
| cd "$REPO_ROOT" | ||
|
|
||
| # Keep this in sync with .github/workflows/dev.yml and cmake/compiler/clang.cmake. |
There was a problem hiding this comment.
nit:
- I think that stating that the clang version must be the same everywhere is obvious for C++ developers, and so could be dropped.
- It seems to me that the
cmake/compiler/clang.cmakereference is a mistake. - I would rather state that the CI image digest must be in sync with
.github/workflows/*.yml(this digest is duplicated many times, this is bad, but this was made long ago and is out of scope ;-) ).
| fi | ||
|
|
||
| build_dir=${BUILD_DIR:-.clang-tidy-build} | ||
| tidy=clang-tidy-$CLANG_TIDY_VERSION |
There was a problem hiding this comment.
nit, opt, personal preference: I would prefer to name this variable clang_tidy, I think it would be clearer for C++ developers
| exit 1 | ||
| fi | ||
|
|
||
| # Reconfigure so CXX_CLANG_TIDY is attached to dd-trace-cpp-objects, then |
There was a problem hiding this comment.
Instead of compiling with clang-tidy step, I think we could rather only run clang-tidy directly.
This would remove the added lines in CMakeLists.txt.
Here also, the call would be simpler:
bin/with-toolchain llvm cmake . -B "$build_dir" --preset ci-clang
run-clang-tidy-$CLANG_TIDY_VERSION -p "$build_dir" -clang-tidy-binary "$tidy" \
-quiet "^$REPO_ROOT/src/"
By the way, it seems that files in include/ are currently not checked.
Moreover, I think this would ease adding, possibly incrementally, the test/ folder. We need to add this, probably in a follow-up PR.
What do you think?
| apt-get update && apt-get upgrade --yes && \ | ||
| apt-get install --yes \ | ||
| wget build-essential clang sed gdb clang-format git ssh shellcheck \ | ||
| wget build-essential clang sed gdb clang-format clang-tidy git ssh shellcheck \ |
There was a problem hiding this comment.
nit, opt, pedantic: By the way, please sort packages alphabetically.
| # compile that target. CMake passes the exact ci-clang compile line | ||
| # (including -stdlib=libc++) to tidy. First-party src/ only; no extra-args. | ||
| bin/with-toolchain llvm cmake . -B "$build_dir" --preset ci-clang \ | ||
| -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ |
There was a problem hiding this comment.
It seems this is redundant with the added line (line 42) in CMakePresets.json.
| before pushing changes. | ||
| - [check-format](check-format) verifies that the source code is formatted as | ||
| [format](format) prefers. | ||
| - [check-tidy](check-tidy) runs **clang-tidy-14** (pinned, same major as the |
There was a problem hiding this comment.
nit: I would prefer a much simpler and terser comment, without bold, without version, without internal technical details: runs Clang Tidy.
|
|
||
| ## Static Analysis | ||
|
|
||
| C++ is analyzed with **clang-tidy-14** (pinned; same major as `clang-format-14`) |
There was a problem hiding this comment.
We need a much simpler and direct documentation, without internal technical details. I suggest:
C++ code is analyzed with Clang Tidy. Run this with the following command:
\```shell
bin/check-tidy
\```
| # readability-redundant-member-init | ||
| # readability-simplify-boolean-expr | ||
| WarningsAsErrors: '*' | ||
| HeaderFilterRegex: '^src/' |
There was a problem hiding this comment.
It seems this never matches because CMake passes absolute paths, so Clang Tidy sees /…/src/datadog/[xxx].h.
I think we should rather remove this HeaderFilterRegex option and add the header option to run-clang-tidy:
run-clang-tidy-$CLANG_TIDY_VERSION -p "$build_dir" -clang-tidy-binary "$tidy" \
-header-filter "^$REPO_ROOT/(src|include)/" -quiet "^$REPO_ROOT/src/"
Add a shared clang-tidy baseline and a CI job that fails on findings, so PRs cannot merge with tidy violations.