Skip to content

clang-tidy: resolve readability-braces-around-statements#762

Open
knoepfel wants to merge 2 commits into
Framework-R-D:mainfrom
knoepfel:readability-braces-around-statements
Open

clang-tidy: resolve readability-braces-around-statements#762
knoepfel wants to merge 2 commits into
Framework-R-D:mainfrom
knoepfel:readability-braces-around-statements

Conversation

@knoepfel

@knoepfel knoepfel commented Jul 23, 2026

Copy link
Copy Markdown
Member

Resolve readability-braces-around-statements clang-tidy warnings.

  • Code quality: Resolved readability-braces-around-statements clang-tidy warnings across form, storage, plugin, and test code by adding explicit braces to conditional and loop bodies.
  • Python bindings: Improved callback, validation, annotation, registration, and initialization error handling, including safer Python error propagation, cleanup, null checks, and void return handling.
  • Documentation: Marked the clang-tidy issue as resolved and recorded PR #762.
  • Tests: Updated test and utility loops/guards to use braced blocks without changing test behavior.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This change applies clang-tidy brace fixes across core, storage, Python, and test code. It also makes several Python callback and validation error paths explicit, updates interpreter setup guards, and marks the corresponding documentation checklist item complete.

Changes

Braced control flow and Python error handling

