c-next 0.1.62 → 0.1.63

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 (55) hide show
  1. package/README.md +86 -63
  2. package/package.json +1 -1
  3. package/src/transpiler/Transpiler.ts +3 -2
  4. package/src/transpiler/__tests__/DualCodePaths.test.ts +1 -1
  5. package/src/transpiler/__tests__/Transpiler.coverage.test.ts +1 -1
  6. package/src/transpiler/__tests__/Transpiler.test.ts +0 -23
  7. package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +156 -70
  8. package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +31 -6
  9. package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +43 -11
  10. package/src/transpiler/output/codegen/CodeGenState.ts +811 -0
  11. package/src/transpiler/output/codegen/CodeGenerator.ts +817 -1377
  12. package/src/transpiler/output/codegen/TypeResolver.ts +193 -149
  13. package/src/transpiler/output/codegen/TypeValidator.ts +148 -370
  14. package/src/transpiler/output/codegen/__tests__/CodeGenState.test.ts +446 -0
  15. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +326 -60
  16. package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +1 -1
  17. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +435 -196
  18. package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +51 -67
  19. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +495 -471
  20. package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +39 -43
  21. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +52 -55
  22. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +122 -62
  23. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +101 -144
  24. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +143 -126
  25. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +287 -320
  26. package/src/transpiler/output/codegen/generators/GeneratorRegistry.ts +12 -0
  27. package/src/transpiler/output/codegen/generators/__tests__/GeneratorRegistry.test.ts +28 -1
  28. package/src/transpiler/output/codegen/generators/declarationGenerators/ArrayDimensionUtils.ts +67 -0
  29. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +121 -51
  30. package/src/transpiler/output/codegen/generators/declarationGenerators/StructGenerator.ts +100 -23
  31. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ArrayDimensionUtils.test.ts +125 -0
  32. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +157 -4
  33. package/src/transpiler/output/codegen/generators/support/HelperGenerator.ts +23 -22
  34. package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +54 -61
  35. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +21 -30
  36. package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +56 -53
  37. package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +22 -30
  38. package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +108 -50
  39. package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +16 -31
  40. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +103 -96
  41. package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +9 -0
  42. package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +58 -103
  43. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +97 -40
  44. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +223 -128
  45. package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +68 -41
  46. package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +198 -47
  47. package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +39 -37
  48. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +191 -453
  49. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +229 -0
  50. package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +60 -0
  51. package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +177 -0
  52. package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +336 -0
  53. package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +201 -0
  54. package/src/transpiler/output/codegen/types/ITypeResolverDeps.ts +0 -23
  55. package/src/transpiler/output/codegen/types/ITypeValidatorDeps.ts +0 -53
@@ -3,13 +3,14 @@
3
3
  * Tests all validation methods for 100% coverage
4
4
  */
5
5
 
6
- import { describe, it, expect, vi } from "vitest";
6
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
7
7
  import TypeValidator from "../TypeValidator";
8
+ import TypeResolver from "../TypeResolver";
9
+ import CodeGenState from "../CodeGenState";
8
10
  import type ICodeGenSymbols from "../../../types/ICodeGenSymbols";
9
11
  import type TTypeInfo from "../types/TTypeInfo";
10
12
  import type TParameterInfo from "../types/TParameterInfo";
11
13
  import type ICallbackTypeInfo from "../types/ICallbackTypeInfo";
12
- import type ITypeValidatorDeps from "../types/ITypeValidatorDeps";
13
14
  import * as Parser from "../../../logic/parser/grammar/CNextParser";
14
15
 
15
16
  // ========================================================================
@@ -50,39 +51,52 @@ function createMockSymbols(
50
51
  }
51
52
 
52
53
  // ========================================================================
53
- // Test Helpers - Mock Dependencies
54
+ // Test Helpers - Setup State
54
55
  // ========================================================================
55
56
 
