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.
- codegraphcontext/__init__.py +2 -0
- codegraphcontext/__main__.py +5 -0
- codegraphcontext/_cgc_rust.cp311-win_amd64.pyd +0 -0
- codegraphcontext/cli/__init__.py +1 -0
- codegraphcontext/cli/cli_helpers.py +774 -0
- codegraphcontext/cli/config_manager.py +1051 -0
- codegraphcontext/cli/main.py +2386 -0
- codegraphcontext/cli/registry_commands.py +404 -0
- codegraphcontext/cli/setup_macos.py +93 -0
- codegraphcontext/cli/setup_wizard.py +991 -0
- codegraphcontext/cli/visualizer.py +50 -0
- codegraphcontext/core/__init__.py +165 -0
- codegraphcontext/core/bundle_registry.py +181 -0
- codegraphcontext/core/cgc_bundle.py +858 -0
- codegraphcontext/core/cgcignore.py +118 -0
- codegraphcontext/core/database.py +273 -0
- codegraphcontext/core/database_falkordb.py +480 -0
- codegraphcontext/core/database_falkordb_remote.py +199 -0
- codegraphcontext/core/database_kuzu.py +636 -0
- codegraphcontext/core/falkor_worker.py +132 -0
- codegraphcontext/core/jobs.py +132 -0
- codegraphcontext/core/watcher.py +260 -0
- codegraphcontext/prompts.py +125 -0
- codegraphcontext/server.py +471 -0
- codegraphcontext/tool_definitions.py +220 -0
- codegraphcontext/tools/__init__.py +0 -0
- codegraphcontext/tools/advanced_language_query_tool.py +103 -0
- codegraphcontext/tools/code_finder.py +1160 -0
- codegraphcontext/tools/graph_builder.py +337 -0
- codegraphcontext/tools/handlers/analysis_handlers.py +114 -0
- codegraphcontext/tools/handlers/indexing_handlers.py +116 -0
- codegraphcontext/tools/handlers/management_handlers.py +339 -0
- codegraphcontext/tools/handlers/query_handlers.py +83 -0
- codegraphcontext/tools/handlers/watcher_handlers.py +83 -0
- codegraphcontext/tools/indexing/__init__.py +1 -0
- codegraphcontext/tools/indexing/constants.py +25 -0
- codegraphcontext/tools/indexing/discovery.py +64 -0
- codegraphcontext/tools/indexing/engine.py +109 -0
- codegraphcontext/tools/indexing/persistence/__init__.py +3 -0
- codegraphcontext/tools/indexing/persistence/parquet_loader.py +643 -0
- codegraphcontext/tools/indexing/persistence/writer.py +1114 -0
- codegraphcontext/tools/indexing/pipeline.py +171 -0
- codegraphcontext/tools/indexing/pre_scan.py +105 -0
- codegraphcontext/tools/indexing/resolution/__init__.py +8 -0
- codegraphcontext/tools/indexing/resolution/calls.py +253 -0
- codegraphcontext/tools/indexing/resolution/inheritance.py +91 -0
- codegraphcontext/tools/indexing/sanitize.py +41 -0
- codegraphcontext/tools/indexing/schema.py +79 -0
- codegraphcontext/tools/indexing/schema_contract.py +44 -0
- codegraphcontext/tools/indexing/scip_pipeline.py +140 -0
- codegraphcontext/tools/languages/c.py +563 -0
- codegraphcontext/tools/languages/cpp.py +616 -0
- codegraphcontext/tools/languages/csharp.py +551 -0
- codegraphcontext/tools/languages/dart.py +378 -0
- codegraphcontext/tools/languages/elixir.py +460 -0
- codegraphcontext/tools/languages/go.py +499 -0
- codegraphcontext/tools/languages/haskell.py +426 -0
- codegraphcontext/tools/languages/java.py +500 -0
- codegraphcontext/tools/languages/javascript.py +589 -0
- codegraphcontext/tools/languages/kotlin.py +640 -0
- codegraphcontext/tools/languages/perl.py +260 -0
- codegraphcontext/tools/languages/php.py +519 -0
- codegraphcontext/tools/languages/python.py +576 -0
- codegraphcontext/tools/languages/ruby.py +537 -0
- codegraphcontext/tools/languages/rust.py +295 -0
- codegraphcontext/tools/languages/scala.py +519 -0
- codegraphcontext/tools/languages/swift.py +491 -0
- codegraphcontext/tools/languages/typescript.py +575 -0
- codegraphcontext/tools/languages/typescriptjsx.py +151 -0
- codegraphcontext/tools/package_resolver.py +472 -0
- codegraphcontext/tools/query_tool_languages/c_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/cpp_toolkit.py +87 -0
- codegraphcontext/tools/query_tool_languages/csharp_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/dart_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/go_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/haskell_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/java_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/javascript_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/perl_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/python_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/ruby_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/rust_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/scala_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/swift_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/typescript_toolkit.py +5 -0
- codegraphcontext/tools/scip_indexer.py +467 -0
- codegraphcontext/tools/scip_pb2.py +2455 -0
- codegraphcontext/tools/system.py +133 -0
- codegraphcontext/tools/tree_sitter_parser.py +103 -0
- codegraphcontext/utils/debug_log.py +90 -0
- codegraphcontext/utils/path_ignore.py +55 -0
- codegraphcontext/utils/repo_path.py +27 -0
- codegraphcontext/utils/tree_sitter_manager.py +285 -0
- codegraphcontext/utils/visualize_graph.py +0 -0
- codegraphcontext/viz/server.py +282 -0
- codegraphcontext_rust-0.5.5.dist-info/METADATA +537 -0
- codegraphcontext_rust-0.5.5.dist-info/RECORD +101 -0
- codegraphcontext_rust-0.5.5.dist-info/WHEEL +4 -0
- codegraphcontext_rust-0.5.5.dist-info/entry_points.txt +3 -0
- codegraphcontext_rust-0.5.5.dist-info/licenses/LICENSE +21 -0
- 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
|