Skip to content

Commit a39311f

Browse files
committed
feat(lint): add clang-tidy static analysis configuration
Add clang-tidy setup for detecting bugs, style issues, and code smells: - .clang-tidy: enable bugprone, cert, clang-analyzer, performance, portability, and readability checks with sensible exclusions - scripts/clang-tidy.sh: wrapper script that auto-generates compile_commands.json via bear if needed
1 parent 45f09c1 commit a39311f

File tree

2 files changed

+157
-0
lines changed

2 files changed

+157
-0
lines changed

.clang-tidy

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
---
2+
# clang-tidy configuration for sqlite-vec
3+
# See: https://clang.llvm.org/extra/clang-tidy/
4+
5+
Checks: >
6+
-*,
7+
bugprone-*,
8+
cert-*,
9+
clang-analyzer-*,
10+
concurrency-*,
11+
misc-*,
12+
performance-*,
13+
portability-*,
14+
readability-*,
15+
-readability-identifier-length,
16+
-readability-magic-numbers,
17+
-readability-function-cognitive-complexity,
18+
-misc-no-recursion,
19+
-cert-dcl37-c,
20+
-cert-dcl51-cpp,
21+
-readability-isolate-declaration,
22+
-readability-identifier-naming,
23+
-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling
24+
25+
# Don't treat warnings as errors (informational only)
26+
WarningsAsErrors: ''
27+
28+
# Header filter (analyze headers in this project)
29+
HeaderFilterRegex: '.*sqlite-vec\.h'
30+
31+
# Check options
32+
CheckOptions:
33+
- key: readability-identifier-naming.FunctionCase
34+
value: lower_case
35+
- key: readability-identifier-naming.VariableCase
36+
value: lower_case
37+
- key: readability-identifier-naming.ParameterCase
38+
value: lower_case
39+
- key: readability-function-size.LineThreshold
40+
value: '200'
41+
- key: readability-function-size.StatementThreshold
42+
value: '150'
43+
- key: cppcoreguidelines-avoid-do-while.IgnoreMacros
44+
value: 'true'

scripts/clang-tidy.sh

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#!/bin/bash
2+
#
3+
# clang-tidy static analysis for sqlite-vec
4+
# Detects potential bugs, style issues, and code smells
5+
#
6+
# Usage: ./scripts/clang-tidy.sh
7+
# Or: make lint-clang-tidy
8+
9+
set -euo pipefail
10+
11+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
12+
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
13+
14+
# Colors for output
15+
RED='\033[0;31m'
16+
GREEN='\033[0;32m'
17+
YELLOW='\033[1;33m'
18+
BLUE='\033[0;34m'
19+
NC='\033[0m' # No Color
20+
21+
echo -e "${BLUE}=== clang-tidy Static Analysis ===${NC}"
22+
23+
# Check if clang-tidy is available
24+
if ! command -v clang-tidy &>/dev/null; then
25+
echo -e "${YELLOW}Warning: clang-tidy not found.${NC}"
26+
echo "Install with:"
27+
echo " Linux: sudo apt-get install clang-tidy"
28+
echo " macOS: brew install llvm"
29+
exit 0
30+
fi
31+
32+
echo "Using: $(clang-tidy --version | head -1)"
33+
34+
# Check if compile_commands.json exists
35+
if [ ! -f "$ROOT_DIR/compile_commands.json" ]; then
36+
echo -e "${YELLOW}compile_commands.json not found. Generating with bear...${NC}"
37+
38+
# Check if bear is available
39+
if ! command -v bear &>/dev/null; then
40+
echo -e "${YELLOW}Warning: bear not found. Install with:${NC}"
41+
echo " Linux: sudo apt-get install bear"
42+
echo " macOS: brew install bear"
43+
echo ""
44+
echo -e "${YELLOW}Running clang-tidy without compile_commands.json (less accurate)${NC}"
45+
else
46+
# Generate compile_commands.json
47+
echo "Generating compile_commands.json with bear..."
48+
cd "$ROOT_DIR"
49+
if bear -- make clean all >/dev/null 2>&1; then
50+
echo -e "${GREEN}Generated compile_commands.json${NC}"
51+
else
52+
echo -e "${YELLOW}Failed to generate compile_commands.json, continuing without it${NC}"
53+
rm -f "$ROOT_DIR/compile_commands.json"
54+
fi
55+
fi
56+
fi
57+
58+
# Output file
59+
OUTPUT_FILE="$ROOT_DIR/clang-tidy-output.txt"
60+
rm -f "$OUTPUT_FILE"
61+
62+
# Run clang-tidy
63+
set +e
64+
if [ -f "$ROOT_DIR/compile_commands.json" ]; then
65+
clang-tidy \
66+
-p="$ROOT_DIR" \
67+
"$ROOT_DIR/sqlite-vec.c" \
68+
2>&1 | tee "$OUTPUT_FILE"
69+
TIDY_EXIT=${PIPESTATUS[0]}
70+
else
71+
# Fallback: run without compile_commands.json
72+
clang-tidy \
73+
"$ROOT_DIR/sqlite-vec.c" \
74+
-- \
75+
-I"$ROOT_DIR/vendor/" \
76+
-DSQLITE_CORE \
77+
-DSQLITE_VEC_STATIC \
78+
2>&1 | tee "$OUTPUT_FILE"
79+
TIDY_EXIT=${PIPESTATUS[0]}
80+
fi
81+
set -e
82+
83+
echo ""
84+
85+
# Count warnings and errors
86+
WARNING_COUNT=$(grep -c "warning:" "$OUTPUT_FILE" 2>/dev/null || echo "0")
87+
ERROR_COUNT=$(grep -c "error:" "$OUTPUT_FILE" 2>/dev/null || echo "0")
88+
89+
echo -e "${BLUE}=== clang-tidy Summary ===${NC}"
90+
echo " Warnings: $WARNING_COUNT"
91+
echo " Errors: $ERROR_COUNT"
92+
93+
if [[ "$WARNING_COUNT" -eq 0 && "$ERROR_COUNT" -eq 0 ]]; then
94+
echo -e "\n${GREEN}PASS: No issues found by clang-tidy${NC}"
95+
rm -f "$OUTPUT_FILE"
96+
exit 0
97+
else
98+
echo -e "\n${YELLOW}Issues found. See $OUTPUT_FILE for details.${NC}"
99+
100+
# Show top issues
101+
if [[ "$WARNING_COUNT" -gt 0 ]]; then
102+
echo -e "\n${YELLOW}Top warnings:${NC}"
103+
grep "warning:" "$OUTPUT_FILE" | head -10
104+
fi
105+
106+
if [[ "$ERROR_COUNT" -gt 0 ]]; then
107+
echo -e "\n${RED}Errors:${NC}"
108+
grep "error:" "$OUTPUT_FILE" | head -10
109+
fi
110+
111+
# Don't fail the build for clang-tidy warnings (informational only)
112+
exit 0
113+
fi

0 commit comments

Comments
 (0)