fix(cpp): capture uninitialized multi-declarators (#1965)

This commit is contained in:
azizur100389 2026-06-02 11:38:41 +01:00 • committed by GitHub
parent eb2ba3dcad
commit 51d06de71e
5 changed files with 44 additions and 2 deletions

View file

@ -16,9 +16,10 @@
"_added": "#1956: c added to the scope-capture bench (was UNBENCHED). C has no inheritance — flat scale source. Adding it exposed + fixed a pre-existing O(n^2) findNodeAtRange root-walk in c/captures.ts (threaded c.node, byte-identical over c-* fixtures); scaling 3.475 -> 0.96."
},
"cpp": {
"fingerprint": "a571d260559fa48994d12970965b4f9df93efd087541ca31dc7818ac4cd2a2a6",
"fingerprint": "4022f436885d15fd2d419e38e0674115e1c5daa7dcb9578de2633160bed94446",
"scaling_budget": 1.5,
"_added": "#1956: cpp added to the scope-capture bench (was UNBENCHED). Heritage-bearing scale source (: public Base, public Mixin) drives emitCppInheritanceCaptures at scale. Adding it exposed + fixed a pre-existing O(n^2) findNodeAtRange root-walk in cpp/captures.ts (~12 sites, threaded c.node, byte-identical over 263 cpp-* fixtures); scaling 2.30 -> 1.12."
"_added": "#1956: cpp added to the scope-capture bench (was UNBENCHED). Heritage-bearing scale source (: public Base, public Mixin) drives emitCppInheritanceCaptures at scale. Adding it exposed + fixed a pre-existing O(n^2) findNodeAtRange root-walk in cpp/captures.ts (~12 sites, threaded c.node, byte-identical over 263 cpp-* fixtures); scaling 2.30 -> 1.12.",
"_rebaselined": "#1965 / #1923 F4: uninitialized non-leading multi-declarators now emit @declaration.variable captures; cpp-adl-inner-callable-outer-noncallable data::Pair a, b adds the legitimate fixture drift. Linear (~1.06)."
},
"csharp": {
"_rebaselined": "#1956 synth-widening: + csharp-qualified-base fixture; the synth now walks record_declaration + struct_declaration base_lists and handles alias_qualified_name (matching the #1940 legacy leg), so record/struct heritage now emits. csharp-record-base gains a record inherits capture. (record->record SAME-namespace EXTENDS is a separate registry resolution gap, tracked as follow-up.) Linear (~1.00). (Earlier #1956: heritage-bearing scale source.)",

View file

@ -99,6 +99,15 @@ const C_SCOPE_QUERY = `
declarator: (init_declarator
declarator: (identifier) @declaration.name)) @declaration.variable
;; Declarations — variables (without initializer), including non-leading
;; declarators in mixed declaration lists.
(declaration
declarator: (identifier) @declaration.name) @declaration.variable
(declaration
declarator: (pointer_declarator
declarator: (identifier) @declaration.name)) @declaration.variable
;; Declarations — macro definitions
(preproc_def
name: (identifier) @declaration.name) @declaration.macro

View file

@ -273,6 +273,15 @@ const CPP_SCOPE_QUERY = `
declarator: (init_declarator
declarator: (identifier) @declaration.name)) @declaration.variable
;; ─── Declarations — variables (without initializer) ─────────────────
;; Covers non-leading declarators in mixed declaration lists.
(declaration
declarator: (identifier) @declaration.name) @declaration.variable
(declaration
declarator: (pointer_declarator
declarator: (identifier) @declaration.name)) @declaration.variable
;; ─── Declarations — macro definitions ───────────────────────────────
(preproc_def
name: (identifier) @declaration.name) @declaration.macro

View file

@ -198,6 +198,14 @@ describe('emitCScopeCaptures — other declarations', () => {
expect(m!['@declaration.name'].text).toBe('x');
});
it('captures all names in mixed initialized and uninitialized declarations', () => {
const matches = allMatches('void f(void) { int a = 1, b, *p, c = 3, d; }', (t) =>
t.includes('@declaration.variable'),
);
const names = matches.map((m) => m['@declaration.name'].text).sort();
expect(names).toEqual(['a', 'b', 'c', 'd', 'p']);
});
it('captures macro as @declaration.macro', () => {
const m = findMatch('#define MAX 100', (t) => t.includes('@declaration.macro'));
expect(m).toBeDefined();

View file

@ -222,6 +222,21 @@ describe('emitCppScopeCaptures — variable declarations', () => {
expect(m).toBeDefined();
expect(m!['@declaration.name'].text).toBe('x');
});
it('captures all names in mixed initialized and uninitialized declarations', () => {
const matches = allMatches('void f() { int a = 1, b, *p, c = 3, d; }', (t) =>
t.includes('@declaration.variable'),
);
const names = matches.map((m) => m['@declaration.name'].text).sort();
expect(names).toEqual(['a', 'b', 'c', 'd', 'p']);
});
it('captures qualified-type multi-declarator variables', () => {
const src = 'namespace data { struct Pair {}; } void f() { data::Pair a, b; }';
const matches = allMatches(src, (t) => t.includes('@declaration.variable'));
const names = matches.map((m) => m['@declaration.name'].text).sort();
expect(names).toEqual(['a', 'b']);
});
});
// ── Declarations — enums ────────────────────────────────────────────────────