Share a clang-tidy report

clang-tidy finds the defects that matter in modern C++ — use-after-move, dangling references, the whole bugprone- family — and reports them the way a compiler does: as text, in a terminal, in whatever order the files were analysed.

On a real codebase that is several thousand lines of output, which means nobody triages it, which means the checks get disabled one by one until the tool runs and reports nothing. The output format is doing most of the damage.

Get HTML out of it

clang-tidy has no HTML writer. CodeChecker does, and it consumes clang-tidy and the Clang Static Analyzer together:

# 1. capture the exact compile commands
CodeChecker log -b "make -j$(nproc)" -o compile_commands.json

# 2. analyse
CodeChecker analyze compile_commands.json -o ./reports \
  --analyzers clang-tidy clangsa

# 3. render
CodeChecker parse -e html -o ./reports_html ./reports
reports_html/
├── index.html         # every finding, filterable by checker and severity
├── *.c.*.html         # source with the diagnostic path stepped through
└── static/

The stepped-through path is the part that cannot survive a terminal. A use-after-move report is an argument across four locations, and reading it as four line numbers is nothing like reading it as a highlighted trail through the source.

If CMake is already building the project, -DCMAKE_EXPORT_COMPILE_COMMANDS=ON gives you step 1 for free.

Publish the folder

Drag reports_html/ (or a zip of it) into Comma:

  • index.html becomes the report body — the filterable finding list.
  • Per-file pages and static/ upload alongside it, with relative references rewritten to the uploaded copies, so the drill-down into a diagnostic path works.
  • Scripts run inside a sandboxed iframe (allow-scripts, no allow-same-origin), so the checker filters and severity toggles keep working.

From CI

CodeChecker parse -e html -o ./reports_html ./reports || true

curl -fsS -X PATCH "https://commareports.com/api/v1/reports/$REPORT_ID" \
  -H "Authorization: Bearer $COMMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile html reports_html/index.html \
        --arg t "clang-tidy — $(git rev-parse --short HEAD)" \
        '{title: $t, html: $html}')"

CodeChecker parse exits non-zero when there are findings, so || true keeps the publish step alive on exactly the runs worth publishing. Supporting pages go up through POST /api/v1/reports/$REPORT_ID/assets as base64 — see the API reference and publishing from CI.

Triage where the trail is

The reason clang-tidy adoption dies is that suppression decisions are invisible. Someone judges a finding a false positive, adds a NOLINT, and the reasoning lives in a commit message nobody reads. The next person sees an unexplained NOLINT and either deletes it or copies the pattern.

A comment anchored to the rendered diagnostic — "the analyser can't see that release() nulls the pointer" — is the reasoning, attached to the evidence. See commenting on HTML, and revisions for watching the count across releases at one URL.

Who can see it

Per report: private, your team, anyone signed in at your domain, or anyone with the link. Analyser output contains source and points at memory-safety defects — restrict it. See sharing & access control.

Limits

  • Entry HTML: 5 MB. Assets: 25 MB per file, 250 MB and 500 files total. A whole-project run can exceed 500 pages — analyse per component.
  • Scripts run, sandboxed — no same-origin access.
  • 60 requests/minute per token.

Try it

Comma is free — unlimited reports, unlimited commenters, unlimited revision history.

Publish an analysis report →

Related