codegraphcontext-rust 0.5.5__cp311-cp311-win_amd64.whl

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 (101) hide show
  1. codegraphcontext/__init__.py +2 -0
  2. codegraphcontext/__main__.py +5 -0
  3. codegraphcontext/_cgc_rust.cp311-win_amd64.pyd +0 -0
  4. codegraphcontext/cli/__init__.py +1 -0
  5. codegraphcontext/cli/cli_helpers.py +774 -0
  6. codegraphcontext/cli/config_manager.py +1051 -0
  7. codegraphcontext/cli/main.py +2386 -0
  8. codegraphcontext/cli/registry_commands.py +404 -0
  9. codegraphcontext/cli/setup_macos.py +93 -0
  10. codegraphcontext/cli/setup_wizard.py +991 -0
  11. codegraphcontext/cli/visualizer.py +50 -0
  12. codegraphcontext/core/__init__.py +165 -0
  13. codegraphcontext/core/bundle_registry.py +181 -0
  14. codegraphcontext/core/cgc_bundle.py +858 -0
  15. codegraphcontext/core/cgcignore.py +118 -0
  16. codegraphcontext/core/database.py +273 -0
  17. codegraphcontext/core/database_falkordb.py +480 -0
  18. codegraphcontext/core/database_falkordb_remote.py +199 -0
  19. codegraphcontext/core/database_kuzu.py +636 -0
  20. codegraphcontext/core/falkor_worker.py +132 -0
  21. codegraphcontext/core/jobs.py +132 -0
  22. codegraphcontext/core/watcher.py +260 -0
  23. codegraphcontext/prompts.py +125 -0
  24. codegraphcontext/server.py +471 -0
  25. codegraphcontext/tool_definitions.py +220 -0
  26. codegraphcontext/tools/__init__.py +0 -0
  27. codegraphcontext/tools/advanced_language_query_tool.py +103 -0
  28. codegraphcontext/tools/code_finder.py +1160 -0
  29. codegraphcontext/tools/graph_builder.py +337 -0
  30. codegraphcontext/tools/handlers/analysis_handlers.py +114 -0
  31. codegraphcontext/tools/handlers/indexing_handlers.py +116 -0
  32. codegraphcontext/tools/handlers/management_handlers.py +339 -0
  33. codegraphcontext/tools/handlers/query_handlers.py +83 -0
  34. codegraphcontext/tools/handlers/watcher_handlers.py +83 -0
  35. codegraphcontext/tools/indexing/__init__.py +1 -0
  36. codegraphcontext/tools/indexing/constants.py +25 -0
  37. codegraphcontext/tools/indexing/discovery.py +64 -0
  38. codegraphcontext/tools/indexing/engine.py +109 -0
  39. codegraphcontext/tools/indexing/persistence/__init__.py +3 -0
  40. codegraphcontext/tools/indexing/persistence/parquet_loader.py +643 -0
  41. codegraphcontext/tools/indexing/persistence/writer.py +1114 -0
  42. codegraphcontext/tools/indexing/pipeline.py +171 -0
  43. codegraphcontext/tools/indexing/pre_scan.py +105 -0
  44. codegraphcontext/tools/indexing/resolution/__init__.py +8 -0
  45. codegraphcontext/tools/indexing/resolution/calls.py +253 -0
  46. codegraphcontext/tools/indexing/resolution/inheritance.py +91 -0
  47. codegraphcontext/tools/indexing/sanitize.py +41 -0
  48. codegraphcontext/tools/indexing/schema.py +79 -0
  49. codegraphcontext/tools/indexing/schema_contract.py +44 -0
  50. codegraphcontext/tools/indexing/scip_pipeline.py +140 -0
  51. codegraphcontext/tools/languages/c.py +563 -0
  52. codegraphcontext/tools/languages/cpp.py +616 -0
  53. codegraphcontext/tools/languages/csharp.py +551 -0
  54. codegraphcontext/tools/languages/dart.py +378 -0
  55. codegraphcontext/tools/languages/elixir.py +460 -0
  56. codegraphcontext/tools/languages/go.py +499 -0
  57. codegraphcontext/tools/languages/haskell.py +426 -0
  58. codegraphcontext/tools/languages/java.py +500 -0
  59. codegraphcontext/tools/languages/javascript.py +589 -0
  60. codegraphcontext/tools/languages/kotlin.py +640 -0
  61. codegraphcontext/tools/languages/perl.py +260 -0
  62. codegraphcontext/tools/languages/php.py +519 -0
  63. codegraphcontext/tools/languages/python.py +576 -0
  64. codegraphcontext/tools/languages/ruby.py +537 -0
  65. codegraphcontext/tools/languages/rust.py +295 -0
  66. codegraphcontext/tools/languages/scala.py +519 -0
  67. codegraphcontext/tools/languages/swift.py +491 -0
  68. codegraphcontext/tools/languages/typescript.py +575 -0
  69. codegraphcontext/tools/languages/typescriptjsx.py +151 -0
  70. codegraphcontext/tools/package_resolver.py +472 -0
  71. codegraphcontext/tools/query_tool_languages/c_toolkit.py +5 -0
  72. codegraphcontext/tools/query_tool_languages/cpp_toolkit.py +87 -0
  73. codegraphcontext/tools/query_tool_languages/csharp_toolkit.py +5 -0
  74. codegraphcontext/tools/query_tool_languages/dart_toolkit.py +5 -0
  75. codegraphcontext/tools/query_tool_languages/go_toolkit.py +5 -0
  76. codegraphcontext/tools/query_tool_languages/haskell_toolkit.py +5 -0
  77. codegraphcontext/tools/query_tool_languages/java_toolkit.py +5 -0
  78. codegraphcontext/tools/query_tool_languages/javascript_toolkit.py +5 -0
  79. codegraphcontext/tools/query_tool_languages/perl_toolkit.py +5 -0
  80. codegraphcontext/tools/query_tool_languages/python_toolkit.py +5 -0
  81. codegraphcontext/tools/query_tool_languages/ruby_toolkit.py +5 -0
  82. codegraphcontext/tools/query_tool_languages/rust_toolkit.py +5 -0
  83. codegraphcontext/tools/query_tool_languages/scala_toolkit.py +5 -0
  84. codegraphcontext/tools/query_tool_languages/swift_toolkit.py +5 -0
  85. codegraphcontext/tools/query_tool_languages/typescript_toolkit.py +5 -0
  86. codegraphcontext/tools/scip_indexer.py +467 -0
  87. codegraphcontext/tools/scip_pb2.py +2455 -0
  88. codegraphcontext/tools/system.py +133 -0
  89. codegraphcontext/tools/tree_sitter_parser.py +103 -0
  90. codegraphcontext/utils/debug_log.py +90 -0
  91. codegraphcontext/utils/path_ignore.py +55 -0
  92. codegraphcontext/utils/repo_path.py +27 -0
  93. codegraphcontext/utils/tree_sitter_manager.py +285 -0
  94. codegraphcontext/utils/visualize_graph.py +0 -0
  95. codegraphcontext/viz/server.py +282 -0
  96. codegraphcontext_rust-0.5.5.dist-info/METADATA +537 -0
  97. codegraphcontext_rust-0.5.5.dist-info/RECORD +101 -0
  98. codegraphcontext_rust-0.5.5.dist-info/WHEEL +4 -0
  99. codegraphcontext_rust-0.5.5.dist-info/entry_points.txt +3 -0
  100. codegraphcontext_rust-0.5.5.dist-info/licenses/LICENSE +21 -0
  101. codegraphcontext_rust-0.5.5.dist-info/sboms/cgc-python.cyclonedx.json +2333 -0