Layer / File(s) Summary
Core and storage control-flow bracing
docs/dev/clang-tidy-fixes-2026-04.md, form/..., phlex/app/..., phlex/model/...
Selected early returns and attribute-setting loops use explicit braces, and the resolved clang-tidy item is marked complete.
Python wrapper dispatch bracing
plugins/python/src/configwrap.cpp, plugins/python/src/dyncall.cpp, plugins/python/src/errorwrap.cpp, plugins/python/src/lifelinewrap.cpp
Wrapper guards and dispatch branches use braced blocks while preserving existing behavior.
Python module error-path handling
plugins/python/src/modulewrap.cpp, plugins/python/src/pymodule.cpp
Callback cleanup, Python error propagation, validation failures, annotation conversion, registration, and initialization paths add explicit checks and return handling.
Test loop and guard bracing
test/form/...
Test output loops, checksum accumulation, vector generation, and failure paths use explicit blocks without changing results.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: aolivier23

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.90% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: fixing clang-tidy readability-braces-around-statements warnings.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/python/src/modulewrap.cpp`:
- Around line 407-422: Update the _sig annotation-processing path to validate
each annotation_as_text result before adding it to the signature types or
setting conversion_ok. After processing ret and args, check PyErr_Occurred()
alongside the returned strings; on any normalization error, return false before
populating signature types, while preserving successful handling of valid empty
strings.
- Around line 413-422: In the normalization path using norm, copy the UTF-8
contents into an owning std::string before decrementing norm. Keep norm alive
through the copy, then release it and return the copied value; preserve the
existing empty-result handling when normalization or UTF-8 conversion fails.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5a41259e-e96d-479a-a39a-19d168ec2501

📥 Commits

Reviewing files that changed from the base of the PR and between 70ca87e and 01e2d2e.

📒 Files selected for processing (21)
  • docs/dev/clang-tidy-fixes-2026-04.md
  • form/form/config.cpp
  • form/form/form_writer.cpp
  • form/persistence/persistence_utils.cpp
  • form/storage/storage_reader.cpp
  • form/storage/storage_writer.cpp
  • phlex/app/load_module.cpp
  • phlex/model/data_cell_index.cpp
  • plugins/python/src/configwrap.cpp
  • plugins/python/src/dyncall.cpp
  • plugins/python/src/errorwrap.cpp
  • plugins/python/src/lifelinewrap.cpp
  • plugins/python/src/modulewrap.cpp
  • plugins/python/src/pymodule.cpp
  • test/form/form_root_schema_read_test.cpp
  • test/form/form_root_schema_write_test.cpp
  • test/form/form_storage_test.cpp
  • test/form/generate_vector.cpp
  • test/form/reader.cpp
  • test/form/test_utils.hpp
  • test/form/writer.cpp
📜 Review details
⏰ Context from checks skipped due to timeout. (4)
  • GitHub Check: Analyze cpp with CodeQL
  • GitHub Check: build (gcc, none)
  • GitHub Check: clang-tidy-check
  • GitHub Check: coverage
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{cpp,cc,cxx,h,hpp}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{cpp,cc,cxx,h,hpp}: Use clang-format tool for all C++ code formatting (VS Code auto-formats on save); configuration defined in .clang-format with 100-character line limit and 2-space indentation
Follow clang-tidy recommendations defined in .clang-tidy

Files:

  • plugins/python/src/lifelinewrap.cpp
  • plugins/python/src/errorwrap.cpp
  • test/form/form_storage_test.cpp
  • test/form/form_root_schema_read_test.cpp
  • phlex/model/data_cell_index.cpp
  • form/form/form_writer.cpp
  • test/form/generate_vector.cpp
  • test/form/form_root_schema_write_test.cpp
  • form/form/config.cpp
  • form/persistence/persistence_utils.cpp
  • test/form/reader.cpp
  • test/form/writer.cpp
  • phlex/app/load_module.cpp
  • form/storage/storage_writer.cpp
  • plugins/python/src/dyncall.cpp
  • form/storage/storage_reader.cpp
  • test/form/test_utils.hpp
  • plugins/python/src/pymodule.cpp
  • plugins/python/src/configwrap.cpp
  • plugins/python/src/modulewrap.cpp
**/*.{hpp,cpp}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{hpp,cpp}: Use .hpp for header files, .cpp for implementation, and *_test.cpp for test files in C++
Enforce 100-character line limit and 2-space indentation in C++ code via .clang-format
Use QualifierAlignment: Right (east-const) style: int const x not const int x in C++
Use PointerAlignment: Left in C++ (pointer * attached to type, not variable name)
All C++ identifiers must use lower_case naming: namespaces, classes, structs, enums, functions, variables, parameters, members, and constants
Exception to C++ naming: template parameters use CamelCase
Exception to C++ naming: macros use UPPER_CASE
Private, protected, and constant members in C++ must have a trailing underscore (_), no trailing underscore on anything else
Use enum class preferred over plain enum in C++
Use std::shared_ptr for shared ownership, std::unique_ptr for exclusive ownership, raw pointers for non-owning references only in C++
Use functors with agent-noun pattern: ModelEvaluator evaluate_model(...) in C++
Apply .clang-tidy checks for bugprone, cert, clang-analyzer, concurrency, cppcoreguidelines, misc, modernize, performance, portability, and readability as defined in the .clang-tidy configuration file
Use phlex:: namespace for core code, phlex::experimental:: for experimental features in C++

Files:

  • plugins/python/src/lifelinewrap.cpp
  • plugins/python/src/errorwrap.cpp
  • test/form/form_storage_test.cpp
  • test/form/form_root_schema_read_test.cpp
  • phlex/model/data_cell_index.cpp
  • form/form/form_writer.cpp
  • test/form/generate_vector.cpp
  • test/form/form_root_schema_write_test.cpp
  • form/form/config.cpp
  • form/persistence/persistence_utils.cpp
  • test/form/reader.cpp
  • test/form/writer.cpp
  • phlex/app/load_module.cpp
  • form/storage/storage_writer.cpp
  • plugins/python/src/dyncall.cpp
  • form/storage/storage_reader.cpp
  • test/form/test_utils.hpp
  • plugins/python/src/pymodule.cpp
  • plugins/python/src/configwrap.cpp
  • plugins/python/src/modulewrap.cpp
plugins/python/**/*.cpp

📄 CodeRabbit inference engine (AGENTS.md)

plugins/python/**/*.cpp: Use std::runtime_error for C++ runtime failures; propagate Python exceptions via PyErr_SetString/PyErr_Format; return nullptr on error; call PyErr_Clear() when recovering in Python/C++ integration
Use manual Py_INCREF/Py_DECREF for reference counting and PyGILRAII RAII wrapper for GIL management in C++ code that interacts with Python
For GC-tracked Python types in C++: use Py_TPFLAGS_HAVE_GC, implement tp_traverse and tp_clear, call PyObject_GC_UnTrack before deallocation

Files:

  • plugins/python/src/lifelinewrap.cpp
  • plugins/python/src/errorwrap.cpp
  • plugins/python/src/dyncall.cpp
  • plugins/python/src/pymodule.cpp
  • plugins/python/src/configwrap.cpp
  • plugins/python/src/modulewrap.cpp
**/*.md

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.md: All Markdown files must follow markdownlint rule MD012: no multiple consecutive blank lines (never more than one blank line in a row)
All Markdown files must follow markdownlint rule MD022: headings must be surrounded by exactly one blank line before and after
All Markdown files must follow markdownlint rule MD031: fenced code blocks must be surrounded by exactly one blank line before and after
All Markdown files must follow markdownlint rule MD032: lists must be surrounded by exactly one blank line before and after (including after headings and code blocks)
All Markdown files must follow markdownlint rule MD034: no bare URLs (use markdown link syntax like [text](destination) instead of plain URLs)
All Markdown files must follow markdownlint rule MD036: use # headings for titles, not Bold:
All Markdown files must follow markdownlint rule MD040: always specify code block language (for example, use 'bash', 'python', '```text', etc.)

