Skip to content

Commit dfb77f1

Browse files
committed
ci: Use CodeChecker as static analysis tool
CodeChecker combines multiple static code analysis tools including `clang-sa`. It also provides the possibility to check against a baseline to report only newly introduced issues. Moreover it is simpler to use. It could eventually replace `clang-sa` completely in the pipeline.
1 parent 1f57c8e commit dfb77f1

File tree

7 files changed

+489
-2
lines changed

7 files changed

+489
-2
lines changed

.github/workflows/codechecker.yaml

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: CodeChecker
2+
3+
on: [push, pull_request]
4+
5+
concurrency:
6+
group: ${{ github.workflow }}-${{ github.ref }}
7+
cancel-in-progress: true
8+
9+
jobs:
10+
codechecker_static_analyzer:
11+
runs-on: ubuntu-24.04
12+
13+
steps:
14+
- name: Checkout code including full history and submodules
15+
uses: actions/checkout@v4
16+
with:
17+
submodules: true
18+
fetch-depth: 0
19+
20+
- name: Install CodeChecker
21+
run: |
22+
sudo apt-get update
23+
sudo apt-get install clang-tools-18 cmake cppcheck libcunit1-dev ninja-build
24+
pip3 install codechecker
25+
26+
- name: Run CodeChecker
27+
run: |
28+
tools/ci/run_ci.sh --run-build --run-code-checker --code-checker diff
29+
env:
30+
CC: clang-18
31+
32+
- name: Upload CodeChecker reports
33+
uses: actions/upload-artifact@v4
34+
with:
35+
name: CodeChecker Reports
36+
path: build-wakaama/code_checker_report/
37+
if-no-files-found: error
38+
if: failure()
39+
40+
- name: Create baseline for Upload
41+
run: |
42+
bash -x tools/ci/run_ci.sh --run-build --run-code-checker --code-checker baseline
43+
env:
44+
CC: clang-18
45+
if: failure()
46+
47+
- name: Upload CodeChecker baseline (for debugging)
48+
uses: actions/upload-artifact@v4
49+
with:
50+
name: CodeChecker Baseline
51+
path: tools/code_checker/reports.baseline
52+
if-no-files-found: error
53+
if: failure()
54+

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,12 @@ Wakaama provides a simple CLI library. It can be enabled with:
133133
- Unit testing: CUnit
134134

135135
On Ubuntu 24.04, used in CI, the dependencies can be installed as such:
136-
- `apt install build-essential clang-format clang-format-18 clang-tools-18 cmake gcovr git libcunit1-dev ninja-build python3-pip`
136+
- `apt install build-essential clang-format clang-format-18 clang-tools-18 cmake cppcheck gcovr git libcunit1-dev ninja-build python3-pip`
137137
- `pip3 install -r tools/requirements-compliance.txt`
138138

139139
For macOS the development dependencies can be installed as such:
140140

141-
`brew install automake clang-format cmake cunit gcc gitlint gnu-getopt make ninja`
141+
`brew install automake clang-format cmake cppcheck cunit gcc gitlint gnu-getopt make ninja`
142142

143143
### Code formatting
144144
#### C

