From 4a94f1aea8ce2318ca6ec90821ed754863f21659 Mon Sep 17 00:00:00 2001 From: Christoph Brandau Date: Wed, 13 Aug 2025 12:45:46 +0200 Subject: [PATCH] fix if var exits for incr --- server/src/tools/checks.py | 13 +++++++++++-- server/src/tools/semantic_tokens.py | 16 +++++++++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/server/src/tools/checks.py b/server/src/tools/checks.py index 3b8367a..dfeaae6 100644 --- a/server/src/tools/checks.py +++ b/server/src/tools/checks.py @@ -144,16 +144,25 @@ class UndeclaredVariableCheck(Visitor): # Second pass: flag VarSub usages that are not accounted for def _scan(node): + # 1) Variable substitutions like $var if isinstance(node, VarSub): var_name = node.value or "" - # Strip leading namespace separator for comparison; treat only leading :: as global if var_name.startswith("::"): return base = var_name - # VarSub.value does not include index; indices are separate children if base not in locals_set and base not in declared_globals: msg = f"Variable '{base}' used in proc is not set locally and not declared global; use 'global {base}' or '$::{base}'" self._violations.append(Violation(Rules.UNDECLARED_VARIABLE, msg, node.pos, node.end_pos)) + # 2) Commands that take a variable name as first argument, e.g., 'incr var [amount]' + elif isinstance(node, Command) and hasattr(node.routine, "contents"): + if node.routine.contents == "incr" and node.args: + first_arg = node.args[0] + text = _word_text(first_arg) or "" + base = text.split("(", 1)[0] + if base and not base.startswith("::"): + if base not in locals_set and base not in declared_globals: + msg = f"Variable '{base}' used in proc is not set locally and not declared global; use 'global {base}'" + self._violations.append(Violation(Rules.UNDECLARED_VARIABLE, msg, first_arg.pos, first_arg.end_pos)) for ch in getattr(node, "children", []): _scan(ch) diff --git a/server/src/tools/semantic_tokens.py b/server/src/tools/semantic_tokens.py index 462629c..f701605 100644 --- a/server/src/tools/semantic_tokens.py +++ b/server/src/tools/semantic_tokens.py @@ -133,7 +133,21 @@ class _Highlighter(Visitor): if len(command.args) == 1 and token_info: (line, col), length = token_info mods = [TokenModifier.reference] - # Mark as reference (read); remove write/declaration (keep simple: we still keep declaration above for consistency) + self._tokens.append(((line, col), length, "variable", mods)) + # Variable modification via 'incr var [amount]' + if routine.contents == "incr" and command.args: + first_arg = command.args[0] + token_info = self._get_token_info(first_arg) + if token_info: + (line, col), length = token_info + mods = [TokenModifier.write] + # Add global flag if explicitly namespaced + try: + name_text = getattr(first_arg, "value", None) or getattr(first_arg, "contents", None) or "" + if isinstance(name_text, str) and name_text.startswith("::"): + mods.append(TokenModifier.globalvar) + except Exception: + pass self._tokens.append(((line, col), length, "variable", mods)) if routine.contents == "proc" and command.args: first_arg = command.args[0]