Skip to content

refactor: addr_of_mut to OnceLock#2486

Merged
HerringtonDarkholme merged 2 commits into
ast-grep:mainfrom
Dsaquel:refactor/addr_of_mut-to-OnceLock
Feb 22, 2026
Merged

refactor: addr_of_mut to OnceLock#2486
HerringtonDarkholme merged 2 commits into
ast-grep:mainfrom
Dsaquel:refactor/addr_of_mut-to-OnceLock

Conversation

@Dsaquel

@Dsaquel Dsaquel commented Feb 18, 2026

Copy link
Copy Markdown
Contributor

I have noticed that addr_of_mut can be replaced by OnceLock in order to remove unsafe.
In fact, the mutation is made only once during project setup if i'm not wrong.

Summary by CodeRabbit

  • Refactor
    • Enhanced thread safety of internal language registration and injection mechanisms through improved global state management patterns.
    • Simplified function safety semantics across language management modules by removing unsafe code patterns and consolidating error handling.
    • Updated internal systems to support better concurrency handling without affecting external API behavior.

@coderabbitai

coderabbitai Bot commented Feb 18, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

The head commit changed during the review from 9dd8b43 to 2ccf176.

📝 Walkthrough

Walkthrough

This pull request converts unsafe global mutable statics to thread-safe OnceLock-based lazy initialization patterns across the CLI and dynamic language modules. The changes remove unsafe blocks and make registration functions safe by eliminating mutable static state.

Changes

Cohort / File(s) Summary
Global State Safety Migration
crates/cli/src/lang/injection.rs, crates/cli/src/lang/lang_globs.rs, crates/dynamic/src/lib.rs
Replaced unsafe mutable global statics (LANG_INJECTIONS, LANG_GLOBS, DYNAMIC_LANG, LANG_INDEX) with thread-safe OnceLock equivalents. Updated registration functions from pub unsafe fn to pub fn and replaced unsafe dereferencing with safe .get() access patterns.
Call Site Updates
crates/cli/src/lang/mod.rs, crates/dynamic/src/custom_lang.rs
Removed unsafe blocks wrapping registration function calls (lang_globs::register, injection::register_injetables, DynamicLang::register) and simplified error propagation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • HerringtonDarkholme

Poem

🐰 Unsafe statics vanished in the night,
OnceLock brought thread-safe delight,
No more pointer dances, no more dread,
Safe state awaits us all ahead!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor: addr_of_mut to OnceLock' clearly and accurately summarizes the main change: replacing unsafe addr_of_mut patterns with thread-safe OnceLock throughout multiple files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

@codecov

codecov Bot commented Feb 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.71429% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.15%. Comparing base (3ae01ae) to head (2ccf176).
⚠️ Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
crates/cli/src/lang/injection.rs 80.00% 3 Missing ⚠️
crates/cli/src/lang/mod.rs 50.00% 1 Missing ⚠️
crates/dynamic/src/custom_lang.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2486   +/-   ##
=======================================
  Coverage   88.14%   88.15%           
=======================================
  Files         108      108           
  Lines       17876    17874    -2     
=======================================
- Hits        15757    15756    -1     
+ Misses       2119     2118    -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@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: 1

🧹 Nitpick comments (2)
crates/cli/src/lang/injection.rs (1)

54-75: Missing debug_assert! for double-registration, unlike lang_globs.rs.

In lang_globs.rs (line 17–20), there is a debug_assert!(LANG_GLOBS.get().is_none(), "language globs already registered") to catch accidental double-registration in debug builds. This file lacks a similar guard. If register_injetables is called twice, .set().ok() silently discards the new data, and line 61's .get().expect(...) would read the stale first registration — a subtle data-loss scenario.

Consider adding a debug_assert! for consistency:

