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.
@@ -4308,6 +4308,9 @@ function extractTypes(tree, cache, language) {
4308
4308
  const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript";
4309
4309
  const isPython = effectiveLanguage === "python";
4310
4310
  const isRust = effectiveLanguage === "rust";
4311
+ if (effectiveLanguage === "go") {
4312
+ return extractGoTypes(tree, cache);
4313
+ }
4311
4314
  if (isRust) {
4312
4315
  return extractRustTypes(tree, cache);
4313
4316
  }
@@ -5443,6 +5446,143 @@ function extractRustDerives(node) {
5443
5446
  }
5444
5447
  return derives;
5445
5448
  }
5449
+ function extractGoTypes(tree, cache) {
5450
+ const types = [];
5451
+ const root = tree.rootNode;
5452
+ const typeDecls = getNodesFromCache(root, "type_declaration", cache);
5453
+ for (const decl of typeDecls) {
5454
+ for (let i2 = 0; i2 < decl.childCount; i2++) {
5455
+ const spec = decl.child(i2);
5456
+ if (!spec || spec.type !== "type_spec") continue;
5457
+ const nameNode = spec.childForFieldName("name");
5458
+ const typeNode = spec.childForFieldName("type");
5459
+ if (!nameNode || !typeNode) continue;
5460
+ const name2 = getNodeText(nameNode);
5461
+ const isInterface = typeNode.type === "interface_type";
5462
+ const isStruct = typeNode.type === "struct_type";
5463
+ if (!isStruct && !isInterface) continue;
5464
+ const fields = [];
5465
+ const methods = [];
5466
+ if (isStruct) {
5467
+ const fieldList = findChildByType(typeNode, "field_declaration_list");
5468
+ if (fieldList) {
5469
+ for (let j = 0; j < fieldList.childCount; j++) {
5470
+ const field = fieldList.child(j);
5471
+ if (!field || field.type !== "field_declaration") continue;
5472
+ const fieldName = field.childForFieldName("name");
5473
+ const fieldType = field.childForFieldName("type");
5474
+ if (fieldName) {
5475
+ fields.push({
5476
+ name: getNodeText(fieldName),
5477
+ type: fieldType ? getNodeText(fieldType) : null,
5478
+ modifiers: [],
5479
+ annotations: []
5480
+ });
5481
+ }
5482
+ }
5483
+ }
5484
+ }
5485
+ const methodDecls = getNodesFromCache(root, "method_declaration", cache);
5486
+ for (const md of methodDecls) {
5487
+ const receiver = md.childForFieldName("receiver");
5488
+ if (!receiver) continue;
5489
+ const receiverText = getNodeText(receiver);
5490
+ if (receiverText.includes(name2)) {
5491
+ const methodNameNode = md.childForFieldName("name");
5492
+ const params = md.childForFieldName("parameters");
5493
+ const result = md.childForFieldName("result");
5494
+ if (methodNameNode) {
5495
+ methods.push({
5496
+ name: getNodeText(methodNameNode),
5497
+ return_type: result ? getNodeText(result) : null,
5498
+ parameters: params ? extractGoParameters(params) : [],
5499
+ annotations: [],
5500
+ modifiers: [],
5501
+ start_line: md.startPosition.row + 1,
5502
+ end_line: md.endPosition.row + 1
5503
+ });
5504
+ }
5505
+ }
5506
+ }
5507
+ let pkg = null;
5508
+ const pkgClause = findChildByType(root, "package_clause");
5509
+ if (pkgClause) {
5510
+ for (let j = 0; j < pkgClause.childCount; j++) {
5511
+ const child = pkgClause.child(j);
5512
+ if (child && child.type === "package_identifier") {
5513
+ pkg = getNodeText(child);
5514
+ break;
5515
+ }
5516
+ }
5517
+ }
5518
+ types.push({
5519
+ name: name2,
5520
+ kind: isInterface ? "interface" : "class",
5521
+ package: pkg,
5522
+ extends: null,
5523
+ implements: [],
5524
+ annotations: [],
5525
+ methods,
5526
+ fields,
5527
+ start_line: decl.startPosition.row + 1,
5528
+ end_line: decl.endPosition.row + 1
5529
+ });
5530
+ }
5531
+ }
5532
+ const functions = getNodesFromCache(root, "function_declaration", cache);
5533
+ if (functions.length > 0) {
5534
+ const moduleFunctions = [];
5535
+ for (const func2 of functions) {
5536
+ const nameNode = func2.childForFieldName("name");
5537
+ const params = func2.childForFieldName("parameters");
5538
+ const result = func2.childForFieldName("result");
5539
+ if (nameNode) {
5540
+ moduleFunctions.push({
5541
+ name: getNodeText(nameNode),
5542
+ return_type: result ? getNodeText(result) : null,
5543
+ parameters: params ? extractGoParameters(params) : [],
5544
+ annotations: [],
5545
+ modifiers: [],
5546
+ start_line: func2.startPosition.row + 1,
5547
+ end_line: func2.endPosition.row + 1
5548
+ });
5549
+ }
5550
+ }
5551
+ if (moduleFunctions.length > 0) {
5552
+ types.push({
5553
+ name: "<module>",
5554
+ kind: "class",
5555
+ package: null,
5556
+ extends: null,
5557
+ implements: [],
5558
+ annotations: [],
5559
+ methods: moduleFunctions,
5560
+ fields: [],
5561
+ start_line: 1,
5562
+ end_line: root.endPosition.row + 1
5563
+ });
5564
+ }
5565
+ }
5566
+ return types;
5567
+ }
5568
+ function extractGoParameters(params) {
5569
+ const parameters = [];
5570
+ for (let i2 = 0; i2 < params.childCount; i2++) {
5571
+ const child = params.child(i2);
5572
+ if (!child || child.type !== "parameter_declaration") continue;
5573
+ const nameNode = child.childForFieldName("name");
5574
+ const typeNode = child.childForFieldName("type");
5575
+ if (nameNode) {
5576
+ parameters.push({
5577
+ name: getNodeText(nameNode),
5578
+ type: typeNode ? getNodeText(typeNode) : null,
5579
+ annotations: [],
5580
+ line: child.startPosition.row + 1
5581
+ });
5582
+ }
5583
+ }
5584
+ return parameters;
5585
+ }
5446
5586
  function findChildByType(node, type) {
5447
5587
  for (let i2 = 0; i2 < node.childCount; i2++) {
5448
5588
  const child = node.child(i2);
@@ -5490,6 +5630,9 @@ function extractCalls(tree, cache, language) {
5490
5630
  const isJavaScript = detectedLanguage === "javascript" || detectedLanguage === "typescript";
5491
5631
  const isPython = detectedLanguage === "python";
5492
5632
  const isRust = detectedLanguage === "rust";
5633
+ if (detectedLanguage === "go") {
5634
+ return extractGoCalls(tree, cache);
5635
+ }
5493
5636
  if (detectedLanguage === "bash") {
5494
5637
  return extractBashCalls(tree, cache);
5495
5638
  }
@@ -6772,6 +6915,104 @@ function resolveRustCall(methodName, receiver, context) {
6772
6915
  status: "external_method"
6773
6916
  };
6774
6917
  }
6918
+ function extractGoCalls(tree, cache) {
6919
+ const calls = [];
6920
+ const callExpressions = getNodesFromCache(tree.rootNode, "call_expression", cache);
6921
+ for (const call of callExpressions) {
6922
+ const callInfo = extractGoCallInfo(call);
6923
+ if (callInfo) {
6924
+ calls.push(callInfo);
6925
+ }
6926
+ }
6927
+ return calls;
6928
+ }
6929
+ function extractGoCallInfo(node) {
6930
+ const funcNode = node.childForFieldName("function");
6931
+ if (!funcNode) return null;
6932
+ let methodName;
6933
+ let receiver = null;
6934
+ if (funcNode.type === "selector_expression") {
6935
+ const operand = funcNode.childForFieldName("operand");
6936
+ const field = funcNode.childForFieldName("field");
6937
+ receiver = operand ? getNodeText(operand) : null;
6938
+ methodName = field ? getNodeText(field) : getNodeText(funcNode);
6939
+ } else if (funcNode.type === "identifier") {
6940
+ methodName = getNodeText(funcNode);
6941
+ } else {
6942
+ methodName = getNodeText(funcNode);
6943
+ }
6944
+ const argsNode = node.childForFieldName("arguments");
6945
+ const args2 = argsNode ? extractGoArguments(argsNode) : [];
6946
+ const inMethod = findGoEnclosingFunction(node);
6947
+ return {
6948
+ method_name: methodName,
6949
+ receiver,
6950
+ arguments: args2,
6951
+ location: {
6952
+ line: node.startPosition.row + 1,
6953
+ column: node.startPosition.column
6954
+ },
6955
+ in_method: inMethod,
6956
+ resolved: false,
6957
+ resolution: { status: "external_method" }
6958
+ };
6959
+ }
6960
+ function extractGoArguments(argsNode) {
6961
+ const args2 = [];
6962
+ let position = 0;
6963
+ for (let i2 = 0; i2 < argsNode.childCount; i2++) {
6964
+ const child = argsNode.child(i2);
6965
+ if (!child) continue;
6966
+ if (child.type === "(" || child.type === ")" || child.type === ",") continue;
6967
+ const expression = getNodeText(child);
6968
+ const variable = child.type === "identifier" ? expression : null;
6969
+ const literal = isGoLiteral(child) ? extractGoLiteralValue(child) : null;
6970
+ args2.push({
6971
+ position: position++,
6972
+ expression,
6973
+ variable,
6974
+ literal
6975
+ });
6976
+ }
6977
+ return args2;
6978
+ }
6979
+ function isGoLiteral(node) {
6980
+ const literalTypes = /* @__PURE__ */ new Set([
6981
+ "interpreted_string_literal",
6982
+ "raw_string_literal",
6983
+ "int_literal",
6984
+ "float_literal",
6985
+ "true",
6986
+ "false",
6987
+ "nil"
6988
+ ]);
6989
+ return literalTypes.has(node.type);
6990
+ }
6991
+ function extractGoLiteralValue(node) {
6992
+ const text = getNodeText(node);
6993
+ if (node.type === "interpreted_string_literal") {
6994
+ return text.slice(1, -1);
6995
+ }
6996
+ if (node.type === "raw_string_literal") {
6997
+ return text.slice(1, -1);
6998
+ }
6999
+ return text;
7000
+ }
7001
+ function findGoEnclosingFunction(node) {
7002
+ let current = node.parent;
7003
+ while (current) {
7004
+ if (current.type === "function_declaration") {
7005
+ const nameNode = current.childForFieldName("name");
7006
+ return nameNode ? getNodeText(nameNode) : null;
7007
+ }
7008
+ if (current.type === "method_declaration") {
7009
+ const nameNode = current.childForFieldName("name");
7010
+ return nameNode ? getNodeText(nameNode) : null;
7011
+ }
7012
+ current = current.parent;
7013
+ }
7014
+ return null;
7015
+ }
6775
7016
 
6776
7017
  // src/core/extractors/imports.ts
6777
7018
  function detectLanguage2(tree) {
@@ -6826,6 +7067,9 @@ function extractImports(tree, language) {
6826
7067
  const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript";
6827
7068
  const isPython = effectiveLanguage === "python";
6828
7069
  const isRust = effectiveLanguage === "rust";
7070
+ if (effectiveLanguage === "go") {
7071
+ return extractGoImports(tree);
7072
+ }
6829
7073
  if (isRust) {
6830
7074
  return extractRustImports(tree);
6831
7075
  }
@@ -7373,6 +7617,61 @@ function extractRustScopedUseList(node, lineNumber) {
7373
7617
  }
7374
7618
  return imports;
7375
7619
  }
7620
+ function extractGoImports(tree) {
7621
+ const imports = [];
7622
+ const importDecls = findNodes(tree.rootNode, "import_declaration");
7623
+ for (const decl of importDecls) {
7624
+ const singleSpec = findGoChildByType(decl, "import_spec");
7625
+ if (singleSpec) {
7626
+ const parsed = parseGoImportSpec(singleSpec);
7627
+ if (parsed) imports.push(parsed);
7628
+ continue;
7629
+ }
7630
+ const specList = findGoChildByType(decl, "import_spec_list");
7631
+ if (specList) {
7632
+ for (let i2 = 0; i2 < specList.childCount; i2++) {
7633
+ const spec = specList.child(i2);
7634
+ if (!spec || spec.type !== "import_spec") continue;
7635
+ const parsed = parseGoImportSpec(spec);
7636
+ if (parsed) imports.push(parsed);
7637
+ }
7638
+ }
7639
+ }
7640
+ return imports;
7641
+ }
7642
+ function parseGoImportSpec(spec) {
7643
+ let alias = null;
7644
+ let path;
7645
+ for (let i2 = 0; i2 < spec.childCount; i2++) {
7646
+ const child = spec.child(i2);
7647
+ if (!child) continue;
7648
+ if (child.type === "package_identifier" || child.type === "blank_identifier" || child.type === "dot") {
7649
+ alias = getNodeText(child);
7650
+ }
7651
+ if (child.type === "interpreted_string_literal") {
7652
+ const text = getNodeText(child);
7653
+ path = text.slice(1, -1);
7654
+ }
7655
+ }
7656
+ if (!path) return null;
7657
+ const shortName = alias || path.split("/").pop() || path;
7658
+ return {
7659
+ imported_name: shortName,
7660
+ from_package: path,
7661
+ alias,
7662
+ is_wildcard: alias === ".",
7663
+ line_number: spec.startPosition.row + 1
7664
+ };
7665
+ }
7666
+ function findGoChildByType(node, type) {
7667
+ for (let i2 = 0; i2 < node.childCount; i2++) {
7668
+ const child = node.child(i2);
7669
+ if (child?.type === type) {
7670
+ return child;
7671
+ }
7672
+ }
7673
+ return null;
7674
+ }
7376
7675
 
7377
7676
  // src/core/extractors/exports.ts
7378
7677
  function extractExports(types) {
@@ -7464,6 +7763,9 @@ function buildCFG(tree, language) {
7464
7763
  if (effectiveLanguage === "bash") {
7465
7764
  return buildBashCFG(tree, blockIdCounter);
7466
7765
  }
7766
+ if (effectiveLanguage === "go") {
7767
+ return buildGoCFG(tree, blockIdCounter);
7768
+ }
7467
7769
  if (isJavaScript) {
7468
7770
  const functions = [
7469
7771
  ...findNodes(tree.rootNode, "function_declaration"),
@@ -7940,6 +8242,58 @@ function isStatement(node, isJavaScript) {
7940
8242
  ]);
7941
8243
  return isJavaScript ? jsStatementTypes.has(node.type) : javaStatementTypes.has(node.type);
7942
8244
  }
8245
+ function buildGoCFG(tree, blockIdCounter) {
8246
+ const allBlocks = [];
8247
+ const allEdges = [];
8248
+ const functions = [
8249
+ ...findNodes(tree.rootNode, "function_declaration"),
8250
+ ...findNodes(tree.rootNode, "method_declaration")
8251
+ ];
8252
+ for (const func2 of functions) {
8253
+ const body2 = func2.childForFieldName("body");
8254
+ if (!body2 || body2.type !== "block") continue;
8255
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, false);
8256
+ allBlocks.push(...blocks);
8257
+ allEdges.push(...edges);
8258
+ blockIdCounter = nextId;
8259
+ }
8260
+ const hasTopLevelDecls = tree.rootNode.children.some(
8261
+ (c) => c !== null && isGoStatement(c)
8262
+ );
8263
+ if (hasTopLevelDecls) {
8264
+ const block = {
8265
+ id: blockIdCounter++,
8266
+ type: "normal",
8267
+ start_line: 1,
8268
+ end_line: tree.rootNode.endPosition.row + 1
8269
+ };
8270
+ allBlocks.push(block);
8271
+ }
8272
+ return { blocks: allBlocks, edges: allEdges };
8273
+ }
8274
+ function isGoStatement(node) {
8275
+ const goStatementTypes = /* @__PURE__ */ new Set([
8276
+ "short_var_declaration",
8277
+ "var_declaration",
8278
+ "assignment_statement",
8279
+ "expression_statement",
8280
+ "if_statement",
8281
+ "for_statement",
8282
+ "switch_statement",
8283
+ "type_switch_statement",
8284
+ "select_statement",
8285
+ "return_statement",
8286
+ "go_statement",
8287
+ "defer_statement",
8288
+ "send_statement",
8289
+ "inc_statement",
8290
+ "dec_statement",
8291
+ "block",
8292
+ "type_declaration",
8293
+ "const_declaration"
8294
+ ]);
8295
+ return goStatementTypes.has(node.type);
8296
+ }
7943
8297
 
7944
8298
  // src/core/extractors/dfg.ts
7945
8299
  function detectLanguage4(tree) {
@@ -7987,6 +8341,9 @@ function buildDFG(tree, cache, language) {
7987
8341
  if (effectiveLanguage === "bash") {
7988
8342
  return buildBashDFG(tree);
7989
8343
  }
8344
+ if (effectiveLanguage === "go") {
8345
+ return buildGoDFG(tree);
8346
+ }
7990
8347
  return buildJavaDFG(tree, cache);
7991
8348
  }
7992
8349
  function buildJavaDFG(tree, cache) {
@@ -8970,6 +9327,259 @@ function isRustKeyword(name2) {
8970
9327
  ]);
8971
9328
  return keywords.has(name2);
8972
9329
  }
9330
+ var GO_KEYWORDS = /* @__PURE__ */ new Set([
9331
+ "break",
9332
+ "case",
9333
+ "chan",
9334
+ "const",
9335
+ "continue",
9336
+ "default",
9337
+ "defer",
9338
+ "else",
9339
+ "fallthrough",
9340
+ "for",
9341
+ "func",
9342
+ "go",
9343
+ "goto",
9344
+ "if",
9345
+ "import",
9346
+ "interface",
9347
+ "map",
9348
+ "package",
9349
+ "range",
9350
+ "return",
9351
+ "select",
9352
+ "struct",
9353
+ "switch",
9354
+ "type",
9355
+ "var",
9356
+ "true",
9357
+ "false",
9358
+ "nil",
9359
+ "iota",
9360
+ "append",
9361
+ "cap",
9362
+ "close",
9363
+ "complex",
9364
+ "copy",
9365
+ "delete",
9366
+ "imag",
9367
+ "len",
9368
+ "make",
9369
+ "new",
9370
+ "panic",
9371
+ "print",
9372
+ "println",
9373
+ "real",
9374
+ "recover",
9375
+ "string",
9376
+ "int",
9377
+ "int8",
9378
+ "int16",
9379
+ "int32",
9380
+ "int64",
9381
+ "uint",
9382
+ "uint8",
9383
+ "uint16",
9384
+ "uint32",
9385
+ "uint64",
9386
+ "float32",
9387
+ "float64",
9388
+ "complex64",
9389
+ "complex128",
9390
+ "byte",
9391
+ "rune",
9392
+ "bool",
9393
+ "error",
9394
+ "any"
9395
+ ]);
9396
+ function buildGoDFG(tree) {
9397
+ const defs = [];
9398
+ const uses = [];
9399
+ let defIdCounter = 1;
9400
+ let useIdCounter = 1;
9401
+ const scopeStack = [/* @__PURE__ */ new Map()];
9402
+ const functions = [
9403
+ ...findNodes(tree.rootNode, "function_declaration"),
9404
+ ...findNodes(tree.rootNode, "method_declaration")
9405
+ ];
9406
+ for (const func2 of functions) {
9407
+ scopeStack.push(/* @__PURE__ */ new Map());
9408
+ const params = func2.childForFieldName("parameters");
9409
+ if (params) {
9410
+ extractGoParamDefs(params, defs, defIdCounter, scopeStack);
9411
+ defIdCounter = defs.length + 1;
9412
+ }
9413
+ const receiver = func2.childForFieldName("receiver");
9414
+ if (receiver) {
9415
+ extractGoParamDefs(receiver, defs, defIdCounter, scopeStack);
9416
+ defIdCounter = defs.length + 1;
9417
+ }
9418
+ const body2 = func2.childForFieldName("body");
9419
+ if (body2) {
9420
+ processGoBlock(body2, defs, uses, scopeStack, { defId: defIdCounter, useId: useIdCounter });
9421
+ defIdCounter = defs.length + 1;
9422
+ useIdCounter = uses.length + 1;
9423
+ }
9424
+ scopeStack.pop();
9425
+ }
9426
+ for (let i2 = 0; i2 < tree.rootNode.childCount; i2++) {
9427
+ const child = tree.rootNode.child(i2);
9428
+ if (!child) continue;
9429
+ if (child.type === "var_declaration") {
9430
+ processGoVarDecl(child, defs, scopeStack, { defId: defIdCounter });
9431
+ defIdCounter = defs.length + 1;
9432
+ }
9433
+ }
9434
+ const chains = computeChains(defs, uses);
9435
+ return { defs, uses, chains };
9436
+ }
9437
+ function extractGoParamDefs(params, defs, _startId, scopeStack) {
9438
+ for (let i2 = 0; i2 < params.childCount; i2++) {
9439
+ const param = params.child(i2);
9440
+ if (!param || param.type !== "parameter_declaration") continue;
9441
+ const typeNode = param.childForFieldName("type");
9442
+ for (let j = 0; j < param.childCount; j++) {
9443
+ const nameNode = param.child(j);
9444
+ if (!nameNode || nameNode.type !== "identifier") continue;
9445
+ if (nameNode === typeNode) continue;
9446
+ const varName = getNodeText(nameNode);
9447
+ if (varName === "_") continue;
9448
+ const def = {
9449
+ id: defs.length + 1,
9450
+ variable: varName,
9451
+ kind: "param",
9452
+ line: param.startPosition.row + 1
9453
+ };
9454
+ defs.push(def);
9455
+ currentScope(scopeStack).set(varName, def.id);
9456
+ }
9457
+ }
9458
+ }
9459
+ function processGoBlock(node, defs, uses, scopeStack, counters) {
9460
+ walkTree(node, (child) => {
9461
+ if (child.type === "short_var_declaration") {
9462
+ const left = child.childForFieldName("left");
9463
+ const right = child.childForFieldName("right");
9464
+ if (right) {
9465
+ extractGoUses(right, uses, scopeStack);
9466
+ }
9467
+ if (left) {
9468
+ extractGoLhsDefs(left, defs, scopeStack, child.startPosition.row + 1);
9469
+ }
9470
+ } else if (child.type === "var_declaration") {
9471
+ processGoVarDecl(child, defs, scopeStack, counters);
9472
+ } else if (child.type === "assignment_statement") {
9473
+ const left = child.childForFieldName("left");
9474
+ const right = child.childForFieldName("right");
9475
+ if (right) {
9476
+ extractGoUses(right, uses, scopeStack);
9477
+ }
9478
+ if (left) {
9479
+ extractGoLhsDefs(left, defs, scopeStack, child.startPosition.row + 1);
9480
+ }
9481
+ } else if (child.type === "for_statement") {
9482
+ const rangeClause = findChildByTypeGo(child, "range_clause");
9483
+ if (rangeClause) {
9484
+ const left = rangeClause.childForFieldName("left");
9485
+ if (left) {
9486
+ extractGoLhsDefs(left, defs, scopeStack, child.startPosition.row + 1);
9487
+ }
9488
+ }
9489
+ } else if (child.type === "call_expression") {
9490
+ extractGoUses(child, uses, scopeStack);
9491
+ } else if (child.type === "return_statement") {
9492
+ for (let i2 = 0; i2 < child.childCount; i2++) {
9493
+ const expr = child.child(i2);
9494
+ if (expr && expr.type !== "return") {
9495
+ extractGoUses(expr, uses, scopeStack);
9496
+ }
9497
+ }
9498
+ }
9499
+ });
9500
+ }
9501
+ function processGoVarDecl(node, defs, scopeStack, _counters) {
9502
+ for (let i2 = 0; i2 < node.childCount; i2++) {
9503
+ const spec = node.child(i2);
9504
+ if (!spec || spec.type !== "var_spec") continue;
9505
+ for (let j = 0; j < spec.childCount; j++) {
9506
+ const nameNode = spec.child(j);
9507
+ if (!nameNode || nameNode.type !== "identifier") continue;
9508
+ const varName = getNodeText(nameNode);
9509
+ if (varName === "_") continue;
9510
+ const def = {
9511
+ id: defs.length + 1,
9512
+ variable: varName,
9513
+ kind: "local",
9514
+ line: spec.startPosition.row + 1
9515
+ };
9516
+ defs.push(def);
9517
+ currentScope(scopeStack).set(varName, def.id);
9518
+ }
9519
+ }
9520
+ }
9521
+ function extractGoLhsDefs(left, defs, scopeStack, line) {
9522
+ if (left.type === "identifier") {
9523
+ const varName = getNodeText(left);
9524
+ if (varName === "_") return;
9525
+ const def = {
9526
+ id: defs.length + 1,
9527
+ variable: varName,
9528
+ kind: "local",
9529
+ line
9530
+ };
9531
+ defs.push(def);
9532
+ currentScope(scopeStack).set(varName, def.id);
9533
+ } else if (left.type === "expression_list") {
9534
+ for (let i2 = 0; i2 < left.childCount; i2++) {
9535
+ const item = left.child(i2);
9536
+ if (item && item.type === "identifier") {
9537
+ const varName = getNodeText(item);
9538
+ if (varName === "_") continue;
9539
+ const def = {
9540
+ id: defs.length + 1,
9541
+ variable: varName,
9542
+ kind: "local",
9543
+ line
9544
+ };
9545
+ defs.push(def);
9546
+ currentScope(scopeStack).set(varName, def.id);
9547
+ }
9548
+ }
9549
+ }
9550
+ }
9551
+ function extractGoUses(node, uses, scopeStack) {
9552
+ walkTree(node, (child) => {
9553
+ if (child.type === "identifier") {
9554
+ const varName = getNodeText(child);
9555
+ if (varName === "_" || GO_KEYWORDS.has(varName)) return;
9556
+ const parent = child.parent;
9557
+ if (parent?.type === "selector_expression" && parent.childForFieldName("field") === child) {
9558
+ return;
9559
+ }
9560
+ if (parent?.type === "parameter_declaration" && parent.childForFieldName("type") === child) {
9561
+ return;
9562
+ }
9563
+ if (parent?.type === "type_identifier") {
9564
+ return;
9565
+ }
9566
+ const defId = findReachingDef(varName, scopeStack);
9567
+ uses.push({
9568
+ id: uses.length + 1,
9569
+ variable: varName,
9570
+ line: child.startPosition.row + 1,
9571
+ def_id: defId
9572
+ });
9573
+ }
9574
+ });
9575
+ }
9576
+ function findChildByTypeGo(node, type) {
9577
+ for (let i2 = 0; i2 < node.childCount; i2++) {
9578
+ const child = node.child(i2);
9579
+ if (child?.type === type) return child;
9580
+ }
9581
+ return null;
9582
+ }
8973
9583
 
8974
9584
  // src/analysis/config-loader.ts
8975
9585
  function parseConfig(content) {