@@ -0,0 +1,563 @@
1
+ from pathlib import Path
2
+ from typing import Any, Dict, Optional, Tuple
3
+ from codegraphcontext.utils.debug_log import debug_log, info_logger, error_logger, warning_logger
4
+ from codegraphcontext.utils.tree_sitter_manager import execute_query
5
+
6
+ C_QUERIES = {
7
+ "functions": """
8
+ (function_definition
9
+ declarator: (function_declarator
10
+ declarator: (identifier) @name
11
+ )
12
+ ) @function_node
13
+
14
+ (function_definition
15
+ declarator: (function_declarator
16
+ declarator: (pointer_declarator
17
+ declarator: (identifier) @name
18
+ )
19
+ )
20
+ ) @function_node
21
+ """,
22
+ "structs": """
23
+ (struct_specifier
24
+ name: (type_identifier) @name
25
+ ) @struct
26
+ """,
27
+ "unions": """
28
+ (union_specifier
29
+ name: (type_identifier) @name
30
+ ) @union
31
+ """,
32
+ "enums": """
33
+ (enum_specifier
34
+ name: (type_identifier) @name
35
+ ) @enum
36
+ """,
37
+ "typedefs": """
38
+ (type_definition
39
+ declarator: (type_identifier) @name
40
+ ) @typedef
41
+ """,
42
+ "imports": """
43
+ (preproc_include
44
+ path: [
45
+ (string_literal) @path
46
+ (system_lib_string) @path
47
+ ]
48
+ ) @import
49
+ """,
50
+ "calls": """
51
+ (call_expression
52
+ function: (identifier) @name
53
+ )
54
+ """,
55
+ "variables": """
56
+ (declaration
57
+ declarator: (init_declarator
58
+ declarator: (identifier) @name
59
+ )
60
+ )
61
+
62
+ (declaration
63
+ declarator: (init_declarator
64
+ declarator: (pointer_declarator
65
+ declarator: (identifier) @name
66
+ )
67
+ )
68
+ )
69
+
70
+ (declaration
71
+ declarator: (identifier) @name
72
+ )
73
+
74
+ (declaration
75
+ declarator: (pointer_declarator
76
+ declarator: (identifier) @name
77
+ )
78
+ )
79
+ """,
80
+ "macros": """
81
+ (preproc_def
82
+ name: (identifier) @name
83
+ ) @macro
84
+ """,
85
+ }
86
+
87
+ class CTreeSitterParser:
88
+ """A C-specific parser using tree-sitter."""
89
+
90
+ def __init__(self, generic_parser_wrapper: Any):
91
+ self.generic_parser_wrapper = generic_parser_wrapper
92
+ self.language_name = "c"
93
+ self.language = generic_parser_wrapper.language
94
+ self.parser = generic_parser_wrapper.parser
95
+
96
+ def _get_node_text(self, node: Any) -> str:
97
+ return node.text.decode("utf-8")
98
+
99
+ def parse(self, path: Path, is_dependency: bool = False, index_source: bool = False) -> Dict[str, Any]:
100
+ """Parses a C file and returns its structure."""
101
+ self.index_source = index_source
102
+ with open(path, "r", encoding="utf-8", errors="ignore") as f:
103
+ source_code = f.read()
104
+
105
+ tree = self.parser.parse(bytes(source_code, "utf8"))
106
+ root_node = tree.root_node
107
+
108
+ functions = self._find_functions(root_node)
109
+ classes = self._find_structs_unions_enums(root_node)
110
+ imports = self._find_imports(root_node)
111
+ function_calls = self._find_calls(root_node)
112
+ variables = self._find_variables(root_node)
113
+ macros = self._find_macros(root_node)
114
+
115
+ return {
116
+ "path": str(path),
117
+ "functions": functions,
118
+ "classes": classes,
119
+ "variables": variables,
120
+ "imports": imports,
121
+ "function_calls": function_calls,
122
+ "macros": macros,
123
+ "is_dependency": is_dependency,
124
+ "lang": self.language_name,
125
+ }
126
+
127
+ def _get_parent_context(self, node: Any, types: tuple = ('function_definition', 'struct_specifier', 'union_specifier', 'enum_specifier')) -> tuple:
128
+ """Get parent context for nested constructs."""
129
+ curr = node.parent
130
+ while curr:
131
+ if curr.type in types:
132
+ if curr.type == 'function_definition':
133
+ # Traverse declarator to find name and use its line number
134
+ decl = curr.child_by_field_name('declarator')
135
+ while decl:
136
+ if decl.type == 'identifier':
137
+ return self._get_node_text(decl), curr.type, decl.start_point[0] + 1
138
+
139
+ # Handle recursive declarators (function, pointer, array, parenthesized)
140
+ child = decl.child_by_field_name('declarator')
141
+ if child:
142
+ decl = child
143
+ else:
144
+ # Fallback if structure is different
145
+ break
146
+ else:
147
+ name_node = curr.child_by_field_name('name')
148
+ if name_node:
149
+ return self._get_node_text(name_node), curr.type, name_node.start_point[0] + 1
150
+ curr = curr.parent
151
+ return None, None, None
152
+
153
+ def _calculate_complexity(self, node: Any) -> int:
154
+ """Calculate cyclomatic complexity for C functions."""
155
+ complexity_nodes = {
156
+ "if_statement", "for_statement", "while_statement", "do_statement",
157
+ "switch_statement", "case_statement", "conditional_expression",
158
+ "logical_expression", "binary_expression", "goto_statement"
159
+ }
160
+ count = 1
161
+
162
+ def traverse(n):
163
+ nonlocal count
164
+ if n.type in complexity_nodes:
165
+ count += 1
166
+ for child in n.children:
167
+ traverse(child)
168
+
169
+ traverse(node)
170
+ return count
171
+
172
+ def _get_docstring(self, node: Any) -> Optional[str]:
173
+ """Extract comments as documentation."""
174
+ # Look for comments before the node
175
+ if node.parent:
176
+ for child in node.parent.children:
177
+ if child.type == 'comment' and child.start_point[0] < node.start_point[0]:
178
+ return self._get_node_text(child)
179
+ return None
180
+
181
+ def _parse_function_args(self, params_node: Any) -> list[Dict[str, Any]]:
182
+ """Enhanced helper to parse function arguments from a (parameter_list) node."""
183
+ args = []
184
+ if not params_node:
185
+ return args
186
+
187
+ for param in params_node.named_children:
188
+ if param.type == "parameter_declaration":
189
+ arg_info: Dict[str, Any] = {"name": "", "type": None, "is_pointer": False, "is_array": False}
190
+
191
+ # Find the declarator (variable name)
192
+ declarator = param.child_by_field_name("declarator")
193
+ if declarator:
194
+ if declarator.type == "identifier":
195
+ arg_info["name"] = self._get_node_text(declarator)
196
+ elif declarator.type == "pointer_declarator":
197
+ arg_info["is_pointer"] = True
198
+ inner_declarator = declarator.child_by_field_name("declarator")
199
+ if inner_declarator and inner_declarator.type == "identifier":
200
+ arg_info["name"] = self._get_node_text(inner_declarator)
201
+ elif declarator.type == "array_declarator":
202
+ arg_info["is_array"] = True
203
+ inner_declarator = declarator.child_by_field_name("declarator")
204
+ if inner_declarator and inner_declarator.type == "identifier":
205
+ arg_info["name"] = self._get_node_text(inner_declarator)
206
+
207
+ # Find the type
208
+ type_node = param.child_by_field_name("type")
209
+ if type_node:
210
+ arg_info["type"] = self._get_node_text(type_node)
211
+
212
+ # Handle variadic arguments
213
+ if param.type == "variadic_parameter":
214
+ arg_info["name"] = "..."
215
+ arg_info["type"] = "variadic"
216
+
217
+ args.append(arg_info)
218
+ return args
219
+
220
+ def _find_functions(self, root_node: Any) -> list[Dict[str, Any]]:
221
+ functions = []
222
+ query_str = C_QUERIES["functions"]
223
+ for match in execute_query(self.language, query_str, root_node):
224
+ capture_name = match[1]
225
+ node = match[0]
226
+ if capture_name == 'name':
227
+ func_node = node.parent.parent.parent
228
+ name = self._get_node_text(node)
229
+
230
+ # Find parameters
231
+ params_node = None
232
+ body_node = None
233
+ for child in func_node.children:
234
+ if child.type == "function_declarator":
235
+ params_node = child.child_by_field_name("parameters")
236
+ elif child.type == "compound_statement":
237
+ body_node = child
238
+
239
+ args = self._parse_function_args(params_node) if params_node else []
240
+ context, context_type, _ = self._get_parent_context(func_node)
241
+
242
+ func_data = {
243
+ "name": name,
244
+ "line_number": node.start_point[0] + 1,
245
+ "end_line": func_node.end_point[0] + 1,
246
+ "args": [arg["name"] for arg in args if arg["name"]], # Simplified args for compatibility
247
+ "docstring": self._get_docstring(func_node),
248
+ "cyclomatic_complexity": self._calculate_complexity(func_node),
249
+ "context": context,
250
+ "context_type": context_type,
251
+ "class_context": None,
252
+ "decorators": [],
253
+ "lang": self.language_name,
254
+ "is_dependency": False,
255
+ "detailed_args": args, # Keep detailed args for future use
256
+ }
257
+
258
+ if self.index_source:
259
+ func_data["source"] = self._get_node_text(func_node)
260
+
261
+ functions.append(func_data)
262
+ return functions
263
+
264
+ def _find_structs_unions_enums(self, root_node: Any) -> list[Dict[str, Any]]:
265
+ """Find structs, unions, and enums (treated as classes in C)."""
266
+ classes = []
267
+
268
+ # Find structs
269
+ query_str = C_QUERIES["structs"]
270
+ for match in execute_query(self.language, query_str, root_node):
271
+ capture_name = match[1]
272
+ node = match[0]
273
+ if capture_name == 'name':
274
+ struct_node = node.parent
275
+ name = self._get_node_text(node)
276
+ context, context_type, _ = self._get_parent_context(struct_node)
277
+
278
+ struct_data = {
279
+ "name": name,
280
+ "line_number": node.start_point[0] + 1,
281
+ "end_line": struct_node.end_point[0] + 1,
282
+ "bases": [], # C doesn't have inheritance
283
+ "docstring": self._get_docstring(struct_node),
284
+ "context": context,
285
+ "decorators": [],
286
+ "lang": self.language_name,
287
+ "is_dependency": False,
288
+ "type": "struct",
289
+ }
290
+
291
+ if self.index_source:
292
+ struct_data["source"] = self._get_node_text(struct_node)
293
+
294
+ classes.append(struct_data)
295
+
296
+ # Find unions
297
+ query_str = C_QUERIES["unions"]
298
+ for match in execute_query(self.language, query_str, root_node):
299
+ capture_name = match[1]
300
+ node = match[0]
301
+ if capture_name == 'name':
302
+ union_node = node.parent
303
+ name = self._get_node_text(node)
304
+ context, context_type, _ = self._get_parent_context(union_node)
305
+
306
+ union_data = {
307
+ "name": name,
308
+ "line_number": node.start_point[0] + 1,
309
+ "end_line": union_node.end_point[0] + 1,
310
+ "bases": [],
311
+ "docstring": self._get_docstring(union_node),
312
+ "context": context,
313
+ "decorators": [],
314
+ "lang": self.language_name,
315
+ "is_dependency": False,
316
+ "type": "union",
317
+ }
318
+
319
+ if self.index_source:
320
+ union_data["source"] = self._get_node_text(union_node)
321
+
322
+ classes.append(union_data)
323
+
324
+ # Find enums
325
+ query_str = C_QUERIES["enums"]
326
+ for match in execute_query(self.language, query_str, root_node):
327
+ capture_name = match[1]
328
+ node = match[0]
329
+ if capture_name == 'name':
330
+ enum_node = node.parent
331
+ name = self._get_node_text(node)
332
+ context, context_type, _ = self._get_parent_context(enum_node)
333
+
334
+ enum_data = {
335
+ "name": name,
336
+ "line_number": node.start_point[0] + 1,
337
+ "end_line": enum_node.end_point[0] + 1,
338
+ "bases": [],
339
+ "docstring": self._get_docstring(enum_node),
340
+ "context": context,
341
+ "decorators": [],
342
+ "lang": self.language_name,
343
+ "is_dependency": False,
344
+ "type": "enum",
345
+ }
346
+
347
+ if self.index_source:
348
+ enum_data["source"] = self._get_node_text(enum_node)
349
+
350
+ classes.append(enum_data)
351
+
352
+ return classes
353
+
354
+ def _find_imports(self, root_node: Any) -> list[Dict[str, Any]]:
355
+ imports = []
356
+ query_str = C_QUERIES["imports"]
357
+ for match in execute_query(self.language, query_str, root_node):
358
+ capture_name = match[1]
359
+ node = match[0]
360
+ if capture_name == 'path':
361
+ path = self._get_node_text(node).strip('"<>')
362
+ context, context_type, _ = self._get_parent_context(node)
363
+
364
+ imports.append({
365
+ "name": path,
366
+ "full_import_name": path,
367
+ "line_number": node.start_point[0] + 1,
368
+ "alias": None,
369
+ "context": context,
370
+ "lang": self.language_name,
371
+ "is_dependency": False,
372
+ })
373
+ return imports
374
+
375
+ def _find_calls(self, root_node: Any) -> list[Dict[str, Any]]:
376
+ """Enhanced function call detection."""
377
+ calls = []
378
+ query_str = C_QUERIES["calls"]
379
+ for match in execute_query(self.language, query_str, root_node):
380
+ capture_name = match[1]
381
+ node = match[0]
382
+ if capture_name == "name":
383
+ call_node = node.parent if node.parent.type == "call_expression" else node.parent.parent
384
+ call_name = self._get_node_text(node)
385
+
386
+ # Extract arguments
387
+ args = []
388
+ args_node = call_node.child_by_field_name("arguments")
389
+ if args_node:
390
+ for child in args_node.children:
391
+ if child.type not in ['(', ')', ',']:
392
+ args.append(self._get_node_text(child))
393
+
394
+ context_name, context_type, context_line = self._get_parent_context(call_node)
395
+
396
+ # print(f"DEBUG_C_PARSER: Call {call_name} context: {context_name}, {context_type}, {context_line}")
397
+
398
+ calls.append({
399
+ "name": call_name,
400
+ "full_name": call_name, # For C, function name is the same as full name
401
+ "line_number": node.start_point[0] + 1,
402
+ "args": args,
403
+ "inferred_obj_type": None,
404
+ "context": (context_name, context_type, context_line),
405
+ "class_context": None,
406
+ "lang": self.language_name,
407
+ "is_dependency": False,
408
+ })
409
+ return calls
410
+
411
+ def _find_variables(self, root_node: Any) -> list[Dict[str, Any]]:
412
+ """Enhanced variable declaration detection."""
413
+ variables = []
414
+ query_str = C_QUERIES["variables"]
415
+ for match in execute_query(self.language, query_str, root_node):
416
+ capture_name = match[1]
417
+ node = match[0]
418
+ if capture_name == "name":
419
+ var_name = self._get_node_text(node)
420
+
421
+ # Find the declaration node
422
+ decl_node = node.parent
423
+ while decl_node and decl_node.type != "declaration":
424
+ decl_node = decl_node.parent
425
+
426
+ # Extract type information
427
+ var_type = None
428
+ is_pointer = False
429
+ is_array = False
430
+ value = None
431
+
432
+ if decl_node:
433
+ # Find type
434
+ for child in decl_node.children:
435
+ if child.type in ["primitive_type", "type_identifier", "sized_type_specifier"]:
436
+ var_type = self._get_node_text(child)
437
+ elif child.type == "init_declarator":
438
+ # Check for pointer/array
439
+ if child.child_by_field_name("declarator"):
440
+ declarator = child.child_by_field_name("declarator")
441
+ if declarator.type == "pointer_declarator":
442
+ is_pointer = True
443
+ elif declarator.type == "array_declarator":
444
+ is_array = True
445
+
446
+ # Check for initial value
447
+ if child.child_by_field_name("value"):
448
+ value = self._get_node_text(child.child_by_field_name("value"))
449
+
450
+ context, context_type, _ = self._get_parent_context(node)
451
+ class_context, _, _ = self._get_parent_context(node, types=('struct_specifier', 'union_specifier', 'enum_specifier'))
452
+
453
+ variables.append({
454
+ "name": var_name,
455
+ "line_number": node.start_point[0] + 1,
456
+ "value": value,
457
+ "type": var_type,
458
+ "context": context,
459
+ "class_context": class_context,
460
+ "lang": self.language_name,
461
+ "is_dependency": False,
462
+ "is_pointer": is_pointer,
463
+ "is_array": is_array,
464
+ })
465
+ return variables
466
+
467
+ def _find_macros(self, root_node: Any) -> list[Dict[str, Any]]:
468
+ """Enhanced preprocessor macro detection."""
469
+ macros = []
470
+ query_str = C_QUERIES["macros"]
471
+ for match in execute_query(self.language, query_str, root_node):
472
+ capture_name = match[1]
473
+ node = match[0]
474
+ if capture_name == 'name':
475
+ macro_node = node.parent
476
+ name = self._get_node_text(node)
477
+
478
+ # Extract macro value
479
+ value = None
480
+ if macro_node.child_by_field_name("value"):
481
+ value = self._get_node_text(macro_node.child_by_field_name("value"))
482
+
483
+ # Extract parameters for function-like macros
484
+ params = []
485
+ if macro_node.child_by_field_name("parameters"):
486
+ params_node = macro_node.child_by_field_name("parameters")
487
+ for child in params_node.children:
488
+ if child.type == "identifier":
489
+ params.append(self._get_node_text(child))
490
+
491
+ context, context_type, _ = self._get_parent_context(macro_node)
492
+
493
+ macro_data = {
494
+ "name": name,
495
+ "line_number": node.start_point[0] + 1,
496
+ "end_line": macro_node.end_point[0] + 1,
497
+ "value": value,
498
+ "params": params,
499
+ "context": context,
500
+ "lang": self.language_name,
501
+ "is_dependency": False,
502
+ }
503
+
504
+ if self.index_source:
505
+ macro_data["source"] = self._get_node_text(macro_node)
506
+
507
+ macros.append(macro_data)
508
+ return macros
509
+
510
+
511
+ def pre_scan_c(files: list[Path], parser_wrapper) -> dict:
512
+ """Scans C files to create a map of function/struct/union/enum names to their file paths."""
513
+ imports_map = {}
514
+ query_str = """
515
+ (function_definition
516
+ declarator: (function_declarator
517
+ declarator: (identifier) @name
518
+ )
519
+ )
520
+
521
+ (function_definition
522
+ declarator: (function_declarator
523
+ declarator: (pointer_declarator
524
+ declarator: (identifier) @name
525
+ )
526
+ )
527
+ )
528
+
529
+ (struct_specifier
530
+ name: (type_identifier) @name
531
+ )
532
+
533
+ (union_specifier
534
+ name: (type_identifier) @name
535
+ )
536
+
537
+ (enum_specifier
538
+ name: (type_identifier) @name
539
+ )
540
+
541
+ (type_definition
542
+ declarator: (type_identifier) @name
543
+ )
544
+
545
+ (preproc_def
546
+ name: (identifier) @name
547
+ )
548
+ """
549
+
550
+
551
+ for path in files:
552
+ try:
553
+ with open(path, "r", encoding="utf-8", errors="ignore") as f:
554
+ tree = parser_wrapper.parser.parse(bytes(f.read(), "utf8"))
555
+
556
+ for capture, _ in execute_query(parser_wrapper.language, query_str, tree.root_node):
557
+ name = capture.text.decode('utf-8')
558
+ if name not in imports_map:
559
+ imports_map[name] = []
560
+ imports_map[name].append(str(path.resolve()))
561
+ except Exception as e:
562
+ warning_logger(f"Tree-sitter pre-scan failed for {path}: {e}")
563
+ return imports_map