rtk-ai/rtk

AggressiveFilter: trailing { on function signature skips brace counting, leaking let-bindings from function bodies

Open

#1323 opened on Apr 15, 2026

View on GitHub
 (1 comment) (0 reactions) (0 assignees)Rust (48,085 stars) (2,914 forks)batch import
bugeffort-smallfilter-qualitygood first issue

Description

Description

When a function signature includes the opening brace on the same line (e.g. fn compute(x: i32) -> i32 {), the FUNC_SIGNATURE branch emits the line and calls continue before the brace-counting code runs. This leaves brace_depth at 0 after the signature, causing the first body line to immediately reset in_impl_body = false, so subsequent let bindings leak through the "Keep type definitions" branch.

Reproduction

#[test]
fn test_aggressive_brace_tracking() {
    let filter = AggressiveFilter;
    let input = r#"fn compute(x: i32) -> i32 {
    let result = x * 2;
    let extra = result + 1;
    extra
}
"#;
    let result = filter.filter(input, &Language::Rust);
    // Bug: brace_depth stays 0 after the signature line because the
    // FUNC_SIGNATURE branch calls `continue` before brace counting runs.
    // The body's `let` lines then match the "Keep type definitions" branch
    // and leak into the output.
    assert!(
        !result.contains("let result = x * 2;"),
        "let binding inside function body should be filtered out"
    );
    assert!(
        !result.contains("let extra = result + 1;"),
        "let binding inside function body should be filtered out"
    );
}

Running this test exposes the bug: both let result and let extra appear in the aggressive-filtered output because they escape through the trimmed.starts_with("let ") branch that is intended only for top-level bindings.

Root cause

In AggressiveFilter::filter (src/core/filter.rs), the signature branch is:

if FUNC_SIGNATURE.is_match(trimmed) {
    result.push_str(line);
    result.push('\n');
    in_impl_body = true;
    brace_depth = 0;
    continue;   // <-- jumps past brace-counting below
}

// Track brace depth for implementation bodies
let open_braces = trimmed.matches('{').count();
let close_braces = trimmed.matches('}').count();

When the signature line ends with { (e.g. fn compute(x: i32) -> i32 {), continue is called before open_braces is counted. brace_depth stays at 0. The very next line hits:

if brace_depth <= 0 {
    in_impl_body = false;
    ...
}

...which turns off in_impl_body immediately. Subsequent let lines fall through to the "Keep type definitions" section and are emitted.

The fix is to count the braces on the signature line itself before (or instead of) calling continue, so that a trailing { is reflected in brace_depth.

Notes

Found while running tailtest on this codebase. The generated test suite documents the current (buggy) behavior -- the assertions will fail once the bug is fixed.

Contributor guide