56
- interface MockDepsOptions {
57
+ interface SetupStateOptions {
57
58
  symbols?: ICodeGenSymbols;
58
59
  typeRegistry?: Map<string, TTypeInfo>;
59
60
  callbackTypes?: Map<string, ICallbackTypeInfo>;
60
61
  knownFunctions?: Set<string>;
61
- knownGlobals?: Set<string>;
62
62
  currentScope?: string | null;
63
63
  scopeMembers?: Map<string, Set<string>>;
64
64
  currentParameters?: Map<string, TParameterInfo>;
65
65
  localVariables?: Set<string>;
66
- resolveIdentifier?: (name: string) => string;
67
- getExpressionType?: (ctx: unknown) => string | null;
68
66
  }
69
67
 
70
- function createMockDeps(options: MockDepsOptions = {}): ITypeValidatorDeps {
71
- return {
72
- symbols: options.symbols ?? createMockSymbols(),
73
- symbolTable: null,
74
- typeRegistry: options.typeRegistry ?? new Map(),
75
- typeResolver: {} as never,
76
- callbackTypes: options.callbackTypes ?? new Map(),
77
- knownFunctions: options.knownFunctions ?? new Set(),
78
- knownGlobals: options.knownGlobals ?? new Set(),
79
- getCurrentScope: () => options.currentScope ?? null,
80
- getScopeMembers: () => options.scopeMembers ?? new Map(),
81
- getCurrentParameters: () => options.currentParameters ?? new Map(),
82
- getLocalVariables: () => options.localVariables ?? new Set(),
83
- resolveIdentifier: options.resolveIdentifier ?? ((name: string) => name),
84
- getExpressionType: options.getExpressionType ?? (() => null),
85
- };
68
+ function setupState(options: SetupStateOptions = {}): void {
69
+ CodeGenState.reset();
70
+ if (options.symbols) {
71
+ CodeGenState.symbols = options.symbols;
72
+ } else {
73
+ CodeGenState.symbols = createMockSymbols();
74
+ }
75
+ if (options.typeRegistry) {
76
+ for (const [k, v] of options.typeRegistry) {
77
+ CodeGenState.typeRegistry.set(k, v);
78
+ }
79
+ }
80
+ if (options.callbackTypes) {
81
+ for (const [k, v] of options.callbackTypes) {
82
+ CodeGenState.callbackTypes.set(k, v);
83
+ }
84
+ }
85
+ if (options.knownFunctions) {
86
+ CodeGenState.knownFunctions = options.knownFunctions;
87
+ }
88
+ if (options.currentScope !== undefined) {
89
+ CodeGenState.currentScope = options.currentScope;
90
+ }
91
+ if (options.scopeMembers) {
92
+ CodeGenState.scopeMembers = options.scopeMembers;
93
+ }
94
+ if (options.currentParameters) {
95
+ CodeGenState.currentParameters = options.currentParameters;
96
+ }
97
+ if (options.localVariables) {
98
+ CodeGenState.localVariables = options.localVariables;
99
+ }
86
100
  }
87
101
 
88
102
  // ========================================================================
@@ -238,14 +252,25 @@ function createMockSwitchCase(
238
252
  // ========================================================================
239
253
 
240
254
  describe("TypeValidator", () => {
255
+ beforeEach(() => {
256
+ CodeGenState.reset();
257
+ });
258
+
259
+ afterEach(() => {
260
+ vi.restoreAllMocks();
261
+ });
262
+
241
263
  describe("validateIncludeNotImplementationFile", () => {
242
264
  it("allows header file includes", () => {
243
- const validator = new TypeValidator(createMockDeps());
265
+ setupState();
244
266
  expect(() =>
245
- validator.validateIncludeNotImplementationFile('#include "file.h"', 1),
267
+ TypeValidator.validateIncludeNotImplementationFile(
268
+ '#include "file.h"',
269
+ 1,
270
+ ),
246
271
  ).not.toThrow();
247
272
  expect(() =>
248
- validator.validateIncludeNotImplementationFile(
273
+ TypeValidator.validateIncludeNotImplementationFile(
249
274
  "#include <file.hpp>",
250
275
  1,
251
276
  ),
@@ -253,22 +278,31 @@ describe("TypeValidator", () => {
253
278
  });
254
279
 
255
280
  it("rejects .c file includes", () => {
256
- const validator = new TypeValidator(createMockDeps());
281
+ setupState();
257
282
  expect(() =>
258
- validator.validateIncludeNotImplementationFile('#include "impl.c"', 5),
283
+ TypeValidator.validateIncludeNotImplementationFile(
284
+ '#include "impl.c"',
285
+ 5,
286
+ ),
259
287
  ).toThrow("E0503");
260
288
  expect(() =>
261
- validator.validateIncludeNotImplementationFile('#include "impl.c"', 5),
289
+ TypeValidator.validateIncludeNotImplementationFile(
290
+ '#include "impl.c"',
291
+ 5,
292
+ ),
262
293
  ).toThrow("impl.c");
263
294
  expect(() =>
264
- validator.validateIncludeNotImplementationFile('#include "impl.c"', 5),
295
+ TypeValidator.validateIncludeNotImplementationFile(
296
+ '#include "impl.c"',
297
+ 5,
298
+ ),
265
299
  ).toThrow("Line 5");
266
300
  });
267
301
 
268
302
  it("rejects .cpp file includes", () => {
269
- const validator = new TypeValidator(createMockDeps());
303
+ setupState();
270
304
  expect(() =>
271
- validator.validateIncludeNotImplementationFile(
305
+ TypeValidator.validateIncludeNotImplementationFile(
272
306
  '#include "impl.cpp"',
273
307
  1,
274
308
  ),
@@ -276,16 +310,19 @@ describe("TypeValidator", () => {
276
310
  });
277
311
 
278
312
  it("rejects .cc file includes", () => {
279
- const validator = new TypeValidator(createMockDeps());
313
+ setupState();
280
314
  expect(() =>
281
- validator.validateIncludeNotImplementationFile("#include <impl.cc>", 1),
315
+ TypeValidator.validateIncludeNotImplementationFile(
316
+ "#include <impl.cc>",
317
+ 1,
318
+ ),
282
319
  ).toThrow("E0503");
283
320
  });
284
321
 
285
322
  it("rejects .cxx file includes", () => {
286
- const validator = new TypeValidator(createMockDeps());
323
+ setupState();
287
324
  expect(() =>
288
- validator.validateIncludeNotImplementationFile(
325
+ TypeValidator.validateIncludeNotImplementationFile(
289
326
  '#include "impl.cxx"',
290
327
  1,
291
328
  ),
@@ -293,9 +330,9 @@ describe("TypeValidator", () => {
293
330
  });
294
331
 
295
332
  it("rejects .c++ file includes", () => {
296
- const validator = new TypeValidator(createMockDeps());
333
+ setupState();
297
334
  expect(() =>
298
- validator.validateIncludeNotImplementationFile(
335
+ TypeValidator.validateIncludeNotImplementationFile(
299
336
  '#include "impl.c++"',
300
337
  1,
301
338
  ),
@@ -303,12 +340,15 @@ describe("TypeValidator", () => {
303
340
  });
304
341
 
305
342
  it("is case-insensitive for extensions", () => {
306
- const validator = new TypeValidator(createMockDeps());
343
+ setupState();
307
344
  expect(() =>
308
- validator.validateIncludeNotImplementationFile('#include "impl.C"', 1),
345
+ TypeValidator.validateIncludeNotImplementationFile(
346
+ '#include "impl.C"',
347
+ 1,
348
+ ),
309
349
  ).toThrow("E0503");
310
350
  expect(() =>
311
- validator.validateIncludeNotImplementationFile(
351
+ TypeValidator.validateIncludeNotImplementationFile(
312
352
  '#include "impl.CPP"',
313
353
  1,
314
354
  ),
@@ -316,36 +356,39 @@ describe("TypeValidator", () => {
316
356
  });
317
357
 
318
358
  it("handles malformed includes gracefully", () => {
319
- const validator = new TypeValidator(createMockDeps());
359
+ setupState();
320
360
  // No path extracted - should not throw
321
361
  expect(() =>
322
- validator.validateIncludeNotImplementationFile("#include", 1),
362
+ TypeValidator.validateIncludeNotImplementationFile("#include", 1),
323
363
  ).not.toThrow();
324
364
  expect(() =>
325
- validator.validateIncludeNotImplementationFile('#include ""', 1),
365
+ TypeValidator.validateIncludeNotImplementationFile('#include ""', 1),
326
366
  ).not.toThrow();
327
367
  });
328
368
 
329
369
  it("handles angle bracket includes", () => {
330
- const validator = new TypeValidator(createMockDeps());
370
+ setupState();
331
371
  expect(() =>
332
- validator.validateIncludeNotImplementationFile(
372
+ TypeValidator.validateIncludeNotImplementationFile(
333
373
  "#include <system.h>",
334
374
  1,
335
375
  ),
336
376
  ).not.toThrow();
337
377
  expect(() =>
338
- validator.validateIncludeNotImplementationFile("#include <impl.c>", 1),
378
+ TypeValidator.validateIncludeNotImplementationFile(
379
+ "#include <impl.c>",
380
+ 1,
381
+ ),
339
382
  ).toThrow("E0503");
340
383
  });
341
384
  });
342
385
 
343
386
  describe("validateIncludeNoCnxAlternative", () => {
344
387
  it("skips .cnx includes", () => {
345
- const validator = new TypeValidator(createMockDeps());
388
+ setupState();
346
389
  const fileExists = vi.fn(() => true);
347
390
  expect(() =>
348
- validator.validateIncludeNoCnxAlternative(
391
+ TypeValidator.validateIncludeNoCnxAlternative(
349
392
  '#include "file.cnx"',
350
393
  1,
351
394
  "/src/main.cnx",
@@ -357,10 +400,10 @@ describe("TypeValidator", () => {
357
400
  });
358
401
 
359
402
  it("skips non-header files", () => {
360
- const validator = new TypeValidator(createMockDeps());
403
+ setupState();
361
404
  const fileExists = vi.fn(() => true);
362
405
  expect(() =>
363
- validator.validateIncludeNoCnxAlternative(
406
+ TypeValidator.validateIncludeNoCnxAlternative(
364
407
  '#include "file.txt"',
365
408
  1,
366
409
  "/src/main.cnx",
@@ -372,10 +415,10 @@ describe("TypeValidator", () => {
372
415
  });
373
416
 
374
417
  it("throws E0504 when .cnx alternative exists for quoted include", () => {
375
- const validator = new TypeValidator(createMockDeps());
418
+ setupState();
376
419
  const fileExists = vi.fn(() => true);
377
420
  expect(() =>
378
- validator.validateIncludeNoCnxAlternative(
421
+ TypeValidator.validateIncludeNoCnxAlternative(
379
422
  '#include "utils.h"',
380
423
  10,
381
424
  "/src/main.cnx",
@@ -384,7 +427,7 @@ describe("TypeValidator", () => {
384
427
  ),
385
428
  ).toThrow("E0504");
386
429
  expect(() =>
387
- validator.validateIncludeNoCnxAlternative(
430
+ TypeValidator.validateIncludeNoCnxAlternative(
388
431
  '#include "utils.h"',
389
432
  10,
390
433
  "/src/main.cnx",
@@ -395,10 +438,10 @@ describe("TypeValidator", () => {
395
438
  });
396
439
 
397
440
  it("does not throw when .cnx alternative does not exist", () => {
398
- const validator = new TypeValidator(createMockDeps());
441
+ setupState();
399
442
  const fileExists = vi.fn(() => false);
400
443
  expect(() =>
401
- validator.validateIncludeNoCnxAlternative(
444
+ TypeValidator.validateIncludeNoCnxAlternative(
402
445
  '#include "utils.h"',
403
446
  1,
404
447
  "/src/main.cnx",
@@ -409,10 +452,10 @@ describe("TypeValidator", () => {
409
452
  });
410
453
 
411
454
  it("throws E0504 when .cnx alternative exists for angle bracket include", () => {
412
- const validator = new TypeValidator(createMockDeps());
455
+ setupState();
413
456
  const fileExists = vi.fn(() => true);
414
457
  expect(() =>
415
- validator.validateIncludeNoCnxAlternative(
458
+ TypeValidator.validateIncludeNoCnxAlternative(
416
459
  "#include <lib/utils.hpp>",
417
460
  5,
418
461
  "/src/main.cnx",
@@ -423,10 +466,10 @@ describe("TypeValidator", () => {
423
466
  });
424
467
 
425
468
  it("searches through all include paths for angle includes", () => {
426
- const validator = new TypeValidator(createMockDeps());
469
+ setupState();
427
470
  const fileExists = vi.fn((path: string) => path.includes("/lib2/"));
428
471
  expect(() =>
429
- validator.validateIncludeNoCnxAlternative(
472
+ TypeValidator.validateIncludeNoCnxAlternative(
430
473
  "#include <utils.h>",
431
474
  1,
432
475
  "/src/main.cnx",
@@ -438,11 +481,11 @@ describe("TypeValidator", () => {
438
481
  });
439
482
 
440
483
  it("handles quoted include without sourcePath", () => {
441
- const validator = new TypeValidator(createMockDeps());
484
+ setupState();
442
485
  const fileExists = vi.fn(() => true);
443
486
  // No source path - cannot resolve relative include
444
487
  expect(() =>
445
- validator.validateIncludeNoCnxAlternative(
488
+ TypeValidator.validateIncludeNoCnxAlternative(
446
489
  '#include "utils.h"',
447
490
  1,
448
491
  null,
@@ -453,10 +496,10 @@ describe("TypeValidator", () => {
453
496
  });
454
497
 
455
498
  it("handles malformed includes", () => {
456
- const validator = new TypeValidator(createMockDeps());
499
+ setupState();
457
500
  const fileExists = vi.fn(() => true);
458
501
  expect(() =>
459
- validator.validateIncludeNoCnxAlternative(
502
+ TypeValidator.validateIncludeNoCnxAlternative(
460
503
  "#include",
461
504
  1,
462
505
  "/src/main.cnx",
@@ -473,50 +516,50 @@ describe("TypeValidator", () => {
473
516
 
474
517
  describe("validateBitmapFieldLiteral", () => {
475
518
  it("allows values within field width", () => {
476
- const validator = new TypeValidator(createMockDeps());
519
+ setupState();
477
520
  const expr = createMockExpression("7");
478
521
  expect(() =>
479
- validator.validateBitmapFieldLiteral(expr, 3, "flags"),
522
+ TypeValidator.validateBitmapFieldLiteral(expr, 3, "flags"),
480
523
  ).not.toThrow();
481
524
  });
482
525
 
483
526
  it("throws for decimal values exceeding field width", () => {
484
- const validator = new TypeValidator(createMockDeps());
527
+ setupState();
485
528
  const expr = createMockExpression("8");
486
529
  expect(() =>
487
- validator.validateBitmapFieldLiteral(expr, 3, "flags"),
530
+ TypeValidator.validateBitmapFieldLiteral(expr, 3, "flags"),
488
531
  ).toThrow("Value 8 exceeds 3-bit field 'flags' maximum of 7");
489
532
  });
490
533
 
491
534
  it("validates hex literals", () => {
492
- const validator = new TypeValidator(createMockDeps());
535
+ setupState();
493
536
  const expr = createMockExpression("0xFF");
494
537
  expect(() =>
495
- validator.validateBitmapFieldLiteral(expr, 8, "byte"),
538
+ TypeValidator.validateBitmapFieldLiteral(expr, 8, "byte"),
496
539
  ).not.toThrow();
497
540
  const exprBad = createMockExpression("0x100");
498
541
  expect(() =>
499
- validator.validateBitmapFieldLiteral(exprBad, 8, "byte"),
542
+ TypeValidator.validateBitmapFieldLiteral(exprBad, 8, "byte"),
500
543
  ).toThrow("Value 256 exceeds 8-bit field 'byte' maximum of 255");
501
544
  });
502
545
 
503
546
  it("validates binary literals", () => {
504
- const validator = new TypeValidator(createMockDeps());
547
+ setupState();
505
548
  const expr = createMockExpression("0b1111");
506
549
  expect(() =>
507
- validator.validateBitmapFieldLiteral(expr, 4, "nibble"),
550
+ TypeValidator.validateBitmapFieldLiteral(expr, 4, "nibble"),
508
551
  ).not.toThrow();
509
552
  const exprBad = createMockExpression("0b10000");
510
553
  expect(() =>
511
- validator.validateBitmapFieldLiteral(exprBad, 4, "nibble"),
554
+ TypeValidator.validateBitmapFieldLiteral(exprBad, 4, "nibble"),
512
555
  ).toThrow("Value 16 exceeds 4-bit field 'nibble' maximum of 15");
513
556
  });
514
557
 
515
558
  it("skips validation for non-literal expressions", () => {
516
- const validator = new TypeValidator(createMockDeps());
559
+ setupState();
517
560
  const expr = createMockExpression("someVariable");
518
561
  expect(() =>
519
- validator.validateBitmapFieldLiteral(expr, 1, "bit"),
562
+ TypeValidator.validateBitmapFieldLiteral(expr, 1, "bit"),
520
563
  ).not.toThrow();
521
564
  });
522
565
  });
@@ -527,58 +570,64 @@ describe("TypeValidator", () => {
527
570
 
528
571
  describe("checkArrayBounds", () => {
529
572
  it("allows valid constant indices", () => {
530
- const validator = new TypeValidator(createMockDeps());
573
+ setupState();
531
574
  const indexExprs = [createMockExpression("0")];
532
575
  const tryEval = vi.fn(() => 0);
533
576
  expect(() =>
534
- validator.checkArrayBounds("arr", [10], indexExprs, 1, tryEval),
577
+ TypeValidator.checkArrayBounds("arr", [10], indexExprs, 1, tryEval),
535
578
  ).not.toThrow();
536
579
  });
537
580
 
538
581
  it("throws for negative indices", () => {
539
- const validator = new TypeValidator(createMockDeps());
582
+ setupState();
540
583
  const indexExprs = [createMockExpression("-1")];
541
584
  const tryEval = vi.fn(() => -1);
542
585
  expect(() =>
543
- validator.checkArrayBounds("arr", [10], indexExprs, 5, tryEval),
586
+ TypeValidator.checkArrayBounds("arr", [10], indexExprs, 5, tryEval),
544
587
  ).toThrow("Array index out of bounds: -1 is negative for 'arr'");
545
588
  });
546
589
 
547
590
  it("throws for index >= dimension", () => {
548
- const validator = new TypeValidator(createMockDeps());
591
+ setupState();
549
592
  const indexExprs = [createMockExpression("10")];
550
593
  const tryEval = vi.fn(() => 10);
551
594
  expect(() =>
552
- validator.checkArrayBounds("arr", [10], indexExprs, 3, tryEval),
595
+ TypeValidator.checkArrayBounds("arr", [10], indexExprs, 3, tryEval),
553
596
  ).toThrow("Array index out of bounds: 10 >= 10 for 'arr' dimension 1");
554
597
  });
555
598
 
556
599
  it("checks all dimensions for multi-dimensional arrays", () => {
557
- const validator = new TypeValidator(createMockDeps());
600
+ setupState();
558
601
  const indexExprs = [createMockExpression("0"), createMockExpression("5")];
559
602
  let callIdx = 0;
560
603
  const tryEval = vi.fn(() => (callIdx++ === 0 ? 0 : 5));
561
604
  expect(() =>
562
- validator.checkArrayBounds("matrix", [3, 4], indexExprs, 1, tryEval),
605
+ TypeValidator.checkArrayBounds(
606
+ "matrix",
607
+ [3, 4],
608
+ indexExprs,
609
+ 1,
610
+ tryEval,
611
+ ),
563
612
  ).toThrow("Array index out of bounds: 5 >= 4 for 'matrix' dimension 2");
564
613
  });
565
614
 
566
615
  it("skips non-constant indices", () => {
567
- const validator = new TypeValidator(createMockDeps());
616
+ setupState();
568
617
  const indexExprs = [createMockExpression("i")];
569
618
  const tryEval = vi.fn(() => undefined);
570
619
  expect(() =>
571
- validator.checkArrayBounds("arr", [10], indexExprs, 1, tryEval),
620
+ TypeValidator.checkArrayBounds("arr", [10], indexExprs, 1, tryEval),
572
621
  ).not.toThrow();
573
622
  });
574
623
 
575
624
  it("skips upper bound check for unsized dimensions (Issue #547)", () => {
576
- const validator = new TypeValidator(createMockDeps());
625
+ setupState();
577
626
  const indexExprs = [createMockExpression("100")];
578
627
  const tryEval = vi.fn(() => 100);
579
628
  // Dimension 0 means unsized array
580
629
  expect(() =>
581
- validator.checkArrayBounds("unsized", [0], indexExprs, 1, tryEval),
630
+ TypeValidator.checkArrayBounds("unsized", [0], indexExprs, 1, tryEval),
582
631
  ).not.toThrow();
583
632
  });
584
633
  });
@@ -589,7 +638,7 @@ describe("TypeValidator", () => {
589
638
 
590
639
  describe("callbackSignaturesMatch", () => {
591
640
  it("returns true for matching signatures", () => {
592
- const validator = new TypeValidator(createMockDeps());
641
+ setupState();
593
642
  const a: ICallbackTypeInfo = {
594
643
  functionName: "handler",
595
644
  returnType: "void",
@@ -620,11 +669,11 @@ describe("TypeValidator", () => {
620
669
  ],
621
670
  typedefName: "other_fp",
622
671
  };
623
- expect(validator.callbackSignaturesMatch(a, b)).toBe(true);
672
+ expect(TypeValidator.callbackSignaturesMatch(a, b)).toBe(true);
624
673
  });
625
674
 
626
675
  it("returns false for different return types", () => {
627
- const validator = new TypeValidator(createMockDeps());
676
+ setupState();
628
677
  const a: ICallbackTypeInfo = {
629
678
  functionName: "a",
630
679
  returnType: "void",
@@ -637,11 +686,11 @@ describe("TypeValidator", () => {
637
686
  parameters: [],
638
687
  typedefName: "b_fp",
639
688
  };
640
- expect(validator.callbackSignaturesMatch(a, b)).toBe(false);
689
+ expect(TypeValidator.callbackSignaturesMatch(a, b)).toBe(false);
641
690
  });
642
691
 
643
692
  it("returns false for different parameter counts", () => {
644
- const validator = new TypeValidator(createMockDeps());
693
+ setupState();
645
694
  const a: ICallbackTypeInfo = {
646
695
  functionName: "a",
647
696
  returnType: "void",
@@ -663,11 +712,11 @@ describe("TypeValidator", () => {
663
712
  parameters: [],
664
713
  typedefName: "b_fp",
665
714
  };
666
- expect(validator.callbackSignaturesMatch(a, b)).toBe(false);
715
+ expect(TypeValidator.callbackSignaturesMatch(a, b)).toBe(false);
667
716
  });
668
717
 
669
718
  it("returns false for different parameter types", () => {
670
- const validator = new TypeValidator(createMockDeps());
719
+ setupState();
671
720
  const a: ICallbackTypeInfo = {
672
721
  functionName: "a",
673
722
  returnType: "void",
@@ -698,11 +747,11 @@ describe("TypeValidator", () => {
698
747
  ],
699
748
  typedefName: "b_fp",
700
749
  };
701
- expect(validator.callbackSignaturesMatch(a, b)).toBe(false);
750
+ expect(TypeValidator.callbackSignaturesMatch(a, b)).toBe(false);
702
751
  });
703
752
 
704
753
  it("returns false for different const-ness", () => {
705
- const validator = new TypeValidator(createMockDeps());
754
+ setupState();
706
755
  const a: ICallbackTypeInfo = {
707
756
  functionName: "a",
708
757
  returnType: "void",
@@ -733,11 +782,11 @@ describe("TypeValidator", () => {
733
782
  ],
734
783
  typedefName: "b_fp",
735
784
  };
736
- expect(validator.callbackSignaturesMatch(a, b)).toBe(false);
785
+ expect(TypeValidator.callbackSignaturesMatch(a, b)).toBe(false);
737
786
  });
738
787
 
739
788
  it("returns false for different pointer-ness", () => {
740
- const validator = new TypeValidator(createMockDeps());
789
+ setupState();
741
790
  const a: ICallbackTypeInfo = {
742
791
  functionName: "a",
743
792
  returnType: "void",
@@ -768,11 +817,11 @@ describe("TypeValidator", () => {
768
817
  ],
769
818
  typedefName: "b_fp",
770
819
  };
771
- expect(validator.callbackSignaturesMatch(a, b)).toBe(false);
820
+ expect(TypeValidator.callbackSignaturesMatch(a, b)).toBe(false);
772
821
  });
773
822
 
774
823
  it("returns false for different array-ness", () => {
775
- const validator = new TypeValidator(createMockDeps());
824
+ setupState();
776
825
  const a: ICallbackTypeInfo = {
777
826
  functionName: "a",
778
827
  returnType: "void",
@@ -803,18 +852,16 @@ describe("TypeValidator", () => {
803
852
  ],
804
853
  typedefName: "b_fp",
805
854
  };
806
- expect(validator.callbackSignaturesMatch(a, b)).toBe(false);
855
+ expect(TypeValidator.callbackSignaturesMatch(a, b)).toBe(false);
807
856
  });
808
857
  });
809
858
 
810
859
  describe("validateCallbackAssignment", () => {
811
860
  it("skips validation for non-function values", () => {
812
- const validator = new TypeValidator(
813
- createMockDeps({ knownFunctions: new Set(["handler"]) }),
814
- );
861
+ setupState({ knownFunctions: new Set(["handler"]) });
815
862
  const expr = createMockExpression("notAFunction");
816
863
  expect(() =>
817
- validator.validateCallbackAssignment(
864
+ TypeValidator.validateCallbackAssignment(
818
865
  "Handler",
819
866
  expr,
820
867
  "callback",
@@ -824,12 +871,10 @@ describe("TypeValidator", () => {
824
871
  });
825
872
 
826
873
  it("skips validation when callback types are not found", () => {
827
- const validator = new TypeValidator(
828
- createMockDeps({ knownFunctions: new Set(["handler"]) }),
829
- );
874
+ setupState({ knownFunctions: new Set(["handler"]) });
830
875
  const expr = createMockExpression("handler");
831
876
  expect(() =>
832
- validator.validateCallbackAssignment(
877
+ TypeValidator.validateCallbackAssignment(
833
878
  "Handler",
834
879
  expr,
835
880
  "callback",
@@ -859,15 +904,13 @@ describe("TypeValidator", () => {
859
904
  },
860
905
  ],
861
906
  ]);
862
- const validator = new TypeValidator(
863
- createMockDeps({
864
- knownFunctions: new Set(["wrongFunc"]),
865
- callbackTypes,
866
- }),
867
- );
907
+ setupState({
908
+ knownFunctions: new Set(["wrongFunc"]),
909
+ callbackTypes,
910
+ });
868
911
  const expr = createMockExpression("wrongFunc");
869
912
  expect(() =>
870
- validator.validateCallbackAssignment(
913
+ TypeValidator.validateCallbackAssignment(
871
914
  "Handler",
872
915
  expr,
873
916
  "callback",
@@ -899,16 +942,14 @@ describe("TypeValidator", () => {
899
942
  },
900
943
  ],
901
944
  ]);
902
- const validator = new TypeValidator(
903
- createMockDeps({
904
- knownFunctions: new Set(["TypeB"]),
905
- callbackTypes,
906
- }),
907
- );
945
+ setupState({
946
+ knownFunctions: new Set(["TypeB"]),
947
+ callbackTypes,
948
+ });
908
949
  const expr = createMockExpression("TypeB");
909
950
  // TypeB is used as a field type, so nominal typing applies
910
951
  expect(() =>
911
- validator.validateCallbackAssignment(
952
+ TypeValidator.validateCallbackAssignment(
912
953
  "TypeA",
913
954
  expr,
914
955
  "handler",
@@ -938,15 +979,13 @@ describe("TypeValidator", () => {
938
979
  },
939
980
  ],
940
981
  ]);
941
- const validator = new TypeValidator(
942
- createMockDeps({
943
- knownFunctions: new Set(["myHandler"]),
944
- callbackTypes,
945
- }),
946
- );
982
+ setupState({
983
+ knownFunctions: new Set(["myHandler"]),
984
+ callbackTypes,
985
+ });
947
986
  const expr = createMockExpression("myHandler");
948
987
  expect(() =>
949
- validator.validateCallbackAssignment(
988
+ TypeValidator.validateCallbackAssignment(
950
989
  "Handler",
951
990
  expr,
952
991
  "callback",
@@ -968,16 +1007,16 @@ describe("TypeValidator", () => {
968
1007
  { baseType: "u32", bitWidth: 32, isArray: false, isConst: false },
969
1008
  ],
970
1009
  ]);
971
- const validator = new TypeValidator(createMockDeps({ typeRegistry }));
972
- expect(validator.checkConstAssignment("x")).toBeNull();
1010
+ setupState({ typeRegistry });
1011
+ expect(TypeValidator.checkConstAssignment("x")).toBeNull();
973
1012
  });
974
1013
 
975
1014
  it("returns error for const variables", () => {
976
1015
  const typeRegistry = new Map<string, TTypeInfo>([
977
1016
  ["x", { baseType: "u32", bitWidth: 32, isArray: false, isConst: true }],
978
1017
  ]);
979
- const validator = new TypeValidator(createMockDeps({ typeRegistry }));
980
- expect(validator.checkConstAssignment("x")).toContain(
1018
+ setupState({ typeRegistry });
1019
+ expect(TypeValidator.checkConstAssignment("x")).toContain(
981
1020
  "cannot assign to const variable 'x'",
982
1021
  );
983
1022
  });
@@ -997,10 +1036,8 @@ describe("TypeValidator", () => {
997
1036
  },
998
1037
  ],
999
1038
  ]);
1000
- const validator = new TypeValidator(
1001
- createMockDeps({ currentParameters }),
1002
- );
1003
- expect(validator.checkConstAssignment("param")).toContain(
1039
+ setupState({ currentParameters });
1040
+ expect(TypeValidator.checkConstAssignment("param")).toContain(
1004
1041
  "cannot assign to const parameter 'param'",
1005
1042
  );
1006
1043
  });
@@ -1012,13 +1049,12 @@ describe("TypeValidator", () => {
1012
1049
  { baseType: "u32", bitWidth: 32, isArray: false, isConst: true },
1013
1050
  ],
1014
1051
  ]);
1015
- const validator = new TypeValidator(
1016
- createMockDeps({
1017
- typeRegistry,
1018
- resolveIdentifier: (name) => (name === "x" ? "Scope_x" : name),
1019
- }),
1020
- );
1021
- expect(validator.checkConstAssignment("x")).toContain(
1052
+ setupState({
1053
+ typeRegistry,
1054
+ currentScope: "Scope",
1055
+ scopeMembers: new Map([["Scope", new Set(["x"])]]),
1056
+ });
1057
+ expect(TypeValidator.checkConstAssignment("x")).toContain(
1022
1058
  "cannot assign to const variable",
1023
1059
  );
1024
1060
  });
@@ -1040,18 +1076,16 @@ describe("TypeValidator", () => {
1040
1076
  },
1041
1077
  ],
1042
1078
  ]);
1043
- const validator = new TypeValidator(
1044
- createMockDeps({ currentParameters }),
1045
- );
1046
- expect(validator.isConstValue("param")).toBe(true);
1079
+ setupState({ currentParameters });
1080
+ expect(TypeValidator.isConstValue("param")).toBe(true);
1047
1081
  });
1048
1082
 
1049
1083
  it("returns true for const variables", () => {
1050
1084
  const typeRegistry = new Map<string, TTypeInfo>([
1051
1085
  ["x", { baseType: "u32", bitWidth: 32, isArray: false, isConst: true }],
1052
1086
  ]);
1053
- const validator = new TypeValidator(createMockDeps({ typeRegistry }));
1054
- expect(validator.isConstValue("x")).toBe(true);
1087
+ setupState({ typeRegistry });
1088
+ expect(TypeValidator.isConstValue("x")).toBe(true);
1055
1089
  });
1056
1090
 
1057
1091
  it("returns false for mutable variables", () => {
@@ -1061,13 +1095,13 @@ describe("TypeValidator", () => {
1061
1095
  { baseType: "u32", bitWidth: 32, isArray: false, isConst: false },
1062
1096
  ],
1063
1097
  ]);
1064
- const validator = new TypeValidator(createMockDeps({ typeRegistry }));
1065
- expect(validator.isConstValue("x")).toBe(false);
1098
+ setupState({ typeRegistry });
1099
+ expect(TypeValidator.isConstValue("x")).toBe(false);
1066
1100
  });
1067
1101
 
1068
1102
  it("returns false for unknown identifiers", () => {
1069
- const validator = new TypeValidator(createMockDeps());
1070
- expect(validator.isConstValue("unknown")).toBe(false);
1103
+ setupState();
1104
+ expect(TypeValidator.isConstValue("unknown")).toBe(false);
1071
1105
  });
1072
1106
  });
1073
1107
 
@@ -1077,30 +1111,36 @@ describe("TypeValidator", () => {
1077
1111
 
1078
1112
  describe("validateBareIdentifierInScope", () => {
1079
1113
  it("does nothing outside a scope", () => {
1080
- const validator = new TypeValidator(
1081
- createMockDeps({ currentScope: null }),
1082
- );
1114
+ setupState({ currentScope: null });
1083
1115
  expect(() =>
1084
- validator.validateBareIdentifierInScope("anything", false, () => false),
1116
+ TypeValidator.validateBareIdentifierInScope(
1117
+ "anything",
1118
+ false,
1119
+ () => false,
1120
+ ),
1085
1121
  ).not.toThrow();
1086
1122
  });
1087
1123
 
1088
1124
  it("allows local variables as bare identifiers", () => {
1089
- const validator = new TypeValidator(
1090
- createMockDeps({ currentScope: "Motor" }),
1091
- );
1125
+ setupState({ currentScope: "Motor" });
1092
1126
  expect(() =>
1093
- validator.validateBareIdentifierInScope("localVar", true, () => false),
1127
+ TypeValidator.validateBareIdentifierInScope(
1128
+ "localVar",
1129
+ true,
1130
+ () => false,
1131
+ ),
1094
1132
  ).not.toThrow();
1095
1133
  });
1096
1134
 
1097
1135
  it("throws for bare scope member access", () => {
1098
1136
  const scopeMembers = new Map([["Motor", new Set(["speed"])]]);
1099
- const validator = new TypeValidator(
1100
- createMockDeps({ currentScope: "Motor", scopeMembers }),
1101
- );
1137
+ setupState({ currentScope: "Motor", scopeMembers });
1102
1138
  expect(() =>
1103
- validator.validateBareIdentifierInScope("speed", false, () => false),
1139
+ TypeValidator.validateBareIdentifierInScope(
1140
+ "speed",
1141
+ false,
1142
+ () => false,
1143
+ ),
1104
1144
  ).toThrow(
1105
1145
  "Use 'this.speed' to access scope member 'speed' inside scope 'Motor'",
1106
1146
  );
@@ -1108,25 +1148,21 @@ describe("TypeValidator", () => {
1108
1148
 
1109
1149
  it("throws for bare register access", () => {
1110
1150
  const symbols = createMockSymbols({ knownRegisters: new Set(["GPIO"]) });
1111
- const validator = new TypeValidator(
1112
- createMockDeps({ symbols, currentScope: "Motor" }),
1113
- );
1151
+ setupState({ symbols, currentScope: "Motor" });
1114
1152
  expect(() =>
1115
- validator.validateBareIdentifierInScope("GPIO", false, () => false),
1153
+ TypeValidator.validateBareIdentifierInScope("GPIO", false, () => false),
1116
1154
  ).toThrow(
1117
1155
  "Use 'global.GPIO' to access register 'GPIO' inside scope 'Motor'",
1118
1156
  );
1119
1157
  });
1120
1158
 
1121
1159
  it("throws for bare global function access", () => {
1122
- const validator = new TypeValidator(
1123
- createMockDeps({
1124
- currentScope: "Motor",
1125
- knownFunctions: new Set(["globalFunc"]),
1126
- }),
1127
- );
1160
+ setupState({
1161
+ currentScope: "Motor",
1162
+ knownFunctions: new Set(["globalFunc"]),
1163
+ });
1128
1164
  expect(() =>
1129
- validator.validateBareIdentifierInScope(
1165
+ TypeValidator.validateBareIdentifierInScope(
1130
1166
  "globalFunc",
1131
1167
  false,
1132
1168
  () => false,
@@ -1137,14 +1173,12 @@ describe("TypeValidator", () => {
1137
1173
  });
1138
1174
 
1139
1175
  it("allows scope-prefixed functions", () => {
1140
- const validator = new TypeValidator(
1141
- createMockDeps({
1142
- currentScope: "Motor",
1143
- knownFunctions: new Set(["Motor_helper"]),
1144
- }),
1145
- );
1176
+ setupState({
1177
+ currentScope: "Motor",
1178
+ knownFunctions: new Set(["Motor_helper"]),
1179
+ });
1146
1180
  expect(() =>
1147
- validator.validateBareIdentifierInScope(
1181
+ TypeValidator.validateBareIdentifierInScope(
1148
1182
  "Motor_helper",
1149
1183
  false,
1150
1184
  () => false,
@@ -1154,20 +1188,20 @@ describe("TypeValidator", () => {
1154
1188
 
1155
1189
  it("throws for bare enum access", () => {
1156
1190
  const symbols = createMockSymbols({ knownEnums: new Set(["State"]) });
1157
- const validator = new TypeValidator(
1158
- createMockDeps({ symbols, currentScope: "Motor" }),
1159
- );
1191
+ setupState({ symbols, currentScope: "Motor" });
1160
1192
  expect(() =>
1161
- validator.validateBareIdentifierInScope("State", false, () => false),
1193
+ TypeValidator.validateBareIdentifierInScope(
1194
+ "State",
1195
+ false,
1196
+ () => false,
1197
+ ),
1162
1198
  ).toThrow("Use 'global.State' to access global enum 'State'");
1163
1199
  });
1164
1200
 
1165
1201
  it("throws for bare struct access", () => {
1166
- const validator = new TypeValidator(
1167
- createMockDeps({ currentScope: "Motor" }),
1168
- );
1202
+ setupState({ currentScope: "Motor" });
1169
1203
  expect(() =>
1170
- validator.validateBareIdentifierInScope("Point", false, () => true),
1204
+ TypeValidator.validateBareIdentifierInScope("Point", false, () => true),
1171
1205
  ).toThrow("Use 'global.Point' to access global struct 'Point'");
1172
1206
  });
1173
1207
 
@@ -1178,11 +1212,13 @@ describe("TypeValidator", () => {
1178
1212
  { baseType: "u32", bitWidth: 32, isArray: false, isConst: false },
1179
1213
  ],
1180
1214
  ]);
1181
- const validator = new TypeValidator(
1182
- createMockDeps({ currentScope: "Motor", typeRegistry }),
1183
- );
1215
+ setupState({ currentScope: "Motor", typeRegistry });
1184
1216
  expect(() =>
1185
- validator.validateBareIdentifierInScope("counter", false, () => false),
1217
+ TypeValidator.validateBareIdentifierInScope(
1218
+ "counter",
1219
+ false,
1220
+ () => false,
1221
+ ),
1186
1222
  ).toThrow("Use 'global.counter' to access global variable 'counter'");
1187
1223
  });
1188
1224
 
@@ -1193,11 +1229,9 @@ describe("TypeValidator", () => {
1193
1229
  { baseType: "u32", bitWidth: 32, isArray: false, isConst: false },
1194
1230
  ],
1195
1231
  ]);
1196
- const validator = new TypeValidator(
1197
- createMockDeps({ currentScope: "Motor", typeRegistry }),
1198
- );
1232
+ setupState({ currentScope: "Motor", typeRegistry });
1199
1233
  expect(() =>
1200
- validator.validateBareIdentifierInScope(
1234
+ TypeValidator.validateBareIdentifierInScope(
1201
1235
  "Motor_speed",
1202
1236
  false,
1203
1237
  () => false,
@@ -1212,36 +1246,36 @@ describe("TypeValidator", () => {
1212
1246
 
1213
1247
  describe("validateNoEarlyExits", () => {
1214
1248
  it("allows blocks without early exits", () => {
1215
- const validator = new TypeValidator(createMockDeps());
1249
+ setupState();
1216
1250
  const block = createMockBlock([
1217
1251
  createMockStatement(),
1218
1252
  createMockStatement(),
1219
1253
  ]);
1220
- expect(() => validator.validateNoEarlyExits(block)).not.toThrow();
1254
+ expect(() => TypeValidator.validateNoEarlyExits(block)).not.toThrow();
1221
1255
  });
1222
1256
 
1223
1257
  it("throws for return statement in critical block", () => {
1224
- const validator = new TypeValidator(createMockDeps());
1258
+ setupState();
1225
1259
  const block = createMockBlock([createMockStatement({ hasReturn: true })]);
1226
- expect(() => validator.validateNoEarlyExits(block)).toThrow("E0853");
1227
- expect(() => validator.validateNoEarlyExits(block)).toThrow(
1260
+ expect(() => TypeValidator.validateNoEarlyExits(block)).toThrow("E0853");
1261
+ expect(() => TypeValidator.validateNoEarlyExits(block)).toThrow(
1228
1262
  "Cannot use 'return' inside critical section",
1229
1263
  );
1230
1264
  });
1231
1265
 
1232
1266
  it("throws for return in nested block", () => {
1233
- const validator = new TypeValidator(createMockDeps());
1267
+ setupState();
1234
1268
  const innerBlock = createMockBlock([
1235
1269
  createMockStatement({ hasReturn: true }),
1236
1270
  ]);
1237
1271
  const block = createMockBlock([
1238
1272
  createMockStatement({ hasBlock: innerBlock }),
1239
1273
  ]);
1240
- expect(() => validator.validateNoEarlyExits(block)).toThrow("E0853");
1274
+ expect(() => TypeValidator.validateNoEarlyExits(block)).toThrow("E0853");
1241
1275
  });
1242
1276
 
1243
1277
  it("throws for return in if statement", () => {
1244
- const validator = new TypeValidator(createMockDeps());
1278
+ setupState();
1245
1279
  const ifStmt = {
1246
1280
  statement: () => [
1247
1281
  {
@@ -1251,11 +1285,11 @@ describe("TypeValidator", () => {
1251
1285
  ],
1252
1286
  } as Partial<Parser.IfStatementContext>;
1253
1287
  const block = createMockBlock([createMockStatement({ hasIf: ifStmt })]);
1254
- expect(() => validator.validateNoEarlyExits(block)).toThrow("E0853");
1288
+ expect(() => TypeValidator.validateNoEarlyExits(block)).toThrow("E0853");
1255
1289
  });
1256
1290
 
1257
1291
  it("throws for return in if statement's nested block", () => {
1258
- const validator = new TypeValidator(createMockDeps());
1292
+ setupState();
1259
1293
  const innerBlock = createMockBlock([
1260
1294
  createMockStatement({ hasReturn: true }),
1261
1295
  ]);
@@ -1268,11 +1302,11 @@ describe("TypeValidator", () => {
1268
1302
  ],
1269
1303
  } as Partial<Parser.IfStatementContext>;
1270
1304
  const block = createMockBlock([createMockStatement({ hasIf: ifStmt })]);
1271
- expect(() => validator.validateNoEarlyExits(block)).toThrow("E0853");
1305
+ expect(() => TypeValidator.validateNoEarlyExits(block)).toThrow("E0853");
1272
1306
  });
1273
1307
 
1274
1308
  it("throws for return in while loop", () => {
1275
- const validator = new TypeValidator(createMockDeps());
1309
+ setupState();
1276
1310
  const whileStmt = {
1277
1311
  statement: () =>
1278
1312
  ({
@@ -1283,11 +1317,11 @@ describe("TypeValidator", () => {
1283
1317
  const block = createMockBlock([
1284
1318
  createMockStatement({ hasWhile: whileStmt }),
1285
1319
  ]);
1286
- expect(() => validator.validateNoEarlyExits(block)).toThrow("E0853");
1320
+ expect(() => TypeValidator.validateNoEarlyExits(block)).toThrow("E0853");
1287
1321
  });
1288
1322
 
1289
1323
  it("throws for return in while loop's nested block", () => {
1290
- const validator = new TypeValidator(createMockDeps());
1324
+ setupState();
1291
1325
  const innerBlock = createMockBlock([
1292
1326
  createMockStatement({ hasReturn: true }),
1293
1327
  ]);
@@ -1301,11 +1335,11 @@ describe("TypeValidator", () => {
1301
1335
  const block = createMockBlock([
1302
1336
  createMockStatement({ hasWhile: whileStmt }),
1303
1337
  ]);
1304
- expect(() => validator.validateNoEarlyExits(block)).toThrow("E0853");
1338
+ expect(() => TypeValidator.validateNoEarlyExits(block)).toThrow("E0853");
1305
1339
  });
1306
1340
 
1307
1341
  it("throws for return in for loop", () => {
1308
- const validator = new TypeValidator(createMockDeps());
1342
+ setupState();
1309
1343
  const forStmt = {
1310
1344
  statement: () =>
1311
1345
  ({
@@ -1314,11 +1348,11 @@ describe("TypeValidator", () => {
1314
1348
  }) as unknown as Parser.StatementContext,
1315
1349
  } as Partial<Parser.ForStatementContext>;
1316
1350
  const block = createMockBlock([createMockStatement({ hasFor: forStmt })]);
1317
- expect(() => validator.validateNoEarlyExits(block)).toThrow("E0853");
1351
+ expect(() => TypeValidator.validateNoEarlyExits(block)).toThrow("E0853");
1318
1352
  });
1319
1353
 
1320
1354
  it("throws for return in for loop's nested block", () => {
1321
- const validator = new TypeValidator(createMockDeps());
1355
+ setupState();
1322
1356
  const innerBlock = createMockBlock([
1323
1357
  createMockStatement({ hasReturn: true }),
1324
1358
  ]);
@@ -1330,11 +1364,11 @@ describe("TypeValidator", () => {
1330
1364
  }) as unknown as Parser.StatementContext,
1331
1365
  } as Partial<Parser.ForStatementContext>;
1332
1366
  const block = createMockBlock([createMockStatement({ hasFor: forStmt })]);
1333
- expect(() => validator.validateNoEarlyExits(block)).toThrow("E0853");
1367
+ expect(() => TypeValidator.validateNoEarlyExits(block)).toThrow("E0853");
1334
1368
  });
1335
1369
 
1336
1370
  it("throws for return in do-while loop", () => {
1337
- const validator = new TypeValidator(createMockDeps());
1371
+ setupState();
1338
1372
  const innerBlock = createMockBlock([
1339
1373
  createMockStatement({ hasReturn: true }),
1340
1374
  ]);
@@ -1344,7 +1378,7 @@ describe("TypeValidator", () => {
1344
1378
  const block = createMockBlock([
1345
1379
  createMockStatement({ hasDoWhile: doWhileStmt }),
1346
1380
  ]);
1347
- expect(() => validator.validateNoEarlyExits(block)).toThrow("E0853");
1381
+ expect(() => TypeValidator.validateNoEarlyExits(block)).toThrow("E0853");
1348
1382
  });
1349
1383
  });
1350
1384
 
@@ -1354,33 +1388,34 @@ describe("TypeValidator", () => {
1354
1388
 
1355
1389
  describe("validateSwitchStatement", () => {
1356
1390
  it("throws for boolean switch expression", () => {
1357
- const validator = new TypeValidator(
1358
- createMockDeps({ getExpressionType: () => "bool" }),
1359
- );
1391
+ setupState();
1392
+ vi.spyOn(TypeResolver, "getExpressionType").mockReturnValue("bool");
1360
1393
  const ctx = createMockSwitchStatement({
1361
1394
  cases: [{} as Parser.SwitchCaseContext],
1362
1395
  });
1363
1396
  const expr = createMockExpression("flag");
1364
- expect(() => validator.validateSwitchStatement(ctx, expr)).toThrow(
1397
+ expect(() => TypeValidator.validateSwitchStatement(ctx, expr)).toThrow(
1365
1398
  "Cannot switch on boolean type (MISRA 16.7)",
1366
1399
  );
1367
1400
  });
1368
1401
 
1369
1402
  it("throws for switch with less than 2 clauses", () => {
1370
- const validator = new TypeValidator(createMockDeps());
1403
+ setupState();
1404
+ vi.spyOn(TypeResolver, "getExpressionType").mockReturnValue(null);
1371
1405
  const ctx = createMockSwitchStatement({
1372
1406
  cases: [
1373
1407
  createMockSwitchCase([createMockCaseLabel({ intLiteral: "1" })]),
1374
1408
  ],
1375
1409
  });
1376
1410
  const expr = createMockExpression("x");
1377
- expect(() => validator.validateSwitchStatement(ctx, expr)).toThrow(
1411
+ expect(() => TypeValidator.validateSwitchStatement(ctx, expr)).toThrow(
1378
1412
  "Switch requires at least 2 clauses (MISRA 16.6)",
1379
1413
  );
1380
1414
  });
1381
1415
 
1382
1416
  it("allows switch with exactly 2 cases", () => {
1383
- const validator = new TypeValidator(createMockDeps());
1417
+ setupState();
1418
+ vi.spyOn(TypeResolver, "getExpressionType").mockReturnValue(null);
1384
1419
  const ctx = createMockSwitchStatement({
1385
1420
  cases: [
1386
1421
  createMockSwitchCase([createMockCaseLabel({ intLiteral: "0" })]),
@@ -1388,11 +1423,14 @@ describe("TypeValidator", () => {
1388
1423
  ],
1389
1424
  });
1390
1425
  const expr = createMockExpression("x");
1391
- expect(() => validator.validateSwitchStatement(ctx, expr)).not.toThrow();
1426
+ expect(() =>
1427
+ TypeValidator.validateSwitchStatement(ctx, expr),
1428
+ ).not.toThrow();
1392
1429
  });
1393
1430
 
1394
1431
  it("allows switch with 1 case + default", () => {
1395
- const validator = new TypeValidator(createMockDeps());
1432
+ setupState();
1433
+ vi.spyOn(TypeResolver, "getExpressionType").mockReturnValue(null);
1396
1434
  const ctx = createMockSwitchStatement({
1397
1435
  cases: [
1398
1436
  createMockSwitchCase([createMockCaseLabel({ intLiteral: "1" })]),
@@ -1400,11 +1438,14 @@ describe("TypeValidator", () => {
1400
1438
  defaultCase: createMockDefaultCase(),
1401
1439
  });
1402
1440
  const expr = createMockExpression("x");
1403
- expect(() => validator.validateSwitchStatement(ctx, expr)).not.toThrow();
1441
+ expect(() =>
1442
+ TypeValidator.validateSwitchStatement(ctx, expr),
1443
+ ).not.toThrow();
1404
1444
  });
1405
1445
 
1406
1446
  it("throws for duplicate case values", () => {
1407
- const validator = new TypeValidator(createMockDeps());
1447
+ setupState();
1448
+ vi.spyOn(TypeResolver, "getExpressionType").mockReturnValue(null);
1408
1449
  const ctx = createMockSwitchStatement({
1409
1450
  cases: [
1410
1451
  createMockSwitchCase([createMockCaseLabel({ intLiteral: "1" })]),
@@ -1412,13 +1453,14 @@ describe("TypeValidator", () => {
1412
1453
  ],
1413
1454
  });
1414
1455
  const expr = createMockExpression("x");
1415
- expect(() => validator.validateSwitchStatement(ctx, expr)).toThrow(
1456
+ expect(() => TypeValidator.validateSwitchStatement(ctx, expr)).toThrow(
1416
1457
  "Duplicate case value '1'",
1417
1458
  );
1418
1459
  });
1419
1460
 
1420
1461
  it("throws for duplicate hex and integer case values (normalized)", () => {
1421
- const validator = new TypeValidator(createMockDeps());
1462
+ setupState();
1463
+ vi.spyOn(TypeResolver, "getExpressionType").mockReturnValue(null);
1422
1464
  const ctx = createMockSwitchStatement({
1423
1465
  cases: [
1424
1466
  createMockSwitchCase([createMockCaseLabel({ intLiteral: "255" })]),
@@ -1426,7 +1468,7 @@ describe("TypeValidator", () => {
1426
1468
  ],
1427
1469
  });
1428
1470
  const expr = createMockExpression("x");
1429
- expect(() => validator.validateSwitchStatement(ctx, expr)).toThrow(
1471
+ expect(() => TypeValidator.validateSwitchStatement(ctx, expr)).toThrow(
1430
1472
  "Duplicate case value '255'",
1431
1473
  );
1432
1474
  });
@@ -1447,9 +1489,8 @@ describe("TypeValidator", () => {
1447
1489
  ],
1448
1490
  ]),
1449
1491
  });
1450
- const validator = new TypeValidator(
1451
- createMockDeps({ symbols, getExpressionType: () => "State" }),
1452
- );
1492
+ setupState({ symbols });
1493
+ vi.spyOn(TypeResolver, "getExpressionType").mockReturnValue("State");
1453
1494
  const ctx = createMockSwitchStatement({
1454
1495
  cases: [
1455
1496
  createMockSwitchCase([createMockCaseLabel({ identifier: "IDLE" })]),
@@ -1459,7 +1500,7 @@ describe("TypeValidator", () => {
1459
1500
  ],
1460
1501
  });
1461
1502
  const expr = createMockExpression("state");
1462
- expect(() => validator.validateSwitchStatement(ctx, expr)).toThrow(
1503
+ expect(() => TypeValidator.validateSwitchStatement(ctx, expr)).toThrow(
1463
1504
  "Non-exhaustive switch on State: covers 2 of 3 variants, missing 1",
1464
1505
  );
1465
1506
  });
@@ -1477,9 +1518,8 @@ describe("TypeValidator", () => {
1477
1518
  ],
1478
1519
  ]),
1479
1520
  });
1480
- const validator = new TypeValidator(
1481
- createMockDeps({ symbols, getExpressionType: () => "State" }),
1482
- );
1521
+ setupState({ symbols });
1522
+ vi.spyOn(TypeResolver, "getExpressionType").mockReturnValue("State");
1483
1523
  const ctx = createMockSwitchStatement({
1484
1524
  cases: [
1485
1525
  createMockSwitchCase([createMockCaseLabel({ identifier: "A" })]),
@@ -1487,7 +1527,9 @@ describe("TypeValidator", () => {
1487
1527
  ],
1488
1528
  });
1489
1529
  const expr = createMockExpression("state");
1490
- expect(() => validator.validateSwitchStatement(ctx, expr)).not.toThrow();
1530
+ expect(() =>
1531
+ TypeValidator.validateSwitchStatement(ctx, expr),
1532
+ ).not.toThrow();
1491
1533
  });
1492
1534
 
1493
1535
  it("allows non-exhaustive enum switch with plain default", () => {
@@ -1504,9 +1546,8 @@ describe("TypeValidator", () => {
1504
1546
  ],
1505
1547
  ]),
1506
1548
  });
1507
- const validator = new TypeValidator(
1508
- createMockDeps({ symbols, getExpressionType: () => "State" }),
1509
- );
1549
+ setupState({ symbols });
1550
+ vi.spyOn(TypeResolver, "getExpressionType").mockReturnValue("State");
1510
1551
  const ctx = createMockSwitchStatement({
1511
1552
  cases: [
1512
1553
  createMockSwitchCase([createMockCaseLabel({ identifier: "A" })]),
@@ -1514,7 +1555,9 @@ describe("TypeValidator", () => {
1514
1555
  defaultCase: createMockDefaultCase(),
1515
1556
  });
1516
1557
  const expr = createMockExpression("state");
1517
- expect(() => validator.validateSwitchStatement(ctx, expr)).not.toThrow();
1558
+ expect(() =>
1559
+ TypeValidator.validateSwitchStatement(ctx, expr),
1560
+ ).not.toThrow();
1518
1561
  });
1519
1562
 
1520
1563
  it("validates default(n) count matches remaining variants", () => {
@@ -1531,9 +1574,8 @@ describe("TypeValidator", () => {
1531
1574
  ],
1532
1575
  ]),
1533
1576
  });
1534
- const validator = new TypeValidator(
1535
- createMockDeps({ symbols, getExpressionType: () => "State" }),
1536
- );
1577
+ setupState({ symbols });
1578
+ vi.spyOn(TypeResolver, "getExpressionType").mockReturnValue("State");
1537
1579
  const ctx = createMockSwitchStatement({
1538
1580
  cases: [
1539
1581
  createMockSwitchCase([createMockCaseLabel({ identifier: "A" })]),
@@ -1541,7 +1583,9 @@ describe("TypeValidator", () => {
1541
1583
  defaultCase: createMockDefaultCase("2"), // default(2) - correct!
1542
1584
  });
1543
1585
  const expr = createMockExpression("state");
1544
- expect(() => validator.validateSwitchStatement(ctx, expr)).not.toThrow();
1586
+ expect(() =>
1587
+ TypeValidator.validateSwitchStatement(ctx, expr),
1588
+ ).not.toThrow();
1545
1589
  });
1546
1590
 
1547
1591
  it("throws when default(n) count is wrong", () => {
@@ -1558,9 +1602,8 @@ describe("TypeValidator", () => {
1558
1602
  ],
1559
1603
  ]),
1560
1604
  });
1561
- const validator = new TypeValidator(
1562
- createMockDeps({ symbols, getExpressionType: () => "State" }),
1563
- );
1605
+ setupState({ symbols });
1606
+ vi.spyOn(TypeResolver, "getExpressionType").mockReturnValue("State");
1564
1607
  const ctx = createMockSwitchStatement({
1565
1608
  cases: [
1566
1609
  createMockSwitchCase([createMockCaseLabel({ identifier: "A" })]),
@@ -1568,7 +1611,7 @@ describe("TypeValidator", () => {
1568
1611
  defaultCase: createMockDefaultCase("1"), // Wrong! Should be 2
1569
1612
  });
1570
1613
  const expr = createMockExpression("state");
1571
- expect(() => validator.validateSwitchStatement(ctx, expr)).toThrow(
1614
+ expect(() => TypeValidator.validateSwitchStatement(ctx, expr)).toThrow(
1572
1615
  "switch covers 2 of 3 State variants (1 explicit + default(1)). Expected 3",
1573
1616
  );
1574
1617
  });
@@ -1587,9 +1630,8 @@ describe("TypeValidator", () => {
1587
1630
  ],
1588
1631
  ]),
1589
1632
  });
1590
- const validator = new TypeValidator(
1591
- createMockDeps({ symbols, getExpressionType: () => "State" }),
1592
- );
1633
+ setupState({ symbols });
1634
+ vi.spyOn(TypeResolver, "getExpressionType").mockReturnValue("State");
1593
1635
  // Case with 2 labels: A || B
1594
1636
  const ctx = createMockSwitchStatement({
1595
1637
  cases: [
@@ -1601,80 +1643,82 @@ describe("TypeValidator", () => {
1601
1643
  ],
1602
1644
  });
1603
1645
  const expr = createMockExpression("state");
1604
- expect(() => validator.validateSwitchStatement(ctx, expr)).not.toThrow();
1646
+ expect(() =>
1647
+ TypeValidator.validateSwitchStatement(ctx, expr),
1648
+ ).not.toThrow();
1605
1649
  });
1606
1650
  });
1607
1651
 
1608
1652
  describe("getDefaultCount", () => {
1609
1653
  it("returns number for default(n)", () => {
1610
- const validator = new TypeValidator(createMockDeps());
1654
+ setupState();
1611
1655
  const ctx = createMockDefaultCase("5");
1612
- expect(validator.getDefaultCount(ctx)).toBe(5);
1656
+ expect(TypeValidator.getDefaultCount(ctx)).toBe(5);
1613
1657
  });
1614
1658
 
1615
1659
  it("returns null for plain default", () => {
1616
- const validator = new TypeValidator(createMockDeps());
1660
+ setupState();
1617
1661
  const ctx = createMockDefaultCase();
1618
- expect(validator.getDefaultCount(ctx)).toBeNull();
1662
+ expect(TypeValidator.getDefaultCount(ctx)).toBeNull();
1619
1663
  });
1620
1664
  });
1621
1665
 
1622
1666
  describe("getCaseLabelValue", () => {
1623
1667
  it("returns qualified type as dot-joined string", () => {
1624
- const validator = new TypeValidator(createMockDeps());
1668
+ setupState();
1625
1669
  const ctx = createMockCaseLabel({ qualifiedType: ["State", "IDLE"] });
1626
- expect(validator.getCaseLabelValue(ctx)).toBe("State.IDLE");
1670
+ expect(TypeValidator.getCaseLabelValue(ctx)).toBe("State.IDLE");
1627
1671
  });
1628
1672
 
1629
1673
  it("returns identifier", () => {
1630
- const validator = new TypeValidator(createMockDeps());
1674
+ setupState();
1631
1675
  const ctx = createMockCaseLabel({ identifier: "MAX_VALUE" });
1632
- expect(validator.getCaseLabelValue(ctx)).toBe("MAX_VALUE");
1676
+ expect(TypeValidator.getCaseLabelValue(ctx)).toBe("MAX_VALUE");
1633
1677
  });
1634
1678
 
1635
1679
  it("returns integer literal", () => {
1636
- const validator = new TypeValidator(createMockDeps());
1680
+ setupState();
1637
1681
  const ctx = createMockCaseLabel({ intLiteral: "42" });
1638
- expect(validator.getCaseLabelValue(ctx)).toBe("42");
1682
+ expect(TypeValidator.getCaseLabelValue(ctx)).toBe("42");
1639
1683
  });
1640
1684
 
1641
1685
  it("returns negative integer literal", () => {
1642
- const validator = new TypeValidator(createMockDeps());
1686
+ setupState();
1643
1687
  const ctx = createMockCaseLabel({ intLiteral: "5", hasNegative: true });
1644
- expect(validator.getCaseLabelValue(ctx)).toBe("-5");
1688
+ expect(TypeValidator.getCaseLabelValue(ctx)).toBe("-5");
1645
1689
  });
1646
1690
 
1647
1691
  it("normalizes hex to decimal", () => {
1648
- const validator = new TypeValidator(createMockDeps());
1692
+ setupState();
1649
1693
  const ctx = createMockCaseLabel({ hexLiteral: "0xFF" });
1650
- expect(validator.getCaseLabelValue(ctx)).toBe("255");
1694
+ expect(TypeValidator.getCaseLabelValue(ctx)).toBe("255");
1651
1695
  });
1652
1696
 
1653
1697
  it("handles negative hex", () => {
1654
- const validator = new TypeValidator(createMockDeps());
1698
+ setupState();
1655
1699
  const ctx = createMockCaseLabel({
1656
1700
  hexLiteral: "0x10",
1657
1701
  hasNegative: true,
1658
1702
  });
1659
- expect(validator.getCaseLabelValue(ctx)).toBe("-16");
1703
+ expect(TypeValidator.getCaseLabelValue(ctx)).toBe("-16");
1660
1704
  });
1661
1705
 
1662
1706
  it("normalizes binary to decimal", () => {
1663
- const validator = new TypeValidator(createMockDeps());
1707
+ setupState();
1664
1708
  const ctx = createMockCaseLabel({ binaryLiteral: "0b1010" });
1665
- expect(validator.getCaseLabelValue(ctx)).toBe("10");
1709
+ expect(TypeValidator.getCaseLabelValue(ctx)).toBe("10");
1666
1710
  });
1667
1711
 
1668
1712
  it("returns char literal as-is", () => {
1669
- const validator = new TypeValidator(createMockDeps());
1713
+ setupState();
1670
1714
  const ctx = createMockCaseLabel({ charLiteral: "'A'" });
1671
- expect(validator.getCaseLabelValue(ctx)).toBe("'A'");
1715
+ expect(TypeValidator.getCaseLabelValue(ctx)).toBe("'A'");
1672
1716
  });
1673
1717
 
1674
1718
  it("returns empty string for unknown label type", () => {
1675
- const validator = new TypeValidator(createMockDeps());
1719
+ setupState();
1676
1720
  const ctx = createMockCaseLabel();
1677
- expect(validator.getCaseLabelValue(ctx)).toBe("");
1721
+ expect(TypeValidator.getCaseLabelValue(ctx)).toBe("");
1678
1722
  });
1679
1723
  });
1680
1724
 
@@ -1684,69 +1728,69 @@ describe("TypeValidator", () => {
1684
1728
 
1685
1729
  describe("validateTernaryCondition", () => {
1686
1730
  it("allows conditions with || operator", () => {
1687
- const validator = new TypeValidator(createMockDeps());
1731
+ setupState();
1688
1732
  const ctx = createMockOrExpression("a || b", { hasOr: true });
1689
- expect(() => validator.validateTernaryCondition(ctx)).not.toThrow();
1733
+ expect(() => TypeValidator.validateTernaryCondition(ctx)).not.toThrow();
1690
1734
  });
1691
1735
 
1692
1736
  it("allows conditions with && operator", () => {
1693
- const validator = new TypeValidator(createMockDeps());
1737
+ setupState();
1694
1738
  const ctx = createMockOrExpression("a && b", { hasAnd: true });
1695
- expect(() => validator.validateTernaryCondition(ctx)).not.toThrow();
1739
+ expect(() => TypeValidator.validateTernaryCondition(ctx)).not.toThrow();
1696
1740
  });
1697
1741
 
1698
1742
  it("allows conditions with = operator", () => {
1699
- const validator = new TypeValidator(createMockDeps());
1743
+ setupState();
1700
1744
  const ctx = createMockOrExpression("a = b", { hasEquality: true });
1701
- expect(() => validator.validateTernaryCondition(ctx)).not.toThrow();
1745
+ expect(() => TypeValidator.validateTernaryCondition(ctx)).not.toThrow();
1702
1746
  });
1703
1747
 
1704
1748
  it("allows conditions with relational operators", () => {
1705
- const validator = new TypeValidator(createMockDeps());
1749
+ setupState();
1706
1750
  const ctx = createMockOrExpression("a < b", { hasRelational: true });
1707
- expect(() => validator.validateTernaryCondition(ctx)).not.toThrow();
1751
+ expect(() => TypeValidator.validateTernaryCondition(ctx)).not.toThrow();
1708
1752
  });
1709
1753
 
1710
1754
  it("throws for bare value condition", () => {
1711
- const validator = new TypeValidator(createMockDeps());
1755
+ setupState();
1712
1756
  const ctx = createMockOrExpression("flag");
1713
- expect(() => validator.validateTernaryCondition(ctx)).toThrow(
1757
+ expect(() => TypeValidator.validateTernaryCondition(ctx)).toThrow(
1714
1758
  "Ternary condition must be a boolean expression",
1715
1759
  );
1716
1760
  });
1717
1761
 
1718
1762
  it("throws when no andExpression", () => {
1719
- const validator = new TypeValidator(createMockDeps());
1763
+ setupState();
1720
1764
  const ctx = {
1721
1765
  getText: () => "bad",
1722
1766
  andExpression: antlrArray([]),
1723
1767
  } as unknown as Parser.OrExpressionContext;
1724
- expect(() => validator.validateTernaryCondition(ctx)).toThrow(
1768
+ expect(() => TypeValidator.validateTernaryCondition(ctx)).toThrow(
1725
1769
  "Ternary condition must be a boolean expression",
1726
1770
  );
1727
1771
  });
1728
1772
 
1729
1773
  it("throws when no equalityExpression", () => {
1730
- const validator = new TypeValidator(createMockDeps());
1774
+ setupState();
1731
1775
  const andExpr = { equalityExpression: antlrArray([]) };
1732
1776
  const ctx = {
1733
1777
  getText: () => "bad",
1734
1778
  andExpression: antlrArray([andExpr]),
1735
1779
  } as unknown as Parser.OrExpressionContext;
1736
- expect(() => validator.validateTernaryCondition(ctx)).toThrow(
1780
+ expect(() => TypeValidator.validateTernaryCondition(ctx)).toThrow(
1737
1781
  "Ternary condition must be a boolean expression",
1738
1782
  );
1739
1783
  });
1740
1784
 
1741
1785
  it("throws when no relationalExpression", () => {
1742
- const validator = new TypeValidator(createMockDeps());
1786
+ setupState();
1743
1787
  const equalityExpr = { relationalExpression: antlrArray([]) };
1744
1788
  const andExpr = { equalityExpression: antlrArray([equalityExpr]) };
1745
1789
  const ctx = {
1746
1790
  getText: () => "bad",
1747
1791
  andExpression: antlrArray([andExpr]),
1748
1792
  } as unknown as Parser.OrExpressionContext;
1749
- expect(() => validator.validateTernaryCondition(ctx)).toThrow(
1793
+ expect(() => TypeValidator.validateTernaryCondition(ctx)).toThrow(
1750
1794
  "Ternary condition must be a boolean expression",
1751
1795
  );
1752
1796
  });
@@ -1754,18 +1798,18 @@ describe("TypeValidator", () => {
1754
1798
 
1755
1799
  describe("validateNoNestedTernary", () => {
1756
1800
  it("allows non-ternary expressions", () => {
1757
- const validator = new TypeValidator(createMockDeps());
1801
+ setupState();
1758
1802
  const ctx = createMockOrExpression("x + 1");
1759
1803
  expect(() =>
1760
- validator.validateNoNestedTernary(ctx, "true branch"),
1804
+ TypeValidator.validateNoNestedTernary(ctx, "true branch"),
1761
1805
  ).not.toThrow();
1762
1806
  });
1763
1807
 
1764
1808
  it("throws for nested ternary", () => {
1765
- const validator = new TypeValidator(createMockDeps());
1809
+ setupState();
1766
1810
  const ctx = createMockOrExpression("a ? b : c");
1767
1811
  expect(() =>
1768
- validator.validateNoNestedTernary(ctx, "true branch"),
1812
+ TypeValidator.validateNoNestedTernary(ctx, "true branch"),
1769
1813
  ).toThrow("Nested ternary not allowed in true branch");
1770
1814
  });
1771
1815
  });
@@ -1824,53 +1868,57 @@ describe("TypeValidator", () => {
1824
1868
  }
1825
1869
 
1826
1870
  it("allows conditions with comparison operators", () => {
1827
- const validator = new TypeValidator(createMockDeps());
1871
+ setupState();
1828
1872
  const ctx = createFullDoWhileExpression("x < 10", {
1829
1873
  hasRelational: true,
1830
1874
  });
1831
- expect(() => validator.validateDoWhileCondition(ctx)).not.toThrow();
1875
+ expect(() => TypeValidator.validateDoWhileCondition(ctx)).not.toThrow();
1832
1876
  });
1833
1877
 
1834
1878
  it("allows conditions with equality operators", () => {
1835
- const validator = new TypeValidator(createMockDeps());
1879
+ setupState();
1836
1880
  const ctx = createFullDoWhileExpression("x = 0", { hasEquality: true });
1837
- expect(() => validator.validateDoWhileCondition(ctx)).not.toThrow();
1881
+ expect(() => TypeValidator.validateDoWhileCondition(ctx)).not.toThrow();
1838
1882
  });
1839
1883
 
1840
1884
  it("allows conditions with && operator", () => {
1841
- const validator = new TypeValidator(createMockDeps());
1885
+ setupState();
1842
1886
  const ctx = createFullDoWhileExpression("a && b", { hasAnd: true });
1843
- expect(() => validator.validateDoWhileCondition(ctx)).not.toThrow();
1887
+ expect(() => TypeValidator.validateDoWhileCondition(ctx)).not.toThrow();
1844
1888
  });
1845
1889
 
1846
1890
  it("allows conditions with || operator", () => {
1847
- const validator = new TypeValidator(createMockDeps());
1891
+ setupState();
1848
1892
  const ctx = createFullDoWhileExpression("a || b", { hasOr: true });
1849
- expect(() => validator.validateDoWhileCondition(ctx)).not.toThrow();
1893
+ expect(() => TypeValidator.validateDoWhileCondition(ctx)).not.toThrow();
1850
1894
  });
1851
1895
 
1852
1896
  it("throws for bare value condition", () => {
1853
- const validator = new TypeValidator(createMockDeps());
1897
+ setupState();
1854
1898
  const ctx = createFullDoWhileExpression("count");
1855
- expect(() => validator.validateDoWhileCondition(ctx)).toThrow("E0701");
1856
- expect(() => validator.validateDoWhileCondition(ctx)).toThrow(
1899
+ expect(() => TypeValidator.validateDoWhileCondition(ctx)).toThrow(
1900
+ "E0701",
1901
+ );
1902
+ expect(() => TypeValidator.validateDoWhileCondition(ctx)).toThrow(
1857
1903
  "do-while condition must be a boolean expression",
1858
1904
  );
1859
1905
  });
1860
1906
 
1861
1907
  it("throws for ternary in do-while condition", () => {
1862
- const validator = new TypeValidator(createMockDeps());
1908
+ setupState();
1863
1909
  const ctx = {
1864
1910
  getText: () => "a ? b : c",
1865
1911
  ternaryExpression: () => ({
1866
1912
  orExpression: () => [{}, {}], // Multiple orExpressions = ternary
1867
1913
  }),
1868
1914
  } as unknown as Parser.ExpressionContext;
1869
- expect(() => validator.validateDoWhileCondition(ctx)).toThrow("E0701");
1915
+ expect(() => TypeValidator.validateDoWhileCondition(ctx)).toThrow(
1916
+ "E0701",
1917
+ );
1870
1918
  });
1871
1919
 
1872
1920
  it("allows boolean literals", () => {
1873
- const validator = new TypeValidator(createMockDeps());
1921
+ setupState();
1874
1922
  // Create full mock expression tree where getText returns "true"
1875
1923
  const bitwiseOrExpr = {
1876
1924
  bitwiseXorExpression: antlrArray([]),
@@ -1898,11 +1946,11 @@ describe("TypeValidator", () => {
1898
1946
  orExpression: antlrArray([orExpr]),
1899
1947
  }),
1900
1948
  } as unknown as Parser.ExpressionContext;
1901
- expect(() => validator.validateDoWhileCondition(ctx)).not.toThrow();
1949
+ expect(() => TypeValidator.validateDoWhileCondition(ctx)).not.toThrow();
1902
1950
  });
1903
1951
 
1904
1952
  it("allows negation expressions", () => {
1905
- const validator = new TypeValidator(createMockDeps());
1953
+ setupState();
1906
1954
  const bitwiseOrExpr = {
1907
1955
  bitwiseXorExpression: antlrArray([]),
1908
1956
  getText: () => "!flag",
@@ -1929,7 +1977,7 @@ describe("TypeValidator", () => {
1929
1977
  orExpression: antlrArray([orExpr]),
1930
1978
  }),
1931
1979
  } as unknown as Parser.ExpressionContext;
1932
- expect(() => validator.validateDoWhileCondition(ctx)).not.toThrow();
1980
+ expect(() => TypeValidator.validateDoWhileCondition(ctx)).not.toThrow();
1933
1981
  });
1934
1982
 
1935
1983
  it("allows bool type variables", () => {
@@ -1939,7 +1987,7 @@ describe("TypeValidator", () => {
1939
1987
  { baseType: "bool", bitWidth: 8, isArray: false, isConst: false },
1940
1988
  ],
1941
1989
  ]);
1942
- const validator = new TypeValidator(createMockDeps({ typeRegistry }));
1990
+ setupState({ typeRegistry });
1943
1991
  const bitwiseOrExpr = {
1944
1992
  bitwiseXorExpression: antlrArray([]),
1945
1993
  getText: () => "isReady",
@@ -1966,19 +2014,19 @@ describe("TypeValidator", () => {
1966
2014
  orExpression: antlrArray([orExpr]),
1967
2015
  }),
1968
2016
  } as unknown as Parser.ExpressionContext;
1969
- expect(() => validator.validateDoWhileCondition(ctx)).not.toThrow();
2017
+ expect(() => TypeValidator.validateDoWhileCondition(ctx)).not.toThrow();
1970
2018
  });
1971
2019
 
1972
2020
  it("shows help message in error", () => {
1973
- const validator = new TypeValidator(createMockDeps());
2021
+ setupState();
1974
2022
  const ctx = createFullDoWhileExpression("count");
1975
- expect(() => validator.validateDoWhileCondition(ctx)).toThrow(
2023
+ expect(() => TypeValidator.validateDoWhileCondition(ctx)).toThrow(
1976
2024
  "help: use explicit comparison: count > 0 or count != 0",
1977
2025
  );
1978
2026
  });
1979
2027
 
1980
2028
  it("throws when no andExpression", () => {
1981
- const validator = new TypeValidator(createMockDeps());
2029
+ setupState();
1982
2030
  const orExpr = {
1983
2031
  getText: () => "bad",
1984
2032
  andExpression: antlrArray([]),
@@ -1989,11 +2037,13 @@ describe("TypeValidator", () => {
1989
2037
  orExpression: antlrArray([orExpr]),
1990
2038
  }),
1991
2039
  } as unknown as Parser.ExpressionContext;
1992
- expect(() => validator.validateDoWhileCondition(ctx)).toThrow("E0701");
2040
+ expect(() => TypeValidator.validateDoWhileCondition(ctx)).toThrow(
2041
+ "E0701",
2042
+ );
1993
2043
  });
1994
2044
 
1995
2045
  it("throws when no equalityExpression", () => {
1996
- const validator = new TypeValidator(createMockDeps());
2046
+ setupState();
1997
2047
  const andExpr = {
1998
2048
  equalityExpression: antlrArray([]),
1999
2049
  };
@@ -2007,11 +2057,13 @@ describe("TypeValidator", () => {
2007
2057
  orExpression: antlrArray([orExpr]),
2008
2058
  }),
2009
2059
  } as unknown as Parser.ExpressionContext;
2010
- expect(() => validator.validateDoWhileCondition(ctx)).toThrow("E0701");
2060
+ expect(() => TypeValidator.validateDoWhileCondition(ctx)).toThrow(
2061
+ "E0701",
2062
+ );
2011
2063
  });
2012
2064
 
2013
2065
  it("throws when no relationalExpression", () => {
2014
- const validator = new TypeValidator(createMockDeps());
2066
+ setupState();
2015
2067
  const equalityExpr = {
2016
2068
  relationalExpression: antlrArray([]),
2017
2069
  };
@@ -2028,7 +2080,9 @@ describe("TypeValidator", () => {
2028
2080
  orExpression: antlrArray([orExpr]),
2029
2081
  }),
2030
2082
  } as unknown as Parser.ExpressionContext;
2031
- expect(() => validator.validateDoWhileCondition(ctx)).toThrow("E0701");
2083
+ expect(() => TypeValidator.validateDoWhileCondition(ctx)).toThrow(
2084
+ "E0701",
2085
+ );
2032
2086
  });
2033
2087
  });
2034
2088
 
@@ -2072,35 +2126,35 @@ describe("TypeValidator", () => {
2072
2126
  }
2073
2127
 
2074
2128
  it("allows conditions without function calls", () => {
2075
- const validator = new TypeValidator(createMockDeps());
2129
+ setupState();
2076
2130
  const ctx = createExpressionWithFunctionCall("x > 0", false);
2077
2131
  expect(() =>
2078
- validator.validateConditionNoFunctionCall(ctx, "if"),
2132
+ TypeValidator.validateConditionNoFunctionCall(ctx, "if"),
2079
2133
  ).not.toThrow();
2080
2134
  });
2081
2135
 
2082
2136
  it("throws for conditions with function calls", () => {
2083
- const validator = new TypeValidator(createMockDeps());
2137
+ setupState();
2084
2138
  const ctx = createExpressionWithFunctionCall("isReady()", true);
2085
2139
  expect(() =>
2086
- validator.validateConditionNoFunctionCall(ctx, "if"),
2140
+ TypeValidator.validateConditionNoFunctionCall(ctx, "if"),
2087
2141
  ).toThrow("E0702");
2088
2142
  expect(() =>
2089
- validator.validateConditionNoFunctionCall(ctx, "if"),
2143
+ TypeValidator.validateConditionNoFunctionCall(ctx, "if"),
2090
2144
  ).toThrow("Function call in 'if' condition is not allowed");
2091
2145
  expect(() =>
2092
- validator.validateConditionNoFunctionCall(ctx, "if"),
2146
+ TypeValidator.validateConditionNoFunctionCall(ctx, "if"),
2093
2147
  ).toThrow("MISRA C:2012 Rule 13.5");
2094
2148
  });
2095
2149
 
2096
2150
  it("returns when ternaryExpression is null", () => {
2097
- const validator = new TypeValidator(createMockDeps());
2151
+ setupState();
2098
2152
  const ctx = {
2099
2153
  getText: () => "x",
2100
2154
  ternaryExpression: () => null,
2101
2155
  } as unknown as Parser.ExpressionContext;
2102
2156
  expect(() =>
2103
- validator.validateConditionNoFunctionCall(ctx, "if"),
2157
+ TypeValidator.validateConditionNoFunctionCall(ctx, "if"),
2104
2158
  ).not.toThrow();
2105
2159
  });
2106
2160
  });
@@ -2138,28 +2192,28 @@ describe("TypeValidator", () => {
2138
2192
  }
2139
2193
 
2140
2194
  it("allows ternary conditions without function calls", () => {
2141
- const validator = new TypeValidator(createMockDeps());
2195
+ setupState();
2142
2196
  const ctx = createOrExprWithFunctionCall("x > 0", false);
2143
2197
  expect(() =>
2144
- validator.validateTernaryConditionNoFunctionCall(ctx),
2198
+ TypeValidator.validateTernaryConditionNoFunctionCall(ctx),
2145
2199
  ).not.toThrow();
2146
2200
  });
2147
2201
 
2148
2202
  it("throws for ternary conditions with function calls", () => {
2149
- const validator = new TypeValidator(createMockDeps());
2203
+ setupState();
2150
2204
  const ctx = createOrExprWithFunctionCall("check()", true);
2151
2205
  expect(() =>
2152
- validator.validateTernaryConditionNoFunctionCall(ctx),
2206
+ TypeValidator.validateTernaryConditionNoFunctionCall(ctx),
2153
2207
  ).toThrow("E0702");
2154
2208
  expect(() =>
2155
- validator.validateTernaryConditionNoFunctionCall(ctx),
2209
+ TypeValidator.validateTernaryConditionNoFunctionCall(ctx),
2156
2210
  ).toThrow("ternary");
2157
2211
  });
2158
2212
  });
2159
2213
 
2160
2214
  describe("hasPostfixFunctionCallInUnary - nested unary", () => {
2161
2215
  it("handles nested unary operators (Issue #366)", () => {
2162
- const validator = new TypeValidator(createMockDeps());
2216
+ setupState();
2163
2217
  // Create nested unary: !!isReady()
2164
2218
  const innerPostfixOp = [
2165
2219
  { argumentList: () => ({}), getText: () => "()" },
@@ -2196,7 +2250,7 @@ describe("TypeValidator", () => {
2196
2250
  } as unknown as Parser.OrExpressionContext;
2197
2251
 
2198
2252
  expect(() =>
2199
- validator.validateTernaryConditionNoFunctionCall(ctx),
2253
+ TypeValidator.validateTernaryConditionNoFunctionCall(ctx),
2200
2254
  ).toThrow("E0702");
2201
2255
  });
2202
2256
  });
@@ -2245,34 +2299,34 @@ describe("TypeValidator", () => {
2245
2299
  }
2246
2300
 
2247
2301
  it("allows valid shift amounts", () => {
2248
- const validator = new TypeValidator(createMockDeps());
2302
+ setupState();
2249
2303
  const { leftType, rightExpr, op, ctx } = createShiftExpression(
2250
2304
  "u8",
2251
2305
  "7",
2252
2306
  "<<",
2253
2307
  );
2254
2308
  expect(() =>
2255
- validator.validateShiftAmount(leftType, rightExpr, op, ctx),
2309
+ TypeValidator.validateShiftAmount(leftType, rightExpr, op, ctx),
2256
2310
  ).not.toThrow();
2257
2311
  });
2258
2312
 
2259
2313
  it("throws for shift amount >= type width", () => {
2260
- const validator = new TypeValidator(createMockDeps());
2314
+ setupState();
2261
2315
  const { leftType, rightExpr, op, ctx } = createShiftExpression(
2262
2316
  "u8",
2263
2317
  "8",
2264
2318
  "<<",
2265
2319
  );
2266
2320
  expect(() =>
2267
- validator.validateShiftAmount(leftType, rightExpr, op, ctx),
2321
+ TypeValidator.validateShiftAmount(leftType, rightExpr, op, ctx),
2268
2322
  ).toThrow("Shift amount (8) exceeds type width (8 bits)");
2269
2323
  expect(() =>
2270
- validator.validateShiftAmount(leftType, rightExpr, op, ctx),
2324
+ TypeValidator.validateShiftAmount(leftType, rightExpr, op, ctx),
2271
2325
  ).toThrow("MISRA C:2012 Rule 12.2");
2272
2326
  });
2273
2327
 
2274
2328
  it("throws for negative shift amounts", () => {
2275
- const validator = new TypeValidator(createMockDeps());
2329
+ setupState();
2276
2330
  // Create expression with negative value
2277
2331
  const literal = { getText: () => "5" };
2278
2332
  const primaryExpr = { literal: () => literal };
@@ -2294,17 +2348,17 @@ describe("TypeValidator", () => {
2294
2348
  } as unknown as Parser.ShiftExpressionContext;
2295
2349
 
2296
2350
  expect(() =>
2297
- validator.validateShiftAmount("u32", addExpr, "<<", ctx),
2351
+ TypeValidator.validateShiftAmount("u32", addExpr, "<<", ctx),
2298
2352
  ).toThrow("Negative shift amount (-5) is undefined behavior");
2299
2353
  });
2300
2354
 
2301
2355
  it("validates different type widths", () => {
2302
- const validator = new TypeValidator(createMockDeps());
2356
+ setupState();
2303
2357
 
2304
2358
  // u16 - max shift is 15
2305
2359
  const shift15 = createShiftExpression("u16", "15", ">>");
2306
2360
  expect(() =>
2307
- validator.validateShiftAmount(
2361
+ TypeValidator.validateShiftAmount(
2308
2362
  shift15.leftType,
2309
2363
  shift15.rightExpr,
2310
2364
  shift15.op,
@@ -2314,7 +2368,7 @@ describe("TypeValidator", () => {
2314
2368
 
2315
2369
  const shift16 = createShiftExpression("u16", "16", ">>");
2316
2370
  expect(() =>
2317
- validator.validateShiftAmount(
2371
+ TypeValidator.validateShiftAmount(
2318
2372
  shift16.leftType,
2319
2373
  shift16.rightExpr,
2320
2374
  shift16.op,
@@ -2325,7 +2379,7 @@ describe("TypeValidator", () => {
2325
2379
  // u32 - max shift is 31
2326
2380
  const shift31 = createShiftExpression("u32", "31", "<<");
2327
2381
  expect(() =>
2328
- validator.validateShiftAmount(
2382
+ TypeValidator.validateShiftAmount(
2329
2383
  shift31.leftType,
2330
2384
  shift31.rightExpr,
2331
2385
  shift31.op,
@@ -2335,7 +2389,7 @@ describe("TypeValidator", () => {
2335
2389
 
2336
2390
  const shift32 = createShiftExpression("u32", "32", "<<");
2337
2391
  expect(() =>
2338
- validator.validateShiftAmount(
2392
+ TypeValidator.validateShiftAmount(
2339
2393
  shift32.leftType,
2340
2394
  shift32.rightExpr,
2341
2395
  shift32.op,
@@ -2346,7 +2400,7 @@ describe("TypeValidator", () => {
2346
2400
  // u64 - max shift is 63
2347
2401
  const shift63 = createShiftExpression("u64", "63", "<<");
2348
2402
  expect(() =>
2349
- validator.validateShiftAmount(
2403
+ TypeValidator.validateShiftAmount(
2350
2404
  shift63.leftType,
2351
2405
  shift63.rightExpr,
2352
2406
  shift63.op,
@@ -2356,7 +2410,7 @@ describe("TypeValidator", () => {
2356
2410
 
2357
2411
  const shift64 = createShiftExpression("u64", "64", "<<");
2358
2412
  expect(() =>
2359
- validator.validateShiftAmount(
2413
+ TypeValidator.validateShiftAmount(
2360
2414
  shift64.leftType,
2361
2415
  shift64.rightExpr,
2362
2416
  shift64.op,
@@ -2366,31 +2420,31 @@ describe("TypeValidator", () => {
2366
2420
  });
2367
2421
 
2368
2422
  it("handles signed types", () => {
2369
- const validator = new TypeValidator(createMockDeps());
2423
+ setupState();
2370
2424
  const { leftType, rightExpr, op, ctx } = createShiftExpression(
2371
2425
  "i8",
2372
2426
  "8",
2373
2427
  "<<",
2374
2428
  );
2375
2429
  expect(() =>
2376
- validator.validateShiftAmount(leftType, rightExpr, op, ctx),
2430
+ TypeValidator.validateShiftAmount(leftType, rightExpr, op, ctx),
2377
2431
  ).toThrow("Shift amount (8) exceeds type width (8 bits)");
2378
2432
  });
2379
2433
 
2380
2434
  it("skips validation for unknown types", () => {
2381
- const validator = new TypeValidator(createMockDeps());
2435
+ setupState();
2382
2436
  const { leftType, rightExpr, op, ctx } = createShiftExpression(
2383
2437
  "CustomType",
2384
2438
  "100",
2385
2439
  "<<",
2386
2440
  );
2387
2441
  expect(() =>
2388
- validator.validateShiftAmount(leftType, rightExpr, op, ctx),
2442
+ TypeValidator.validateShiftAmount(leftType, rightExpr, op, ctx),
2389
2443
  ).not.toThrow();
2390
2444
  });
2391
2445
 
2392
2446
  it("skips validation for non-constant shift amounts", () => {
2393
- const validator = new TypeValidator(createMockDeps());
2447
+ setupState();
2394
2448
  // Create expression without literal
2395
2449
  const primaryExpr = { literal: () => null };
2396
2450
  const postfixExpr = {
@@ -2411,36 +2465,36 @@ describe("TypeValidator", () => {
2411
2465
  } as unknown as Parser.ShiftExpressionContext;
2412
2466
 
2413
2467
  expect(() =>
2414
- validator.validateShiftAmount("u8", addExpr, "<<", ctx),
2468
+ TypeValidator.validateShiftAmount("u8", addExpr, "<<", ctx),
2415
2469
  ).not.toThrow();
2416
2470
  });
2417
2471
 
2418
2472
  it("handles hex shift amounts", () => {
2419
- const validator = new TypeValidator(createMockDeps());
2473
+ setupState();
2420
2474
  const { leftType, rightExpr, op, ctx } = createShiftExpression(
2421
2475
  "u8",
2422
2476
  "0x08",
2423
2477
  "<<",
2424
2478
  );
2425
2479
  expect(() =>
2426
- validator.validateShiftAmount(leftType, rightExpr, op, ctx),
2480
+ TypeValidator.validateShiftAmount(leftType, rightExpr, op, ctx),
2427
2481
  ).toThrow("Shift amount (8) exceeds type width (8 bits)");
2428
2482
  });
2429
2483
 
2430
2484
  it("handles binary shift amounts", () => {
2431
- const validator = new TypeValidator(createMockDeps());
2485
+ setupState();
2432
2486
  const { leftType, rightExpr, op, ctx } = createShiftExpression(
2433
2487
  "u8",
2434
2488
  "0b1000",
2435
2489
  "<<",
2436
2490
  );
2437
2491
  expect(() =>
2438
- validator.validateShiftAmount(leftType, rightExpr, op, ctx),
2492
+ TypeValidator.validateShiftAmount(leftType, rightExpr, op, ctx),
2439
2493
  ).toThrow("Shift amount (8) exceeds type width (8 bits)");
2440
2494
  });
2441
2495
 
2442
2496
  it("handles complex multiplicative expressions gracefully", () => {
2443
- const validator = new TypeValidator(createMockDeps());
2497
+ setupState();
2444
2498
  // Create expression with multiple multiplicative terms
2445
2499
  const multExpr1 = { unaryExpression: () => [] };
2446
2500
  const multExpr2 = { unaryExpression: () => [] };
@@ -2452,12 +2506,12 @@ describe("TypeValidator", () => {
2452
2506
  } as unknown as Parser.ShiftExpressionContext;
2453
2507
 
2454
2508
  expect(() =>
2455
- validator.validateShiftAmount("u8", addExpr, "<<", ctx),
2509
+ TypeValidator.validateShiftAmount("u8", addExpr, "<<", ctx),
2456
2510
  ).not.toThrow();
2457
2511
  });
2458
2512
 
2459
2513
  it("handles nested unary expressions", () => {
2460
- const validator = new TypeValidator(createMockDeps());
2514
+ setupState();
2461
2515
  // Create nested unary: -(-5) = 5
2462
2516
  const innerLiteral = { getText: () => "5" };
2463
2517
  const innerPrimaryExpr = { literal: () => innerLiteral };
@@ -2490,12 +2544,12 @@ describe("TypeValidator", () => {
2490
2544
 
2491
2545
  // This should evaluate to 5, which is valid for u8
2492
2546
  expect(() =>
2493
- validator.validateShiftAmount("u8", addExpr, "<<", ctx),
2547
+ TypeValidator.validateShiftAmount("u8", addExpr, "<<", ctx),
2494
2548
  ).not.toThrow();
2495
2549
  });
2496
2550
 
2497
2551
  it("handles multiple unary expressions gracefully", () => {
2498
- const validator = new TypeValidator(createMockDeps());
2552
+ setupState();
2499
2553
  const unaryExpr1 = {
2500
2554
  postfixExpression: () => null,
2501
2555
  unaryExpression: () => null,
@@ -2515,12 +2569,12 @@ describe("TypeValidator", () => {
2515
2569
  } as unknown as Parser.ShiftExpressionContext;
2516
2570
 
2517
2571
  expect(() =>
2518
- validator.validateShiftAmount("u8", addExpr, "<<", ctx),
2572
+ TypeValidator.validateShiftAmount("u8", addExpr, "<<", ctx),
2519
2573
  ).not.toThrow();
2520
2574
  });
2521
2575
 
2522
2576
  it("handles binary literal in nested unary (coverage for evaluateUnaryExpression)", () => {
2523
- const validator = new TypeValidator(createMockDeps());
2577
+ setupState();
2524
2578
  // Create nested unary with binary literal: -0b100 = -4
2525
2579
  const innerLiteral = { getText: () => "0b100" }; // binary for 4
2526
2580
  const innerPrimaryExpr = { literal: () => innerLiteral };
@@ -2548,12 +2602,12 @@ describe("TypeValidator", () => {
2548
2602
 
2549
2603
  // -4 is negative, should throw
2550
2604
  expect(() =>
2551
- validator.validateShiftAmount("u8", addExpr, "<<", ctx),
2605
+ TypeValidator.validateShiftAmount("u8", addExpr, "<<", ctx),
2552
2606
  ).toThrow("Negative shift amount (-4) is undefined behavior");
2553
2607
  });
2554
2608
 
2555
2609
  it("handles nested unary returning null in evaluateUnaryExpression", () => {
2556
- const validator = new TypeValidator(createMockDeps());
2610
+ setupState();
2557
2611
  // Create nested unary that returns null (no literal)
2558
2612
  const innerPrimaryExpr = { literal: () => null };
2559
2613
  const innerPostfixExpr = {
@@ -2580,12 +2634,12 @@ describe("TypeValidator", () => {
2580
2634
 
2581
2635
  // Cannot evaluate, should skip validation
2582
2636
  expect(() =>
2583
- validator.validateShiftAmount("u8", addExpr, "<<", ctx),
2637
+ TypeValidator.validateShiftAmount("u8", addExpr, "<<", ctx),
2584
2638
  ).not.toThrow();
2585
2639
  });
2586
2640
 
2587
2641
  it("handles fallthrough case in evaluateUnaryExpression when nothing returns value", () => {
2588
- const validator = new TypeValidator(createMockDeps());
2642
+ setupState();
2589
2643
  // Create unary expression that has neither postfix nor nested unary
2590
2644
  const unaryExpr = {
2591
2645
  postfixExpression: () => null,
@@ -2602,12 +2656,12 @@ describe("TypeValidator", () => {
2602
2656
 
2603
2657
  // Cannot evaluate, should skip validation
2604
2658
  expect(() =>
2605
- validator.validateShiftAmount("u8", addExpr, "<<", ctx),
2659
+ TypeValidator.validateShiftAmount("u8", addExpr, "<<", ctx),
2606
2660
  ).not.toThrow();
2607
2661
  });
2608
2662
 
2609
2663
  it("handles hex literal in evaluateUnaryExpression via nested unary path", () => {
2610
- const validator = new TypeValidator(createMockDeps());
2664
+ setupState();
2611
2665
  // Create nested unary with hex literal: -0x08 = -8
2612
2666
  const innerLiteral = { getText: () => "0x08" }; // hex for 8
2613
2667
  const innerPrimaryExpr = { literal: () => innerLiteral };
@@ -2635,12 +2689,12 @@ describe("TypeValidator", () => {
2635
2689
 
2636
2690
  // -8 is negative, should throw
2637
2691
  expect(() =>
2638
- validator.validateShiftAmount("u8", addExpr, "<<", ctx),
2692
+ TypeValidator.validateShiftAmount("u8", addExpr, "<<", ctx),
2639
2693
  ).toThrow("Negative shift amount (-8) is undefined behavior");
2640
2694
  });
2641
2695
 
2642
2696
  it("handles negative value in evaluateUnaryExpression when inner has negative getText", () => {
2643
- const validator = new TypeValidator(createMockDeps());
2697
+ setupState();
2644
2698
  // Create unary with postfixExpr where getText starts with "-"
2645
2699
  const innerLiteral = { getText: () => "5" };
2646
2700
  const innerPrimaryExpr = { literal: () => innerLiteral };
@@ -2670,12 +2724,12 @@ describe("TypeValidator", () => {
2670
2724
 
2671
2725
  // --5 should evaluate to 5 (double negative)
2672
2726
  expect(() =>
2673
- validator.validateShiftAmount("u8", addExpr, "<<", ctx),
2727
+ TypeValidator.validateShiftAmount("u8", addExpr, "<<", ctx),
2674
2728
  ).not.toThrow();
2675
2729
  });
2676
2730
 
2677
2731
  it("handles case where numMatch fails in evaluateUnaryExpression", () => {
2678
- const validator = new TypeValidator(createMockDeps());
2732
+ setupState();
2679
2733
  // Create unary with a literal that doesn't match any pattern
2680
2734
  const innerLiteral = { getText: () => "abc" }; // Not a number
2681
2735
  const innerPrimaryExpr = { literal: () => innerLiteral };
@@ -2703,12 +2757,12 @@ describe("TypeValidator", () => {
2703
2757
 
2704
2758
  // Cannot evaluate, should skip validation (value stays null)
2705
2759
  expect(() =>
2706
- validator.validateShiftAmount("u8", addExpr, "<<", ctx),
2760
+ TypeValidator.validateShiftAmount("u8", addExpr, "<<", ctx),
2707
2761
  ).not.toThrow();
2708
2762
  });
2709
2763
 
2710
2764
  it("hits line 1168 in evaluateUnaryExpression (double-nested null return)", () => {
2711
- const validator = new TypeValidator(createMockDeps());
2765
+ setupState();
2712
2766
  // Create deeply nested unary where inner has no postfix and no nested
2713
2767
  // This forces evaluateUnaryExpression to reach the final return null
2714
2768
  const innerInnerUnaryExpr = {
@@ -2736,7 +2790,7 @@ describe("TypeValidator", () => {
2736
2790
 
2737
2791
  // Cannot evaluate, should skip validation
2738
2792
  expect(() =>
2739
- validator.validateShiftAmount("u8", addExpr, "<<", ctx),
2793
+ TypeValidator.validateShiftAmount("u8", addExpr, "<<", ctx),
2740
2794
  ).not.toThrow();
2741
2795
  });
2742
2796
  });
@@ -2748,10 +2802,8 @@ describe("TypeValidator", () => {
2748
2802
  describe("resolveBareIdentifier - outside scope coverage", () => {
2749
2803
  it("returns null for enum identifier when outside scope", () => {
2750
2804
  const symbols = createMockSymbols({ knownEnums: new Set(["State"]) });
2751
- const validator = new TypeValidator(
2752
- createMockDeps({ symbols, currentScope: null }),
2753
- );
2754
- const result = validator.resolveBareIdentifier(
2805
+ setupState({ symbols, currentScope: null });
2806
+ const result = TypeValidator.resolveBareIdentifier(
2755
2807
  "State",
2756
2808
  false,
2757
2809
  () => false,
@@ -2760,10 +2812,8 @@ describe("TypeValidator", () => {
2760
2812
  });
2761
2813
 
2762
2814
  it("returns null for struct identifier when outside scope", () => {
2763
- const validator = new TypeValidator(
2764
- createMockDeps({ currentScope: null }),
2765
- );
2766
- const result = validator.resolveBareIdentifier(
2815
+ setupState({ currentScope: null });
2816
+ const result = TypeValidator.resolveBareIdentifier(
2767
2817
  "Point",
2768
2818
  false,
2769
2819
  () => true,
@@ -2773,10 +2823,8 @@ describe("TypeValidator", () => {
2773
2823
 
2774
2824
  it("returns null for register identifier when outside scope", () => {
2775
2825
  const symbols = createMockSymbols({ knownRegisters: new Set(["GPIO"]) });
2776
- const validator = new TypeValidator(
2777
- createMockDeps({ symbols, currentScope: null }),
2778
- );
2779
- const result = validator.resolveBareIdentifier(
2826
+ setupState({ symbols, currentScope: null });
2827
+ const result = TypeValidator.resolveBareIdentifier(
2780
2828
  "GPIO",
2781
2829
  false,
2782
2830
  () => false,
@@ -2790,114 +2838,90 @@ describe("TypeValidator", () => {
2790
2838
  // ========================================================================
2791
2839
 
2792
2840
  describe("validateIntegerAssignment", () => {
2793
- function createValidatorWithMockResolver(mockResolver: {
2794
- isIntegerType?: (type: string) => boolean;
2795
- validateLiteralFitsType?: (literal: string, type: string) => void;
2796
- validateTypeConversion?: (target: string, source: string | null) => void;
2797
- }) {
2798
- const deps = createMockDeps();
2799
- const fullMockResolver = {
2800
- isIntegerType: mockResolver.isIntegerType ?? (() => true),
2801
- validateLiteralFitsType:
2802
- mockResolver.validateLiteralFitsType ?? vi.fn(),
2803
- validateTypeConversion: mockResolver.validateTypeConversion ?? vi.fn(),
2804
- };
2805
- return new TypeValidator({
2806
- ...deps,
2807
- typeResolver: fullMockResolver as never,
2808
- });
2809
- }
2810
-
2811
2841
  it("skips validation for compound assignments", () => {
2812
- const validateLiteralFitsType = vi.fn();
2813
- const validateTypeConversion = vi.fn();
2814
- const validator = createValidatorWithMockResolver({
2815
- validateLiteralFitsType,
2816
- validateTypeConversion,
2817
- });
2842
+ setupState();
2843
+ const literalSpy = vi.spyOn(TypeResolver, "validateLiteralFitsType");
2844
+ const conversionSpy = vi.spyOn(TypeResolver, "validateTypeConversion");
2818
2845
 
2819
- validator.validateIntegerAssignment("u8", "10", null, true);
2846
+ TypeValidator.validateIntegerAssignment("u8", "10", null, true);
2820
2847
 
2821
- expect(validateLiteralFitsType).not.toHaveBeenCalled();
2822
- expect(validateTypeConversion).not.toHaveBeenCalled();
2848
+ expect(literalSpy).not.toHaveBeenCalled();
2849
+ expect(conversionSpy).not.toHaveBeenCalled();
2823
2850
  });
2824
2851
 
2825
2852
  it("skips validation for non-integer types", () => {
2826
- const validateLiteralFitsType = vi.fn();
2827
- const validator = createValidatorWithMockResolver({
2828
- isIntegerType: () => false,
2829
- validateLiteralFitsType,
2830
- });
2853
+ setupState();
2854
+ const spy = vi.spyOn(TypeResolver, "validateLiteralFitsType");
2831
2855
 
2832
- validator.validateIntegerAssignment("f32", "10", null, false);
2856
+ TypeValidator.validateIntegerAssignment("f32", "10", null, false);
2833
2857
 
2834
- expect(validateLiteralFitsType).not.toHaveBeenCalled();
2858
+ expect(spy).not.toHaveBeenCalled();
2835
2859
  });
2836
2860
 
2837
2861
  it("validates decimal literal fits in target type", () => {
2838
- const validateLiteralFitsType = vi.fn();
2839
- const validator = createValidatorWithMockResolver({
2840
- validateLiteralFitsType,
2841
- });
2862
+ setupState();
2863
+ const spy = vi
2864
+ .spyOn(TypeResolver, "validateLiteralFitsType")
2865
+ .mockImplementation(() => {});
2842
2866
 
2843
- validator.validateIntegerAssignment("u8", "100", null, false);
2867
+ TypeValidator.validateIntegerAssignment("u8", "100", null, false);
2844
2868
 
2845
- expect(validateLiteralFitsType).toHaveBeenCalledWith("100", "u8");
2869
+ expect(spy).toHaveBeenCalledWith("100", "u8");
2846
2870
  });
2847
2871
 
2848
2872
  it("validates negative decimal literal fits in target type", () => {
2849
- const validateLiteralFitsType = vi.fn();
2850
- const validator = createValidatorWithMockResolver({
2851
- validateLiteralFitsType,
2852
- });
2873
+ setupState();
2874
+ const spy = vi
2875
+ .spyOn(TypeResolver, "validateLiteralFitsType")
2876
+ .mockImplementation(() => {});
2853
2877
 
2854
- validator.validateIntegerAssignment("i8", "-50", null, false);
2878
+ TypeValidator.validateIntegerAssignment("i8", "-50", null, false);
2855
2879
 
2856
- expect(validateLiteralFitsType).toHaveBeenCalledWith("-50", "i8");
2880
+ expect(spy).toHaveBeenCalledWith("-50", "i8");
2857
2881
  });
2858
2882
 
2859
2883
  it("validates hex literal fits in target type", () => {
2860
- const validateLiteralFitsType = vi.fn();
2861
- const validator = createValidatorWithMockResolver({
2862
- validateLiteralFitsType,
2863
- });
2884
+ setupState();
2885
+ const spy = vi
2886
+ .spyOn(TypeResolver, "validateLiteralFitsType")
2887
+ .mockImplementation(() => {});
2864
2888
 
2865
- validator.validateIntegerAssignment("u8", "0xFF", null, false);
2889
+ TypeValidator.validateIntegerAssignment("u8", "0xFF", null, false);
2866
2890
 
2867
- expect(validateLiteralFitsType).toHaveBeenCalledWith("0xFF", "u8");
2891
+ expect(spy).toHaveBeenCalledWith("0xFF", "u8");
2868
2892
  });
2869
2893
 
2870
2894
  it("validates binary literal fits in target type", () => {
2871
- const validateLiteralFitsType = vi.fn();
2872
- const validator = createValidatorWithMockResolver({
2873
- validateLiteralFitsType,
2874
- });
2895
+ setupState();
2896
+ const spy = vi
2897
+ .spyOn(TypeResolver, "validateLiteralFitsType")
2898
+ .mockImplementation(() => {});
2875
2899
 
2876
- validator.validateIntegerAssignment("u8", "0b11111111", null, false);
2900
+ TypeValidator.validateIntegerAssignment("u8", "0b11111111", null, false);
2877
2901
 
2878
- expect(validateLiteralFitsType).toHaveBeenCalledWith("0b11111111", "u8");
2902
+ expect(spy).toHaveBeenCalledWith("0b11111111", "u8");
2879
2903
  });
2880
2904
 
2881
2905
  it("validates type conversion for non-literal expressions", () => {
2882
- const validateTypeConversion = vi.fn();
2883
- const validator = createValidatorWithMockResolver({
2884
- validateTypeConversion,
2885
- });
2906
+ setupState();
2907
+ const spy = vi
2908
+ .spyOn(TypeResolver, "validateTypeConversion")
2909
+ .mockImplementation(() => {});
2886
2910
 
2887
- validator.validateIntegerAssignment("u8", "myVariable", "u16", false);
2911
+ TypeValidator.validateIntegerAssignment("u8", "myVariable", "u16", false);
2888
2912
 
2889
- expect(validateTypeConversion).toHaveBeenCalledWith("u8", "u16");
2913
+ expect(spy).toHaveBeenCalledWith("u8", "u16");
2890
2914
  });
2891
2915
 
2892
2916
  it("trims whitespace from expression text", () => {
2893
- const validateLiteralFitsType = vi.fn();
2894
- const validator = createValidatorWithMockResolver({
2895
- validateLiteralFitsType,
2896
- });
2917
+ setupState();
2918
+ const spy = vi
2919
+ .spyOn(TypeResolver, "validateLiteralFitsType")
2920
+ .mockImplementation(() => {});
2897
2921
 
2898
- validator.validateIntegerAssignment("u8", " 100 ", null, false);
2922
+ TypeValidator.validateIntegerAssignment("u8", " 100 ", null, false);
2899
2923
 
2900
- expect(validateLiteralFitsType).toHaveBeenCalledWith("100", "u8");
2924
+ expect(spy).toHaveBeenCalledWith("100", "u8");
2901
2925
  });
2902
2926
  });
2903
2927
  });