Skip to content

Commit de28509

Browse files
authored
🦺 Enable clang-tidy & pre-commit checks (#72)
* 🦺 Enable clang-tidy & pre-commit checks * fixup clang-tidy
1 parent 9172e20 commit de28509

11 files changed

Lines changed: 186 additions & 23 deletions

File tree

.clangd

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
CompileFlags:
22
CompilationDatabase: .
33
BuiltinHeaders: QueryDriver
4-

.github/workflows/ci.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,19 @@ concurrency:
2626
cancel-in-progress: true
2727

2828
jobs:
29+
pre-commit:
30+
name: 🧹 Lint
31+
runs-on: ubuntu-latest
32+
steps:
33+
- uses: actions/checkout@v4
34+
- uses: actions/setup-python@v5
35+
with:
36+
python-version: "3.12"
37+
- run: sudo apt-get install -y doxygen
38+
- uses: pre-commit/action@v3.0.1
39+
2940
package_and_upload_all_check:
41+
name: 🔎 Package Validation
3042
uses: libhal/ci/.github/workflows/package_and_upload_all.yml@5.x.y
3143
with:
3244
modules_support_needed: true

.pre-commit-config.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
repos:
2+
# General file fixes
3+
- repo: https://github.com/pre-commit/pre-commit-hooks
4+
rev: v4.5.0
5+
hooks:
6+
- id: end-of-file-fixer
7+
- id: trailing-whitespace
8+
- id: mixed-line-ending
9+
args: [--fix=lf]
10+
11+
# Spell checking
12+
- repo: https://github.com/streetsidesoftware/cspell-cli
13+
rev: v8.6.0
14+
hooks:
15+
- id: cspell
16+
files: \.(cpp|cppm|hpp|h|md)$
17+
18+
# C++ formatting with clang-format
19+
- repo: https://github.com/pre-commit/mirrors-clang-format
20+
rev: v21.1.8
21+
hooks:
22+
- id: clang-format
23+
types_or: [c, c++]
24+
files: \.(cpp|cppm|hpp|h|c)$
25+
26+
# Doxygen documentation checker
27+
- repo: local
28+
hooks:
29+
- id: doxygen-check
30+
name: doxygen-check
31+
entry: doxygen
32+
args: [docs/doxygen.conf]
33+
language: system
34+
pass_filenames: false
35+
files: \.(cpp|cppm|hpp|h)$

CMakeLists.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,30 @@ set(BUILD_UNIT_TESTS ON)
2323
set(RUN_UNIT_TESTS ON)
2424
set(BUILD_BENCHMARKS ON)
2525
set(RUN_BENCHMARKS OFF)
26+
set(USE_CLANG_TIDY ON)
2627

2728
project(async_context LANGUAGES CXX)
2829

30+
# ==============================================================================
31+
# Find clang-tidy
32+
# ==============================================================================
33+
34+
if(CMAKE_CROSSCOMPILING)
35+
message(STATUS "Cross compiling, skipping clang-tidy")
36+
else()
37+
if(USE_CLANG_TIDY)
38+
find_program(CLANG_TIDY_EXE NAMES clang-tidy)
39+
if(CLANG_TIDY_EXE)
40+
message(STATUS "Clang-tidy found: ${CLANG_TIDY_EXE}")
41+
set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_EXE};--config-file=${CMAKE_CURRENT_SOURCE_DIR}/.clang-tidy;--fix")
42+
else()
43+
message(STATUS "Clang-tidy not found - continuing without clang-tidy")
44+
endif()
45+
else()
46+
message(WARNING "Clang-tidy checks disabled")
47+
endif()
48+
endif()
49+
2950
# ==============================================================================
3051
# Library
3152
# ==============================================================================

benchmarks/benchmark.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,14 @@
3333
import async_context;
3434

3535
// Quick Bench: https://quick-bench.com/
36-
// Compiler flags: -std=c++23 -O3 -DNDEBUG
36+
// Compiler flags: -std=c++23 -O3 -D NDEBUG
3737

3838
// ============================================================================
3939
// BENCHMARKS
4040
// ============================================================================
4141

42+
// NOLINTBEGIN(clang-analyzer-deadcode.DeadStores)
43+
4244
// ----------------------------------------------------------------------------
4345
// 1. BASELINE: Direct returns, 3 levels deep
4446
// ----------------------------------------------------------------------------
@@ -477,4 +479,4 @@ static void bm_future_void_coroutine_context_resume(benchmark::State& state)
477479
BENCHMARK(bm_future_void_coroutine_context_resume);
478480

479481
BENCHMARK_MAIN();
480-
// NOLINTEND(readability-identifier-naming)
482+
// NOLINTEND(clang-analyzer-deadcode.DeadStores)

