Skip to content

Commit 4e4c0e4

Browse files
committed
Add clang-tidy to pre-commit
1 parent 20a4aee commit 4e4c0e4

22 files changed

Lines changed: 291 additions & 80 deletions

‎.clang-tidy‎

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
# Layout is clang-format's job (see .clang-format), so clang-tidy does no
6+
# formatting of its own (FormatStyle: none below). Each enabled check is meant
7+
# to be adoptable on its own, so findings can be fixed one check at a time.
8+
#
9+
# Checks are opt-in (-*) by group, minus the ones below. They cannot be
10+
# commented inline because Checks is a single YAML string.
11+
#
12+
# Disabled because they conflict with the C-style CUDA driver API idioms:
13+
# bugprone-easily-swappable-parameters: wrappers of driver calls take many
14+
# adjacent parameters of the same type; the signatures mirror the API.
15+
# bugprone-assignment-in-if-condition: `if (CUDA_SUCCESS != (err = CALL(...)))`
16+
# is the standard error-handling pattern here.
17+
# performance-no-int-to-ptr: opaque handles and file descriptors are
18+
# converted to pointers with reinterpret_cast on purpose.
19+
# modernize-avoid-c-arrays: arrays are passed to and filled by C APIs.
20+
# modernize-return-braced-init-list: `return {};` vs. an explicit type is
21+
# left to the author; it adds noise for the driver-API result structs.
22+
#
23+
# Disabled because they do not match the codebase style:
24+
# performance-enum-size: enum underlying types are left as they are.
25+
# misc-const-correctness: const on every local is not the convention here.
26+
# readability-function-cognitive-complexity: a metric threshold, not a defect;
27+
# it flags only ensure_fn_table, which is flat error handling.
28+
# readability-identifier-length: short names such as the handle parameter `h`
29+
# are used throughout.
30+
# readability-implicit-bool-conversion: `if (ptr)` and `if (handle)` are the
31+
# idiom for pointers and handles.
32+
# misc-include-cleaner: too noisy with the CUDA and CPython umbrella headers.
33+
# misc-no-recursion: recursion is used deliberately.
34+
# misc-use-anonymous-namespace: file-local functions use `static`.
35+
# modernize-use-trailing-return-type: the code uses `Type\nname()` layout.
36+
Checks: >
37+
-*,
38+
bugprone-*,
39+
-bugprone-easily-swappable-parameters,
40+
-bugprone-assignment-in-if-condition,
41+
clang-analyzer-*,
42+
misc-*,
43+
-misc-include-cleaner,
44+
-misc-const-correctness,
45+
-misc-no-recursion,
46+
-misc-use-anonymous-namespace,
47+
modernize-*,
48+
-modernize-use-trailing-return-type,
49+
-modernize-avoid-c-arrays,
50+
-modernize-return-braced-init-list,
51+
performance-*,
52+
-performance-enum-size,
53+
-performance-no-int-to-ptr,
54+
readability-*,
55+
-readability-function-cognitive-complexity,
56+
-readability-identifier-length,
57+
-readability-implicit-bool-conversion
58+
FormatStyle: none
59+
CheckOptions:
60+
# Records whose members are all public (the *Box and guard structs) are plain
61+
# data holders; only a mix of public and private members is flagged.
62+
misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic: true
63+
WarningsAsErrors: '*'
64+
# Only report diagnostics for our own headers, not CUDA/CPython/libstdc++.
65+
HeaderFilterRegex: 'cuda_core/cuda/core/_(cpp|include)/'
66+
ExcludeHeaderFilterRegex: 'cuda_core/cuda/core/_include/(dlpack|aoti_shim)\.h'

‎.pre-commit-config.yaml‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ repos:
4141

4242
- repo: local
4343
hooks:
44+
# cuda.h and nvrtc.h come from pinned nvidia-cuda-* wheels, so no local CUDA Toolkit is needed.
45+
- id: clang-tidy
46+
name: clang-tidy
47+
entry: python ./toolshed/run_clang_tidy.py --cuda-wheel
48+
language: python
49+
files: ^cuda_core/cuda/core/_cpp/.*\.cpp$
50+
additional_dependencies: [clang-tidy==22.1.8, nvidia-cuda-runtime==13.4.92, nvidia-cuda-nvrtc==13.4.92]
51+
4452
- id: check-precommit-installed
4553
name: Warn if the pre-commit git hook is not installed
4654
entry: python ./toolshed/check_precommit_installed.py

