From 4c2dfbe578793f81435e667071de6f3c8cd7ca67 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 26 Jul 2026 23:31:29 +0200 Subject: [PATCH] build: add clang-tidy clang-format was already declared, in the dev group. clang-tidy was not available at all: not on PATH, no brew llvm, and the Xcode command line tools do not ship it. It goes into a group of its own rather than into dev, because the wheel is 44 MB against 1.8 MB for clang-format (115 MB against 26 MB unpacked, measured in fresh isolated environments). In dev, the format CI job would pull it on every run without using it. Two things were needed to make it actually run on this project: A compilation database. The test build is the right entry point, since that is what instantiates the templates -- an uninstantiated template is never analysed, which is the same reason the warnings from #75 saw nothing until #79 added the missing instantiations. The macOS SDK. CMake omits -isysroot because AppleClang finds the SDK implicitly; the standalone clang-tidy does not, and failed on signal.h from doctest, leaving the translation unit half parsed. CMAKE_OSX_SYSROOT puts the sysroot into the database, after which the unit parses with zero errors. The check selection is measured rather than guessed. Everything on produced 750+ findings, dominated by readability-identifier-length (427 -- i, j, da and daa are the notation of the domain) and modernize-use-trailing-return-type (225 -- a style the project does not use). The config turns the families on and names each exclusion with its reason, including two that are worth revisiting: modernize-use-nodiscard is off because annotating 57 members is an API decision rather than a lint fix, and bugprone-throwing-static-initialization only ever fires on the deliberate test fixtures. What remains is 51 findings and no errors. run-clang-tidy.py was tried and dropped: with two translation units it is no faster (1:56 against 1:58) and reports every finding in the header once per unit, 89 instead of 51. The justfile was untracked until now. It is included because the sysroot workaround and the compilation database step are not obvious enough to leave in one working copy. No source changes. --- .clang-tidy | 44 ++++++++++++++++++++++++++++++++++++++++++++ justfile | 31 +++++++++++++++++++++++++++++++ pyproject.toml | 3 +++ uv.lock | 23 +++++++++++++++++++++++ 4 files changed, 101 insertions(+) create mode 100644 .clang-tidy create mode 100644 justfile diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..243a59c --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,44 @@ +--- +# Broad families, minus the checks that fight the domain rather than help it. +# Each exclusion is deliberate: +# +# bugprone-branch-clone false positive on `if constexpr` +# bugprone-easily-swappable-parameters h(i, j), check_equal_size(a, b) +# bugprone-throwing-static-init* only fires on the test fixtures, +# the header itself has no globals +# misc-include-cleaner noisy for a single umbrella header +# modernize-use-nodiscard 57 sites; annotating the API with +# [[nodiscard]] is a decision to make +# on purpose, not a lint fix +# modernize-use-trailing-return-type style the project does not use +# portability-avoid-pragma-once #pragma once is a deliberate choice +# readability-function-cognitive-* binary()/ternary() are inherently so +# readability-identifier-length i, j, f, g, da, daa are the notation +# readability-magic-numbers the constants are the formulas +# readability-math-missing-parentheses precedence is the notation as well +# readability-named-parameter unused parameters in tag types +Checks: > + bugprone-*, + clang-analyzer-*, + misc-*, + modernize-*, + performance-*, + portability-*, + readability-*, + -bugprone-branch-clone, + -bugprone-easily-swappable-parameters, + -bugprone-throwing-static-initialization, + -misc-include-cleaner, + -modernize-use-nodiscard, + -modernize-use-trailing-return-type, + -portability-avoid-pragma-once, + -readability-function-cognitive-complexity, + -readability-identifier-length, + -readability-magic-numbers, + -readability-math-missing-parentheses, + -readability-named-parameter + +# Only our own headers. Eigen, doctest and pybind11 are not ours to fix. +HeaderFilterRegex: 'include/hyperjet/.*\.h$' + +FormatStyle: file diff --git a/justfile b/justfile new file mode 100644 index 0000000..a30acae --- /dev/null +++ b/justfile @@ -0,0 +1,31 @@ +# Format all C++ sources in place +format: + uv run --only-group dev clang-format -i include/hyperjet/*.h python/src/*.h python/src/*.cpp test/src/*.cpp benchmark/src/*.cpp + +# Generate the compilation database that clang-tidy needs +compile-db: + #!/usr/bin/env bash + set -euo pipefail + # The test build is the right entry point: it instantiates the templates, and + # an uninstantiated template is never analysed. + args=(-Stest -Bbuild/tidy -DCMAKE_BUILD_TYPE=Debug + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON + -DCMAKE_POLICY_VERSION_MINIMUM=3.5) + # AppleClang knows the macOS SDK implicitly, the standalone clang-tidy does + # not, so the sysroot has to end up in the compilation database. + if [ "$(uname)" = Darwin ]; then + args+=("-DCMAKE_OSX_SYSROOT=$(xcrun --show-sdk-path)") + fi + cmake "${args[@]}" > /dev/null + +# One invocation for all units rather than run-clang-tidy.py: with only two of +# them the parallel driver is no faster, and it reports every finding in the +# header once per unit instead of once. + +# Run clang-tidy over the test translation units +tidy: compile-db + uv run --only-group tidy clang-tidy -p build/tidy --quiet test/src/*.cpp + +# Same, applying the fixes clang-tidy can make itself +tidy-fix: compile-db + uv run --only-group tidy clang-tidy -p build/tidy --quiet --fix test/src/*.cpp diff --git a/pyproject.toml b/pyproject.toml index b352e27..05499b1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,6 +33,9 @@ Repository = "https://github.com/oberbichler/HyperJet" [dependency-groups] dev = ["clang-format>=19.0", "ruff>=0.11"] +# Separate group: the clang-tidy wheel is ~44 MB against ~2 MB for +# clang-format, and the format CI job has no use for it. +tidy = ["clang-tidy>=19.0"] test = ["pytest>=8.0"] [tool.scikit-build] diff --git a/uv.lock b/uv.lock index fa16340..e93dae4 100644 --- a/uv.lock +++ b/uv.lock @@ -27,6 +27,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ce/2d/35c5301c6d04f4babf218ad9716c061abebb8a56a1bbad167a86dfe966d3/clang_format-22.1.5-py2.py3-none-win_arm64.whl", hash = "sha256:4f5ac3b91bb5700c43cb96beb32e360a5aa6a7f94105d7900054f6496554d9b9", size = 1344987, upload-time = "2026-05-06T13:12:20.88Z" }, ] +[[package]] +name = "clang-tidy" +version = "22.1.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/d0/f9dc63658854dc4508270daab0e10a34a61330d35c53cfe679b692e57560/clang_tidy-22.1.8.tar.gz", hash = "sha256:d81205d15cc82eea10e9e3b65e99732bb0bc77144535648a4a1f77d9cb4eda50", size = 11746, upload-time = "2026-07-14T10:30:19.551Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/14/27f6ed1ffdf3fcc53d4482a5f1292b39751c7426ca70deca8bb7d04f5dae/clang_tidy-22.1.8-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:04b6c97bcdc032763d0d924531def281acd0b5a939bcc79994cbf3c6fe83e1ae", size = 31672907, upload-time = "2026-07-14T10:29:37.701Z" }, + { url = "https://files.pythonhosted.org/packages/01/23/949977d4304e30eeef80206b37a9305084926ea06b99708961fcbf27913f/clang_tidy-22.1.8-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:916d7cbc9590e719459738fedc5ba76ac91f128d671390e574a0779014c84d73", size = 30823043, upload-time = "2026-07-14T10:29:41.887Z" }, + { url = "https://files.pythonhosted.org/packages/ac/b7/61ed8c319f2d9ddb9762a550a6fee434bdef7bdc46d5a4b50929f1c90ec0/clang_tidy-22.1.8-py2.py3-none-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1eaddaa7415e8c5e39aeefbfd15174f1ab2a671c86f7ebb200eb523cf9465559", size = 42155015, upload-time = "2026-07-14T10:29:45.608Z" }, + { url = "https://files.pythonhosted.org/packages/82/19/0f2668f8f5e2452b096a2b898f2b6bcecbceb6dd0c7f75d1755ce1f18d8b/clang_tidy-22.1.8-py2.py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a3de07ba82d4403d8b692ae63a5520d4db5c606014c92c24bbcef9259057bf1", size = 44070377, upload-time = "2026-07-14T10:29:49.58Z" }, + { url = "https://files.pythonhosted.org/packages/6c/61/7c0c87952090de362d18703a8a2206ae30129c811c66f9d01f4094d59e87/clang_tidy-22.1.8-py2.py3-none-manylinux_2_28_i686.whl", hash = "sha256:879a53cc5ba9824197f97e83bd86686f9c159da18afd004e8f6d161c985f9b31", size = 49709888, upload-time = "2026-07-14T10:29:53.323Z" }, + { url = "https://files.pythonhosted.org/packages/87/78/cbe472f8a2f29df7c982f1a3782f515059f3e1488c668c946ac04df79dab/clang_tidy-22.1.8-py2.py3-none-manylinux_2_31_armv7l.whl", hash = "sha256:79d109db0bc74c4f20253ea997f73eac4fa6ec26171fa08c05fb82dd3ee94bc1", size = 40445704, upload-time = "2026-07-14T10:29:57.312Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e0/be72d44c059a936af7d4b355d0c844e934d7f4c3c4eba578783d7fc486d2/clang_tidy-22.1.8-py2.py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:788200119549b80e3b3cc4c1ecc422b6bec6e2559ea2116494fe6c72092ec4c2", size = 41319020, upload-time = "2026-07-14T10:30:01.303Z" }, + { url = "https://files.pythonhosted.org/packages/97/34/223288ebf27f33b3842ab750ab5915ef3244f7802d4f7633dacf7a195ab2/clang_tidy-22.1.8-py2.py3-none-musllinux_1_2_i686.whl", hash = "sha256:8ad32751aa4697575fb34faabe70ee497aa32d31d4dfffe25f2655797dff1c2c", size = 51914038, upload-time = "2026-07-14T10:30:05.637Z" }, + { url = "https://files.pythonhosted.org/packages/8d/d1/a8019bfe6dcb103a081ffc0a869cb2b463a826e5005030d0abf211278b53/clang_tidy-22.1.8-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:19d11334f5f9af90a655e5ca46b1e472d44ec025a8d10fef95accb3ea19b8c60", size = 46732713, upload-time = "2026-07-14T10:30:10Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ad/6bb2c2a0a7255ca624dca7ee172678b215c62ce79891a487f8ccc90bc48b/clang_tidy-22.1.8-py2.py3-none-win32.whl", hash = "sha256:182dc0b73688add32cd02595d510c0b010f77a645774dbb04e296d347c1a014f", size = 23553468, upload-time = "2026-07-14T10:30:13.42Z" }, + { url = "https://files.pythonhosted.org/packages/54/af/0580f6145d8a0c218844208a6c90ce539a4bdf65a66b672e6b4604a81c0a/clang_tidy-22.1.8-py2.py3-none-win_amd64.whl", hash = "sha256:df9bf841ecbf501d08b6fa34523be840f59b1a76d16b6ee5edb0e5c7c22b59c2", size = 26666952, upload-time = "2026-07-14T10:30:16.843Z" }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -58,6 +77,9 @@ dev = [ test = [ { name = "pytest" }, ] +tidy = [ + { name = "clang-tidy" }, +] [package.metadata] requires-dist = [ @@ -73,6 +95,7 @@ dev = [ { name = "ruff", specifier = ">=0.11" }, ] test = [{ name = "pytest", specifier = ">=8.0" }] +tidy = [{ name = "clang-tidy", specifier = ">=19.0" }] [[package]] name = "iniconfig"