c-next 0.2.6 → 0.2.7

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.
Files changed (37) hide show
  1. package/dist/index.js +387 -433
  2. package/dist/index.js.map +4 -4
  3. package/package.json +1 -1
  4. package/src/transpiler/Transpiler.ts +50 -29
  5. package/src/transpiler/__tests__/Transpiler.coverage.test.ts +2 -1
  6. package/src/transpiler/data/PathResolver.ts +10 -6
  7. package/src/transpiler/data/__tests__/PathResolver.test.ts +32 -0
  8. package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +1 -12
  9. package/src/transpiler/logic/analysis/SignedShiftAnalyzer.ts +239 -0
  10. package/src/transpiler/logic/analysis/__tests__/SignedShiftAnalyzer.test.ts +414 -0
  11. package/src/transpiler/logic/analysis/__tests__/StructFieldAnalyzer.test.ts +15 -75
  12. package/src/transpiler/logic/analysis/__tests__/runAnalyzers.test.ts +3 -15
  13. package/src/transpiler/logic/analysis/runAnalyzers.ts +11 -2
  14. package/src/transpiler/logic/analysis/types/ISignedShiftError.ts +15 -0
  15. package/src/transpiler/logic/symbols/SymbolUtils.ts +4 -1
  16. package/src/transpiler/logic/symbols/__tests__/SymbolUtils.test.ts +10 -11
  17. package/src/transpiler/logic/symbols/c/__tests__/CResolver.integration.test.ts +4 -4
  18. package/src/transpiler/logic/symbols/cpp/__tests__/CppResolver.integration.test.ts +4 -4
  19. package/src/transpiler/output/codegen/CodeGenerator.ts +12 -4
  20. package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +3 -3
  21. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +26 -26
  22. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +12 -11
  23. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +21 -21
  24. package/src/transpiler/output/codegen/generators/expressions/AccessExprGenerator.ts +7 -326
  25. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +14 -275
  26. package/src/transpiler/output/codegen/generators/expressions/UnaryExprGenerator.ts +13 -1
  27. package/src/transpiler/output/codegen/generators/expressions/__tests__/AccessExprGenerator.test.ts +0 -573
  28. package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +8 -439
  29. package/src/transpiler/output/codegen/generators/expressions/__tests__/UnaryExprGenerator.test.ts +196 -0
  30. package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +7 -2
  31. package/src/transpiler/output/codegen/helpers/TypedefParamParser.ts +34 -0
  32. package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +48 -0
  33. package/src/transpiler/output/codegen/helpers/__tests__/TypedefParamParser.test.ts +88 -0
  34. package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +15 -2
  35. package/src/transpiler/output/headers/__tests__/BaseHeaderGenerator.test.ts +87 -0
  36. package/src/utils/ExpressionUtils.ts +51 -0
  37. package/src/utils/types/IParameterSymbol.ts +2 -0
@@ -583,117 +583,12 @@ describe("PostfixExpressionGenerator", () => {
583
583
  });
584
584
  });
585
585
 