doc/code_checker.rst

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Static Code analysis with CodeChecker
2+
3+
Wakaama uses [`CodeChecker`](https://codechecker.readthedocs.io/) for static code analysis.
4+
5+
It's possible to run `CodeChecker` in two different modes: `full` and `diff`
6+
7+
In `full` mode all found issues are reported. In `diff` mode only new issues are shown.
8+
9+
The `diff` mode compares found issues with a 'base line' and shows only newly found issues.
10+
11+
## Running `CodeChecker`
12+
13+
The `CodeChecker` is run as part of the CI GitHub Actions. But it can be run manually:
14+
15+
To show new issues:
16+
```
17+
tools/ci/run_ci.sh --run-build --run-code-checker --code-checker diff
18+
```
19+
20+
To show *all* issues:
21+
```
22+
tools/ci/run_ci.sh --run-build --run-code-checker --code-checker full
23+
```
24+
25+
Create new 'base line':
26+
```
27+
tools/ci/run_ci.sh --run-build --run-code-checker --code-checker baseline
28+
```

tools/ci/run_ci.sh

+72
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ OPT_SONARQUBE=""
3131
OPT_SOURCE_DIRECTORY="${REPO_ROOT_DIR}"
3232
OPT_BUILD_DIRECTORY="build-wakaama"
3333
OPT_TEST_COVERAGE_REPORT=""
34+
OPT_CODE_CHECKER="full"
3435
OPT_VERBOSE=0
3536
OPT_WRAPPER_CMD=""
3637
RUN_BUILD=0
@@ -41,6 +42,7 @@ RUN_GITLINT=0
4142
RUN_GIT_BLAME_IGNORE=0
4243
RUN_TESTS=0
4344
RUN_DOXYGEN=0
45+
RUN_CODE_CHECKER=0
4446

4547
HELP_MSG="usage: ${SCRIPT_NAME} <OPTIONS>...
4648
Runs build and test steps in CI.
@@ -72,6 +74,9 @@ Options:
7274
(WRAPPER: path to build-wrapper)
7375
--test-coverage REPORT Enable code coverage measurement, output REPORT
7476
(REPORT: xml html text none)
77+
--code-checker ACTION Run the CodeChecker code analyzer to create a baseline,
78+
do a full check or a PR check (show just difference to baseline)
79+
(TYPE: full, diff, baseline)
7580
-v, --verbose Verbose output
7681
-a, --all Run all steps required for a MR
7782
-h, --help Display this help and exit
@@ -85,6 +90,7 @@ Available steps (executed by --all):
8590
--run-build Build all targets
8691
--run-tests Execute tests (works only for top level project)
8792
--run-doxygen Build the Doxygen documentation of the code
93+
--run-code-checker Run the CodeChecker code analyzer
8894
"
8995

9096
function usage() {
@@ -229,6 +235,46 @@ function run_doxygen() {
229235
GIT_REVISION=$(git rev-parse @) WORKING_DIR=$(pwd) DOXYGEN_OUT_DIR=build-wakaama/doxygen \
230236
doxygen doc/doxygen/Doxyfile
231237
}
238+
239+
function run_code_checker() {
240+
readonly config_file="${REPO_ROOT_DIR}/tools/code_checker/config.json"
241+
readonly ignore_file="${REPO_ROOT_DIR}/tools/code_checker/ignore.txt"
242+
readonly baseline_file="${REPO_ROOT_DIR}/tools/code_checker/reports.baseline"
243+
readonly code_checker_result_dir="build-wakaama/code_checker_result/"
244+
readonly code_checker_report="build-wakaama/code_checker_report/"
245+
246+
set +e +o pipefail
247+
CodeChecker check --logfile build-wakaama/compile_commands.json \
248+
--config "$config_file" \
249+
--ignore "$ignore_file" \
250+
--output $code_checker_result_dir \
251+
|| true # Currently failing with found issues
252+
set -e -o pipefail
253+
254+
if [ "${OPT_CODE_CHECKER}" = "diff" ]; then
255+
CodeChecker cmd diff -b "$baseline_file" \
256+
-n $code_checker_result_dir \
257+
-o html \
258+
--export "${code_checker_report}" \
259+
--new
260+
else
261+
if [ "${OPT_CODE_CHECKER}" = "baseline" ]; then
262+
output_format="baseline"
263+
output_location="$baseline_file"
264+
else
265+
output_format="html"
266+
output_location="$code_checker_report"
267+
fi
268+
269+
CodeChecker parse -e "$output_format" \
270+
-o "$output_location" \
271+
--config "$config_file" \
272+
--ignore "$ignore_file" \
273+
--trim-path-prefix="${REPO_ROOT_DIR}" \
274+
"$code_checker_result_dir"
275+
fi
276+
}
277+
232278
# Parse Options
233279

234280
if [[ "$OSTYPE" == "darwin"* ]]; then
@@ -260,12 +306,14 @@ if ! PARSED_OPTS=$($getopt -o vah \
260306
-l run-git-blame-ignore \
261307
-l run-tests \
262308
-l run-doxygen \
309+
-l run-code-checker \
263310
-l sanitizer: \
264311
-l scan-build: \
265312
-l sonarqube: \
266313
-l source-directory: \
267314
-l build-directory: \
268315
-l test-coverage: \
316+
-l code-checker: \
269317
-l verbose \
270318
--name "${SCRIPT_NAME}" -- "$@");
271319
then
@@ -328,6 +376,12 @@ while true; do
328376
RUN_DOXYGEN=1
329377
shift
330378
;;
379+
--run-code-checker)
380+
RUN_CODE_CHECKER=1
381+
# Analyzing works only when code gets actually built
382+
RUN_CLEAN=1
383+
shift
384+
;;
331385
--sanitizer)
332386
OPT_SANITIZER=$2
333387
shift 2
@@ -356,6 +410,10 @@ while true; do
356410
OPT_TEST_COVERAGE_REPORT=$2
357411
shift 2
358412
;;
413+
--code-checker)
414+
OPT_CODE_CHECKER=$2
415+
shift 2
416+
;;
359417
--)
360418
shift
361419
break
@@ -411,6 +469,11 @@ if [ -n "${OPT_SCAN_BUILD}" ] && [ -n "${OPT_SONARQUBE}" ]; then
411469
exit 1
412470
fi
413471

472+
if [ "${RUN_CODE_CHECKER}" = "1" ] && [ -n "${OPT_SONARQUBE}" ]; then
473+
echo "--sonarqube and --code-checker can not be enabled at the same time"
474+
exit 1
475+
fi
476+
414477
if [ -n "${OPT_SONARQUBE}" ]; then
415478
OPT_TEST_COVERAGE_REPORT="${OPT_TEST_COVERAGE_REPORT:-none}"
416479
OPT_WRAPPER_CMD="${OPT_SONARQUBE} \
@@ -431,6 +494,10 @@ if [ -n "${OPT_SCAN_BUILD}" ]; then
431494
--exclude examples/shared/tinydtls"
432495
fi
433496

497+
if [ "${RUN_CODE_CHECKER}" = "1" ]; then
498+
CMAKE_ARGS="${CMAKE_ARGS} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug"
499+
fi
500+
434501
# Run Steps
435502

436503
if [ "${RUN_GITLINT}" -eq 1 ]; then
@@ -464,3 +531,8 @@ fi
464531
if [ "${RUN_DOXYGEN}" -eq 1 ]; then
465532
run_doxygen
466533
fi
534+
535+
if [ "${RUN_CODE_CHECKER}" = "1" ]; then
536+
run_code_checker
537+
fi
538+

tools/code_checker/config.json

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"analyze": [
3+
"--disable=cplusplus",
4+
"--disable=cppcheck-exceptDeallocThrow",
5+
"--disable=cppcheck-exceptThrowInDestructor",
6+
"--disable=cppcheck-leakUnsafeArgAlloc",
7+
"--disable=cppcheck-rethrowNoCurrentException",
8+
"--disable=cppcheck-thisSubtraction",
9+
"--disable=cppcheck-throwInNoexceptFunction",
10+
"--clean"
11+
]
12+
}

tools/code_checker/ignore.txt

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-*/transport/tinydtls/third_party/*
2+
-*/tests/*

0 commit comments

Comments
 (0)