conanfile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class async_context_conan(ConanFile):
3333
description = ("Implementation of C++20 coroutines targeting embedded system by eliminating the usage of the global heap and providing a 'context' which contains a coroutine stack frame and other useful utilities for scheduling.")
3434
topics = ("async", "coroutines", "stack", "scheduling", "scheduler")
3535
settings = "compiler", "build_type", "os", "arch"
36-
exports_sources = "modules/*", "benchmarks/*", "tests/*", "CMakeLists.txt", "LICENSE"
36+
exports_sources = "modules/*", "benchmarks/*", "tests/*", "CMakeLists.txt", "LICENSE", ".clang-tidy"
3737
package_type = "static-library"
3838
shared = False
3939

cspell.json

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"version": "0.2",
3+
"language": "en",
4+
"words": [
5+
"cppm",
6+
"noexcept",
7+
"nullptr",
8+
"constexpr",
9+
"decltype",
10+
"typename",
11+
"templated",
12+
"allocator",
13+
"deallocate",
14+
"deallocator",
15+
"deallocating",
16+
"realloc",
17+
"inout",
18+
"libhal",
19+
"RAII",
20+
"dtor",
21+
"ctor",
22+
"ctors",
23+
"dtors",
24+
"intptr",
25+
"uintptr",
26+
"ptrdiff",
27+
"ifdef",
28+
"ifndef",
29+
"endif",
30+
"elif",
31+
"pragma",
32+
"nodiscard",
33+
"nothrow",
34+
"initializer",
35+
"uninitialised",
36+
"uninitialized",
37+
"Khalil",
38+
"Estell",
39+
"NOLINTNEXTLINE",
40+
"bugprone",
41+
"println",
42+
"cassert",
43+
"coro",
44+
"chrono",
45+
"EABI",
46+
"NDEBUG",
47+
"malloc",
48+
"uptr"
49+
],
50+
"ignorePaths": [
51+
"build/",
52+
"*.json",
53+
"*.bmi",
54+
"compile_commands.json"
55+
],
56+
"enableFiletypes": [
57+
"cpp",
58+
"c",
59+
"markdown"
60+
]
61+
}

docs/doxygen.conf

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Adapted from https://github.com/xtensor-stack/xtensor/blob/master/docs/Doxyfile
2+
PROJECT_NAME = "async_context"
3+
INPUT = ../modules
4+
FILE_PATTERNS = *.cppm *.hpp
5+
EXTRACT_STATIC = YES
6+
EXCLUDE_PATTERNS = */third_party/*
7+
HAVE_DOT = YES
8+
OUTPUT_DIRECTORY = build
9+
XML_OUTPUT = xml
10+
GENERATE_LATEX = NO
11+
GENERATE_MAN = NO
12+
GENERATE_RTF = NO
13+
CASE_SENSE_NAMES = NO
14+
GENERATE_HTML = NO
15+
GENERATE_XML = YES
16+
RECURSIVE = YES
17+
QUIET = YES
18+
PREDEFINED = IN_DOXYGEN
19+
EXCLUDE_SYMBOLS = detail
20+
GENERATE_TREEVIEW = YES
21+
SOURCE_BROWSER = YES
22+
WARN_IF_UNDOCUMENTED = YES

modules/async_context.cppm

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,7 +1591,7 @@ struct final_awaiter
15911591
* continuation of the calling coroutine.
15921592
*
15931593
* @param p_completing_coroutine The coroutine handle that is completing
1594-
* @return The coroutine handle to resume next, which is a symmetryic transfer
1594+
* @return The coroutine handle to resume next, which is a symmetric transfer
15951595
* from this completing coroutine to its continuation (what called it
15961596
* originally).
15971597
*/
@@ -1643,15 +1643,19 @@ struct promise_return_base
16431643
void return_value(U&& p_value) noexcept
16441644
requires std::is_constructible_v<T, U&&>
16451645
{
1646-
// set future to its awaited T value
1646+
// NOLINTBEGIN(clang-analyzer-core.CallAndMessage): clang-tidy incorrectly
1647+
// assumes this pointer is uninitialized. The promise is constructed from
1648+
// the future returned by `get_return_object()`, which properly initializes
1649+
// this promise.
16471650
m_future_state->template emplace<T>(std::forward<U>(p_value));
1651+
// NOLINTEND(clang-analyzer-core.CallAndMessage)
16481652
}
16491653

16501654
/**
16511655
* @brief Pointer to the future state that should be set at future<T>
16521656
* construction.
16531657
*/
1654-
future_state<T>* m_future_state;
1658+
future_state<T>* m_future_state = nullptr;
16551659
};
16561660

16571661
/**
@@ -1667,14 +1671,19 @@ struct promise_return_base<void>
16671671
*/
16681672
void return_void() noexcept
16691673
{
1674+
// NOLINTBEGIN(clang-analyzer-core.CallAndMessage): clang-tidy incorrectly
1675+
// assumes this pointer is uninitialized. The promise is constructed from
1676+
// the future returned by `get_return_object()`, which properly initializes
1677+
// this promise.
16701678
*m_future_state = std::monostate{};
1679+
// NOLINTEND(clang-analyzer-core.CallAndMessage)
16711680
}
16721681

16731682
/**
16741683
* @brief Pointer to the future state that should be set at future<void>
16751684
* construction.
16761685
*/
1677-
future_state<void>* m_future_state;
1686+
future_state<void>* m_future_state = nullptr;
16781687
};
16791688

16801689
/**

tests/cancel.test.cpp

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,22 +45,22 @@ boost::ut::suite<"cancellation_tests"> cancellation_tests = []() {
4545
};
4646

4747
{
48-
expect(that % count == counter_pair{ 0, 0 });
48+
expect(that % count == counter_pair{ .constructed = 0, .destructed = 0 });
4949
expect(that % ends_reached == 0);
5050

5151
auto future = c(ctx);
5252

53-
expect(that % count == counter_pair{ 0, 0 });
53+
expect(that % count == counter_pair{ .constructed = 0, .destructed = 0 });
5454
expect(that % ends_reached == 0);
5555

5656
future.resume();
5757

58-
expect(that % count == counter_pair{ 3, 0 });
58+
expect(that % count == counter_pair{ .constructed = 3, .destructed = 0 });
5959
expect(that % ends_reached == 0);
6060
expect(that % 0 < ctx.memory_used());
6161
} // destroy future
6262

63-
expect(that % count == counter_pair{ 3, 3 });
63+
expect(that % count == counter_pair{ .constructed = 3, .destructed = 3 });
6464
expect(that % ends_reached == 0);
6565
expect(that % 0 == ctx.memory_used());
6666
};
@@ -104,23 +104,23 @@ boost::ut::suite<"cancellation_tests"> cancellation_tests = []() {
104104
co_return;
105105
};
106106

107-
expect(that % count == counter_pair{ 0, 0 });
107+
expect(that % count == counter_pair{ .constructed = 0, .destructed = 0 });
108108
expect(that % ends_reached == 0);
109109

110110
auto future = c(ctx);
111111

112-
expect(that % count == counter_pair{ 0, 0 });
112+
expect(that % count == counter_pair{ .constructed = 0, .destructed = 0 });
113113
expect(that % ends_reached == 0);
114114

115115
future.resume();
116116

117-
expect(that % count == counter_pair{ 3, 0 });
117+
expect(that % count == counter_pair{ .constructed = 3, .destructed = 0 });
118118
expect(that % ends_reached == 0);
119119
expect(that % 0 < ctx.memory_used());
120120

121121
future.cancel();
122122

123-
expect(that % count == counter_pair{ 3, 3 });
123+
expect(that % count == counter_pair{ .constructed = 3, .destructed = 3 });
124124
expect(that % ends_reached == 0);
125125
expect(that % 0 == ctx.memory_used());
126126
};
@@ -164,25 +164,25 @@ boost::ut::suite<"cancellation_tests"> cancellation_tests = []() {
164164
co_return;
165165
};
166166

167-
expect(that % count == counter_pair{ 0, 0 });
167+
expect(that % count == counter_pair{ .constructed = 0, .destructed = 0 });
168168
expect(that % ends_reached == 0);
169169

170170
auto future = c(ctx);
171171

172-
expect(that % count == counter_pair{ 0, 0 });
172+
expect(that % count == counter_pair{ .constructed = 0, .destructed = 0 });
173173
expect(that % ends_reached == 0);
174174

175175
future.resume();
176176

177-
expect(that % count == counter_pair{ 3, 0 });
177+
expect(that % count == counter_pair{ .constructed = 3, .destructed = 0 });
178178
expect(that % ends_reached == 0);
179179
expect(that % 0 < ctx.memory_used());
180180
expect(that % false == future.has_value());
181181
expect(that % false == future.done());
182182

183183
ctx.cancel();
184184

185-
expect(that % count == counter_pair{ 3, 3 });
185+
expect(that % count == counter_pair{ .constructed = 3, .destructed = 3 });
186186
expect(that % ends_reached == 0);
187187
expect(that % 0 == ctx.memory_used());
188188
expect(that % false == future.has_value());
@@ -232,12 +232,12 @@ boost::ut::suite<"cancellation_tests"> cancellation_tests = []() {
232232
co_return;
233233
};
234234

235-
expect(that % count == counter_pair{ 0, 0 });
235+
expect(that % count == counter_pair{ .constructed = 0, .destructed = 0 });
236236
expect(that % ends_reached == 0);
237237

238238
auto future = c(ctx);
239239

240-
expect(that % count == counter_pair{ 0, 0 });
240+
expect(that % count == counter_pair{ .constructed = 0, .destructed = 0 });
241241
expect(that % ends_reached == 0);
242242

243243
std::println("Resume until future reaches suspension @ coroutine A");
@@ -247,7 +247,7 @@ boost::ut::suite<"cancellation_tests"> cancellation_tests = []() {
247247
<< "runtime_error exception was not thrown!";
248248
expect(that % future.done());
249249
expect(that % not future.has_value());
250-
expect(that % count == counter_pair{ 3, 3 });
250+
expect(that % count == counter_pair{ .constructed = 3, .destructed = 3 });
251251
expect(that % ends_reached == 0);
252252
expect(that % 0 == ctx.memory_used());
253253
};

0 commit comments

Comments
 (0)