586
- describe(".length property", () => {
587
- it("returns argc for main args.length", () => {
588
- const ctx = createMockPostfixExpressionContext("args", [
589
- createMockPostfixOp({ identifier: "length" }),
590
- ]);
591
- const input = createMockInput();
592
- const state = createMockState({ mainArgsName: "args" });
593
- const orchestrator = createMockOrchestrator({
594
- generatePrimaryExpr: () => "argv",
595
- });
596
-
597
- const result = generatePostfixExpression(ctx, input, state, orchestrator);
598
- expect(result.code).toBe("argc");
599
- });
600
-
601
- it("returns comment for unknown type", () => {
602
- const ctx = createMockPostfixExpressionContext("unknown", [
603
- createMockPostfixOp({ identifier: "length" }),
604
- ]);
605
- const input = createMockInput();
606
- const state = createMockState();
607
- const orchestrator = createMockOrchestrator({
608
- generatePrimaryExpr: () => "unknown",
609
- });
610
-
611
- const result = generatePostfixExpression(ctx, input, state, orchestrator);
612
- expect(result.code).toContain("unknown type");
613
- expect(result.code).toContain("0");
614
- });
615
-
616
- it("returns array dimension for array type", () => {
617
- const typeRegistry = new Map<string, TTypeInfo>([
618
- [
619
- "arr",
620
- {
621
- baseType: "u32",
622
- bitWidth: 32,
623
- isArray: true,
624
- arrayDimensions: [10],
625
- isConst: false,
626
- },
627
- ],
628
- ]);
629
- const ctx = createMockPostfixExpressionContext("arr", [
630
- createMockPostfixOp({ identifier: "length" }),
631
- ]);
632
- const input = createMockInput({ typeRegistry });
633
- const state = createMockState();
634
- const orchestrator = createMockOrchestrator({
635
- generatePrimaryExpr: () => "arr",
636
- });
637
-
638
- const result = generatePostfixExpression(ctx, input, state, orchestrator);
639
- expect(result.code).toBe("10");
640
- });
641
-
642
- it("returns strlen for string type", () => {
643
- const typeRegistry = new Map<string, TTypeInfo>([
644
- [
645
- "str",
646
- {
647
- baseType: "char",
648
- bitWidth: 8,
649
- isArray: false,
650
- isConst: false,
651
- isString: true,
652
- },
653
- ],
654
- ]);
655
- const ctx = createMockPostfixExpressionContext("str", [
656
- createMockPostfixOp({ identifier: "length" }),
657
- ]);
658
- const input = createMockInput({ typeRegistry });
659
- const state = createMockState();
660
- const orchestrator = createMockOrchestrator({
661
- generatePrimaryExpr: () => "str",
662
- });
663
-
664
- const result = generatePostfixExpression(ctx, input, state, orchestrator);
665
- expect(result.code).toBe("strlen(str)");
666
- });
667
-
668
- it("uses cached length when available", () => {
669
- const typeRegistry = new Map<string, TTypeInfo>([
670
- [
671
- "str",
672
- {
673
- baseType: "char",
674
- bitWidth: 8,
675
- isArray: false,
676
- isConst: false,
677
- isString: true,
678
- },
679
- ],
680
- ]);
681
- const ctx = createMockPostfixExpressionContext("str", [
682
- createMockPostfixOp({ identifier: "length" }),
683
- ]);
684
- const input = createMockInput({ typeRegistry });
685
- const state = createMockState({
686
- lengthCache: new Map([["str", "__len_str"]]),
687
- });
688
- const orchestrator = createMockOrchestrator({
689
- generatePrimaryExpr: () => "str",
690
- });
691
-
692
- const result = generatePostfixExpression(ctx, input, state, orchestrator);
693
- expect(result.code).toBe("__len_str");
694
- });
586
+ // Note: .length property tests removed (ADR-058)
587
+ // .length is deprecated - use explicit properties instead:
588
+ // .bit_length, .byte_length, .element_count, .char_count
695
589
 
696
- it("returns bit width for integer type", () => {
590
+ describe(".length property deprecation", () => {
591
+ it("throws deprecation error for .length property access", () => {
697
592
  const typeRegistry = new Map<string, TTypeInfo>([
698
593
  [
699
594
  "val",
@@ -714,335 +609,9 @@ describe("PostfixExpressionGenerator", () => {
714
609
  generatePrimaryExpr: () => "val",
715
610
  });
716
611
 
717
- const result = generatePostfixExpression(ctx, input, state, orchestrator);
718
- expect(result.code).toBe("32");
719
- });
720
-
721
- it("returns 32 for enum type", () => {
722
- const typeRegistry = new Map<string, TTypeInfo>([
723
- [
724
- "color",
725
- {
726
- baseType: "Color",
727
- bitWidth: 32,
728
- isArray: false,
729
- isConst: false,
730
- isEnum: true,
731
- },
732
- ],
733
- ]);
734
- const ctx = createMockPostfixExpressionContext("color", [
735
- createMockPostfixOp({ identifier: "length" }),
736
- ]);
737
- const input = createMockInput({ typeRegistry });
738
- const state = createMockState();
739
- const orchestrator = createMockOrchestrator({
740
- generatePrimaryExpr: () => "color",
741
- });
742
-
743
- const result = generatePostfixExpression(ctx, input, state, orchestrator);
744
- expect(result.code).toBe("32");
745
- });
746
-
747
- it("returns dimension for 2D array type at depth 0", () => {
748
- const typeRegistry = new Map<string, TTypeInfo>([
749
- [
750
- "matrix",
751
- {
752
- baseType: "u32",
753
- bitWidth: 32,
754
- isArray: true,
755
- arrayDimensions: [3, 4],
756
- isConst: false,
757
- },
758
- ],
759
- ]);
760
- const ctx = createMockPostfixExpressionContext("matrix", [
761
- createMockPostfixOp({ identifier: "length" }),
762
- ]);
763
- const input = createMockInput({ typeRegistry });
764
- const state = createMockState();
765
- const orchestrator = createMockOrchestrator({
766
- generatePrimaryExpr: () => "matrix",
767
- });
768
-
769
- const result = generatePostfixExpression(ctx, input, state, orchestrator);
770
- expect(result.code).toBe("3");
771
- });
772
-
773
- it("returns dimension for 2D array type at depth 1", () => {
774
- const typeRegistry = new Map<string, TTypeInfo>([
775
- [
776
- "matrix",
777
- {
778
- baseType: "u32",
779
- bitWidth: 32,
780
- isArray: true,
781
- arrayDimensions: [3, 4],
782
- isConst: false,
783
- },
784
- ],
785
- ]);
786
- const ctx = createMockPostfixExpressionContext("matrix", [
787
- createMockPostfixOp({ expressions: [createMockExpression("0")] }),
788
- createMockPostfixOp({ identifier: "length" }),
789
- ]);
790
- const input = createMockInput({ typeRegistry });
791
- const state = createMockState();
792
- const orchestrator = createMockOrchestrator({
793
- generatePrimaryExpr: () => "matrix",
794
- generateExpression: () => "0",
795
- });
796
-
797
- const result = generatePostfixExpression(ctx, input, state, orchestrator);
798
- expect(result.code).toBe("4");
799
- });
800
-
801
- it("returns bit width when subscriptDepth exceeds dimensions", () => {
802
- const typeRegistry = new Map<string, TTypeInfo>([
803
- [
804
- "arr",
805
- {
806
- baseType: "u32",
807
- bitWidth: 32,
808
- isArray: true,
809
- arrayDimensions: [10],
810
- isConst: false,
811
- },
812
- ],
813
- ]);
814
- const ctx = createMockPostfixExpressionContext("arr", [
815
- createMockPostfixOp({ expressions: [createMockExpression("0")] }),
816
- createMockPostfixOp({ identifier: "length" }),
817
- ]);
818
- const input = createMockInput({ typeRegistry });
819
- const state = createMockState();
820
- const orchestrator = createMockOrchestrator({
821
- generatePrimaryExpr: () => "arr",
822
- generateExpression: () => "0",
823
- });
824
-
825
- const result = generatePostfixExpression(ctx, input, state, orchestrator);
826
- expect(result.code).toBe("32");
827
- });
828
-
829
- it("returns strlen for string array element", () => {
830
- const typeRegistry = new Map<string, TTypeInfo>([
831
- [
832
- "names",
833
- {
834
- baseType: "char",
835
- bitWidth: 8,
836
- isArray: true,
837
- arrayDimensions: [5, 32],
838
- isConst: false,
839
- isString: true,
840
- },
841
- ],
842
- ]);
843
- const ctx = createMockPostfixExpressionContext("names", [
844
- createMockPostfixOp({ expressions: [createMockExpression("0")] }),
845
- createMockPostfixOp({ identifier: "length" }),
846
- ]);
847
- const input = createMockInput({ typeRegistry });
848
- const state = createMockState();
849
- const orchestrator = createMockOrchestrator({
850
- generatePrimaryExpr: () => "names",
851
- generateExpression: () => "0",
852
- });
853
-
854
- const result = generatePostfixExpression(ctx, input, state, orchestrator);
855
- expect(result.code).toBe("strlen(names[0])");
856
- });
857
-
858
- it("returns dimension for string array at depth 0", () => {
859
- const typeRegistry = new Map<string, TTypeInfo>([
860
- [
861
- "names",
862
- {
863
- baseType: "char",
864
- bitWidth: 8,
865
- isArray: true,
866
- arrayDimensions: [5, 32],
867
- isConst: false,
868
- isString: true,
869
- },
870
- ],
871
- ]);
872
- const ctx = createMockPostfixExpressionContext("names", [
873
- createMockPostfixOp({ identifier: "length" }),
874
- ]);
875
- const input = createMockInput({ typeRegistry });
876
- const state = createMockState();
877
- const orchestrator = createMockOrchestrator({
878
- generatePrimaryExpr: () => "names",
879
- });
880
-
881
- const result = generatePostfixExpression(ctx, input, state, orchestrator);
882
- expect(result.code).toBe("5");
883
- });
884
-
885
- it("returns struct field array dimension for struct member access", () => {
886
- const typeRegistry = new Map<string, TTypeInfo>([
887
- [
888
- "config",
889
- {
890
- baseType: "Config",
891
- bitWidth: 0,
892
- isArray: false,
893
- isConst: false,
894
- },
895
- ],
896
- ]);
897
- const symbols = createMockSymbols({
898
- knownStructs: new Set(["Config"]),
899
- });
900
- const ctx = createMockPostfixExpressionContext("config", [
901
- createMockPostfixOp({ identifier: "values" }),
902
- createMockPostfixOp({ identifier: "length" }),
903
- ]);
904
- const input = createMockInput({ symbols, typeRegistry });
905
- const state = createMockState();
906
- const orchestrator = createMockOrchestrator({
907
- generatePrimaryExpr: () => "config",
908
- isKnownStruct: (name) => name === "Config",
909
- getMemberTypeInfo: () => ({
910
- baseType: "u32",
911
- isArray: true,
912
- bitWidth: 32,
913
- isConst: false,
914
- }),
915
- getStructFieldInfo: () => ({
916
- type: "u32",
917
- dimensions: [10],
918
- }),
919
- });
920
-
921
- const result = generatePostfixExpression(ctx, input, state, orchestrator);
922
- expect(result.code).toBe("10");
923
- });
924
-
925
- it("returns bit width for scalar struct field", () => {
926
- const typeRegistry = new Map<string, TTypeInfo>([
927
- [
928
- "point",
929
- {
930
- baseType: "Point",
931
- bitWidth: 0,
932
- isArray: false,
933
- isConst: false,
934
- },
935
- ],
936
- ]);
937
- const symbols = createMockSymbols({
938
- knownStructs: new Set(["Point"]),
939
- });
940
- const ctx = createMockPostfixExpressionContext("point", [
941
- createMockPostfixOp({ identifier: "x" }),
942
- createMockPostfixOp({ identifier: "length" }),
943
- ]);
944
- const input = createMockInput({ symbols, typeRegistry });
945
- const state = createMockState();
946
- const orchestrator = createMockOrchestrator({
947
- generatePrimaryExpr: () => "point",
948
- isKnownStruct: (name) => name === "Point",
949
- getMemberTypeInfo: () => ({
950
- baseType: "i32",
951
- isArray: false,
952
- bitWidth: 32,
953
- isConst: false,
954
- }),
955
- getStructFieldInfo: () => ({
956
- type: "i32",
957
- }),
958
- });
959
-
960
- const result = generatePostfixExpression(ctx, input, state, orchestrator);
961
- expect(result.code).toBe("32");
962
- });
963
-
964
- it("returns strlen for string struct field", () => {
965
- const typeRegistry = new Map<string, TTypeInfo>([
966
- [
967
- "person",
968
- {
969
- baseType: "Person",
970
- bitWidth: 0,
971
- isArray: false,
972
- isConst: false,
973
- },
974
- ],
975
- ]);
976
- const symbols = createMockSymbols({
977
- knownStructs: new Set(["Person"]),
978
- });
979
- const ctx = createMockPostfixExpressionContext("person", [
980
- createMockPostfixOp({ identifier: "name" }),
981
- createMockPostfixOp({ identifier: "length" }),
982
- ]);
983
- const input = createMockInput({ symbols, typeRegistry });
984
- const state = createMockState();
985
- const orchestrator = createMockOrchestrator({
986
- generatePrimaryExpr: () => "person",
987
- isKnownStruct: (name) => name === "Person",
988
- getMemberTypeInfo: () => ({
989
- baseType: "string<32>",
990
- isArray: false,
991
- bitWidth: 32,
992
- isConst: false,
993
- }),
994
- getStructFieldInfo: () => ({
995
- type: "string<32>",
996
- dimensions: [32],
997
- }),
998
- });
999
-
1000
- const result = generatePostfixExpression(ctx, input, state, orchestrator);
1001
- expect(result.code).toBe("strlen(person.name)");
1002
- expect(result.effects).toContainEqual({
1003
- type: "include",
1004
- header: "string",
1005
- });
1006
- });
1007
-
1008
- it("returns first dimension for multi-dimensional string struct field at depth 0", () => {
1009
- const typeRegistry = new Map<string, TTypeInfo>([
1010
- [
1011
- "data",
1012
- {
1013
- baseType: "Data",
1014
- bitWidth: 0,
1015
- isArray: false,
1016
- isConst: false,
1017
- },
1018
- ],
1019
- ]);
1020
- const symbols = createMockSymbols({
1021
- knownStructs: new Set(["Data"]),
1022
- });
1023
- const ctx = createMockPostfixExpressionContext("data", [
1024
- createMockPostfixOp({ identifier: "names" }),
1025
- createMockPostfixOp({ identifier: "length" }),
1026
- ]);
1027
- const input = createMockInput({ symbols, typeRegistry });
1028
- const state = createMockState();
1029
- const orchestrator = createMockOrchestrator({
1030
- generatePrimaryExpr: () => "data",
1031
- isKnownStruct: (name) => name === "Data",
1032
- getMemberTypeInfo: () => ({
1033
- baseType: "string<32>",
1034
- isArray: true,
1035
- bitWidth: 32,
1036
- isConst: false,
1037
- }),
1038
- getStructFieldInfo: () => ({
1039
- type: "string<32>",
1040
- dimensions: [5, 32],
1041
- }),
1042
- });
1043
-
1044
- const result = generatePostfixExpression(ctx, input, state, orchestrator);
1045
- expect(result.code).toBe("5");
612
+ expect(() =>
613
+ generatePostfixExpression(ctx, input, state, orchestrator),
614
+ ).toThrow("'.length' on 'val' is deprecated");
1046
615
  });
1047
616
  });
1048
617
 
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Unit tests for UnaryExprGenerator
3
+ *
4
+ * Tests bitwise NOT (~) MISRA-compliant cast generation:
5
+ * - Unsigned types get cast back to original type (MISRA 10.1/10.3)
6
+ * - Signed types and unresolvable types are unchanged
7
+ * - C++ mode uses static_cast
8
+ */
9
+
10
+ import { describe, it, expect, vi, afterEach } from "vitest";
11
+ import generateUnaryExpr from "../UnaryExprGenerator";
12
+ import type { UnaryExpressionContext } from "../../../../../logic/parser/grammar/CNextParser";
13
+ import type IGeneratorInput from "../../IGeneratorInput";
14
+ import type IGeneratorState from "../../IGeneratorState";
15
+ import type IOrchestrator from "../../IOrchestrator";
16
+ import CodeGenState from "../../../../../state/CodeGenState";
17
+
18
+ vi.mock("../../../TypeResolver", () => {
19
+ return {
20
+ default: {
21
+ getUnaryExpressionType: vi.fn(),
22
+ isUnsignedType: vi.fn(),
23
+ },
24
+ };
25
+ });
26
+
27
+ import TypeResolver from "../../../TypeResolver";
28
+
29
+ // ========================================================================
30
+ // Test Helpers
31
+ // ========================================================================
32
+
33
+ /**
34
+ * Create a mock UnaryExpressionContext for a prefix unary expression.
35
+ * The node has no postfixExpression (prefix case) and a child unaryExpression.
36
+ */
37
+ function createMockUnaryNode(fullText: string): UnaryExpressionContext {
38
+ const innerUnary = {} as UnaryExpressionContext;
39
+ return {
40
+ postfixExpression: () => null,
41
+ unaryExpression: () => innerUnary,
42
+ getText: () => fullText,
43
+ } as unknown as UnaryExpressionContext;
44
+ }
45
+
46
+ const mockInput = {} as IGeneratorInput;
47
+ const mockState = {} as IGeneratorState;
48
+
49
+ function createMockOrchestrator(innerResult: string): IOrchestrator {
50
+ return {
51
+ generateUnaryExpr: () => innerResult,
52
+ generatePostfixExpr: () => "",
53
+ } as unknown as IOrchestrator;
54
+ }
55
+
56
+ // ========================================================================
57
+ // Tests
58
+ // ========================================================================
59
+
60
+ describe("UnaryExprGenerator", () => {
61
+ afterEach(() => {
62
+ vi.mocked(TypeResolver.getUnaryExpressionType).mockReset();
63
+ vi.mocked(TypeResolver.isUnsignedType).mockReset();
64
+ CodeGenState.cppMode = false;
65
+ });
66
+
67
+ describe("bitwise NOT on unsigned types", () => {
68
+ it("should cast ~u8 to (uint8_t)~c in C mode", () => {
69
+ vi.mocked(TypeResolver.getUnaryExpressionType).mockReturnValue("u8");
70
+ vi.mocked(TypeResolver.isUnsignedType).mockReturnValue(true);
71
+
72
+ const node = createMockUnaryNode("~c");
73
+ const orchestrator = createMockOrchestrator("c");
74
+ const result = generateUnaryExpr(
75
+ node,
76
+ mockInput,
77
+ mockState,
78
+ orchestrator,
79
+ );
80
+
81
+ expect(result.code).toBe("(uint8_t)~c");
82
+ expect(result.effects).toEqual([]);
83
+ });
84
+
85
+ it("should cast ~u16 to (uint16_t)~c in C mode", () => {
86
+ vi.mocked(TypeResolver.getUnaryExpressionType).mockReturnValue("u16");
87
+ vi.mocked(TypeResolver.isUnsignedType).mockReturnValue(true);
88
+
89
+ const node = createMockUnaryNode("~c");
90
+ const orchestrator = createMockOrchestrator("c");
91
+ const result = generateUnaryExpr(
92
+ node,
93
+ mockInput,
94
+ mockState,
95
+ orchestrator,
96
+ );
97
+
98
+ expect(result.code).toBe("(uint16_t)~c");
99
+ expect(result.effects).toEqual([]);
100
+ });
101
+
102
+ it("should use static_cast in C++ mode", () => {
103
+ CodeGenState.cppMode = true;
104
+ vi.mocked(TypeResolver.getUnaryExpressionType).mockReturnValue("u8");
105
+ vi.mocked(TypeResolver.isUnsignedType).mockReturnValue(true);
106
+
107
+ const node = createMockUnaryNode("~c");
108
+ const orchestrator = createMockOrchestrator("c");
109
+ const result = generateUnaryExpr(
110
+ node,
111
+ mockInput,
112
+ mockState,
113
+ orchestrator,
114
+ );
115
+
116
+ expect(result.code).toBe("static_cast<uint8_t>(~c)");
117
+ expect(result.effects).toEqual([]);
118
+ });
119
+ });
120
+
121
+ describe("bitwise NOT on signed/unresolvable types", () => {
122
+ it("should not cast ~i8 (signed type)", () => {
123
+ vi.mocked(TypeResolver.getUnaryExpressionType).mockReturnValue("i8");
124
+ vi.mocked(TypeResolver.isUnsignedType).mockReturnValue(false);
125
+
126
+ const node = createMockUnaryNode("~c");
127
+ const orchestrator = createMockOrchestrator("c");
128
+ const result = generateUnaryExpr(
129
+ node,
130
+ mockInput,
131
+ mockState,
132
+ orchestrator,
133
+ );
134
+
135
+ expect(result.code).toBe("~c");
136
+ expect(result.effects).toEqual([]);
137
+ });
138
+
139
+ it("should not cast when type is unresolvable", () => {
140
+ vi.mocked(TypeResolver.getUnaryExpressionType).mockReturnValue(null);
141
+
142
+ const node = createMockUnaryNode("~expr");
143
+ const orchestrator = createMockOrchestrator("expr");
144
+ const result = generateUnaryExpr(
145
+ node,
146
+ mockInput,
147
+ mockState,
148
+ orchestrator,
149
+ );
150
+
151
+ expect(result.code).toBe("~expr");
152
+ expect(result.effects).toEqual([]);
153
+ });
154
+ });
155
+
156
+ describe("other unary operators", () => {
157
+ it("should generate logical NOT unchanged", () => {
158
+ const node = createMockUnaryNode("!flag");
159
+ const orchestrator = createMockOrchestrator("flag");
160
+ const result = generateUnaryExpr(
161
+ node,
162
+ mockInput,
163
+ mockState,
164
+ orchestrator,
165
+ );
166
+
167
+ expect(result.code).toBe("!flag");
168
+ });
169
+
170
+ it("should generate negation unchanged", () => {
171
+ const node = createMockUnaryNode("-x");
172
+ const orchestrator = createMockOrchestrator("x");
173
+ const result = generateUnaryExpr(
174
+ node,
175
+ mockInput,
176
+ mockState,
177
+ orchestrator,
178
+ );
179
+
180
+ expect(result.code).toBe("-x");
181
+ });
182
+
183
+ it("should generate address-of unchanged", () => {
184
+ const node = createMockUnaryNode("&x");
185
+ const orchestrator = createMockOrchestrator("x");
186
+ const result = generateUnaryExpr(
187
+ node,
188
+ mockInput,
189
+ mockState,
190
+ orchestrator,
191
+ );
192
+
193
+ expect(result.code).toBe("&x");
194
+ });
195
+ });
196
+ });
@@ -212,6 +212,9 @@ class ParameterInputAdapter {
212
212
  };
213
213
  }
214
214
 
215
+ // Issue #914: Callback typedef overrides — param carries resolved pointer/const info
216
+ const isCallbackPointer = param.isCallbackPointer ?? false;
217
+
215
218
  return {
216
219
  name: param.name,
217
220
  baseType: param.type,
@@ -221,8 +224,10 @@ class ParameterInputAdapter {
221
224
  isArray: false,
222
225
  isCallback: false,
223
226
  isString: false,
224
- isPassByValue: deps.isPassByValue,
225
- isPassByReference: !deps.isPassByValue,
227
+ isPassByValue: isCallbackPointer ? false : deps.isPassByValue,
228
+ isPassByReference: isCallbackPointer ? true : !deps.isPassByValue,
229
+ forcePointerSyntax: isCallbackPointer || undefined,
230
+ forceConst: param.isCallbackConst || undefined,
226
231
  };
227
232
  }
228
233