Cha
1.18.0 - 2026-05-22
v1.18.0
May 22 2026 at 11:51 UTC
Internal: Dogfooding cleanup
Built-in detectors now use AST queries instead of text scanning, resolving a longstanding hypocrisy where Cha advertised AST-based analysis but several core plugins did substring matches that misfired on strings, comments, and unrelated identifiers.
Added
cha_core::query— host-side tree-sitter query helper (run_query/run_queries/node_to_match). Both built-in plugins and the WASMtree_queryhost import now go through this single API.DeadCodeAnalyzer::entry_points— entry-point names are now configurable via[plugins.dead_code] entry_points = [...]. Default list expanded from Rust-only (5 names) to multi-language (Rust + Python__init__etc + Goinit+ C_start+ tokio).LengthAnalyzer::complexity_factor_threshold— was hardcoded10.0, now configurable via[plugins.length].
Fixed
unsafe_api: rewritten from line-basedline.contains+ odd-quote-count heuristic to per-language tree-sitter queries. lvgl baseline picks up 19 realsprintf/strcpy/strcat/systemcall sites; previously zero. Comments and string literals containing keywords likeunsafeno longer false-positive.dead_code: substringis_in_file_referencedreplaced with AST identifier scan. Token-concat macro detection rewritten — instead of nuking the entire file when any#define ... ##exists, parse define bodies forprefix##X##suffixslots, scan call sites for invocation arguments, synthesize plausible expansion names, and add them to the reference set. lvgl thorvg'sSTYLE_DEFdispatch table no longer hides every dispatch function.IdentifierPositionslookup is now O(1) per symbol viaHashMap<name, Vec<line>>.error_handling:unwrap_abuseuses tree-sitter ((call_expression field_expression unwrap|expect)); empty-catch detection is per-language (Rust skipped, TScatch_clause, Pythonexcept_clause). String literals and comments containing the substringunwraporcatchno longer trigger.hardcoded_secret: regex matches now run againststring_literalnode text only, not full source lines. Comments and identifier names with secret-like substrings no longer false-positive.cha fix:String::replacewhole-content substitution replaced with tree-sitter identifier-node range collection + byte-offset reverse substitution. The previous implementation could rewrite identifier names inside string literals and comments, corrupting source files.git_metrics::check_test_ratio:f.contains("test") || f.contains("spec")replaced withcha_core::is_test_path. The substring check wrongly countedrequest.rs/spectrum.rsetc. as test files, polluting the test-to-production ratio that driveslow_test_ratio.wasm.rs::infer_file_role: replaced duplicate test-path heuristics withcha_core::is_test_path. WASM plugins'FileRole::Testclassification now matches the canonical convention used elsewhere (__tests__/,__mocks__/,.test.ts,.spec.ts).find_macro_invocation_args: word-boundary check added —STYLE_DEFno longer matchesSTYLE_DEFINEinvocations.
Removed
unsafe_apiis_in_stringheuristic — superseded by tree-sitter queries that distinguish string literals at the AST level.error_handlingline-baseddetect_empty_catch— replaced with grammar-aware queries.HostState::query_cache— query compilation now lives incha_core::query(compile-on-demand; LRU caching to be added if measurement warrants).