c-next 0.1.70 → 0.1.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/lib/__tests__/parseCHeader.mocked.test.ts +69 -54
- package/src/lib/parseCHeader.ts +56 -23
- package/src/lib/parseWithSymbols.ts +195 -53
- package/src/transpiler/Transpiler.ts +180 -63
- package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +1 -2
- package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +1 -2
- package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +51 -2
- package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +18 -12
- package/src/transpiler/logic/analysis/__tests__/InitializationAnalyzer.test.ts +9 -9
- package/src/transpiler/logic/analysis/__tests__/runAnalyzers.test.ts +5 -5
- package/src/transpiler/logic/symbols/SymbolTable.ts +729 -265
- package/src/transpiler/logic/symbols/SymbolUtils.ts +2 -2
- package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +415 -751
- package/src/transpiler/logic/symbols/c/__tests__/CResolver.integration.test.ts +573 -0
- package/src/transpiler/logic/symbols/c/__tests__/testHelpers.ts +20 -0
- package/src/transpiler/logic/symbols/c/collectors/EnumCollector.ts +82 -0
- package/src/transpiler/logic/symbols/c/collectors/FunctionCollector.ts +106 -0
- package/src/transpiler/logic/symbols/c/collectors/StructCollector.ts +173 -0
- package/src/transpiler/logic/symbols/c/collectors/TypedefCollector.ts +35 -0
- package/src/transpiler/logic/symbols/c/collectors/VariableCollector.ts +80 -0
- package/src/transpiler/logic/symbols/c/index.ts +333 -0
- package/src/transpiler/logic/symbols/c/utils/DeclaratorUtils.ts +269 -0
- package/src/transpiler/logic/symbols/cnext/__tests__/BitmapCollector.test.ts +50 -11
- package/src/transpiler/logic/symbols/cnext/__tests__/CNextResolver.integration.test.ts +45 -34
- package/src/transpiler/logic/symbols/cnext/__tests__/EnumCollector.test.ts +30 -13
- package/src/transpiler/logic/symbols/cnext/__tests__/FunctionCollector.test.ts +279 -64
- package/src/transpiler/logic/symbols/cnext/__tests__/RegisterCollector.test.ts +60 -13
- package/src/transpiler/logic/symbols/cnext/__tests__/ScopeCollector.test.ts +40 -37
- package/src/transpiler/logic/symbols/cnext/__tests__/StructCollector.test.ts +131 -45
- package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolInfoAdapter.test.ts +223 -139
- package/src/transpiler/logic/symbols/cnext/__tests__/VariableCollector.test.ts +79 -25
- package/src/transpiler/logic/symbols/cnext/__tests__/testUtils.ts +53 -0
- package/src/transpiler/logic/symbols/cnext/adapters/TSymbolInfoAdapter.ts +83 -43
- package/src/transpiler/logic/symbols/cnext/collectors/BitmapCollector.ts +14 -13
- package/src/transpiler/logic/symbols/cnext/collectors/EnumCollector.ts +11 -10
- package/src/transpiler/logic/symbols/cnext/collectors/FunctionCollector.ts +83 -34
- package/src/transpiler/logic/symbols/cnext/collectors/RegisterCollector.ts +22 -18
- package/src/transpiler/logic/symbols/cnext/collectors/ScopeCollector.ts +53 -35
- package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +30 -23
- package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +18 -19
- package/src/transpiler/logic/symbols/cnext/index.ts +36 -14
- package/src/transpiler/logic/symbols/cnext/types/IScopeCollectorResult.ts +2 -2
- package/src/transpiler/logic/symbols/cnext/utils/SymbolNameUtils.ts +27 -0
- package/src/transpiler/logic/symbols/cpp/__tests__/CppResolver.integration.test.ts +270 -0
- package/src/transpiler/logic/symbols/cpp/__tests__/testHelpers.ts +20 -0
- package/src/transpiler/logic/symbols/cpp/collectors/ClassCollector.ts +317 -0
- package/src/transpiler/logic/symbols/cpp/collectors/EnumCollector.ts +71 -0
- package/src/transpiler/logic/symbols/cpp/collectors/FunctionCollector.ts +155 -0
- package/src/transpiler/logic/symbols/cpp/collectors/NamespaceCollector.ts +65 -0
- package/src/transpiler/logic/symbols/cpp/collectors/TypeAliasCollector.ts +46 -0
- package/src/transpiler/logic/symbols/cpp/collectors/VariableCollector.ts +54 -0
- package/src/transpiler/logic/symbols/cpp/index.ts +366 -0
- package/src/transpiler/logic/symbols/cpp/utils/DeclaratorUtils.ts +248 -0
- package/src/transpiler/logic/symbols/shared/IExtractedParameter.ts +18 -0
- package/src/transpiler/logic/symbols/shared/ParameterExtractorUtils.ts +73 -0
- package/src/transpiler/output/codegen/CodeGenerator.ts +268 -1674
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +7 -1
- package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +2 -1
- package/src/transpiler/output/codegen/assignment/handlers/AssignmentHandlerUtils.ts +7 -1
- package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +6 -2
- package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +2 -1
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +21 -8
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopedRegisterGenerator.ts +3 -2
- package/src/transpiler/output/codegen/generators/expressions/CallExprUtils.ts +9 -3
- package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +3 -4
- package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprUtils.test.ts +4 -8
- package/src/transpiler/output/codegen/helpers/ArgumentGenerator.ts +236 -0
- package/src/transpiler/output/codegen/helpers/CppConstructorHelper.ts +3 -3
- package/src/transpiler/output/codegen/helpers/FunctionContextManager.ts +435 -0
- package/src/transpiler/output/codegen/helpers/StringOperationsHelper.ts +203 -0
- package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +8 -12
- package/src/transpiler/output/codegen/helpers/TypeRegistrationEngine.ts +520 -0
- package/src/transpiler/output/codegen/helpers/VariableDeclHelper.ts +735 -0
- package/src/transpiler/output/codegen/helpers/VariableDeclarationFormatter.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/ArgumentGenerator.test.ts +521 -0
- package/src/transpiler/output/codegen/helpers/__tests__/CppConstructorHelper.test.ts +4 -5
- package/src/transpiler/output/codegen/helpers/__tests__/FunctionContextManager.test.ts +983 -0
- package/src/transpiler/output/codegen/helpers/__tests__/StringOperationsHelper.test.ts +269 -0
- package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +31 -32
- package/src/transpiler/output/codegen/helpers/__tests__/TypeRegistrationEngine.test.ts +186 -0
- package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclHelper.test.ts +460 -0
- package/src/transpiler/output/codegen/helpers/types/IArgumentGeneratorCallbacks.ts +32 -0
- package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +5 -1
- package/src/transpiler/output/codegen/types/IFunctionContextCallbacks.ts +12 -0
- package/src/transpiler/output/codegen/types/IVariableFormatInput.ts +1 -1
- package/src/transpiler/output/codegen/utils/QualifiedNameGenerator.ts +114 -0
- package/src/transpiler/output/codegen/utils/__tests__/QualifiedNameGenerator.test.ts +183 -0
- package/src/transpiler/output/headers/BaseHeaderGenerator.ts +4 -4
- package/src/transpiler/output/headers/ExternalTypeHeaderBuilder.ts +7 -7
- package/src/transpiler/output/headers/HeaderGenerator.ts +9 -7
- package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +19 -20
- package/src/transpiler/output/headers/__tests__/BaseHeaderGenerator.test.ts +15 -18
- package/src/transpiler/output/headers/__tests__/CHeaderGenerator.test.ts +63 -64
- package/src/transpiler/output/headers/__tests__/CppHeaderGenerator.test.ts +36 -32
- package/src/transpiler/output/headers/__tests__/ExternalTypeHeaderBuilder.test.ts +26 -26
- package/src/transpiler/output/headers/__tests__/HeaderGenerator.test.ts +87 -59
- package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +57 -58
- package/src/transpiler/output/headers/adapters/HeaderSymbolAdapter.ts +222 -0
- package/src/transpiler/output/headers/adapters/__tests__/HeaderSymbolAdapter.test.ts +538 -0
- package/src/transpiler/output/headers/types/IGroupedSymbols.ts +8 -8
- package/src/transpiler/output/headers/types/IHeaderSymbol.ts +62 -0
- package/src/transpiler/state/CodeGenState.ts +20 -33
- package/src/transpiler/state/SymbolRegistry.ts +181 -0
- package/src/transpiler/{types → state}/TranspilerState.ts +1 -1
- package/src/transpiler/state/__tests__/CodeGenState.test.ts +67 -59
- package/src/transpiler/state/__tests__/SymbolRegistry.test.ts +249 -0
- package/src/transpiler/{types → state}/__tests__/TranspilerState.test.ts +1 -1
- package/src/transpiler/types/ICachedFileEntry.ts +1 -1
- package/src/transpiler/types/IConflict.ts +14 -0
- package/src/transpiler/types/IPipelineInput.ts +0 -3
- package/src/transpiler/types/ISerializedSymbol.ts +11 -0
- package/src/transpiler/types/TPrimitiveKind.ts +20 -0
- package/src/transpiler/types/TType.ts +103 -0
- package/src/transpiler/types/TVisibility.ts +6 -0
- package/src/transpiler/types/symbol-kinds/TSymbolKind.ts +10 -0
- package/src/transpiler/types/symbol-kinds/TSymbolKindC.ts +12 -0
- package/src/transpiler/types/symbol-kinds/TSymbolKindCNext.ts +16 -0
- package/src/transpiler/types/symbol-kinds/TSymbolKindCpp.ts +14 -0
- package/src/transpiler/types/symbols/IBaseSymbol.ts +31 -0
- package/src/transpiler/{logic/symbols/types → types/symbols}/IBitmapFieldInfo.ts +2 -2
- package/src/transpiler/types/symbols/IBitmapSymbol.ts +21 -0
- package/src/transpiler/{logic/symbols/types → types/symbols}/IEnumSymbol.ts +5 -6
- package/src/transpiler/types/symbols/IFieldInfo.ts +26 -0
- package/src/transpiler/types/symbols/IFunctionSymbol.ts +30 -0
- package/src/transpiler/types/symbols/IParameterInfo.ts +26 -0
- package/src/transpiler/{logic/symbols/types → types/symbols}/IRegisterMemberInfo.ts +4 -4
- package/src/transpiler/types/symbols/IRegisterSymbol.ts +18 -0
- package/src/transpiler/types/symbols/IScopeSymbol.ts +32 -0
- package/src/transpiler/{logic/symbols/types → types/symbols}/IStructFieldInfo.ts +2 -1
- package/src/transpiler/types/symbols/IStructSymbol.ts +15 -0
- package/src/transpiler/types/symbols/IVariableSymbol.ts +30 -0
- package/src/transpiler/types/symbols/SymbolGuards.ts +43 -0
- package/src/transpiler/types/symbols/TAnySymbol.ts +22 -0
- package/src/transpiler/types/symbols/TSymbol.ts +32 -0
- package/src/transpiler/types/symbols/__tests__/IBaseSymbol.test.ts +56 -0
- package/src/transpiler/types/symbols/__tests__/SymbolGuards.test.ts +57 -0
- package/src/transpiler/types/symbols/c/ICBaseSymbol.ts +28 -0
- package/src/transpiler/types/symbols/c/ICEnumMemberSymbol.ts +17 -0
- package/src/transpiler/types/symbols/c/ICEnumSymbol.ts +17 -0
- package/src/transpiler/types/symbols/c/ICFieldInfo.ts +16 -0
- package/src/transpiler/types/symbols/c/ICFunctionSymbol.ts +21 -0
- package/src/transpiler/types/symbols/c/ICParameterInfo.ts +19 -0
- package/src/transpiler/types/symbols/c/ICStructSymbol.ts +21 -0
- package/src/transpiler/types/symbols/c/ICTypedefSymbol.ts +14 -0
- package/src/transpiler/types/symbols/c/ICVariableSymbol.ts +26 -0
- package/src/transpiler/types/symbols/c/TCSymbol.ts +26 -0
- package/src/transpiler/types/symbols/cpp/ICppBaseSymbol.ts +31 -0
- package/src/transpiler/types/symbols/cpp/ICppClassSymbol.ts +15 -0
- package/src/transpiler/types/symbols/cpp/ICppEnumMemberSymbol.ts +14 -0
- package/src/transpiler/types/symbols/cpp/ICppEnumSymbol.ts +14 -0
- package/src/transpiler/types/symbols/cpp/ICppFieldInfo.ts +16 -0
- package/src/transpiler/types/symbols/cpp/ICppFunctionSymbol.ts +21 -0
- package/src/transpiler/types/symbols/cpp/ICppNamespaceSymbol.ts +11 -0
- package/src/transpiler/types/symbols/cpp/ICppParameterInfo.ts +19 -0
- package/src/transpiler/types/symbols/cpp/ICppStructSymbol.ts +16 -0
- package/src/transpiler/types/symbols/cpp/ICppTypeAliasSymbol.ts +14 -0
- package/src/transpiler/types/symbols/cpp/ICppVariableSymbol.ts +23 -0
- package/src/transpiler/types/symbols/cpp/TCppSymbol.ts +30 -0
- package/src/utils/CppNamespaceUtils.ts +3 -4
- package/src/utils/FunctionUtils.ts +92 -0
- package/src/utils/ParameterUtils.ts +55 -0
- package/src/utils/PrimitiveKindUtils.ts +33 -0
- package/src/utils/ScopeUtils.ts +105 -0
- package/src/utils/TTypeUtils.ts +159 -0
- package/src/utils/TypeResolver.ts +132 -0
- package/src/utils/__tests__/CppNamespaceUtils.test.ts +92 -99
- package/src/utils/__tests__/FunctionUtils.test.ts +284 -0
- package/src/utils/__tests__/ParameterUtils.test.ts +174 -0
- package/src/utils/__tests__/PrimitiveKindUtils.test.ts +59 -0
- package/src/utils/__tests__/ScopeUtils.test.ts +53 -0
- package/src/utils/__tests__/TTypeUtils.test.ts +245 -0
- package/src/utils/__tests__/TypeResolver.test.ts +332 -0
- package/src/utils/cache/CacheManager.ts +91 -50
- package/src/utils/cache/__tests__/CacheManager.test.ts +180 -114
- package/src/transpiler/logic/symbols/AutoConstUpdater.ts +0 -93
- package/src/transpiler/logic/symbols/CSymbolCollector.ts +0 -648
- package/src/transpiler/logic/symbols/CppSymbolCollector.ts +0 -874
- package/src/transpiler/logic/symbols/SymbolCollectorContext.ts +0 -68
- package/src/transpiler/logic/symbols/__tests__/AutoConstUpdater.test.ts +0 -418
- package/src/transpiler/logic/symbols/__tests__/CSymbolCollector.test.ts +0 -685
- package/src/transpiler/logic/symbols/__tests__/CppSymbolCollector.test.ts +0 -1146
- package/src/transpiler/logic/symbols/__tests__/SymbolCollectorContext.test.ts +0 -290
- package/src/transpiler/logic/symbols/__tests__/cTestHelpers.ts +0 -43
- package/src/transpiler/logic/symbols/__tests__/cppTestHelpers.ts +0 -40
- package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolAdapter.test.ts +0 -595
- package/src/transpiler/logic/symbols/cnext/adapters/TSymbolAdapter.ts +0 -345
- package/src/transpiler/logic/symbols/types/IBaseSymbol.ts +0 -27
- package/src/transpiler/logic/symbols/types/IBitmapSymbol.ts +0 -23
- package/src/transpiler/logic/symbols/types/ICollectorContext.ts +0 -19
- package/src/transpiler/logic/symbols/types/IConflict.ts +0 -20
- package/src/transpiler/logic/symbols/types/IFieldInfo.ts +0 -18
- package/src/transpiler/logic/symbols/types/IFunctionSymbol.ts +0 -25
- package/src/transpiler/logic/symbols/types/IParameterInfo.ts +0 -24
- package/src/transpiler/logic/symbols/types/IRegisterSymbol.ts +0 -20
- package/src/transpiler/logic/symbols/types/IScopeSymbol.ts +0 -19
- package/src/transpiler/logic/symbols/types/IStructSymbol.ts +0 -16
- package/src/transpiler/logic/symbols/types/IVariableSymbol.ts +0 -30
- package/src/transpiler/logic/symbols/types/TSymbol.ts +0 -36
- package/src/transpiler/logic/symbols/types/__tests__/SymbolGuards.test.ts +0 -244
- package/src/transpiler/logic/symbols/types/typeGuards.ts +0 -44
- package/src/utils/types/ESymbolKind.ts +0 -19
- package/src/utils/types/ISymbol.ts +0 -64
- /package/src/transpiler/{types → constants}/BITMAP_BACKING_TYPE.ts +0 -0
- /package/src/transpiler/{types → constants}/BITMAP_SIZE.ts +0 -0
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for CResolver
|
|
3
|
+
* Migrated from CSymbolCollector tests to test the new composable collector pattern.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, it } from "vitest";
|
|
7
|
+
import CResolver from "../index";
|
|
8
|
+
import TestHelpers from "./testHelpers";
|
|
9
|
+
import SymbolTable from "../../SymbolTable";
|
|
10
|
+
import ESourceLanguage from "../../../../../utils/types/ESourceLanguage";
|
|
11
|
+
|
|
12
|
+
describe("CResolver - Basic Functionality", () => {
|
|
13
|
+
it("returns empty result for empty translation unit", () => {
|
|
14
|
+
const tree = TestHelpers.parseC("");
|
|
15
|
+
expect(tree).toBeDefined();
|
|
16
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
17
|
+
expect(result.symbols).toEqual([]);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("tracks source file correctly", () => {
|
|
21
|
+
const tree = TestHelpers.parseC(`void foo();`);
|
|
22
|
+
const result = CResolver.resolve(tree!, "myfile.h");
|
|
23
|
+
expect(result.symbols[0].sourceFile).toBe("myfile.h");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("tracks source line numbers", () => {
|
|
27
|
+
const tree = TestHelpers.parseC(`
|
|
28
|
+
|
|
29
|
+
void foo();`);
|
|
30
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
31
|
+
expect(result.symbols[0].sourceLine).toBe(3);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("sets source language to C", () => {
|
|
35
|
+
const tree = TestHelpers.parseC(`void foo();`);
|
|
36
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
37
|
+
expect(result.symbols[0].sourceLanguage).toBe(ESourceLanguage.C);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("returns empty warnings initially", () => {
|
|
41
|
+
const tree = TestHelpers.parseC(`void foo();`);
|
|
42
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
43
|
+
expect(result.warnings).toEqual([]);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("CResolver - Function Definitions", () => {
|
|
48
|
+
it("collects function definition", () => {
|
|
49
|
+
const tree = TestHelpers.parseC(`void foo() { }`);
|
|
50
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
51
|
+
|
|
52
|
+
expect(result.symbols).toHaveLength(1);
|
|
53
|
+
const symbol = result.symbols[0];
|
|
54
|
+
expect(symbol.name).toBe("foo");
|
|
55
|
+
expect(symbol.kind).toBe("function");
|
|
56
|
+
if (symbol.kind === "function") {
|
|
57
|
+
expect(symbol.type).toBe("void");
|
|
58
|
+
expect(symbol.isDeclaration).toBe(false);
|
|
59
|
+
}
|
|
60
|
+
expect(symbol.isExported).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("collects function with return type", () => {
|
|
64
|
+
const tree = TestHelpers.parseC(`int getCount() { return 0; }`);
|
|
65
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
66
|
+
|
|
67
|
+
if (result.symbols[0].kind === "function") {
|
|
68
|
+
expect(result.symbols[0].type).toBe("int");
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("collects function with complex return type", () => {
|
|
73
|
+
const tree = TestHelpers.parseC(`unsigned long getValue() { return 0; }`);
|
|
74
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
75
|
+
|
|
76
|
+
if (result.symbols[0].kind === "function") {
|
|
77
|
+
expect(result.symbols[0].type).toBe("unsigned long");
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("defaults to int when no return type specified", () => {
|
|
82
|
+
const tree = TestHelpers.parseC(`foo() { }`);
|
|
83
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
84
|
+
|
|
85
|
+
if (result.symbols[0].kind === "function") {
|
|
86
|
+
expect(result.symbols[0].type).toBe("int");
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("collects multiple function definitions", () => {
|
|
91
|
+
const tree = TestHelpers.parseC(`
|
|
92
|
+
void init() { }
|
|
93
|
+
int process() { return 0; }
|
|
94
|
+
void cleanup() { }
|
|
95
|
+
`);
|
|
96
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
97
|
+
|
|
98
|
+
expect(result.symbols).toHaveLength(3);
|
|
99
|
+
expect(result.symbols.map((s) => s.name)).toEqual([
|
|
100
|
+
"init",
|
|
101
|
+
"process",
|
|
102
|
+
"cleanup",
|
|
103
|
+
]);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
describe("CResolver - Function Prototypes", () => {
|
|
108
|
+
it("collects function prototype", () => {
|
|
109
|
+
const tree = TestHelpers.parseC(`void bar();`);
|
|
110
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
111
|
+
|
|
112
|
+
expect(result.symbols).toHaveLength(1);
|
|
113
|
+
const symbol = result.symbols[0];
|
|
114
|
+
expect(symbol.name).toBe("bar");
|
|
115
|
+
expect(symbol.kind).toBe("function");
|
|
116
|
+
if (symbol.kind === "function") {
|
|
117
|
+
expect(symbol.isDeclaration).toBe(true);
|
|
118
|
+
}
|
|
119
|
+
expect(symbol.isExported).toBe(true);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("collects extern function prototype", () => {
|
|
123
|
+
const tree = TestHelpers.parseC(`extern void externalFunc();`);
|
|
124
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
125
|
+
|
|
126
|
+
expect(result.symbols[0].name).toBe("externalFunc");
|
|
127
|
+
expect(result.symbols[0].isExported).toBe(false);
|
|
128
|
+
if (result.symbols[0].kind === "function") {
|
|
129
|
+
expect(result.symbols[0].isDeclaration).toBe(true);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("collects function prototype with parameters", () => {
|
|
134
|
+
const tree = TestHelpers.parseC(`int add(int a, int b);`);
|
|
135
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
136
|
+
|
|
137
|
+
expect(result.symbols[0].name).toBe("add");
|
|
138
|
+
if (result.symbols[0].kind === "function") {
|
|
139
|
+
expect(result.symbols[0].type).toBe("int");
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe("CResolver - Variable Declarations", () => {
|
|
145
|
+
it("collects global variable", () => {
|
|
146
|
+
const tree = TestHelpers.parseC(`int counter;`);
|
|
147
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
148
|
+
|
|
149
|
+
expect(result.symbols).toHaveLength(1);
|
|
150
|
+
const symbol = result.symbols[0];
|
|
151
|
+
expect(symbol.name).toBe("counter");
|
|
152
|
+
expect(symbol.kind).toBe("variable");
|
|
153
|
+
if (symbol.kind === "variable") {
|
|
154
|
+
expect(symbol.type).toBe("int");
|
|
155
|
+
}
|
|
156
|
+
expect(symbol.isExported).toBe(true);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("collects extern variable", () => {
|
|
160
|
+
const tree = TestHelpers.parseC(`extern int globalValue;`);
|
|
161
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
162
|
+
|
|
163
|
+
const symbol = result.symbols[0];
|
|
164
|
+
expect(symbol.name).toBe("globalValue");
|
|
165
|
+
expect(symbol.kind).toBe("variable");
|
|
166
|
+
expect(symbol.isExported).toBe(false);
|
|
167
|
+
if (symbol.kind === "variable") {
|
|
168
|
+
expect(symbol.isExtern).toBe(true);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("collects multiple variables in one declaration", () => {
|
|
173
|
+
const tree = TestHelpers.parseC(`int x, y, z;`);
|
|
174
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
175
|
+
|
|
176
|
+
expect(result.symbols).toHaveLength(3);
|
|
177
|
+
expect(result.symbols.map((s) => s.name)).toEqual(["x", "y", "z"]);
|
|
178
|
+
result.symbols.forEach((s) => {
|
|
179
|
+
expect(s.kind).toBe("variable");
|
|
180
|
+
if (s.kind === "variable") {
|
|
181
|
+
expect(s.type).toBe("int");
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe("CResolver - Typedefs", () => {
|
|
188
|
+
it("collects simple typedef", () => {
|
|
189
|
+
const tree = TestHelpers.parseC(`typedef int MyInt;`);
|
|
190
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
191
|
+
|
|
192
|
+
expect(result.symbols).toHaveLength(1);
|
|
193
|
+
const symbol = result.symbols[0];
|
|
194
|
+
expect(symbol.name).toBe("MyInt");
|
|
195
|
+
expect(symbol.kind).toBe("type");
|
|
196
|
+
if (symbol.kind === "type") {
|
|
197
|
+
expect(symbol.type).toBe("int");
|
|
198
|
+
}
|
|
199
|
+
expect(symbol.isExported).toBe(true);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("collects typedef with unsigned type", () => {
|
|
203
|
+
const tree = TestHelpers.parseC(`typedef unsigned char uint8_t;`);
|
|
204
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
205
|
+
|
|
206
|
+
expect(result.symbols[0].name).toBe("uint8_t");
|
|
207
|
+
expect(result.symbols[0].kind).toBe("type");
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("collects multiple typedefs", () => {
|
|
211
|
+
const tree = TestHelpers.parseC(`
|
|
212
|
+
typedef int Int32;
|
|
213
|
+
typedef unsigned int UInt32;
|
|
214
|
+
`);
|
|
215
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
216
|
+
|
|
217
|
+
expect(result.symbols).toHaveLength(2);
|
|
218
|
+
expect(result.symbols[0].name).toBe("Int32");
|
|
219
|
+
expect(result.symbols[1].name).toBe("UInt32");
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
describe("CResolver - Structs", () => {
|
|
224
|
+
it("collects named struct", () => {
|
|
225
|
+
const tree = TestHelpers.parseC(`struct Point { int x; int y; };`);
|
|
226
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
227
|
+
|
|
228
|
+
const structSym = result.symbols.find((s) => s.name === "Point");
|
|
229
|
+
expect(structSym).toBeDefined();
|
|
230
|
+
expect(structSym?.kind).toBe("struct");
|
|
231
|
+
expect(structSym?.isExported).toBe(true);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("marks named struct as needing struct keyword", () => {
|
|
235
|
+
const tree = TestHelpers.parseC(`struct Point { int x; int y; };`);
|
|
236
|
+
const symbolTable = new SymbolTable();
|
|
237
|
+
CResolver.resolve(tree!, "test.h", symbolTable);
|
|
238
|
+
|
|
239
|
+
expect(symbolTable.checkNeedsStructKeyword("Point")).toBe(true);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("collects typedef struct (anonymous)", () => {
|
|
243
|
+
const tree = TestHelpers.parseC(`typedef struct { int x; int y; } Point;`);
|
|
244
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
245
|
+
|
|
246
|
+
const structSym = result.symbols.find(
|
|
247
|
+
(s) => s.name === "Point" && s.kind === "struct",
|
|
248
|
+
);
|
|
249
|
+
expect(structSym).toBeDefined();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it("does not mark typedef struct as needing struct keyword", () => {
|
|
253
|
+
const tree = TestHelpers.parseC(`typedef struct { int x; int y; } Point;`);
|
|
254
|
+
const symbolTable = new SymbolTable();
|
|
255
|
+
CResolver.resolve(tree!, "test.h", symbolTable);
|
|
256
|
+
|
|
257
|
+
expect(symbolTable.checkNeedsStructKeyword("Point")).toBe(false);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it("collects typedef struct with tag name", () => {
|
|
261
|
+
const tree = TestHelpers.parseC(
|
|
262
|
+
`typedef struct _Point { int x; int y; } Point;`,
|
|
263
|
+
);
|
|
264
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
265
|
+
|
|
266
|
+
const structSym = result.symbols.find(
|
|
267
|
+
(s) => s.name === "_Point" && s.kind === "struct",
|
|
268
|
+
);
|
|
269
|
+
expect(structSym).toBeDefined();
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it("collects union", () => {
|
|
273
|
+
const tree = TestHelpers.parseC(`union Data { int i; float f; };`);
|
|
274
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
275
|
+
|
|
276
|
+
const unionSym = result.symbols.find((s) => s.name === "Data");
|
|
277
|
+
expect(unionSym).toBeDefined();
|
|
278
|
+
expect(unionSym?.kind).toBe("struct");
|
|
279
|
+
if (unionSym?.kind === "struct") {
|
|
280
|
+
expect(unionSym.isUnion).toBe(true);
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it("skips anonymous struct without typedef", () => {
|
|
285
|
+
const tree = TestHelpers.parseC(`struct { int x; } point;`);
|
|
286
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
287
|
+
|
|
288
|
+
// Should only have the variable, no struct symbol
|
|
289
|
+
expect(result.symbols).toHaveLength(1);
|
|
290
|
+
expect(result.symbols[0].name).toBe("point");
|
|
291
|
+
expect(result.symbols[0].kind).toBe("variable");
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
describe("CResolver - Struct Fields", () => {
|
|
296
|
+
it("collects struct fields into symbol table", () => {
|
|
297
|
+
const tree = TestHelpers.parseC(`struct Point { int x; int y; };`);
|
|
298
|
+
const symbolTable = new SymbolTable();
|
|
299
|
+
CResolver.resolve(tree!, "test.h", symbolTable);
|
|
300
|
+
|
|
301
|
+
const fieldsMap = symbolTable.getStructFields("Point");
|
|
302
|
+
expect(fieldsMap).toBeDefined();
|
|
303
|
+
expect(fieldsMap?.size).toBe(2);
|
|
304
|
+
expect(fieldsMap?.get("x")?.type).toBe("int");
|
|
305
|
+
expect(fieldsMap?.get("y")?.type).toBe("int");
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it("collects struct fields with different types", () => {
|
|
309
|
+
const tree = TestHelpers.parseC(
|
|
310
|
+
`struct Person { char name[32]; int age; float height; };`,
|
|
311
|
+
);
|
|
312
|
+
const symbolTable = new SymbolTable();
|
|
313
|
+
CResolver.resolve(tree!, "test.h", symbolTable);
|
|
314
|
+
|
|
315
|
+
const fieldsMap = symbolTable.getStructFields("Person");
|
|
316
|
+
expect(fieldsMap).toBeDefined();
|
|
317
|
+
expect(fieldsMap?.size).toBe(3);
|
|
318
|
+
expect(fieldsMap?.get("name")?.type).toBe("char");
|
|
319
|
+
expect(fieldsMap?.get("age")?.type).toBe("int");
|
|
320
|
+
expect(fieldsMap?.get("height")?.type).toBe("float");
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it("collects array field dimensions", () => {
|
|
324
|
+
const tree = TestHelpers.parseC(`struct Buffer { char data[256]; };`);
|
|
325
|
+
const symbolTable = new SymbolTable();
|
|
326
|
+
CResolver.resolve(tree!, "test.h", symbolTable);
|
|
327
|
+
|
|
328
|
+
const fieldsMap = symbolTable.getStructFields("Buffer");
|
|
329
|
+
expect(fieldsMap?.get("data")?.arrayDimensions).toEqual([256]);
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it("collects multi-dimensional array fields", () => {
|
|
333
|
+
const tree = TestHelpers.parseC(`struct Matrix { int data[3][3]; };`);
|
|
334
|
+
const symbolTable = new SymbolTable();
|
|
335
|
+
CResolver.resolve(tree!, "test.h", symbolTable);
|
|
336
|
+
|
|
337
|
+
const fieldsMap = symbolTable.getStructFields("Matrix");
|
|
338
|
+
expect(fieldsMap?.get("data")?.arrayDimensions).toEqual([3, 3]);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it("collects nested struct field type correctly", () => {
|
|
342
|
+
const tree = TestHelpers.parseC(`
|
|
343
|
+
struct Inner { int value; };
|
|
344
|
+
struct Outer { struct Inner inner; };
|
|
345
|
+
`);
|
|
346
|
+
const symbolTable = new SymbolTable();
|
|
347
|
+
CResolver.resolve(tree!, "test.h", symbolTable);
|
|
348
|
+
|
|
349
|
+
const fieldsMap = symbolTable.getStructFields("Outer");
|
|
350
|
+
expect(fieldsMap?.get("inner")?.type).toBe("Inner");
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it("warns about reserved field names", () => {
|
|
354
|
+
const tree = TestHelpers.parseC(`struct Test { int length; };`);
|
|
355
|
+
const symbolTable = new SymbolTable();
|
|
356
|
+
const result = CResolver.resolve(tree!, "test.h", symbolTable);
|
|
357
|
+
|
|
358
|
+
expect(result.warnings.length).toBeGreaterThan(0);
|
|
359
|
+
expect(result.warnings[0]).toContain("length");
|
|
360
|
+
expect(result.warnings[0]).toContain("conflicts with C-Next");
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
describe("CResolver - Enums", () => {
|
|
365
|
+
it("collects named enum", () => {
|
|
366
|
+
const tree = TestHelpers.parseC(`enum Color { RED, GREEN, BLUE };`);
|
|
367
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
368
|
+
|
|
369
|
+
const enumSym = result.symbols.find(
|
|
370
|
+
(s) => s.name === "Color" && s.kind === "enum",
|
|
371
|
+
);
|
|
372
|
+
expect(enumSym).toBeDefined();
|
|
373
|
+
expect(enumSym?.isExported).toBe(true);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it("collects enum members", () => {
|
|
377
|
+
const tree = TestHelpers.parseC(`enum Color { RED, GREEN, BLUE };`);
|
|
378
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
379
|
+
|
|
380
|
+
const members = result.symbols.filter((s) => s.kind === "enum_member");
|
|
381
|
+
expect(members).toHaveLength(3);
|
|
382
|
+
expect(members.map((m) => m.name)).toEqual(["RED", "GREEN", "BLUE"]);
|
|
383
|
+
members.forEach((m) => {
|
|
384
|
+
if (m.kind === "enum_member") {
|
|
385
|
+
expect(m.parent).toBe("Color");
|
|
386
|
+
}
|
|
387
|
+
expect(m.isExported).toBe(true);
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it("collects enum member line numbers", () => {
|
|
392
|
+
const tree = TestHelpers.parseC(`enum Status {
|
|
393
|
+
OK,
|
|
394
|
+
ERROR,
|
|
395
|
+
PENDING
|
|
396
|
+
};`);
|
|
397
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
398
|
+
|
|
399
|
+
const members = result.symbols.filter((s) => s.kind === "enum_member");
|
|
400
|
+
expect(members[0].sourceLine).toBe(2);
|
|
401
|
+
expect(members[1].sourceLine).toBe(3);
|
|
402
|
+
expect(members[2].sourceLine).toBe(4);
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
it("skips anonymous enum", () => {
|
|
406
|
+
const tree = TestHelpers.parseC(`enum { OPTION_A, OPTION_B };`);
|
|
407
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
408
|
+
|
|
409
|
+
// Anonymous enums don't create an Enum symbol
|
|
410
|
+
const enumSym = result.symbols.find((s) => s.kind === "enum");
|
|
411
|
+
expect(enumSym).toBeUndefined();
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
describe("CResolver - Complex Declarators", () => {
|
|
416
|
+
it("handles array variable declaration", () => {
|
|
417
|
+
const tree = TestHelpers.parseC(`int values[10];`);
|
|
418
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
419
|
+
|
|
420
|
+
expect(result.symbols[0].name).toBe("values");
|
|
421
|
+
expect(result.symbols[0].kind).toBe("variable");
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
it("handles function pointer typedef", () => {
|
|
425
|
+
const tree = TestHelpers.parseC(`typedef void (*Callback)(int);`);
|
|
426
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
427
|
+
|
|
428
|
+
expect(result.symbols[0].name).toBe("Callback");
|
|
429
|
+
expect(result.symbols[0].kind).toBe("type");
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
it("handles pointer variable", () => {
|
|
433
|
+
const tree = TestHelpers.parseC(`int *ptr;`);
|
|
434
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
435
|
+
|
|
436
|
+
expect(result.symbols[0].name).toBe("ptr");
|
|
437
|
+
expect(result.symbols[0].kind).toBe("variable");
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
it("handles array field declarator (Issue #355)", () => {
|
|
441
|
+
const tree = TestHelpers.parseC(`struct Test { char buf[8]; };`);
|
|
442
|
+
const symbolTable = new SymbolTable();
|
|
443
|
+
CResolver.resolve(tree!, "test.h", symbolTable);
|
|
444
|
+
|
|
445
|
+
const fieldsMap = symbolTable.getStructFields("Test");
|
|
446
|
+
expect(fieldsMap?.get("buf")).toBeDefined();
|
|
447
|
+
expect(fieldsMap?.get("buf")?.arrayDimensions).toEqual([8]);
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
it("handles multi-dimensional array field declarator", () => {
|
|
451
|
+
const tree = TestHelpers.parseC(`struct Matrix { int data[4][4]; };`);
|
|
452
|
+
const symbolTable = new SymbolTable();
|
|
453
|
+
CResolver.resolve(tree!, "test.h", symbolTable);
|
|
454
|
+
|
|
455
|
+
const fieldsMap = symbolTable.getStructFields("Matrix");
|
|
456
|
+
expect(fieldsMap?.get("data")).toBeDefined();
|
|
457
|
+
expect(fieldsMap?.get("data")?.arrayDimensions).toEqual([4, 4]);
|
|
458
|
+
});
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
describe("CResolver - Edge Cases", () => {
|
|
462
|
+
it("handles struct with single field", () => {
|
|
463
|
+
const tree = TestHelpers.parseC(`struct Minimal { int x; };`);
|
|
464
|
+
const symbolTable = new SymbolTable();
|
|
465
|
+
const result = CResolver.resolve(tree!, "test.h", symbolTable);
|
|
466
|
+
|
|
467
|
+
expect(result.symbols.find((s) => s.name === "Minimal")).toBeDefined();
|
|
468
|
+
expect(symbolTable.getStructFields("Minimal")?.size).toBe(1);
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
it("handles struct with type qualifiers", () => {
|
|
472
|
+
const tree = TestHelpers.parseC(`struct Test { const int value; };`);
|
|
473
|
+
const symbolTable = new SymbolTable();
|
|
474
|
+
CResolver.resolve(tree!, "test.h", symbolTable);
|
|
475
|
+
|
|
476
|
+
const fieldsMap = symbolTable.getStructFields("Test");
|
|
477
|
+
expect(fieldsMap?.get("value")).toBeDefined();
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
it("handles declaration without init declarator list", () => {
|
|
481
|
+
const tree = TestHelpers.parseC(`struct Point { int x; };`);
|
|
482
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
483
|
+
|
|
484
|
+
expect(result.symbols).toHaveLength(1);
|
|
485
|
+
expect(result.symbols[0].kind).toBe("struct");
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
it("handles static storage class", () => {
|
|
489
|
+
const tree = TestHelpers.parseC(`static int privateVar;`);
|
|
490
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
491
|
+
|
|
492
|
+
expect(result.symbols[0].name).toBe("privateVar");
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
it("handles const qualifier", () => {
|
|
496
|
+
const tree = TestHelpers.parseC(`const int MAX_VALUE = 100;`);
|
|
497
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
498
|
+
|
|
499
|
+
expect(result.symbols[0].name).toBe("MAX_VALUE");
|
|
500
|
+
expect(result.symbols[0].kind).toBe("variable");
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
it("handles mixed declarations", () => {
|
|
504
|
+
const tree = TestHelpers.parseC(`
|
|
505
|
+
typedef int Int;
|
|
506
|
+
struct Point { int x; int y; };
|
|
507
|
+
enum Status { OK, ERROR };
|
|
508
|
+
void init();
|
|
509
|
+
extern int counter;
|
|
510
|
+
`);
|
|
511
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
512
|
+
|
|
513
|
+
const typedef = result.symbols.find((s) => s.name === "Int");
|
|
514
|
+
const struct = result.symbols.find((s) => s.name === "Point");
|
|
515
|
+
const enumSym = result.symbols.find(
|
|
516
|
+
(s) => s.name === "Status" && s.kind === "enum",
|
|
517
|
+
);
|
|
518
|
+
const func = result.symbols.find((s) => s.name === "init");
|
|
519
|
+
const variable = result.symbols.find((s) => s.name === "counter");
|
|
520
|
+
|
|
521
|
+
expect(typedef?.kind).toBe("type");
|
|
522
|
+
expect(struct?.kind).toBe("struct");
|
|
523
|
+
expect(enumSym?.kind).toBe("enum");
|
|
524
|
+
expect(func?.kind).toBe("function");
|
|
525
|
+
expect(variable?.kind).toBe("variable");
|
|
526
|
+
});
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
describe("CResolver - Additional Edge Cases", () => {
|
|
530
|
+
it("does not duplicate named enum as variable", () => {
|
|
531
|
+
const tree = TestHelpers.parseC(`enum Status { OK, ERROR };`);
|
|
532
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
533
|
+
|
|
534
|
+
const enumSymbols = result.symbols.filter((s) => s.name === "Status");
|
|
535
|
+
expect(enumSymbols).toHaveLength(1);
|
|
536
|
+
expect(enumSymbols[0].kind).toBe("enum");
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
it("handles struct field with anonymous struct type", () => {
|
|
540
|
+
const tree = TestHelpers.parseC(
|
|
541
|
+
`struct Outer { struct { int x; } inner; };`,
|
|
542
|
+
);
|
|
543
|
+
const symbolTable = new SymbolTable();
|
|
544
|
+
CResolver.resolve(tree!, "test.h", symbolTable);
|
|
545
|
+
|
|
546
|
+
const fieldsMap = symbolTable.getStructFields("Outer");
|
|
547
|
+
expect(fieldsMap?.get("inner")).toBeDefined();
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
it("handles function returning pointer", () => {
|
|
551
|
+
const tree = TestHelpers.parseC(`int* getPtr();`);
|
|
552
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
553
|
+
|
|
554
|
+
expect(result.symbols[0].name).toBe("getPtr");
|
|
555
|
+
expect(result.symbols[0].kind).toBe("function");
|
|
556
|
+
});
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
describe("CResolver - Without SymbolTable", () => {
|
|
560
|
+
it("still collects symbols without symbolTable", () => {
|
|
561
|
+
const tree = TestHelpers.parseC(`struct Point { int x; int y; };`);
|
|
562
|
+
const result = CResolver.resolve(tree!, "test.h");
|
|
563
|
+
|
|
564
|
+
expect(result.symbols.find((s) => s.name === "Point")).toBeDefined();
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
it("does not crash when collecting struct fields without symbolTable", () => {
|
|
568
|
+
const tree = TestHelpers.parseC(`struct Point { int x; int y; };`);
|
|
569
|
+
expect(() => CResolver.resolve(tree!, "test.h")).not.toThrow();
|
|
570
|
+
});
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
// ADR-055 Phase 7: CTSymbolAdapter tests removed - adapter deleted
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helpers for C collector tests.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import HeaderParser from "../../../parser/HeaderParser";
|
|
6
|
+
import { CompilationUnitContext } from "../../../parser/c/grammar/CParser";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Parse C source code and return the compilation unit context.
|
|
10
|
+
*/
|
|
11
|
+
function parseC(source: string): CompilationUnitContext | null {
|
|
12
|
+
const result = HeaderParser.parseC(source);
|
|
13
|
+
return result.tree;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class TestHelpers {
|
|
17
|
+
static readonly parseC = parseC;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default TestHelpers;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EnumCollector - Collects enum symbols from C parse trees.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { EnumSpecifierContext } from "../../../parser/c/grammar/CParser";
|
|
6
|
+
import type ICEnumSymbol from "../../../../types/symbols/c/ICEnumSymbol";
|
|
7
|
+
import type ICEnumMemberSymbol from "../../../../types/symbols/c/ICEnumMemberSymbol";
|
|
8
|
+
import ESourceLanguage from "../../../../../utils/types/ESourceLanguage";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Result of collecting an enum - includes both the enum symbol and its members.
|
|
12
|
+
*/
|
|
13
|
+
interface IEnumCollectorResult {
|
|
14
|
+
readonly enum: ICEnumSymbol;
|
|
15
|
+
readonly members: ReadonlyArray<ICEnumMemberSymbol>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
class EnumCollector {
|
|
19
|
+
/**
|
|
20
|
+
* Collect an enum symbol and its members from a specifier context.
|
|
21
|
+
*
|
|
22
|
+
* @param enumSpec The enum specifier context
|
|
23
|
+
* @param sourceFile Source file path
|
|
24
|
+
* @param line Source line number
|
|
25
|
+
*/
|
|
26
|
+
static collect(
|
|
27
|
+
enumSpec: EnumSpecifierContext,
|
|
28
|
+
sourceFile: string,
|
|
29
|
+
line: number,
|
|
30
|
+
): IEnumCollectorResult | null {
|
|
31
|
+
const identifier = enumSpec.Identifier();
|
|
32
|
+
if (!identifier) return null;
|
|
33
|
+
|
|
34
|
+
const name = identifier.getText();
|
|
35
|
+
|
|
36
|
+
// Collect enum members as separate symbols and as inline member info
|
|
37
|
+
const memberSymbols: ICEnumMemberSymbol[] = [];
|
|
38
|
+
const memberInfos: Array<{
|
|
39
|
+
readonly name: string;
|
|
40
|
+
readonly value?: number;
|
|
41
|
+
}> = [];
|
|
42
|
+
const enumList = enumSpec.enumeratorList();
|
|
43
|
+
|
|
44
|
+
if (enumList) {
|
|
45
|
+
for (const enumeratorDef of enumList.enumerator()) {
|
|
46
|
+
const enumConst = enumeratorDef.enumerationConstant();
|
|
47
|
+
if (enumConst) {
|
|
48
|
+
const memberName = enumConst.Identifier()?.getText();
|
|
49
|
+
if (memberName) {
|
|
50
|
+
memberInfos.push({ name: memberName });
|
|
51
|
+
memberSymbols.push({
|
|
52
|
+
kind: "enum_member",
|
|
53
|
+
name: memberName,
|
|
54
|
+
sourceFile,
|
|
55
|
+
sourceLine: enumeratorDef.start?.line ?? line,
|
|
56
|
+
sourceLanguage: ESourceLanguage.C,
|
|
57
|
+
isExported: true,
|
|
58
|
+
parent: name,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const enumSymbol: ICEnumSymbol = {
|
|
66
|
+
kind: "enum",
|
|
67
|
+
name,
|
|
68
|
+
sourceFile,
|
|
69
|
+
sourceLine: line,
|
|
70
|
+
sourceLanguage: ESourceLanguage.C,
|
|
71
|
+
isExported: true,
|
|
72
|
+
members: memberInfos,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
enum: enumSymbol,
|
|
77
|
+
members: memberSymbols,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export default EnumCollector;
|