Add Fortran/Fypp static analysis linter#1193
Add Fortran/Fypp static analysis linter#1193sbryngelson wants to merge 8 commits intoMFlowCode:masterfrom
Conversation
Nitpicks 🔍
|
There was a problem hiding this comment.
Pull request overview
This PR adds a Python-based static analysis linter (lint_source.py) to detect common Fortran/Fypp code issues that cause silent bugs. The linter checks for duplicate entries in Fypp loop lists, duplicate consecutive source lines, and hardcoded byte size assumptions that break single-precision builds.
Changes:
- Added
toolchain/mfc/lint_source.pywith three static analysis checks for Fortran/Fypp code - Integrated the linter into the precheck hook as step 5/6
- Added CI workflow step to run Fortran/Fypp static analysis
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| toolchain/mfc/lint_source.py | New static analysis linter with checks for Fypp list duplicates, duplicate consecutive lines, and hardcoded byte sizes |
| toolchain/bootstrap/precheck.sh | Updated step numbering to 6 total steps and added Fortran/Fypp analysis as step 5 |
| .github/workflows/lint-source.yml | Added new CI step to run the static analysis linter |
There was a problem hiding this comment.
1 issue found across 3 files
Confidence score: 5/5
- Overall low risk since the only issue is a low-severity linting edge case, not a runtime or user-facing change.
- Most notable concern:
toolchain/mfc/lint_source.pyonly checks quoted list entries, so duplicate non-string items in#:for ... in [...]lists can slip through, reducing lint coverage. - Pay close attention to
toolchain/mfc/lint_source.py- duplicate detection ignores non-string list items.
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="toolchain/mfc/lint_source.py">
<violation number="1" location="toolchain/mfc/lint_source.py:62">
P2: This only checks quoted list entries, so duplicate numeric/tuple items in `#:for ... in [...]` lists (e.g., `[1, 2, 3]`) are silently ignored. The linter should parse the full list so duplicates in non-string entries are also detected.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
toolchain/mfc/lint_source.py (1)
42-43:_check_single_fypp_list— quote-matching regex allows mixed delimiters.
r"['\"]([^'\"]*)['\"]"matches any opening quote paired with any closing quote, so'foo"is a valid match. In the MFC Fypp codebase, list entries are uniformly'single-quoted', so no false positives have been seen. Consider using two separate patterns or a back-reference to enforce consistent quoting:♻️ Proposed fix using alternation with back-reference
- entries = re.findall(r"['\"]([^'\"]*)['\"]", list_content) + entries = re.findall(r"'([^']*)'|\"([^\"]*)\"", list_content) + entries = [a or b for a, b in entries]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@toolchain/mfc/lint_source.py` around lines 42 - 43, The regex in _check_single_fypp_list that builds entries using re.findall currently allows mismatched opening/closing quotes (e.g., "'foo\""); update the pattern used to extract list_content entries to enforce matching delimiters — either restrict to single quotes (since Fypp uses single-quoted entries) or use a back-reference/alternation so the opening quote is the same as the closing quote; modify the entries assignment (the variable entries derived from list_content in _check_single_fypp_list) to use the corrected regex and ensure subsequent logic that iterates over entries continues to work with the new extraction.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@toolchain/mfc/lint_source.py`:
- Around line 126-152: The check_hardcoded_byte_size function is flagging
patterns inside inline Fortran comments because byte_re is run against the whole
stripped line; to fix, before testing byte_re.search, remove the inline comment
portion by taking the substring up to the first unquoted '!' (i.e., split on '!'
and use the left part) so only actual code is scanned; update the loop in
check_hardcoded_byte_size to compute a code_only variable from line (respecting
full-line comments via _is_comment_or_blank) and run byte_re.search on that
code_only string (references: check_hardcoded_byte_size, _is_comment_or_blank,
byte_re, lines loop).
---
Nitpick comments:
In `@toolchain/mfc/lint_source.py`:
- Around line 42-43: The regex in _check_single_fypp_list that builds entries
using re.findall currently allows mismatched opening/closing quotes (e.g.,
"'foo\""); update the pattern used to extract list_content entries to enforce
matching delimiters — either restrict to single quotes (since Fypp uses
single-quoted entries) or use a back-reference/alternation so the opening quote
is the same as the closing quote; modify the entries assignment (the variable
entries derived from list_content in _check_single_fypp_list) to use the
corrected regex and ensure subsequent logic that iterates over entries continues
to work with the new extraction.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1193 +/- ##
=======================================
Coverage 44.04% 44.04%
=======================================
Files 70 70
Lines 20499 20499
Branches 1993 1993
=======================================
Hits 9028 9028
Misses 10330 10330
Partials 1141 1141 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="toolchain/mfc/lint_source.py">
<violation number="1" location="toolchain/mfc/lint_source.py:145">
P2: The inline comment stripping uses `split("!")`, which also cuts `!` inside string literals. That can hide real `int(8._wp, ...)` usages on lines that include a string with `!`, leading to false negatives. Use a comment-stripping approach that ignores `!` inside quotes.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
41630a6 to
2b4221e
Compare
576996d to
10e0984
Compare
Adds toolchain/mfc/lint_source.py with three checks that catch copy-paste and precision bugs in Fortran/Fypp source: - Duplicate entries in Fypp #:for lists (e.g. broadcast lists) - Identical adjacent source lines (duplicated accumulations, args) - Hardcoded int(8._wp, ...) that assumes 8-byte reals Integrated into precheck.sh (step 5/6) and lint-source.yml CI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds -Wconversion to the GNU debug compiler flags in CMakeLists.txt. This catches implicit type coercions (e.g. integer = real truncation) at compile time. Adds a Conversion Warnings Diff step and count to cleanliness.yml, following the same delta-from-master pattern as the existing checks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract inner parsing logic of check_fypp_list_duplicates into _check_single_fypp_list helper to resolve R0914 (too-many-locals), R1702 (too-many-nested-blocks), and R1716 (chained-comparison). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
byte_re was run against the full stripped line, so a comment like ! old code: int(8._wp, kind=i64) would be flagged even though the pattern is inside a Fortran ! comment. Strip the inline comment portion before searching. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This PR adds a 6th lint check (Fortran/Fypp analysis). Update CLAUDE.md and common-pitfalls.md to match. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- m_mpi_proxy.fpp: fix duplicate 'bc_x%ve2' → 'bc_x%ve3' in MPI broadcast Fypp list; bc_x%ve3 was never broadcast to all ranks - m_assign_variables.fpp: remove duplicate R3bar accumulation line in QBMM path; bubble radius cubed was summed twice per iteration - m_rhs.fpp: fix cylindrical viscous boundary call passing dq_prim_dy_vf twice; 4th arg should be dq_prim_dz_vf (z-gradient) - m_data_input.f90, m_data_output.fpp, m_start_up.fpp (all targets): replace hardcoded WP_MOK = int(8._wp,...) with storage_size(0._stp)/8 for correct mixed-precision MPI-IO offset computation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The hardcoded byte-size linter should recommend storage_size(0._stp)/8, not 0._wp, since field I/O uses storage precision. In mixed-precision builds (wp=double, stp=half) the current message would misdirect. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6f3c845 to
51a6f2e
Compare
The linter will intentionally fail until PRs MFlowCode#1187 (WP_MOK), MFlowCode#1241 (R3bar duplicate), and this PR's dq_prim_dy fix (now in MFlowCode#1187) merge first. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude Code ReviewHead SHA: bd96007
Summary
Findings1. PR description–diff mismatch ( 2. Comment-stripping heuristic ( if byte_re.search(stripped.split("!")[0]):Splitting on the first 3. Duplicate-line check: 4. if python3 toolchain/mfc/lint_source.py 2>&1; then
ok "Fortran/Fypp analysis passed."When the check passes the script prints nothing, so this works fine today. If Improvement opportunities
|
Summary
Adds a new Python-based static analysis linter (
toolchain/mfc/lint_source.py) that catches patterns known to cause silent bugs in Fortran/Fypp source code. Integrated into both the local precheck hook and CI.Checks
#:for VAR in [...]listsbc_x%ve2listed twice in MPI broadcast, silently skippingbc_x%ve3R3baraccumulation, repeated subroutine argumentint(8._wp, ...)patterns that assume 8-byte realsWP_MOK = int(8._wp, MPI_OFFSET_KIND)breaks in single precisionAll three checks are motivated by real bugs found in the codebase.
Integration
toolchain/bootstrap/precheck.sh: Added as step 5/6 (bumped doc check to 6/6), runs during./mfc.sh precheckand the pre-commit hook.github/workflows/lint-source.yml: Added as a new CI step alongside existing grep-based checksCMakeLists.txt: Added-Wconversionto GNU debug builds, tracked in cleanliness CIDependencies
This PR will fail precheck/CI until the following PRs merge first:
dq_prim_dy_vf→dq_prim_dz_vfduplicate line bugR3barline inm_assign_variables.fppThe source bug fixes were intentionally moved out of this PR and into their respective dedicated fix PRs. This PR now contains only the linter infrastructure. Once #1187 and #1241 are merged, this PR will pass cleanly.
Test plan
python3 toolchain/mfc/lint_source.py— verify clean (no issues)./mfc.sh precheck— verify Fortran/Fypp analysis appears as step 5/6🤖 Generated with Claude Code
Closes #1211