diff --git a/gitnexus/src/core/ingestion/languages/cpp/arity-metadata.ts b/gitnexus/src/core/ingestion/languages/cpp/arity-metadata.ts index 7bfb0e09d..fb47d3122 100644 --- a/gitnexus/src/core/ingestion/languages/cpp/arity-metadata.ts +++ b/gitnexus/src/core/ingestion/languages/cpp/arity-metadata.ts @@ -127,8 +127,13 @@ function normalizeCppParamType(raw: string): string { t = t.replace(/\b(const|volatile|restrict|mutable|constexpr)\b/g, '').trim(); // Strip reference/pointer markers t = t.replace(/[&*]+\s*$/, '').trim(); - // Strip template parameters - t = t.replace(/<[^>]*>/g, '').trim(); + // Strip template parameters (loop handles nested: Map> → Map) + while (t.includes('<')) { + const stripped = t.replace(/<[^<>]*>/g, ''); + if (stripped === t) break; // avoid infinite loop on malformed input + t = stripped; + } + t = t.trim(); // Map std:: types to canonical short forms const STD_MAP: Record = { 'std::string': 'string', diff --git a/gitnexus/src/core/ingestion/languages/cpp/interpret.ts b/gitnexus/src/core/ingestion/languages/cpp/interpret.ts index 93fa3372e..a5c1692a8 100644 --- a/gitnexus/src/core/ingestion/languages/cpp/interpret.ts +++ b/gitnexus/src/core/ingestion/languages/cpp/interpret.ts @@ -64,7 +64,7 @@ export function interpretCppTypeBinding(captures: CaptureMatch): ParsedTypeBindi // Synthesize a dotted rawName ("receiver.field") so compound-receiver // can resolve the chain: look up receiver's class, then field's type. const receiver = captures['@type-binding.member-access-receiver']?.text; - if (receiver !== undefined && name !== undefined) { + if (receiver !== undefined) { return { boundName: name, rawTypeName: `${receiver}.${type}`, source: 'assignment-inferred' }; } source = 'assignment-inferred'; @@ -90,8 +90,13 @@ export function normalizeCppTypeName(text: string): string { t = t .replace(/\b(const|volatile|restrict|static|extern|inline|mutable|constexpr|consteval)\b/g, '') .trim(); - // Strip template parameters: List → List - t = t.replace(/<[^>]*>/g, '').trim(); + // Strip template parameters (loop handles nested: Map> → Map) + while (t.includes('<')) { + const stripped = t.replace(/<[^<>]*>/g, ''); + if (stripped === t) break; // avoid infinite loop on malformed input + t = stripped; + } + t = t.trim(); // Strip pointer stars while (t.endsWith('*')) t = t.slice(0, -1).trim(); while (t.startsWith('*')) t = t.slice(1).trim(); diff --git a/gitnexus/test/integration/resolvers/cpp.test.ts b/gitnexus/test/integration/resolvers/cpp.test.ts index 44d084b51..cbe105494 100644 --- a/gitnexus/test/integration/resolvers/cpp.test.ts +++ b/gitnexus/test/integration/resolvers/cpp.test.ts @@ -1,7 +1,7 @@ /** * C++: diamond inheritance + include-based imports + ambiguous #include disambiguation */ -import { describe, it, expect, beforeAll } from 'vitest'; +import { describe, expect, beforeAll } from 'vitest'; import path from 'path'; import { FIXTURES, diff --git a/gitnexus/test/unit/group/include-extractor.test.ts b/gitnexus/test/unit/group/include-extractor.test.ts index 49dcf0600..7bf71a6f0 100644 --- a/gitnexus/test/unit/group/include-extractor.test.ts +++ b/gitnexus/test/unit/group/include-extractor.test.ts @@ -11,8 +11,7 @@ describe('IncludeExtractor', () => { let extractor: IncludeExtractor; beforeEach(() => { - tmpDir = path.join(os.tmpdir(), `gitnexus-include-${Date.now()}`); - fs.mkdirSync(tmpDir, { recursive: true }); + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gitnexus-include-')); extractor = new IncludeExtractor(); }); @@ -164,15 +163,13 @@ int main() { return 0; }`, describe('cross-repo matching', () => { it('provider and consumer produce matching contractIds', async () => { // Simulate provider repo (header-only) - const providerDir = path.join(os.tmpdir(), `gitnexus-include-provider-${Date.now()}`); - fs.mkdirSync(providerDir, { recursive: true }); + const providerDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gitnexus-include-provider-')); const providerFile = path.join(providerDir, 'map/base/dice_map_view.h'); fs.mkdirSync(path.dirname(providerFile), { recursive: true }); fs.writeFileSync(providerFile, '#pragma once\nclass DiceMapView {};'); // Simulate consumer repo - const consumerDir = path.join(os.tmpdir(), `gitnexus-include-consumer-${Date.now()}`); - fs.mkdirSync(consumerDir, { recursive: true }); + const consumerDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gitnexus-include-consumer-')); const consumerFile = path.join(consumerDir, 'src/controller.cpp'); fs.mkdirSync(path.dirname(consumerFile), { recursive: true }); fs.writeFileSync(consumerFile, '#include "map/base/dice_map_view.h"\nvoid init() {}');