Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 6 additions & 12 deletions .bca-baseline.toml
Original file line number Diff line number Diff line change
Expand Up @@ -259,12 +259,6 @@ qualified = "RubyCode::get_op_type"
metric = "halstead.effort"
value = 101217.532578918

[[entry]]
path = "big-code-analysis-ast/src/lang_helpers/doc_comment.rs"
qualified = "<file>"
metric = "loc.ploc"
value = 642.0

[[entry]]
path = "big-code-analysis-ast/src/lang_helpers/doc_comment.rs"
qualified = "bind_leading"
Expand Down Expand Up @@ -775,12 +769,6 @@ qualified = "assemble_globals"
metric = "nargs"
value = 6.0

[[entry]]
path = "big-code-analysis-cli/src/walk.rs"
qualified = "classify_dropped_child"
metric = "nargs"
value = 5.0

[[entry]]
path = "big-code-analysis-cli/src/walk.rs"
qualified = "expand_seed_paths"
Expand Down Expand Up @@ -1267,6 +1255,12 @@ qualified = "RustCode::compute"
metric = "nargs"
value = 5.0

[[entry]]
path = "src/metrics/loc/shared.rs"
qualified = "credit_bare_continuation_rows"
metric = "nargs"
value = 5.0

[[entry]]
path = "src/metrics/loc/tcl.rs"
qualified = "TclCode::compute"
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/add-lang/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ Create the file, add `mod <lang>;` to `checker.rs`, and write
`holds_doc_comment_in_body`) — what the language's own
documentation tool reads (#1597). They feed `dloc`; the defaults
answer `false`, which is right for a language with no doc
convention. Where one exists, `lang_helpers/doc_comment.rs` has the
convention. Where one exists, `lang_helpers/doc_text.rs` has the
shared opener tests.
- `is_func_space` / `is_func_space_with_code`, `is_func`,
`is_closure` — forward to the table: `crate::roles::<lang>::opens_space`
Expand Down
23 changes: 22 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,18 @@ jobs:
# runs doctests for correctness — only their coverage is omitted.
- name: Clean coverage data
run: cargo llvm-cov clean --workspace
#
# LLVM_PROFILE_FILE_NAME drops the `%p` cargo-llvm-cov puts in its
# default name. nextest runs every test in a process of its own, so
# one raw profile per process came to ~8,000 files and 15 GB, and
# the job ran the runner out of disk (PR #1804). Without `%p`, every
# process of one test binary merges on-line into `%4m`'s pool of
# four files: LLVM locks the file and adds the counters, so no count
# is lost. Measured on that PR: 101 files and 62 MB, with every
# file's covered lines and regions identical to the default naming.
- name: Run tests with coverage instrumentation
env:
LLVM_PROFILE_FILE_NAME: big-code-analysis-%4m.profraw
run: cargo llvm-cov --no-report nextest --all-features --workspace --locked
# Codecov's native format preserves region coverage (lcov would drop to
# line-only).
Expand Down Expand Up @@ -739,7 +750,8 @@ jobs:
# SHA256, mirroring the actionlint and checkmake patterns below.
# Bump RUMDL_SHA256 in lockstep with `RUMDL_VERSION` (and with the
# `rumdl = …` pin in `mise.toml` and the `Dockerfile`'s
# `RUMDL_VERSION` + per-arch SHA256 table). To regenerate the
# `RUMDL_VERSION` + per-arch SHA256 table); `make
# check-rumdl-lockstep` fails when they disagree. To regenerate the
# SHA256 after a version bump (swap the triple for
# `aarch64-unknown-linux-gnu` to get the Dockerfile's arm64 entry):
# curl -fsSL https://github.com/rvben/rumdl/releases/download/v${RUMDL_VERSION}/rumdl-v${RUMDL_VERSION}-x86_64-unknown-linux-gnu.tar.gz.sha256
Expand Down Expand Up @@ -1013,6 +1025,15 @@ jobs:
# gate without surfacing the regression in CI.
- name: check-ruff-lockstep self-tests (explicit)
run: python3 -m unittest -q utils/check-ruff-lockstep-test.py
# Defensive twin for the rumdl-lockstep gate (#1779): mise.toml,
# the `Install rumdl` step above and the Dockerfile must pin one
# rumdl version, and the Dockerfile's x86_64 hash must equal
# `RUMDL_SHA256`. Comments were the whole mechanism before, and
# #1653's bump nearly left the Dockerfile behind.
- name: check-rumdl-lockstep (explicit)
run: python3 utils/check-rumdl-lockstep.py
- name: check-rumdl-lockstep self-tests (explicit)
run: python3 -m unittest -q utils/check-rumdl-lockstep-test.py
# Defensive twin for the enums-codegen-drift gate (#405):
# running any grammar regen previously regenerated
# `src/c_langs_macros/*.rs` to a pre-optimization form
Expand Down
21 changes: 21 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,27 @@ repos:
entry: python3 -m unittest -q utils/check-ruff-lockstep-test.py
pass_filenames: false

# rumdl version lockstep (#1779). mise.toml, the CI lint job and
# the Dockerfile each pin rumdl, and the Dockerfile's x86_64 hash
# must equal CI's. #1653's bump nearly left the Dockerfile behind.
# .rumdl-lockstep-baseline.txt records the last accepted version and
# hash, so a bump that keeps the old hash fails too.
- id: check-rumdl-lockstep
name: check-rumdl-lockstep
language: system
files: '^(mise\.toml|Dockerfile|\.github/workflows/ci\.yml|\.rumdl-lockstep-baseline\.txt|utils/check-rumdl-lockstep\.py)$'
entry: python3 utils/check-rumdl-lockstep.py
pass_filenames: false

# Self-tests for the rumdl-lockstep gate. Runs on edits to the
# script or its test file.
- id: check-rumdl-lockstep-test
name: check-rumdl-lockstep-test
language: system
files: '^utils/check-rumdl-lockstep(-test)?\.py$'
entry: python3 -m unittest -q utils/check-rumdl-lockstep-test.py
pass_filenames: false

# Publish metadata for the crates.io uploads (#1224). The four
# top-level crates pin internal deps at `=<version>`, so none can
# be `cargo publish --dry-run`-ed before the tag that publishes
Expand Down
13 changes: 13 additions & 0 deletions .rumdl-lockstep-baseline.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# rumdl lockstep baseline: the rumdl release and its x86_64 tarball
# SHA256 that check-rumdl-lockstep.py last accepted (#1779).
# Maintained by `python3 utils/check-rumdl-lockstep.py --update`; see the
# script's docstring.
#
# The gate fails when the version pinned in mise.toml, ci.yml and the
# Dockerfile has moved but the hash in ci.yml and the Dockerfile is still
# the one recorded here: the bump kept the old release's hash. A bump
# that pastes the new release's hash into both files fails too, until
# `--update` records the new pair; commit this file with that bump.
#
# One record: `<version> <sha256>`.
0.3.2 f527d1374765d826c1627ceab3d1f46e548268731a495b5b12a3af529b3d79e8
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ and `cargo run -p big-code-analysis-web --`.
`check-grammar-marker-sync.py`, `check-enums-codegen-drift.sh`,
`check-grammar-crate.py`, `check-grammars-crates.sh`,
`check-excluded-manifests.py`, `check-ruff-lockstep.py`,
`check-rumdl-lockstep.py`,
`check-publish-metadata.py`, `check-test-lang-gates.py`,
`check-role-census.py`, `check-role-coverage.py`,
`check-role-bypass.py` (the three role-table gates, all reading
Expand Down
71 changes: 68 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,18 @@ for historical reference.
(`EISDIR` on unix) rather than a skip. The Python
`Ast.from_path` `ValueError` names the reason.

- **`make check-rumdl-lockstep`** (`utils/check-rumdl-lockstep.py`,
#1779) fails when the rumdl pin in `mise.toml`, the CI lint job's
`RUMDL_VERSION` / `RUMDL_SHA256` and the `Dockerfile` disagree on the
version, naming the file that differs, or when the `Dockerfile`'s
x86_64 SHA256 differs from CI's. `.rumdl-lockstep-baseline.txt`
records the version and hash it last accepted, so a bump that moves
the version but keeps the old hash fails by name, and an honest bump
fails until `python3 utils/check-rumdl-lockstep.py --update` records
the new pair in the same commit. It is wired into `make lint`, `make pre-commit`, `make ci`,
the pre-commit hooks (which also run on an edit to the baseline) and
the CI lint job.

### Changed

- **The role-bypass baseline is empty** (#1701, part of #1690). The
Expand Down Expand Up @@ -901,6 +913,14 @@ for historical reference.
whose predicates call it (metrics, `ops`, `find` and `count`) all
lend the cache. (#1785)

- **`bca check` measures its ignored-file summary on the `--jobs`
thread budget** (#1307). Walked directories were re-listed serially
after the walk; they are now claimed per directory by scoped worker
threads, which cuts a 65,720-directory tree from 340 ms to 143 ms.
The `--report-skipped` listing is byte-identical, including which
spelling of a path reached by overlapping seeds is printed (the
first-named seed's).

### Deprecated

- `FromPathError::Unreadable`: superseded by `Skipped(SkipReason)`;
Expand Down Expand Up @@ -1187,9 +1207,8 @@ for historical reference.
than an identifier walk, because `[temp.pre]/5` allows a template
declaration at most one declarator and a walk would read an array
bound, an initialiser's callee or a function pointer's parameter
name. Cpp and Mozcpp alike. A pointer-to-member-function data member
(`static int (S::*fp)(T);`, and the plain `int (S::*pmf)(int);`)
still reads as a method — #1718.
name. Cpp and Mozcpp alike. A templated pointer-to-member-function
data member (`static int (S::*fp)(T);`) is left to #1718, below.

- **Ruby's `npm` counts a `def` wherever the class body's statements
reach it** (#1401). The member walk read the body's direct children
Expand Down Expand Up @@ -1332,6 +1351,52 @@ for historical reference.
stdin, so the after side applied no exclusions and reported the files
they should have hidden as added.

- `utils/perturb.py` refuses a `cargo test` argv that can run more than
one test target without `--no-fail-fast`, instead of reporting the
guards in later targets as uncaught (#1787). It sees through a wrapper
in front of cargo (`timeout`, `env`, `nice`, `rustup run`), counts a
`-p` inside a short-option cluster (`-qpa`), and refuses a second
`--target`.

- `npa` / `npm` (C++, Mozcpp): a templated pointer-to-member data
member such as `template<class T> static int (S::*fp)(T);` is counted
as an attribute instead of a method, and the methods
`template<class T> int (*S::*getPp())(T);` and
`template<class T> static int S::*getPd();` as methods instead of
attributes. A method returning a member-function pointer stays a
method, and the parenthesised non-templated `int (S::*pmf)(int);` was
already correct (#1718). A member function template whose every
parameter parses as an expression, such as
`template<class T> void connect(T* obj, void (T::*slot)());`, is
counted as a method instead of an attribute: both grammars read it as
a variable with a parenthesised initialiser, which a class member
cannot have. Still misread by the grammars' error recovery, as before:
the unparenthesised `int S::*getPd();` as data, and
`static constexpr int (S::*fp)(int) = nullptr;` as a method.

- Ruby `npa` counts `attr_*` macros and `@x` / `@@x` class-scope
assignments wherever the class body runs them: under a conditional,
loop, `begin` / `rescue` / `ensure`, `case` arm, statement modifier,
parentheses, an assignment's right side, or a call's argument. A bare
`private` / `public` / `protected` shadowed by a local of the same
name — bound by an assignment, `for` or `rescue =>` the walk reads —
no longer changes attribute visibility, and a marker inside a
wrapper or in expression position now sets it, as it already did for
`npm`. The attribute and method walks share one traversal and agree
on a body's visibility (#1719).

- `loc` (Bash, Tcl, iRules): a line-continuation row holding only the
`\` counts as code instead of blank, or as comment where it continues
a Tcl or iRules comment (`# note \`), in its enclosing function, proc
or event handler as well as the file (#1445). One that continues
nothing counts as the line it starts once joined to the next row: a
comment where that row is one (`\` + `# note`), blank where it is
empty, code otherwise. Where CRLF line endings
reach the parser unchanged (the library's `analyze`, Python's
`Ast.parse`; `bca` converts them first), the Tcl and iRules grammars
still lex such a row as a word (#1802). The C family, Ruby and Elixir
splice the row the same way and still count it as blank (#1801).

## [2.4.0] - 2026-10-21

### Added
Expand Down
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ EOF

# ---------------------------------------------------------------------------
# rumdl (Markdown linter/formatter) — SHA256-verified release tarball.
# `make check-rumdl-lockstep` holds RUMDL_VERSION and the x86_64 hash to
# the CI lint job's pin, and the version to mise.toml (#1779).
# ---------------------------------------------------------------------------
RUN <<'EOF'
set -eux
Expand Down
Loading
Loading