Cha
1.12.0 - 2026-04-28
v1.12.0
Apr 28 2026 at 13:57 UTC
Added
SymbolIndex— structural view of a file, cached separately fromSourceModel. New type incha-core::modelcarrying the fields consumers likecha deps, LSP workspace-symbols, and futurecha summaryall share — class/function names + signatures + positions +type_aliases— without per-function-body data (complexity, body hash, TypeRef origin, cognitive, chain depth etc. stay inSourceModel).ProjectCache::{get,put}_symbolsstore tosymbols/{chash}.bin, mirrored independently ofparse/{chash}.bin. Sameenv_hashmechanism invalidates both on parser code changes.cached_symbols(path)is a new warm fast path that skipsSourceModeldeserialisation entirely —symbols/{chash}.binis roughly 10% the size ofparse/{chash}.bin.cached_parsenow populates both caches on every fresh parse, so the two views are always in lockstep.lvgl src/warm benchmarks (379 files):deps --type imports1.28s → 38ms (34×),--type classes1.30s → 56ms (23×),--type calls1.30s → 48ms (27×). Edge counts unchanged vs. pre-migration (1351/142/8109).cha-cli/src/c_oop_enrichgrows aenrich_c_oop_symbols/attribute_methods_by_name_from_symbolspair alongside the existingSourceModelfunctions. Sharedattribute_one_rawkeeps attribution rules single-sourced; build-index / write-back are deliberate parallel code paths because the two storage types have to stay independent.cha-cli/src/parse_cache.rs(new module) hosts bothcached_parseandcached_symbols.
- C++ parser now handles
ClassName::method()out-of-class definitions, namespaces, and templates. Three gaps in the previous CppParser have been closed:void Foo::bar() {...}(and::global(),A::B::c(), destructorsFoo::~Foo(), operatorsFoo::operator+()) was silently dropped —find_func_name_nodeonly accepted bareidentifierdeclarators. It now also unwrapsqualified_identifier,destructor_name, andoperator_name.- Out-of-class method definitions now attribute to their owning same-file class:
void Foo::bar()bumpsClassInfo::method_countonFooand flipshas_behavior. Cross-file attribution still runs throughcha-cli::c_oop_enrich. namespace_definition,linkage_specification(extern "C" { ... }), andtemplate_declarationare now explicitly matched in the top-level dispatch (previously fell through to the generic recursion arm) — same observable behaviour, but the nesting constructs are now a stable hook rather than an accidental default-case artefact.- C++-specific declarator helpers moved to a new
cha-parser/src/cpp.rssoc_lang.rsstays below thelarge_filegate.
SourceModel.type_aliasesnow populated for Rust, TypeScript, Python, and Go (previously all four returned emptyvec![]with parser-side TODOs). Each parser recognises its language's alias form and records(alias, rhs)pairs: Rusttype X = Y;/pub type X<T> = Y;, TypeScripttype X = Y;/export type X<T> = Y;, Python 3.12+type X = Yand pre-3.12X: TypeAlias = Y, Gotype X = Y(only the true alias form —type X Ydefined types are excluded). Plain PythonX = Yassignments remain unclassified (too ambiguous). Shared extraction lives in a newcha-parser/src/type_aliases.rsmodule so per-language files stay below thelarge_filegate.
Changed
boundary_leakdetector migrated toProjectIndex. The three smells it emits (abstraction_boundary_leak,return_type_leak,test_only_type_in_production) previously parsed the whole project a second time — the codebase noted a "cached model occasionally drops typedef aliases" concern with root cause TBD. v1.11.0's binary-mtime cache keying removed the suspected root cause, and a newcache::tests::cache_roundtrip_preserves_type_aliasesunit test makes the invariant a testable one.boundary_leak::detectnow takes&ProjectIndexand shares the same parse pass asanemic_domain_model,typed_intimacy,module_envy, and friends. Verified against lvgl'ssrc/tree: 155 findings before = 155 findings after (abstraction_boundary_leak: 154, return_type_leak: 1). Completes roadmap S8.infra.4.
Fixed
- C++: template specialisation methods attribute to the right class.
template<> void Foo<int>::bar()used to drop on the floor because the qualifierFoo<int>(atemplate_typenode) didn't match the stored class nameFoo.attach_to_classnow strips trailing<...>template arguments before matching, so out-of-class specialisations attribute correctly. Same stripping applies to any declaration whose declarator surfacesFoo<...>as the owning scope. - C++: real inheritance (
class Derived : public Base) now recognised.extract_classconsults thebase_class_clausechild and pulls the firsttype_identifier(ortemplate_type's underlying name) asparent_name. Falls back to the first-field heuristic only when no base clause is present, so legacy C struct-embedding cases still work. Also fixes the class-name extraction for templated classes sotemplate<typename T> class Foo {...}stores"Foo"instead of"Foo<T>". - C++: reference-return methods no longer vanish.
const int& Foo::get()and similarreference_declarator-wrapped definitions used to be silently dropped because tree-sitter-cpp'sreference_declaratorhas nodeclaratorfield — the declarator walker returnedNone. Bothfind_func_name_node(c_lang) anddescend_to_qualified_identifier(cpp) now fall back to the first named child when the field is absent. Same fix path covers reference-return + qualified (const T& Foo::bar()) so class attribution still works. 6 additional regression tests (reference/pointer return types, multi-method attribution, constructor,extern "C", const member) added incha-parser/tests/cpp_enhancements.rs(14 total).