**/*.md: Do not use multiple consecutive blank lines in Markdown (MD012)
Surround Markdown headings with exactly one blank line (MD022)
Surround Markdown fenced code blocks with exactly one blank line (MD031)
Surround Markdown lists with exactly one blank line (MD032)
Do not use bare URLs in Markdown; use [text](url) syntax instead (MD034)
Use # headings in Markdown, not **Bold** for section titles (MD036)
Always specify language on fenced code blocks in Markdown (MD040)

Files:

  • docs/dev/clang-tidy-fixes-2026-04.md
**/*.hpp

📄 CodeRabbit inference engine (AGENTS.md)

Avoid boolean parameters in C++ interfaces; prefer enumerations instead

Files:

  • test/form/test_utils.hpp
🔇 Additional comments (21)
docs/dev/clang-tidy-fixes-2026-04.md (1)

149-150: LGTM!

form/form/config.cpp (1)

8-10: LGTM!

form/form/form_writer.cpp (1)

50-52: LGTM!

form/persistence/persistence_utils.cpp (1)

9-15: LGTM!

form/storage/storage_reader.cpp (1)

214-224: LGTM!

Also applies to: 291-302, 320-330, 380-391

form/storage/storage_writer.cpp (1)

71-73: LGTM!

Also applies to: 97-99

phlex/app/load_module.cpp (1)

71-73: LGTM!

phlex/model/data_cell_index.cpp (1)

92-94: LGTM!

test/form/form_root_schema_read_test.cpp (1)

21-23: LGTM!

test/form/form_root_schema_write_test.cpp (1)

22-24: LGTM!

test/form/form_storage_test.cpp (1)

40-42: LGTM!

test/form/generate_vector.cpp (1)

24-26: LGTM!

test/form/reader.cpp (1)

122-131: LGTM!

Also applies to: 177-179

test/form/test_utils.hpp (1)

33-36: LGTM!

Also applies to: 92-94

test/form/writer.cpp (1)

85-87: LGTM!

Also applies to: 101-103, 113-115, 135-137

plugins/python/src/configwrap.cpp (1)

33-35: LGTM!

Also applies to: 95-161

plugins/python/src/dyncall.cpp (1)

17-40: LGTM!

Also applies to: 70-96

plugins/python/src/errorwrap.cpp (1)