‎CONTRIBUTING.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Thank you for your interest in contributing to CUDA Python! Based on the type of
3232
- [Review Guidance](#review-guidance)
3333
- [Pull Request Reviews](#pull-request-reviews)
3434
- [Pixi lockfiles](#pixi-lockfiles)
35+
- [Secret Scanning](#secret-scanning)
3536
- [Signing Your Work](#signing-your-work)
3637
- [Code signing](#code-signing)
3738
- [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco)
@@ -247,6 +248,12 @@ hook environment, so no system-wide installation is required. Vendored code
247248
`.pre-commit-config.yaml`. To format in your editor, install the same version
248249
with `pip install clang-format==23.1.3`.
249250

251+
`cuda_core`'s C++ sources are also checked with `clang-tidy`, configured by
252+
[`.clang-tidy`](.clang-tidy). To apply automatic fixes, run the script directly
253+
with clang-tidy's `--fix` option (without `--cuda-wheel` it uses `CUDA_PATH` or
254+
`CUDA_HOME`) and then run clang-format on the result: `python
255+
toolshed/run_clang_tidy.py --fix <files>`.
256+
250257
## CodeRabbit
251258

252259
This section explains how to use CodeRabbit for CUDA Python pull request review.

‎cuda_core/cuda/core/_cpp/rt/context.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,15 +125,15 @@ struct GreenCtxBox {
125125
CUgreenCtx resource;
126126
};
127127

128-
static const ContextBox *
128+
const ContextBox *
129129
get_box(const ContextHandle &h) noexcept
130130
{
131131
const CUcontext *p = h.get();
132132
return reinterpret_cast<const ContextBox *>(reinterpret_cast<const char *>(p) - offsetof(ContextBox, resource));
133133
}
134134

135135
// See REGISTRY_DESIGN.md (Level 1: Driver Handle -> Resource Handle)
136-
static HandleRegistry<CUcontext, ContextHandle> context_registry;
136+
HandleRegistry<CUcontext, ContextHandle> context_registry;
137137

138138
// Create a context handle reference, with optional green context as source.
139139
ContextHandle

‎cuda_core/cuda/core/_cpp/rt/context_scope.hpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ cleanup_in_context(
126126
}
127127
std::invoke(std::forward<AfterCleanup>(after_cleanup));
128128
if (status != CUDA_SUCCESS || restore != CUDA_SUCCESS) {
129-
char operation_name[160];
129+
char operation_name[kOperationNameSize];
130130
format_operation(operation_name, sizeof(operation_name), name, handle);
131131
if (status != CUDA_SUCCESS) {
132132
report_cuda_error(operation_name, status, detail);

‎cuda_core/cuda/core/_cpp/rt/driver_api.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
namespace cuda_core::rt {
1010

1111
// The pointers. Null until ensure_fn_table() fills the table. See driver_api.hpp.
12-
#define CUDA_CORE_DEFINE_DRIVER_FN(name, introduced) decltype(&name) p_##name = nullptr;
12+
#define CUDA_CORE_DEFINE_DRIVER_FN(name, introduced) decltype(&(name)) p_##name = nullptr;
1313
CUDA_CORE_DRIVER_FUNCTIONS(CUDA_CORE_DEFINE_DRIVER_FN)
1414
#undef CUDA_CORE_DEFINE_DRIVER_FN
1515

‎cuda_core/cuda/core/_cpp/rt/driver_api.hpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ namespace cuda_core::rt {
141141
X(cuStreamIsCapturing, 10000) \
142142
X(cuThreadExchangeStreamCaptureMode, 10010)
143143

144-
#define CUDA_CORE_DECLARE_DRIVER_FN(name, introduced) extern decltype(&name) p_##name;
144+
#define CUDA_CORE_DECLARE_DRIVER_FN(name, introduced) extern decltype(&(name)) p_##name;
145145
CUDA_CORE_DRIVER_FUNCTIONS(CUDA_CORE_DECLARE_DRIVER_FN)
146146
#undef CUDA_CORE_DECLARE_DRIVER_FN
147147

@@ -229,7 +229,7 @@ struct Unavailable;
229229
template <class R, class... A>
230230
struct Unavailable<R (*)(A...)> {
231231
static R
232-
call(A...) noexcept
232+
call(A... /*unused*/) noexcept
233233
{
234234
return UnavailableStatus<R>::value;
235235
}

‎cuda_core/cuda/core/_cpp/rt/error.cpp‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ namespace {
2727
// Thread-local detail attached to the next raised CUDAError with a matching
2828
// status (see take_last_error_detail()). Written only by propagating helpers.
2929
// The taken copy stays valid until the next take on the same thread.
30-
thread_local char last_error_detail[512] = {0};
31-
thread_local char taken_error_detail[512] = {0};
30+
thread_local char last_error_detail[kErrorMessageSize] = {0};
31+
thread_local char taken_error_detail[kErrorMessageSize] = {0};
3232
thread_local CUresult last_error_detail_status = CUDA_SUCCESS;
3333
} // namespace
3434

@@ -66,7 +66,7 @@ format_operation(char *buffer, size_t size, const char *operation, unsigned long
6666
void
6767
report_status_code(const char *operation, long code) noexcept
6868
{
69-
char message[256];
69+
char message[kErrorMessageSize];
7070
std::snprintf(message, sizeof(message), "%s failed (status %ld)", operation, code);
7171
report_message(message);
7272
}
@@ -80,7 +80,7 @@ report_cuda_error(const char *operation, CUresult status, const char *detail) no
8080
if (status == CUDA_SUCCESS || status == CUDA_ERROR_DEINITIALIZED) {
8181
return;
8282
}
83-
char message[512];
83+
char message[kErrorMessageSize];
8484
format_cuda_error(message, sizeof(message), operation, status, detail);
8585
report_message(message);
8686
}
@@ -122,7 +122,7 @@ note_context_not_restored(CUcontext previous, CUresult operation_status, CUresul
122122
if (DRIVER_CALL(cuCtxGetCurrent, &current) != CUDA_SUCCESS) {
123123
current = nullptr;
124124
}
125-
char cause[128] = {0};
125+
char cause[kErrorMessageSize] = {0};
126126
if (operation_status != CUDA_SUCCESS) {
127127
const char *error_name = nullptr;
128128
if (DRIVER_CALL(cuGetErrorName, restore_status, &error_name) == CUDA_SUCCESS) {

‎cuda_core/cuda/core/_cpp/rt/error.hpp‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,17 @@
55
#pragma once
66

77
#include <cuda.h>
8+
#include <cstddef>
89

910
namespace cuda_core::rt {
1011

12+
// Sizes of the stack buffers that format error text. Messages are truncated by
13+
// snprintf, never overrun.
14+
constexpr std::size_t kOperationNameSize = 160; // "<call> (handle 0x...)" from format_operation()
15+
constexpr std::size_t kErrorMessageSize = 512; // a full error message or error detail
16+
// A message that embeds one error message after some fixed text.
17+
constexpr std::size_t kNestedMessageSize = kErrorMessageSize + (kErrorMessageSize / 2);
18+
1119
// ============================================================================
1220
// Thread-local error handling
1321
// ============================================================================

‎cuda_core/cuda/core/_cpp/rt/graph.cpp‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ struct GraphHierarchy {
106106

107107
// See REGISTRY_DESIGN.md (Level 1: Driver Handle -> Resource Handle)
108108
using GraphRegistry = HandleRegistry<CUgraph, GraphHandle>;
109-
static GraphRegistry graph_registry;
109+
GraphRegistry graph_registry;
110110

111111
// Immutable resource owners for one version of a graph node's parameters.
112112
// Inheriting DeferredCleanupItem lets CUDA's user-object destructor enqueue
@@ -140,7 +140,7 @@ free_deleter(const void *p) noexcept
140140
GraphBox *
141141
get_box(const GraphHandle &h) noexcept
142142
{
143-
auto *value = reinterpret_cast<const GraphBoxBase *>(h.get());
143+
const auto *value = reinterpret_cast<const GraphBoxBase *>(h.get());
144144
return const_cast<GraphBox *>(static_cast<const GraphBox *>(value));
145145
}
146146

@@ -254,7 +254,7 @@ struct PreparedAttachmentState {
254254
explicit PreparedAttachmentState(GraphHandle h_graph_) : h_graph(std::move(h_graph_)) {}
255255
};
256256

257-
void
257+
static void
258258
rollback_prepared_attachment(PreparedAttachmentState *state) noexcept
259259
{
260260
if (!state) {
@@ -389,7 +389,7 @@ graph_prepare_child_graph_update(
389389
return CUDA_SUCCESS;
390390
}
391391

392-
void
392+
static void
393393
publish_child_graph_update(PreparedChildGraphUpdateState &state, GraphHandle *out_child)
394394
{
395395
GraphBox *parent = get_box(state.h_parent);

0 commit comments

Comments
 (0)