circle-ir 3.21.0 → 3.22.0

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.
@@ -4373,6 +4373,9 @@ function extractTypes(tree, cache, language) {
4373
4373
  const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript";
4374
4374
  const isPython = effectiveLanguage === "python";
4375
4375
  const isRust = effectiveLanguage === "rust";
4376
+ if (effectiveLanguage === "go") {
4377
+ return extractGoTypes(tree, cache);
4378
+ }
4376
4379
  if (isRust) {
4377
4380
  return extractRustTypes(tree, cache);
4378
4381
  }
@@ -5508,6 +5511,143 @@ function extractRustDerives(node) {
5508
5511
  }
5509
5512
  return derives;
5510
5513
  }
5514
+ function extractGoTypes(tree, cache) {
5515
+ const types = [];
5516
+ const root = tree.rootNode;
5517
+ const typeDecls = getNodesFromCache(root, "type_declaration", cache);
5518
+ for (const decl of typeDecls) {
5519
+ for (let i2 = 0; i2 < decl.childCount; i2++) {
5520
+ const spec = decl.child(i2);
5521
+ if (!spec || spec.type !== "type_spec") continue;
5522
+ const nameNode = spec.childForFieldName("name");
5523
+ const typeNode = spec.childForFieldName("type");
5524
+ if (!nameNode || !typeNode) continue;
5525
+ const name2 = getNodeText(nameNode);
5526
+ const isInterface = typeNode.type === "interface_type";
5527
+ const isStruct = typeNode.type === "struct_type";
5528
+ if (!isStruct && !isInterface) continue;
5529
+ const fields = [];
5530
+ const methods = [];
5531
+ if (isStruct) {
5532
+ const fieldList = findChildByType(typeNode, "field_declaration_list");
5533
+ if (fieldList) {
5534
+ for (let j = 0; j < fieldList.childCount; j++) {
5535
+ const field = fieldList.child(j);
5536
+ if (!field || field.type !== "field_declaration") continue;
5537
+ const fieldName = field.childForFieldName("name");
5538
+ const fieldType = field.childForFieldName("type");
5539
+ if (fieldName) {
5540
+ fields.push({
5541
+ name: getNodeText(fieldName),
5542
+ type: fieldType ? getNodeText(fieldType) : null,
5543
+ modifiers: [],
5544
+ annotations: []
5545
+ });
5546
+ }
5547
+ }
5548
+ }
5549
+ }
5550
+ const methodDecls = getNodesFromCache(root, "method_declaration", cache);
5551
+ for (const md of methodDecls) {
5552
+ const receiver = md.childForFieldName("receiver");
5553
+ if (!receiver) continue;
5554
+ const receiverText = getNodeText(receiver);
5555
+ if (receiverText.includes(name2)) {
5556
+ const methodNameNode = md.childForFieldName("name");
5557
+ const params = md.childForFieldName("parameters");
5558
+ const result = md.childForFieldName("result");
5559
+ if (methodNameNode) {
5560
+ methods.push({
5561
+ name: getNodeText(methodNameNode),
5562
+ return_type: result ? getNodeText(result) : null,
5563
+ parameters: params ? extractGoParameters(params) : [],
5564
+ annotations: [],
5565
+ modifiers: [],
5566
+ start_line: md.startPosition.row + 1,
5567
+ end_line: md.endPosition.row + 1
5568
+ });
5569
+ }
5570
+ }
5571
+ }
5572
+ let pkg = null;
5573
+ const pkgClause = findChildByType(root, "package_clause");
5574
+ if (pkgClause) {
5575
+ for (let j = 0; j < pkgClause.childCount; j++) {
5576
+ const child = pkgClause.child(j);
5577
+ if (child && child.type === "package_identifier") {
5578
+ pkg = getNodeText(child);
5579
+ break;
5580
+ }
5581
+ }
5582
+ }
5583
+ types.push({
5584
+ name: name2,
5585
+ kind: isInterface ? "interface" : "class",
5586
+ package: pkg,
5587
+ extends: null,
5588
+ implements: [],
5589
+ annotations: [],
5590
+ methods,
5591
+ fields,
5592
+ start_line: decl.startPosition.row + 1,
5593
+ end_line: decl.endPosition.row + 1
5594
+ });
5595
+ }
5596
+ }
5597
+ const functions = getNodesFromCache(root, "function_declaration", cache);
5598
+ if (functions.length > 0) {
5599
+ const moduleFunctions = [];
5600
+ for (const func2 of functions) {
5601
+ const nameNode = func2.childForFieldName("name");
5602
+ const params = func2.childForFieldName("parameters");
5603
+ const result = func2.childForFieldName("result");
5604
+ if (nameNode) {
5605
+ moduleFunctions.push({
5606
+ name: getNodeText(nameNode),
5607
+ return_type: result ? getNodeText(result) : null,
5608
+ parameters: params ? extractGoParameters(params) : [],
5609
+ annotations: [],
5610
+ modifiers: [],
5611
+ start_line: func2.startPosition.row + 1,
5612
+ end_line: func2.endPosition.row + 1
5613
+ });
5614
+ }
5615
+ }
5616
+ if (moduleFunctions.length > 0) {
5617
+ types.push({
5618
+ name: "<module>",
5619
+ kind: "class",
5620
+ package: null,
5621
+ extends: null,
5622
+ implements: [],
5623
+ annotations: [],
5624
+ methods: moduleFunctions,
5625
+ fields: [],
5626
+ start_line: 1,
5627
+ end_line: root.endPosition.row + 1
5628
+ });
5629
+ }
5630
+ }
5631
+ return types;
5632
+ }
5633
+ function extractGoParameters(params) {
5634
+ const parameters = [];
5635
+ for (let i2 = 0; i2 < params.childCount; i2++) {
5636
+ const child = params.child(i2);
5637
+ if (!child || child.type !== "parameter_declaration") continue;
5638
+ const nameNode = child.childForFieldName("name");
5639
+ const typeNode = child.childForFieldName("type");
5640
+ if (nameNode) {
5641
+ parameters.push({
5642
+ name: getNodeText(nameNode),
5643
+ type: typeNode ? getNodeText(typeNode) : null,
5644
+ annotations: [],
5645
+ line: child.startPosition.row + 1
5646
+ });
5647
+ }
5648
+ }
5649
+ return parameters;
5650
+ }
5511
5651
  function findChildByType(node, type) {
5512
5652
  for (let i2 = 0; i2 < node.childCount; i2++) {
5513
5653
  const child = node.child(i2);
@@ -5555,6 +5695,9 @@ function extractCalls(tree, cache, language) {
5555
5695
  const isJavaScript = detectedLanguage === "javascript" || detectedLanguage === "typescript";
5556
5696
  const isPython = detectedLanguage === "python";
5557
5697
  const isRust = detectedLanguage === "rust";
5698
+ if (detectedLanguage === "go") {
5699
+ return extractGoCalls(tree, cache);
5700
+ }
5558
5701
  if (detectedLanguage === "bash") {
5559
5702
  return extractBashCalls(tree, cache);
5560
5703
  }
@@ -6837,6 +6980,104 @@ function resolveRustCall(methodName, receiver, context) {
6837
6980
  status: "external_method"
6838
6981
  };
6839
6982
  }
6983
+ function extractGoCalls(tree, cache) {
6984
+ const calls = [];
6985
+ const callExpressions = getNodesFromCache(tree.rootNode, "call_expression", cache);
6986
+ for (const call of callExpressions) {
6987
+ const callInfo = extractGoCallInfo(call);
6988
+ if (callInfo) {
6989
+ calls.push(callInfo);
6990
+ }
6991
+ }
6992
+ return calls;
6993
+ }
6994
+ function extractGoCallInfo(node) {
6995
+ const funcNode = node.childForFieldName("function");
6996
+ if (!funcNode) return null;
6997
+ let methodName;
6998
+ let receiver = null;
6999
+ if (funcNode.type === "selector_expression") {
7000
+ const operand = funcNode.childForFieldName("operand");
7001
+ const field = funcNode.childForFieldName("field");
7002
+ receiver = operand ? getNodeText(operand) : null;
7003
+ methodName = field ? getNodeText(field) : getNodeText(funcNode);
7004
+ } else if (funcNode.type === "identifier") {
7005
+ methodName = getNodeText(funcNode);
7006
+ } else {
7007
+ methodName = getNodeText(funcNode);
7008
+ }
7009
+ const argsNode = node.childForFieldName("arguments");
7010
+ const args2 = argsNode ? extractGoArguments(argsNode) : [];
7011
+ const inMethod = findGoEnclosingFunction(node);
7012
+ return {
7013
+ method_name: methodName,
7014
+ receiver,
7015
+ arguments: args2,
7016
+ location: {
7017
+ line: node.startPosition.row + 1,
7018
+ column: node.startPosition.column
7019
+ },
7020
+ in_method: inMethod,
7021
+ resolved: false,
7022
+ resolution: { status: "external_method" }
7023
+ };
7024
+ }
7025
+ function extractGoArguments(argsNode) {
7026
+ const args2 = [];
7027
+ let position = 0;
7028
+ for (let i2 = 0; i2 < argsNode.childCount; i2++) {
7029
+ const child = argsNode.child(i2);
7030
+ if (!child) continue;
7031
+ if (child.type === "(" || child.type === ")" || child.type === ",") continue;
7032
+ const expression = getNodeText(child);
7033
+ const variable = child.type === "identifier" ? expression : null;
7034
+ const literal = isGoLiteral(child) ? extractGoLiteralValue(child) : null;
7035
+ args2.push({
7036
+ position: position++,
7037
+ expression,
7038
+ variable,
7039
+ literal
7040
+ });
7041
+ }
7042
+ return args2;
7043
+ }
7044
+ function isGoLiteral(node) {
7045
+ const literalTypes = /* @__PURE__ */ new Set([
7046
+ "interpreted_string_literal",
7047
+ "raw_string_literal",
7048
+ "int_literal",
7049
+ "float_literal",
7050
+ "true",
7051
+ "false",
7052
+ "nil"
7053
+ ]);
7054
+ return literalTypes.has(node.type);
7055
+ }
7056
+ function extractGoLiteralValue(node) {
7057
+ const text = getNodeText(node);
7058
+ if (node.type === "interpreted_string_literal") {
7059
+ return text.slice(1, -1);
7060
+ }
7061
+ if (node.type === "raw_string_literal") {
7062
+ return text.slice(1, -1);
7063
+ }
7064
+ return text;
7065
+ }
7066
+ function findGoEnclosingFunction(node) {
7067
+ let current = node.parent;
7068
+ while (current) {
7069
+ if (current.type === "function_declaration") {
7070
+ const nameNode = current.childForFieldName("name");
7071
+ return nameNode ? getNodeText(nameNode) : null;
7072
+ }
7073
+ if (current.type === "method_declaration") {
7074
+ const nameNode = current.childForFieldName("name");
7075
+ return nameNode ? getNodeText(nameNode) : null;
7076
+ }
7077
+ current = current.parent;
7078
+ }
7079
+ return null;
7080
+ }
6840
7081
 
6841
7082
  // src/core/extractors/imports.ts
6842
7083
  function detectLanguage2(tree) {
@@ -6891,6 +7132,9 @@ function extractImports(tree, language) {
6891
7132
  const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript";
6892
7133
  const isPython = effectiveLanguage === "python";
6893
7134
  const isRust = effectiveLanguage === "rust";
7135
+ if (effectiveLanguage === "go") {
7136
+ return extractGoImports(tree);
7137
+ }
6894
7138
  if (isRust) {
6895
7139
  return extractRustImports(tree);
6896
7140
  }
@@ -7438,6 +7682,61 @@ function extractRustScopedUseList(node, lineNumber) {
7438
7682
  }
7439
7683
  return imports;
7440
7684
  }
7685
+ function extractGoImports(tree) {
7686
+ const imports = [];
7687
+ const importDecls = findNodes(tree.rootNode, "import_declaration");
7688
+ for (const decl of importDecls) {
7689
+ const singleSpec = findGoChildByType(decl, "import_spec");
7690
+ if (singleSpec) {
7691
+ const parsed = parseGoImportSpec(singleSpec);
7692
+ if (parsed) imports.push(parsed);
7693
+ continue;
7694
+ }
7695
+ const specList = findGoChildByType(decl, "import_spec_list");
7696
+ if (specList) {
7697
+ for (let i2 = 0; i2 < specList.childCount; i2++) {
7698
+ const spec = specList.child(i2);
7699
+ if (!spec || spec.type !== "import_spec") continue;
7700
+ const parsed = parseGoImportSpec(spec);
7701
+ if (parsed) imports.push(parsed);
7702
+ }
7703
+ }
7704
+ }
7705
+ return imports;
7706
+ }
7707
+ function parseGoImportSpec(spec) {
7708
+ let alias = null;
7709
+ let path;
7710
+ for (let i2 = 0; i2 < spec.childCount; i2++) {
7711
+ const child = spec.child(i2);
7712
+ if (!child) continue;
7713
+ if (child.type === "package_identifier" || child.type === "blank_identifier" || child.type === "dot") {
7714
+ alias = getNodeText(child);
7715
+ }
7716
+ if (child.type === "interpreted_string_literal") {
7717
+ const text = getNodeText(child);
7718
+ path = text.slice(1, -1);
7719
+ }
7720
+ }
7721
+ if (!path) return null;
7722
+ const shortName = alias || path.split("/").pop() || path;
7723
+ return {
7724
+ imported_name: shortName,
7725
+ from_package: path,
7726
+ alias,
7727
+ is_wildcard: alias === ".",
7728
+ line_number: spec.startPosition.row + 1
7729
+ };
7730
+ }
7731
+ function findGoChildByType(node, type) {
7732
+ for (let i2 = 0; i2 < node.childCount; i2++) {
7733
+ const child = node.child(i2);
7734
+ if (child?.type === type) {
7735
+ return child;
7736
+ }
7737
+ }
7738
+ return null;
7739
+ }
7441
7740
 
7442
7741
  // src/core/extractors/exports.ts
7443
7742
  function extractExports(types) {
@@ -7529,6 +7828,9 @@ function buildCFG(tree, language) {
7529
7828
  if (effectiveLanguage === "bash") {
7530
7829
  return buildBashCFG(tree, blockIdCounter);
7531
7830
  }
7831
+ if (effectiveLanguage === "go") {
7832
+ return buildGoCFG(tree, blockIdCounter);
7833
+ }
7532
7834
  if (isJavaScript) {
7533
7835
  const functions = [
7534
7836
  ...findNodes(tree.rootNode, "function_declaration"),
@@ -8005,6 +8307,58 @@ function isStatement(node, isJavaScript) {
8005
8307
  ]);
8006
8308
  return isJavaScript ? jsStatementTypes.has(node.type) : javaStatementTypes.has(node.type);
8007
8309
  }
8310
+ function buildGoCFG(tree, blockIdCounter) {
8311
+ const allBlocks = [];
8312
+ const allEdges = [];
8313
+ const functions = [
8314
+ ...findNodes(tree.rootNode, "function_declaration"),
8315
+ ...findNodes(tree.rootNode, "method_declaration")
8316
+ ];
8317
+ for (const func2 of functions) {
8318
+ const body2 = func2.childForFieldName("body");
8319
+ if (!body2 || body2.type !== "block") continue;
8320
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, false);
8321
+ allBlocks.push(...blocks);
8322
+ allEdges.push(...edges);
8323
+ blockIdCounter = nextId;
8324
+ }
8325
+ const hasTopLevelDecls = tree.rootNode.children.some(
8326
+ (c) => c !== null && isGoStatement(c)
8327
+ );
8328
+ if (hasTopLevelDecls) {
8329
+ const block = {
8330
+ id: blockIdCounter++,
8331
+ type: "normal",
8332
+ start_line: 1,
8333
+ end_line: tree.rootNode.endPosition.row + 1
8334
+ };
8335
+ allBlocks.push(block);
8336
+ }
8337
+ return { blocks: allBlocks, edges: allEdges };
8338
+ }
8339
+ function isGoStatement(node) {
8340
+ const goStatementTypes = /* @__PURE__ */ new Set([
8341
+ "short_var_declaration",
8342
+ "var_declaration",
8343
+ "assignment_statement",
8344
+ "expression_statement",
8345
+ "if_statement",
8346
+ "for_statement",
8347
+ "switch_statement",
8348
+ "type_switch_statement",
8349
+ "select_statement",
8350
+ "return_statement",
8351
+ "go_statement",
8352
+ "defer_statement",
8353
+ "send_statement",
8354
+ "inc_statement",
8355
+ "dec_statement",
8356
+ "block",
8357
+ "type_declaration",
8358
+ "const_declaration"
8359
+ ]);
8360
+ return goStatementTypes.has(node.type);
8361
+ }
8008
8362
 
8009
8363
  // src/core/extractors/dfg.ts
8010
8364
  function detectLanguage4(tree) {
@@ -8052,6 +8406,9 @@ function buildDFG(tree, cache, language) {
8052
8406
  if (effectiveLanguage === "bash") {
8053
8407
  return buildBashDFG(tree);
8054
8408
  }
8409
+ if (effectiveLanguage === "go") {
8410
+ return buildGoDFG(tree);
8411
+ }
8055
8412
  return buildJavaDFG(tree, cache);
8056
8413
  }
8057
8414
  function buildJavaDFG(tree, cache) {
@@ -9035,6 +9392,259 @@ function isRustKeyword(name2) {
9035
9392
  ]);
9036
9393
  return keywords.has(name2);
9037
9394
  }
9395
+ var GO_KEYWORDS = /* @__PURE__ */ new Set([
9396
+ "break",
9397
+ "case",
9398
+ "chan",
9399
+ "const",
9400
+ "continue",
9401
+ "default",
9402
+ "defer",
9403
+ "else",
9404
+ "fallthrough",
9405
+ "for",
9406
+ "func",
9407
+ "go",
9408
+ "goto",
9409
+ "if",
9410
+ "import",
9411
+ "interface",
9412
+ "map",
9413
+ "package",
9414
+ "range",
9415
+ "return",
9416
+ "select",
9417
+ "struct",
9418
+ "switch",
9419
+ "type",
9420
+ "var",
9421
+ "true",
9422
+ "false",
9423
+ "nil",
9424
+ "iota",
9425
+ "append",
9426
+ "cap",
9427
+ "close",
9428
+ "complex",
9429
+ "copy",
9430
+ "delete",
9431
+ "imag",
9432
+ "len",
9433
+ "make",
9434
+ "new",
9435
+ "panic",
9436
+ "print",
9437
+ "println",
9438
+ "real",
9439
+ "recover",
9440
+ "string",
9441
+ "int",
9442
+ "int8",
9443
+ "int16",
9444
+ "int32",
9445
+ "int64",
9446
+ "uint",
9447
+ "uint8",
9448
+ "uint16",
9449
+ "uint32",
9450
+ "uint64",
9451
+ "float32",
9452
+ "float64",
9453
+ "complex64",
9454
+ "complex128",
9455
+ "byte",
9456
+ "rune",
9457
+ "bool",
9458
+ "error",
9459
+ "any"
9460
+ ]);
9461
+ function buildGoDFG(tree) {
9462
+ const defs = [];
9463
+ const uses = [];
9464
+ let defIdCounter = 1;
9465
+ let useIdCounter = 1;
9466
+ const scopeStack = [/* @__PURE__ */ new Map()];
9467
+ const functions = [
9468
+ ...findNodes(tree.rootNode, "function_declaration"),
9469
+ ...findNodes(tree.rootNode, "method_declaration")
9470
+ ];
9471
+ for (const func2 of functions) {
9472
+ scopeStack.push(/* @__PURE__ */ new Map());
9473
+ const params = func2.childForFieldName("parameters");
9474
+ if (params) {
9475
+ extractGoParamDefs(params, defs, defIdCounter, scopeStack);
9476
+ defIdCounter = defs.length + 1;
9477
+ }
9478
+ const receiver = func2.childForFieldName("receiver");
9479
+ if (receiver) {
9480
+ extractGoParamDefs(receiver, defs, defIdCounter, scopeStack);
9481
+ defIdCounter = defs.length + 1;
9482
+ }
9483
+ const body2 = func2.childForFieldName("body");
9484
+ if (body2) {
9485
+ processGoBlock(body2, defs, uses, scopeStack, { defId: defIdCounter, useId: useIdCounter });
9486
+ defIdCounter = defs.length + 1;
9487
+ useIdCounter = uses.length + 1;
9488
+ }
9489
+ scopeStack.pop();
9490
+ }
9491
+ for (let i2 = 0; i2 < tree.rootNode.childCount; i2++) {
9492
+ const child = tree.rootNode.child(i2);
9493
+ if (!child) continue;
9494
+ if (child.type === "var_declaration") {
9495
+ processGoVarDecl(child, defs, scopeStack, { defId: defIdCounter });
9496
+ defIdCounter = defs.length + 1;
9497
+ }
9498
+ }
9499
+ const chains = computeChains(defs, uses);
9500
+ return { defs, uses, chains };
9501
+ }
9502
+ function extractGoParamDefs(params, defs, _startId, scopeStack) {
9503
+ for (let i2 = 0; i2 < params.childCount; i2++) {
9504
+ const param = params.child(i2);
9505
+ if (!param || param.type !== "parameter_declaration") continue;
9506
+ const typeNode = param.childForFieldName("type");
9507
+ for (let j = 0; j < param.childCount; j++) {
9508
+ const nameNode = param.child(j);
9509
+ if (!nameNode || nameNode.type !== "identifier") continue;
9510
+ if (nameNode === typeNode) continue;
9511
+ const varName = getNodeText(nameNode);
9512
+ if (varName === "_") continue;
9513
+ const def = {
9514
+ id: defs.length + 1,
9515
+ variable: varName,
9516
+ kind: "param",
9517
+ line: param.startPosition.row + 1
9518
+ };
9519
+ defs.push(def);
9520
+ currentScope(scopeStack).set(varName, def.id);
9521
+ }
9522
+ }
9523
+ }
9524
+ function processGoBlock(node, defs, uses, scopeStack, counters) {
9525
+ walkTree(node, (child) => {
9526
+ if (child.type === "short_var_declaration") {
9527
+ const left = child.childForFieldName("left");
9528
+ const right = child.childForFieldName("right");
9529
+ if (right) {
9530
+ extractGoUses(right, uses, scopeStack);
9531
+ }
9532
+ if (left) {
9533
+ extractGoLhsDefs(left, defs, scopeStack, child.startPosition.row + 1);
9534
+ }
9535
+ } else if (child.type === "var_declaration") {
9536
+ processGoVarDecl(child, defs, scopeStack, counters);
9537
+ } else if (child.type === "assignment_statement") {
9538
+ const left = child.childForFieldName("left");
9539
+ const right = child.childForFieldName("right");
9540
+ if (right) {
9541
+ extractGoUses(right, uses, scopeStack);
9542
+ }
9543
+ if (left) {
9544
+ extractGoLhsDefs(left, defs, scopeStack, child.startPosition.row + 1);
9545
+ }
9546
+ } else if (child.type === "for_statement") {
9547
+ const rangeClause = findChildByTypeGo(child, "range_clause");
9548
+ if (rangeClause) {
9549
+ const left = rangeClause.childForFieldName("left");
9550
+ if (left) {
9551
+ extractGoLhsDefs(left, defs, scopeStack, child.startPosition.row + 1);
9552
+ }
9553
+ }
9554
+ } else if (child.type === "call_expression") {
9555
+ extractGoUses(child, uses, scopeStack);
9556
+ } else if (child.type === "return_statement") {
9557
+ for (let i2 = 0; i2 < child.childCount; i2++) {
9558
+ const expr = child.child(i2);
9559
+ if (expr && expr.type !== "return") {
9560
+ extractGoUses(expr, uses, scopeStack);
9561
+ }
9562
+ }
9563
+ }
9564
+ });
9565
+ }
9566
+ function processGoVarDecl(node, defs, scopeStack, _counters) {
9567
+ for (let i2 = 0; i2 < node.childCount; i2++) {
9568
+ const spec = node.child(i2);
9569
+ if (!spec || spec.type !== "var_spec") continue;
9570
+ for (let j = 0; j < spec.childCount; j++) {
9571
+ const nameNode = spec.child(j);
9572
+ if (!nameNode || nameNode.type !== "identifier") continue;
9573
+ const varName = getNodeText(nameNode);
9574
+ if (varName === "_") continue;
9575
+ const def = {
9576
+ id: defs.length + 1,
9577
+ variable: varName,
9578
+ kind: "local",
9579
+ line: spec.startPosition.row + 1
9580
+ };
9581
+ defs.push(def);
9582
+ currentScope(scopeStack).set(varName, def.id);
9583
+ }
9584
+ }
9585
+ }
9586
+ function extractGoLhsDefs(left, defs, scopeStack, line) {
9587
+ if (left.type === "identifier") {
9588
+ const varName = getNodeText(left);
9589
+ if (varName === "_") return;
9590
+ const def = {
9591
+ id: defs.length + 1,
9592
+ variable: varName,
9593
+ kind: "local",
9594
+ line
9595
+ };
9596
+ defs.push(def);
9597
+ currentScope(scopeStack).set(varName, def.id);
9598
+ } else if (left.type === "expression_list") {
9599
+ for (let i2 = 0; i2 < left.childCount; i2++) {
9600
+ const item = left.child(i2);
9601
+ if (item && item.type === "identifier") {
9602
+ const varName = getNodeText(item);
9603
+ if (varName === "_") continue;
9604
+ const def = {
9605
+ id: defs.length + 1,
9606
+ variable: varName,
9607
+ kind: "local",
9608
+ line
9609
+ };
9610
+ defs.push(def);
9611
+ currentScope(scopeStack).set(varName, def.id);
9612
+ }
9613
+ }
9614
+ }
9615
+ }
9616
+ function extractGoUses(node, uses, scopeStack) {
9617
+ walkTree(node, (child) => {
9618
+ if (child.type === "identifier") {
9619
+ const varName = getNodeText(child);
9620
+ if (varName === "_" || GO_KEYWORDS.has(varName)) return;
9621
+ const parent = child.parent;
9622
+ if (parent?.type === "selector_expression" && parent.childForFieldName("field") === child) {
9623
+ return;
9624
+ }
9625
+ if (parent?.type === "parameter_declaration" && parent.childForFieldName("type") === child) {
9626
+ return;
9627
+ }
9628
+ if (parent?.type === "type_identifier") {
9629
+ return;
9630
+ }
9631
+ const defId = findReachingDef(varName, scopeStack);
9632
+ uses.push({
9633
+ id: uses.length + 1,
9634
+ variable: varName,
9635
+ line: child.startPosition.row + 1,
9636
+ def_id: defId
9637
+ });
9638
+ }
9639
+ });
9640
+ }
9641
+ function findChildByTypeGo(node, type) {
9642
+ for (let i2 = 0; i2 < node.childCount; i2++) {
9643
+ const child = node.child(i2);
9644
+ if (child?.type === type) return child;
9645
+ }
9646
+ return null;
9647
+ }
9038
9648
 
9039
9649
  // src/analysis/config-loader.ts
9040
9650
  function parseConfig(content) {