Proposed fix
 pub fn register_injetables(injections: Vec<SerializableInjection>) -> Result<()> {
+  debug_assert!(
+    LANG_INJECTIONS.get().is_none(),
+    "language injections already registered"
+  );
   let mut injectable = HashMap::new();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/lang/injection.rs` around lines 54 - 75, Add a debug-only
assertion at the start of register_injetables to ensure we aren't
double-registering: call debug_assert!(LANG_INJECTIONS.get().is_none(),
"language injections already registered") (and optionally do the same for
INJECTABLE_LANGS if you want both guards) before building and setting the maps
so a debug build will catch accidental second registrations instead of silently
dropping the new data.
crates/cli/src/lang/lang_globs.rs (1)

153-165: Test uses the global OnceLock — may conflict with other tests calling register().

OnceLock can only be set once per process. Since Rust's test harness runs tests as threads in a single process, if any other test in this crate (or integration tests) also calls register(), the debug_assert! will fire or data will be silently dropped. This is a pre-existing test-isolation concern with global state, not introduced by this PR — just worth noting as a known limitation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/lang/lang_globs.rs` around lines 153 - 165, The test uses the
global OnceLock LANG_GLOBS via register(), which can only be set once per
process and will conflict with other tests; modify the test or code so tests
don't rely on global state: either add a cfg(test)-only helper to reset or
initialize LANG_GLOBS (exposing a test_reset or test_set function) and call that
from test_merge_with_globs, or refactor register()/LANG_GLOBS to allow injection
of a local globs instance (e.g., accept a Globs param or provide a non-global
merge_globs_in_place) so the test can operate on a per-test Globs instance
instead of calling the global register(); update test_merge_with_globs to use
the new helper/injectable API and reference the existing register(), LANG_GLOBS,
and merge_globs symbols when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/dynamic/src/lib.rs`:
- Around line 157-159: Remove the incorrect "/// # Safety" doc heading above the
non-unsafe function register and instead document the one-time-call requirement
as a normal doc comment; update the comment block for pub fn register(regs:
Vec<Registration>) -> Result<(), DynamicLangError> so the note "The register
function should be called exactly once before use." appears as a regular
documentation line (not under a Safety section) immediately above the function
signature.

---

Nitpick comments:
In `@crates/cli/src/lang/injection.rs`:
- Around line 54-75: Add a debug-only assertion at the start of
register_injetables to ensure we aren't double-registering: call
debug_assert!(LANG_INJECTIONS.get().is_none(), "language injections already
registered") (and optionally do the same for INJECTABLE_LANGS if you want both
guards) before building and setting the maps so a debug build will catch
accidental second registrations instead of silently dropping the new data.

In `@crates/cli/src/lang/lang_globs.rs`:
- Around line 153-165: The test uses the global OnceLock LANG_GLOBS via
register(), which can only be set once per process and will conflict with other
tests; modify the test or code so tests don't rely on global state: either add a
cfg(test)-only helper to reset or initialize LANG_GLOBS (exposing a test_reset
or test_set function) and call that from test_merge_with_globs, or refactor
register()/LANG_GLOBS to allow injection of a local globs instance (e.g., accept
a Globs param or provide a non-global merge_globs_in_place) so the test can
operate on a per-test Globs instance instead of calling the global register();
update test_merge_with_globs to use the new helper/injectable API and reference
the existing register(), LANG_GLOBS, and merge_globs symbols when making the
change.

Comment thread crates/dynamic/src/lib.rs Outdated
@Dsaquel Dsaquel force-pushed the refactor/addr_of_mut-to-OnceLock branch from 9dd8b43 to 2ccf176 Compare February 18, 2026 12:12
@HerringtonDarkholme HerringtonDarkholme added this pull request to the merge queue Feb 22, 2026
@HerringtonDarkholme

Copy link
Copy Markdown
Member

Thanks!

Merged via the queue into ast-grep:main with commit 9246cea Feb 22, 2026
4 of 5 checks passed
@Dsaquel Dsaquel deleted the refactor/addr_of_mut-to-OnceLock branch February 22, 2026 20:18
nicopauss pushed a commit to Intersec/lib-common that referenced this pull request Apr 1, 2026
##### [\`v0.41.0\`](https://github.com/ast-grep/ast-grep/blob/HEAD/CHANGELOG.md#0410)

- chore(deps): update pyo3/maturin-action action to v1.50.0 [`#2465`](ast-grep/ast-grep#2465)
- fix(deps): update rust-wasm-bindgen monorepo [`#2491`](ast-grep/ast-grep#2491)
- chore(deps): update rust crate toml\_edit to v0.25.3 [`#2469`](ast-grep/ast-grep#2469)
- chore(deps): update dependency web-tree-sitter to ^0.26.0 [`#2492`](ast-grep/ast-grep#2492)
- refactor: addr\_of\_mut to OnceLock [`#2486`](ast-grep/ast-grep#2486)
- feat: support ast-grep-wasm [`#2484`](ast-grep/ast-grep#2484)
- chore(deps): update rust crate clap to v4.5.60 [`#2483`](ast-grep/ast-grep#2483)
- chore(deps): update rust crate anyhow to v1.0.102 [`#2489`](ast-grep/ast-grep#2489)
- chore(deps): update dependency oxlint to v1.49.0 [`#2488`](ast-grep/ast-grep#2488)
- feat: make default rule id to filename [`#2482`](ast-grep/ast-grep#2482)
- chore(deps): update dependency oxlint to v1.48.0 [`#2481`](ast-grep/ast-grep#2481)
- chore(deps): update rust crate napi-derive to v3.5.2 [`#2475`](ast-grep/ast-grep#2475)
- chore(deps): update rust crate napi to v3.8.3 [`#2474`](ast-grep/ast-grep#2474)
- chore(deps): update rust crate futures to v0.3.32 [`#2476`](ast-grep/ast-grep#2476)
- chore(deps): update rust crate clap to v4.5.58 [`#2470`](ast-grep/ast-grep#2470)
- fix: parse each language injection region as independent tree [`#2479`](ast-grep/ast-grep#2479)
- chore(deps): update dependency [@types/node](https://github.com/types/node) to v24.10.13 [`#2467`](ast-grep/ast-grep#2467)
- chore(deps): update rust crate clap\_complete to v4.5.66 [`#2471`](ast-grep/ast-grep#2471)
- chore(deps): update rust crate predicates to v3.1.4 [`#2472`](ast-grep/ast-grep#2472)
- chore(deps): update dependency oxlint to v1.47.0 [`#2468`](ast-grep/ast-grep#2468)
- chore(deps): update rust crate tempfile to v3.25.0 [`#2466`](ast-grep/ast-grep#2466)
- fix(deps): update rust crate toml\_edit to 0.25.0 [`#2473`](ast-grep/ast-grep#2473)
- chore(deps): update rust crate tree-sitter to v0.26.5 [`#2458`](ast-grep/ast-grep#2458)
- chore(deps): update dependency [@types/node](https://github.com/types/node) to v24.10.12 [`#2438`](ast-grep/ast-grep#2438)
- chore(deps): update rust crate schemars to v1.2.1 [`#2457`](ast-grep/ast-grep#2457)
- chore(deps): update rust crate clap to v4.5.57 [`#2455`](ast-grep/ast-grep#2455)
- chore(deps): update rust crate anyhow to v1.0.101 [`#2462`](ast-grep/ast-grep#2462)
- chore(deps): update rust crate inquire to v0.9.3 [`#2463`](ast-grep/ast-grep#2463)
- chore(deps): update dependency oxlint to v1.43.0 [`#2459`](ast-grep/ast-grep#2459)
- chore(deps): update rust crate regex to v1.12.3 [`#2461`](ast-grep/ast-grep#2461)
- chore(deps): update rust crate clap to v4.5.55 [`#2454`](ast-grep/ast-grep#2454)
- chore(deps): update dependency oxlint to v1.42.0 [`#2452`](ast-grep/ast-grep#2452)
- chore(deps): update dependency oxlint to v1.41.0 [`#2447`](ast-grep/ast-grep#2447)
- chore(deps): update rust crate assert\_cmd to v2.1.2 [`#2437`](ast-grep/ast-grep#2437)
- chore(deps): update rust crate thiserror to v2.0.18 [`#2446`](ast-grep/ast-grep#2446)
- chore(deps): update dependency oxlint to v1.39.0 [`#2442`](ast-grep/ast-grep#2442)
- chore(deps): update rust crate inquire to v0.9.2 [`#2445`](ast-grep/ast-grep#2445)
- fix: improve max diagnostic impl to use one atomic op [`781ec81`](ast-grep/ast-grep@781ec81)
- fix: udpate schema [`e645fdf`](ast-grep/ast-grep@e645fdf)
- fix: move dumping to core crate [`0b2acb9`](ast-grep/ast-grep@0b2acb9)

Renovate-Branch: renovate/2024.6-ast-grep-cli-0.x
Change-Id: I88da2bd1f360bebda04663520c30423d0cb7ddd1
Priv-Id: 72123de3a05b89754a6bf040b3bd2708f3d9a9e2
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.

2 participants