ex_ast 0.12.0, Elixir 1.18.4 / OTP 27.
Repro
source = """
conn
|> assert_has(".a", checked: true)
|> assert_has(".b", checked: true)
"""
ExAST.Patcher.find_all(source, "assert_has(_, _, checked: _)")
# => 1 match (line 3)
Expected 2 matches (lines 2 and 3). Same behavior through mix ex_ast.search.
What seems to happen
With pipe normalization, the line-3 call's first argument contains the line-2 call (assert_has(assert_has(conn, ".a", ...), ".b", ...)), and only the outermost matching node is reported — inner matches nested inside an already-matched node are skipped.
Why it matters
Long |> chains are the dominant style in Phoenix test suites. We used ex_ast to audit a real suite for a misused option and it reported 9 sites where there were actually 12 — the 3 missing ones were earlier stages of pipe chains whose later stage also matched. An undercount is risky for exactly the audit/replace workflows the tool is built for.
If this is intentional overlapping-match suppression, it would be good to document it and/or offer an option to include nested matches; for pipe chains specifically, each stage feels like a distinct match to a user.
ex_ast 0.12.0, Elixir 1.18.4 / OTP 27.
Repro
Expected 2 matches (lines 2 and 3). Same behavior through
mix ex_ast.search.What seems to happen
With pipe normalization, the line-3 call's first argument contains the line-2 call (
assert_has(assert_has(conn, ".a", ...), ".b", ...)), and only the outermost matching node is reported — inner matches nested inside an already-matched node are skipped.Why it matters
Long
|>chains are the dominant style in Phoenix test suites. We used ex_ast to audit a real suite for a misused option and it reported 9 sites where there were actually 12 — the 3 missing ones were earlier stages of pipe chains whose later stage also matched. An undercount is risky for exactly the audit/replace workflows the tool is built for.If this is intentional overlapping-match suppression, it would be good to document it and/or offer an option to include nested matches; for pipe chains specifically, each stage feels like a distinct match to a user.