72-74: LGTM!

plugins/python/src/lifelinewrap.cpp (1)

22-24: LGTM!

plugins/python/src/modulewrap.cpp (1)

184-199: LGTM!

Also applies to: 233-235, 288-295, 315-331, 355-357, 379-387, 495-497, 1049-1051, 1062-1064, 1197-1199, 1210-1212, 1398-1400

plugins/python/src/pymodule.cpp (1)

56-58: LGTM!

Also applies to: 95-97, 109-111, 173-193

Comment on lines +407 to +422
if (!normalizer) {
return "";
}
// LCOV_EXCL_STOP
}

PyObject* norm = PyObject_CallOneArg(normalizer, pyobj);
if (!norm)
if (!norm) {
return "";
}

char const* ann = PyUnicode_AsUTF8(norm);
Py_DECREF(norm);
if (!ann)
if (!ann) {
return "";
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -C 8 'annotation_as_text|conversion_ok = true' plugins/python/src/modulewrap.cpp

Repository: Framework-R-D/phlex

Length of output: 2231


🏁 Script executed:

#!/bin/bash
set -euo pipefail

wc -l plugins/python/src/modulewrap.cpp
sed -n '418,455p' plugins/python/src/modulewrap.cpp
sed -n '430,465p' plugins/python/src/modulewrap.cpp
sed -n '420,455p' plugins/python/src/modulewrap.cpp

Repository: Framework-R-D/phlex

Length of output: 4283


Preserve annotation-normalization errors on the _sig path.

In plugins/python/src/modulewrap.cpp lines 447-452, annotation_as_text(ret/args) returns "" on Python exception/error, but this branch then pushes those empty strings and sets conversion_ok = true without checking PyErr_Occurred(). Check each returned string and return false before populating the signature types so registration doesn’t continue with invalid annotations while a Python exception stays pending.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/python/src/modulewrap.cpp` around lines 407 - 422, Update the _sig
annotation-processing path to validate each annotation_as_text result before
adding it to the signature types or setting conversion_ok. After processing ret
and args, check PyErr_Occurred() alongside the returned strings; on any
normalization error, return false before populating signature types, while
preserving successful handling of valid empty strings.

Source: Coding guidelines

Comment on lines 413 to +422
PyObject* norm = PyObject_CallOneArg(normalizer, pyobj);
if (!norm)
if (!norm) {
return "";
}

char const* ann = PyUnicode_AsUTF8(norm);
Py_DECREF(norm);
if (!ann)
if (!ann) {
return "";
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -C 3 'PyUnicode_AsUTF8\(norm\)|Py_DECREF\(norm\)|return ann' plugins/python/src/modulewrap.cpp

Repository: Framework-R-D/phlex

Length of output: 413


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '390,435p' plugins/python/src/modulewrap.cpp
printf '\n--- return/annotations usage nearby ---\n'
rg -n -C 2 'annotation_as_text|\.as_string|conversion_ok|_sig|annotate|as_string' plugins/python/src/modulewrap.cpp

Repository: Framework-R-D/phlex

Length of output: 3082


🌐 Web query:

Python C API PyUnicode_AsUTF8 object owned by PyObject decref documentation

💡 Result:

The Python C API function PyUnicode_AsUTF8 returns a pointer to a cached, read-only UTF-8 representation of the provided Unicode object [1][2]. Regarding object ownership and memory management: 1. Ownership: The caller does not own the returned pointer and is not responsible for deallocating the memory [1][2]. 2. Deallocation: You must not call Py_DECREF or any other deallocation function on the returned pointer [1][2]. The buffer is owned by the underlying Unicode object and is automatically deallocated when that Unicode object is garbage collected [1][2]. 3. Invalidity: Because the buffer is tied to the lifecycle of the Unicode object, the pointer becomes invalid once the Unicode object is garbage collected [1][2]. If the Unicode object is released (e.g., via Py_DECREF) before you finish using the returned buffer, accessing that buffer results in use-after-free behavior. In summary, the returned pointer is a "borrowed" view of memory managed by the Python object itself [1][3]. Do not attempt to modify this memory or manage its lifecycle manually [1][3].

Citations:


Copy the normalized annotation while norm is still alive.

PyUnicode_AsUTF8(norm) gives you a pointer managed by the norm Unicode object, so decrementing norm before returning/copying can make the returned std::string point to freed memory — the same kind of “dangling reference” you’d avoid with any borrowed buffer.

Suggested fix
 char const* ann = PyUnicode_AsUTF8(norm);
-Py_DECREF(norm);
 if (!ann) {
+  Py_DECREF(norm);
   return "";
 }
- return ann;
+std::string result{ann};
+Py_DECREF(norm);
+return result;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
PyObject* norm = PyObject_CallOneArg(normalizer, pyobj);
if (!norm)
if (!norm) {
return "";
}
char const* ann = PyUnicode_AsUTF8(norm);
Py_DECREF(norm);
if (!ann)
if (!ann) {
return "";
}
PyObject* norm = PyObject_CallOneArg(normalizer, pyobj);
if (!norm) {
return "";
}
char const* ann = PyUnicode_AsUTF8(norm);
if (!ann) {
Py_DECREF(norm);
return "";
}
std::string result{ann};
Py_DECREF(norm);
return result;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/python/src/modulewrap.cpp` around lines 413 - 422, In the
normalization path using norm, copy the UTF-8 contents into an owning
std::string before decrementing norm. Keep norm alive through the copy, then
release it and return the copied value; preserve the existing empty-result
handling when normalization or UTF-8 conversion fails.

Source: Coding guidelines

@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 50.00000% with 39 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
plugins/python/src/modulewrap.cpp 45.83% 0 Missing and 13 partials ⚠️
plugins/python/src/pymodule.cpp 0.00% 2 Missing and 7 partials ⚠️
plugins/python/src/configwrap.cpp 0.00% 1 Missing and 6 partials ⚠️
plugins/python/src/dyncall.cpp 71.42% 4 Missing and 2 partials ⚠️
form/form/config.cpp 0.00% 0 Missing and 1 partial ⚠️
form/form/form_writer.cpp 0.00% 0 Missing and 1 partial ⚠️
phlex/app/load_module.cpp 0.00% 0 Missing and 1 partial ⚠️
plugins/python/src/lifelinewrap.cpp 0.00% 1 Missing ⚠️

❌ Your patch check has failed because the patch coverage (50.00%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

@@            Coverage Diff             @@
##             main     #762      +/-   ##
==========================================
- Coverage   83.88%   83.83%   -0.05%     
==========================================
  Files         172      172              
  Lines        7203     7219      +16     
  Branches      845      845              
==========================================
+ Hits         6042     6052      +10     
- Misses        882      887       +5     
- Partials      279      280       +1     
Flag Coverage Δ
scripts 80.09% <ø> (ø)
unittests 85.70% <50.00%> (-0.08%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
form/persistence/persistence_utils.cpp 92.85% <100.00%> (ø)
form/storage/storage_reader.cpp 81.73% <100.00%> (ø)
form/storage/storage_writer.cpp 87.93% <100.00%> (ø)
phlex/model/data_cell_index.cpp 90.16% <100.00%> (ø)
plugins/python/src/errorwrap.cpp 80.43% <100.00%> (ø)
form/form/config.cpp 84.61% <0.00%> (ø)
form/form/form_writer.cpp 82.75% <0.00%> (ø)
phlex/app/load_module.cpp 86.27% <0.00%> (ø)
plugins/python/src/lifelinewrap.cpp 50.00% <0.00%> (ø)
plugins/python/src/dyncall.cpp 79.72% <71.42%> (-2.24%) ⬇️
... and 3 more

... and 2 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 70ca87e...01e2d2e. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant