From b8d9f1f06090fb96464304c84dcbd0872e17e873 Mon Sep 17 00:00:00 2001 From: blasty Date: Thu, 9 Jul 2026 20:48:19 +0200 Subject: rename: refuse pseudocode goto-labels with a clear message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pressing 'n' on a Hex-Rays goto label (LABEL_n, or any 'goto TARGET') in the decompiler routed to a 'local' rename, which the API rejects with a misleading "Local variable 'LABEL_114' not found" — the user just saw a cryptic failure. The rename tool has no label category (only func/global/local/stack) and idalib exposes no other way to rename pseudocode labels. Detect a label token under the cursor (_is_pseudocode_label) and report the limitation up front instead of opening a prompt that's doomed to fail. Add a pilot check (uses main's labels when the current function has none). full suite 61/61. --- tests/test_tui.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'tests') diff --git a/tests/test_tui.py b/tests/test_tui.py index f74863a..ca5cea9 100644 --- a/tests/test_tui.py +++ b/tests/test_tui.py @@ -592,6 +592,43 @@ async def run(db): check("rename reverted cleanly", rr.get("summary", {}).get("ok", 0) == 1, str(rr.get("summary"))) + # A Hex-Rays goto label has no rename API; pressing 'n' on one must be + # refused up front with a clear message, not open a prompt that then + # fails with a misleading 'local variable not found'. + def _find_label(): + for i, t in enumerate(dec._texts): + mm = re.search(r"\bLABEL_\d+\b", t) + if mm: + return i, mm.start(), mm.group(0) + return None + lab = _find_label() + if lab is None: # current func has none; main reliably has labels + await pilot.press("g") + await pilot.pause(0.1) + for ch in "main": + await pilot.press(ch) + await pilot.press("enter") + await wait_until(pilot, lambda: app._cur and app._cur.name == "main", 20) + if app._active != "decomp": + await pilot.press("tab") + await wait_until(pilot, lambda: dec.loaded_ea == app._cur.ea, 25) + lab = _find_label() + if lab is not None: + li, lc, ltok = lab + dec.focus() + dec.cursor, dec.cursor_x = li, lc + 1 + dec.refresh() + await pilot.pause(0.05) + await pilot.press("n") + await pilot.pause(0.1) + ri2 = app.query_one("#rename", Input) + st = str(app.query_one("#status").render()) + check("renaming a pseudocode label is refused with a clear message", + (not ri2.display) and "label" in st.lower(), + f"display={ri2.display} status={st!r}") + else: + check("found a pseudocode label to test", False, "no LABEL_ found") + # Decompiler follow of a name NOT in refs (the function's own name). await pilot.press("g") await pilot.pause(0.1) -- cgit v1.3.1-sl0p