code_analyze_core/languages/
csharp.rs1use tree_sitter::Node;
5
6pub const ELEMENT_QUERY: &str = r"
9(method_declaration name: (identifier) @method_name) @function
10(constructor_declaration name: (identifier) @ctor_name) @function
11(class_declaration name: (identifier) @class_name) @class
12(interface_declaration name: (identifier) @interface_name) @class
13(record_declaration name: (identifier) @record_name) @class
14";
15
16pub const CALL_QUERY: &str = r"
18(invocation_expression
19 function: (member_access_expression name: (identifier) @call))
20(invocation_expression
21 function: (identifier) @call)
22";
23
24pub const REFERENCE_QUERY: &str = r"
26(base_list (identifier) @type_ref)
27(base_list (generic_name (identifier) @type_ref))
28(type_argument_list (identifier) @type_ref)
29(type_parameter_list (type_parameter (identifier) @type_ref))
30";
31
32pub const IMPORT_QUERY: &str = r"
39(using_directive) @import_path
40";
41
42#[must_use]
47pub fn extract_inheritance(node: &Node, source: &str) -> Vec<String> {
48 let mut bases = Vec::new();
49
50 for i in 0..node.child_count() {
52 if let Some(child) = node.child(u32::try_from(i).unwrap_or(u32::MAX))
53 && child.kind() == "base_list"
54 {
55 bases.extend(extract_base_list(&child, source));
56 break;
57 }
58 }
59
60 bases
61}
62
63fn extract_base_list(node: &Node, source: &str) -> Vec<String> {
65 let mut bases = Vec::new();
66
67 for i in 0..node.named_child_count() {
68 if let Some(child) = node.named_child(u32::try_from(i).unwrap_or(u32::MAX)) {
69 match child.kind() {
70 "identifier" => {
71 let end = child.end_byte();
72 if end <= source.len() {
73 bases.push(source[child.start_byte()..end].to_string());
74 }
75 }
76 "generic_name" => {
77 if let Some(id) = child.named_child(0)
79 && id.kind() == "identifier"
80 {
81 let end = id.end_byte();
82 if end <= source.len() {
83 bases.push(source[id.start_byte()..end].to_string());
84 }
85 }
86 }
87 _ => {}
88 }
89 }
90 }
91
92 bases
93}
94
95#[must_use]
103pub fn find_method_for_receiver(
104 node: &Node,
105 source: &str,
106 _depth: Option<usize>,
107) -> Option<String> {
108 if node.kind() != "method_declaration" && node.kind() != "constructor_declaration" {
109 return None;
110 }
111
112 let mut current = *node;
114 let mut in_type_body = false;
115 while let Some(parent) = current.parent() {
116 match parent.kind() {
117 "class_declaration"
118 | "interface_declaration"
119 | "record_declaration"
120 | "struct_declaration"
121 | "enum_declaration" => {
122 in_type_body = true;
123 break;
124 }
125 _ => {
126 current = parent;
127 }
128 }
129 }
130
131 if !in_type_body {
132 return None;
133 }
134
135 node.child_by_field_name("name").and_then(|n| {
136 let end = n.end_byte();
137 if end <= source.len() {
138 Some(source[n.start_byte()..end].to_string())
139 } else {
140 None
141 }
142 })
143}
144
145#[cfg(all(test, feature = "lang-csharp"))]
146mod tests {
147 use super::*;
148 use tree_sitter::Parser;
149
150 fn parse_csharp(src: &str) -> tree_sitter::Tree {
151 let mut parser = Parser::new();
152 parser
153 .set_language(&tree_sitter_c_sharp::LANGUAGE.into())
154 .expect("Error loading C# language");
155 parser.parse(src, None).expect("Failed to parse C#")
156 }
157
158 #[test]
159 fn test_csharp_method_in_class() {
160 let src = "class Foo { void Bar() { Baz(); } void Baz() {} }";
162 let tree = parse_csharp(src);
163 let root = tree.root_node();
164
165 let mut methods: Vec<String> = Vec::new();
168 let mut stack = vec![root];
169 while let Some(node) = stack.pop() {
170 if node.kind() == "method_declaration" {
171 if let Some(name_node) = node.child_by_field_name("name") {
172 methods.push(src[name_node.start_byte()..name_node.end_byte()].to_string());
173 }
174 }
175 for i in 0..node.child_count() {
176 if let Some(child) = node.child(u32::try_from(i).unwrap_or(u32::MAX)) {
177 stack.push(child);
178 }
179 }
180 }
181 methods.sort();
182
183 assert_eq!(methods, vec!["Bar", "Baz"]);
185 }
186
187 #[test]
188 fn test_csharp_constructor() {
189 let src = "class Foo { public Foo() {} }";
191 let tree = parse_csharp(src);
192 let root = tree.root_node();
193
194 let mut ctors: Vec<String> = Vec::new();
196 let mut stack = vec![root];
197 while let Some(node) = stack.pop() {
198 if node.kind() == "constructor_declaration" {
199 if let Some(name_node) = node.child_by_field_name("name") {
200 ctors.push(src[name_node.start_byte()..name_node.end_byte()].to_string());
201 }
202 }
203 for i in 0..node.child_count() {
204 if let Some(child) = node.child(u32::try_from(i).unwrap_or(u32::MAX)) {
205 stack.push(child);
206 }
207 }
208 }
209
210 assert_eq!(ctors, vec!["Foo"]);
212 }
213
214 #[test]
215 fn test_csharp_interface() {
216 let src = "interface IBar { void Do(); }";
218 let tree = parse_csharp(src);
219 let root = tree.root_node();
220
221 let mut interfaces: Vec<String> = Vec::new();
223 let mut stack = vec![root];
224 while let Some(node) = stack.pop() {
225 if node.kind() == "interface_declaration" {
226 if let Some(name_node) = node.child_by_field_name("name") {
227 interfaces.push(src[name_node.start_byte()..name_node.end_byte()].to_string());
228 }
229 }
230 for i in 0..node.child_count() {
231 if let Some(child) = node.child(u32::try_from(i).unwrap_or(u32::MAX)) {
232 stack.push(child);
233 }
234 }
235 }
236
237 assert_eq!(interfaces, vec!["IBar"]);
239 }
240
241 #[test]
242 fn test_csharp_using_directive() {
243 let src = "using System;";
245 let tree = parse_csharp(src);
246 let root = tree.root_node();
247
248 let mut imports: Vec<String> = Vec::new();
250 let mut stack = vec![root];
251 while let Some(node) = stack.pop() {
252 if node.kind() == "using_directive" {
253 imports.push(src[node.start_byte()..node.end_byte()].to_string());
254 }
255 for i in 0..node.child_count() {
256 if let Some(child) = node.child(u32::try_from(i).unwrap_or(u32::MAX)) {
257 stack.push(child);
258 }
259 }
260 }
261
262 assert_eq!(imports, vec!["using System;"]);
264 }
265
266 #[test]
267 fn test_csharp_async_method() {
268 let src = "class C { async Task Foo() { await Bar(); } Task Bar() { return Task.CompletedTask; } }";
270 let tree = parse_csharp(src);
271 let root = tree.root_node();
272
273 let mut methods: Vec<String> = Vec::new();
275 let mut stack = vec![root];
276 while let Some(node) = stack.pop() {
277 if node.kind() == "method_declaration" {
278 if let Some(name_node) = node.child_by_field_name("name") {
279 methods.push(src[name_node.start_byte()..name_node.end_byte()].to_string());
280 }
281 }
282 for i in 0..node.child_count() {
283 if let Some(child) = node.child(u32::try_from(i).unwrap_or(u32::MAX)) {
284 stack.push(child);
285 }
286 }
287 }
288
289 assert!(methods.contains(&"Foo".to_string()));
291 }
292
293 #[test]
294 fn test_csharp_generic_class() {
295 let src = "class Generic<T> { T value; }";
297 let tree = parse_csharp(src);
298 let root = tree.root_node();
299
300 let mut classes: Vec<String> = Vec::new();
302 let mut stack = vec![root];
303 while let Some(node) = stack.pop() {
304 if node.kind() == "class_declaration" {
305 if let Some(name_node) = node.child_by_field_name("name") {
306 classes.push(src[name_node.start_byte()..name_node.end_byte()].to_string());
307 }
308 }
309 for i in 0..node.child_count() {
310 if let Some(child) = node.child(u32::try_from(i).unwrap_or(u32::MAX)) {
311 stack.push(child);
312 }
313 }
314 }
315
316 assert_eq!(classes, vec!["Generic"]);
318 }
319
320 #[test]
321 fn test_csharp_inheritance_extraction() {
322 let src = "class Dog : Animal, ICanRun {}";
324 let tree = parse_csharp(src);
325 let root = tree.root_node();
326
327 let mut base_list_node: Option<Node> = None;
329 let mut stack = vec![root];
330 while let Some(node) = stack.pop() {
331 if node.kind() == "base_list" {
332 base_list_node = Some(node);
333 break;
334 }
335 for i in 0..node.child_count() {
336 if let Some(child) = node.child(u32::try_from(i).unwrap_or(u32::MAX)) {
337 stack.push(child);
338 }
339 }
340 }
341
342 let mut class_node: Option<Node> = None;
344 let mut stack2 = vec![root];
345 while let Some(node) = stack2.pop() {
346 if node.kind() == "class_declaration" {
347 class_node = Some(node);
348 break;
349 }
350 for i in 0..node.child_count() {
351 if let Some(child) = node.child(u32::try_from(i).unwrap_or(u32::MAX)) {
352 stack2.push(child);
353 }
354 }
355 }
356 let class = class_node.expect("class_declaration not found");
357 let _ = base_list_node; let bases = extract_inheritance(&class, src);
359
360 assert_eq!(bases, vec!["Animal", "ICanRun"]);
362 }
363
364 #[test]
365 fn test_csharp_find_method_for_receiver() {
366 let src = "class MyClass { void MyMethod() {} }";
368 let tree = parse_csharp(src);
369 let root = tree.root_node();
370
371 let mut method_node: Option<Node> = None;
373 let mut stack = vec![root];
374 while let Some(node) = stack.pop() {
375 if node.kind() == "method_declaration" {
376 method_node = Some(node);
377 break;
378 }
379 for i in 0..node.child_count() {
380 if let Some(child) = node.child(u32::try_from(i).unwrap_or(u32::MAX)) {
381 stack.push(child);
382 }
383 }
384 }
385
386 let method = method_node.expect("method_declaration not found");
387 let name = find_method_for_receiver(&method, src, None);
388
389 assert_eq!(name, Some("MyMethod".to_string()));
391 }
392}