context_creator/core/semantic/
query_engine.rs

1//! Tree-sitter query engine for efficient semantic analysis
2//!
3//! This module provides a declarative query-based approach to semantic analysis
4//! using Tree-sitter's query engine, replacing manual AST traversal.
5
6use crate::core::semantic::analyzer::{AnalysisResult, FunctionCall, Import, TypeReference};
7use crate::utils::error::ContextCreatorError;
8use std::collections::HashMap;
9use tree_sitter::{Language, Parser, Query, QueryCursor, Tree};
10
11/// Query engine for semantic analysis using Tree-sitter queries
12pub struct QueryEngine {
13    #[allow(dead_code)]
14    language: Language,
15    #[allow(dead_code)]
16    language_name: String,
17    import_query: Query,
18    function_call_query: Query,
19    type_reference_query: Query,
20}
21
22impl QueryEngine {
23    /// Create a new query engine for the specified language
24    pub fn new(language: Language, language_name: &str) -> Result<Self, ContextCreatorError> {
25        let import_query = Self::create_import_query(language, language_name)?;
26        let function_call_query = Self::create_function_call_query(language, language_name)?;
27        let type_reference_query = Self::create_type_reference_query(language, language_name)?;
28
29        Ok(Self {
30            language,
31            language_name: language_name.to_string(),
32            import_query,
33            function_call_query,
34            type_reference_query,
35        })
36    }
37
38    /// Analyze content using Tree-sitter queries
39    pub fn analyze_with_parser(
40        &self,
41        parser: &mut Parser,
42        content: &str,
43    ) -> Result<AnalysisResult, ContextCreatorError> {
44        // Parse the content
45        let tree = parser.parse(content, None).ok_or_else(|| {
46            ContextCreatorError::ParseError("Failed to parse content".to_string())
47        })?;
48
49        self.analyze_tree(&tree, content)
50    }
51
52    /// Analyze a parsed tree using queries
53    pub fn analyze_tree(
54        &self,
55        tree: &Tree,
56        content: &str,
57    ) -> Result<AnalysisResult, ContextCreatorError> {
58        let mut result = AnalysisResult::default();
59        let mut query_cursor = QueryCursor::new();
60        let root_node = tree.root_node();
61
62        // Execute import query
63        let import_matches =
64            query_cursor.matches(&self.import_query, root_node, content.as_bytes());
65        result.imports = self.extract_imports(import_matches, content)?;
66
67        // Execute function call query
68        let call_matches =
69            query_cursor.matches(&self.function_call_query, root_node, content.as_bytes());
70        result.function_calls = self.extract_function_calls(call_matches, content)?;
71
72        // Execute type reference query
73        let type_matches =
74            query_cursor.matches(&self.type_reference_query, root_node, content.as_bytes());
75        result.type_references = self.extract_type_references(type_matches, content)?;
76
77        Ok(result)
78    }
79
80    /// Create import query for the specified language
81    fn create_import_query(
82        language: Language,
83        language_name: &str,
84    ) -> Result<Query, ContextCreatorError> {
85        let query_text = match language_name {
86            "rust" => {
87                r#"
88                ; Use declarations
89                (use_declaration) @rust_import
90
91                ; Module declarations  
92                (mod_item
93                  name: (identifier) @mod_name
94                ) @rust_module
95
96                ; Extern crate declarations
97                (extern_crate_declaration
98                  name: (identifier) @crate_name
99                ) @extern_crate
100            "#
101            }
102            "python" => {
103                r#"
104                ; Simple import statements (import os, import sys)
105                (import_statement
106                  (dotted_name) @module_name
107                ) @simple_import
108
109                ; From import statements with absolute modules (from pathlib import Path)
110                (import_from_statement
111                  module_name: (dotted_name) @from_module
112                  (dotted_name) @import_item
113                ) @from_import
114                
115                ; From import with aliased imports  
116                (import_from_statement
117                  module_name: (dotted_name) @from_module
118                  (aliased_import
119                    name: (dotted_name) @import_item
120                  )
121                ) @from_import_aliased
122
123                ; Relative from imports (from . import utils, from ..lib import helper)
124                (import_from_statement
125                  module_name: (relative_import) @relative_module
126                  (dotted_name) @import_item
127                ) @relative_from_import
128
129                ; Relative from imports with aliased imports
130                (import_from_statement
131                  module_name: (relative_import) @relative_module
132                  (aliased_import
133                    name: (dotted_name) @import_item
134                  )
135                ) @relative_from_import_aliased
136            "#
137            }
138            "javascript" => {
139                r#"
140                ; Import declarations
141                (import_statement
142                  (import_clause
143                    [
144                      (identifier) @import_name
145                      (namespace_import (identifier) @import_name)
146                      (named_imports
147                        (import_specifier
148                          [
149                            (identifier) @import_name
150                            name: (identifier) @import_name
151                          ]
152                        )
153                      )
154                    ]
155                  )?
156                  source: (string) @module_path
157                ) @js_import
158
159                ; Require calls (CommonJS)
160                (call_expression
161                  function: (identifier) @require_fn (#eq? @require_fn "require")
162                  arguments: (arguments (string) @module_path)
163                ) @require
164            "#
165            }
166            "typescript" => {
167                r#"
168                ; Import declarations
169                (import_statement
170                  (import_clause
171                    [
172                      (identifier) @import_name
173                      (namespace_import (identifier) @import_name)
174                      (named_imports
175                        (import_specifier
176                          [
177                            (identifier) @import_name
178                            name: (identifier) @import_name
179                          ]
180                        )
181                      )
182                    ]
183                  )?
184                  source: (string) @module_path
185                ) @ts_import
186
187                ; Require calls (CommonJS)
188                (call_expression
189                  function: (identifier) @require_fn (#eq? @require_fn "require")
190                  arguments: (arguments (string) @module_path)
191                ) @require
192            "#
193            }
194            _ => {
195                return Err(ContextCreatorError::ParseError(format!(
196                    "Unsupported language for import queries: {language_name}"
197                )))
198            }
199        };
200
201        Query::new(language, query_text).map_err(|e| {
202            ContextCreatorError::ParseError(format!("Failed to create import query: {e}"))
203        })
204    }
205
206    /// Create function call query for the specified language
207    fn create_function_call_query(
208        language: Language,
209        language_name: &str,
210    ) -> Result<Query, ContextCreatorError> {
211        let query_text = match language_name {
212            "rust" => {
213                r#"
214                ; Simple function calls (helper)
215                (call_expression
216                  function: (identifier) @fn_name
217                ) @call
218
219                ; Scoped function calls (lib::greet)
220                (call_expression
221                  function: (scoped_identifier
222                    path: (identifier) @module_name
223                    name: (identifier) @fn_name
224                  )
225                ) @scoped_call
226
227                ; Nested scoped function calls (lib::User::new)
228                (call_expression
229                  function: (scoped_identifier
230                    path: (scoped_identifier
231                      path: (identifier) @module_name
232                      name: (identifier) @type_name
233                    )
234                    name: (identifier) @fn_name
235                  )
236                ) @nested_scoped_call
237
238                ; Method calls (obj.method())
239                (call_expression
240                  function: (field_expression
241                    field: (field_identifier) @method_name
242                  )
243                ) @method_call
244
245                ; Macro calls (println!)
246                (macro_invocation
247                  macro: (identifier) @macro_name
248                ) @macro_call
249            "#
250            }
251            "python" => {
252                r#"
253                ; Simple function calls (print, len)
254                (call
255                  function: (identifier) @fn_name
256                ) @call
257
258                ; Module attribute calls (os.path, module.func)
259                (call
260                  function: (attribute
261                    object: (identifier) @module_name
262                    attribute: (identifier) @fn_name
263                  )
264                ) @module_call
265
266                ; Nested attribute calls (os.path.join)
267                (call
268                  function: (attribute
269                    attribute: (identifier) @fn_name
270                  )
271                ) @nested_call
272            "#
273            }
274            "javascript" => {
275                r#"
276                ; Function calls
277                (call_expression
278                  function: [
279                    (identifier) @fn_name
280                    (member_expression
281                      object: (identifier) @module_name
282                      property: (property_identifier) @fn_name
283                    )
284                  ]
285                ) @call
286            "#
287            }
288            "typescript" => {
289                r#"
290                ; Function calls
291                (call_expression
292                  function: [
293                    (identifier) @fn_name
294                    (member_expression
295                      object: (identifier) @module_name
296                      property: (property_identifier) @fn_name
297                    )
298                  ]
299                ) @call
300            "#
301            }
302            _ => {
303                return Err(ContextCreatorError::ParseError(format!(
304                    "Unsupported language for function call queries: {language_name}"
305                )))
306            }
307        };
308
309        Query::new(language, query_text).map_err(|e| {
310            ContextCreatorError::ParseError(format!("Failed to create function call query: {e}"))
311        })
312    }
313
314    /// Create type reference query for the specified language
315    fn create_type_reference_query(
316        language: Language,
317        language_name: &str,
318    ) -> Result<Query, ContextCreatorError> {
319        let query_text = match language_name {
320            "rust" => {
321                r#"
322                ; Type identifiers (excluding definitions)
323                (type_identifier) @type_name
324                (#not-match? @type_name "^(i8|i16|i32|i64|i128|u8|u16|u32|u64|u128|f32|f64|bool|char|str|String|Vec|Option|Result)$")
325
326                ; Generic types
327                (generic_type
328                  type: (type_identifier) @type_name
329                )
330
331                ; Scoped type identifiers
332                (scoped_type_identifier
333                  path: (identifier) @module_name
334                  name: (type_identifier) @type_name
335                )
336
337                ; Types in function parameters
338                (parameter
339                  type: [
340                    (type_identifier) @param_type
341                    (generic_type type: (type_identifier) @param_type)
342                    (reference_type type: (type_identifier) @param_type)
343                  ]
344                )
345
346                ; Return types
347                (function_item
348                  return_type: [
349                    (type_identifier) @return_type
350                    (generic_type type: (type_identifier) @return_type)
351                    (reference_type type: (type_identifier) @return_type)
352                  ]
353                )
354
355                ; Field types in structs
356                (field_declaration
357                  type: [
358                    (type_identifier) @field_type
359                    (generic_type type: (type_identifier) @field_type)
360                    (reference_type type: (type_identifier) @field_type)
361                  ]
362                )
363
364                ; Trait bounds
365                (trait_bounds
366                  (type_identifier) @trait_name
367                )
368
369                ; Types in use statements (traits and types)
370                (use_declaration
371                  (scoped_identifier
372                    name: (identifier) @imported_type
373                  )
374                )
375                (#match? @imported_type "^[A-Z]")
376            "#
377            }
378            "python" => {
379                r#"
380                ; Type identifiers in type positions
381                (type (identifier) @type_name)
382
383                ; Function parameter type annotations 
384                (typed_parameter (identifier) @param_type)
385
386                ; Class inheritance 
387                (class_definition
388                  superclasses: (argument_list (identifier) @parent_class)
389                )
390
391                ; Generic/subscript type references
392                (subscript (identifier) @subscript_type)
393            "#
394            }
395            "javascript" => {
396                r#"
397                ; JSX element types (React components)
398                (jsx_element
399                  open_tag: (jsx_opening_element
400                    name: (identifier) @jsx_type
401                  )
402                )
403                (#match? @jsx_type "^[A-Z]")
404
405                ; JSX self-closing elements
406                (jsx_self_closing_element
407                  name: (identifier) @jsx_type
408                )
409                (#match? @jsx_type "^[A-Z]")
410            "#
411            }
412            "typescript" => {
413                r#"
414                ; Type annotations
415                (type_annotation
416                  (type_identifier) @type_name
417                )
418
419                ; Predefined type annotations (void, any, etc.)
420                (type_annotation
421                  (predefined_type) @type_name
422                )
423
424                ; Generic type arguments
425                (type_arguments
426                  (type_identifier) @type_arg
427                )
428
429                ; Interface declarations
430                (interface_declaration
431                  name: (type_identifier) @interface_name
432                )
433
434                ; Type aliases
435                (type_alias_declaration
436                  name: (type_identifier) @type_alias
437                )
438            "#
439            }
440            _ => {
441                return Err(ContextCreatorError::ParseError(format!(
442                    "Unsupported language for type queries: {language_name}"
443                )))
444            }
445        };
446
447        Query::new(language, query_text).map_err(|e| {
448            ContextCreatorError::ParseError(format!("Failed to create type reference query: {e}"))
449        })
450    }
451
452    /// Extract imports from query matches
453    fn extract_imports<'a>(
454        &self,
455        matches: tree_sitter::QueryMatches<'a, 'a, &'a [u8]>,
456        content: &str,
457    ) -> Result<Vec<Import>, ContextCreatorError> {
458        let mut imports = Vec::new();
459        let import_query_captures = self.import_query.capture_names();
460
461        for match_ in matches {
462            let mut module = String::new();
463            let mut items = Vec::new();
464            let mut is_relative = false;
465            let mut line = 0;
466
467            for capture in match_.captures {
468                let capture_name = &import_query_captures[capture.index as usize];
469                let node = capture.node;
470                line = node.start_position().row + 1;
471
472                match capture_name.as_str() {
473                    "rust_import" => {
474                        // Parse Rust use declaration
475                        let (parsed_module, parsed_items, is_rel) =
476                            self.parse_rust_use_declaration(node, content);
477                        module = parsed_module;
478                        items = parsed_items;
479                        is_relative = is_rel;
480                    }
481                    "js_import" | "ts_import" => {
482                        // For JavaScript/TypeScript, we rely on module_path and import_name captures
483                        // The module and items will be set by those specific captures
484                    }
485                    "simple_import" => {
486                        // Python simple import statement
487                    }
488                    "from_import" | "from_import_aliased" => {
489                        // Python from import statement
490                    }
491                    "relative_from_import" | "relative_from_import_aliased" => {
492                        // Python relative from import statement
493                        is_relative = true;
494                    }
495                    "rust_module" => {
496                        // Parse module declaration (mod item)
497                        let (parsed_module, parsed_items, is_rel) =
498                            self.parse_rust_module_declaration(node, content);
499                        module = parsed_module;
500                        items = parsed_items;
501                        is_relative = is_rel;
502                    }
503                    "mod_name" | "crate_name" => {
504                        if let Ok(name) = node.utf8_text(content.as_bytes()) {
505                            // Only set module if it's not already set by the full module parsing
506                            if module.is_empty() {
507                                module = name.to_string();
508                                is_relative = capture_name == "mod_name";
509                            }
510                        }
511                    }
512                    "module_name" => {
513                        // For Python simple imports and Rust/JS module paths
514                        if let Ok(name) = node.utf8_text(content.as_bytes()) {
515                            module = name.trim_matches('"').to_string();
516                        }
517                    }
518                    "from_module" => {
519                        // For Python from imports
520                        if let Ok(name) = node.utf8_text(content.as_bytes()) {
521                            module = name.to_string();
522                        }
523                    }
524                    "relative_module" => {
525                        // For Python relative imports (. or ..lib)
526                        if let Ok(name) = node.utf8_text(content.as_bytes()) {
527                            module = name.to_string();
528                            is_relative = true;
529                        }
530                    }
531                    "import_name" | "import_item" => {
532                        if let Ok(name) = node.utf8_text(content.as_bytes()) {
533                            items.push(name.to_string());
534                        }
535                    }
536                    "module_path" => {
537                        if let Ok(name) = node.utf8_text(content.as_bytes()) {
538                            module = name.trim_matches('"').trim_matches('\'').to_string();
539                            // Check if it's a relative import for JavaScript/TypeScript
540                            if module.starts_with('.') {
541                                is_relative = true;
542                            }
543                        }
544                    }
545                    _ => {}
546                }
547            }
548
549            if !module.is_empty() || !items.is_empty() {
550                // Security check: validate the module path before adding
551                if self.is_secure_import(&module) {
552                    imports.push(Import {
553                        module,
554                        items,
555                        is_relative,
556                        line,
557                    });
558                } else {
559                    // Log dangerous imports but don't include them
560                    eprintln!("Warning: Blocked potentially dangerous import: {module}");
561                }
562            }
563        }
564
565        Ok(imports)
566    }
567
568    /// Extract function calls from query matches
569    fn extract_function_calls<'a>(
570        &self,
571        matches: tree_sitter::QueryMatches<'a, 'a, &'a [u8]>,
572        content: &str,
573    ) -> Result<Vec<FunctionCall>, ContextCreatorError> {
574        let mut calls = Vec::new();
575        let call_query_captures = self.function_call_query.capture_names();
576
577        for match_ in matches {
578            let mut name = String::new();
579            let mut module = None;
580            let mut line = 0;
581            let mut module_name = String::new();
582            let mut type_name = String::new();
583
584            for capture in match_.captures {
585                let capture_name = &call_query_captures[capture.index as usize];
586                let node = capture.node;
587                line = node.start_position().row + 1;
588
589                match capture_name.as_str() {
590                    "fn_name" | "method_name" => {
591                        if let Ok(fn_name) = node.utf8_text(content.as_bytes()) {
592                            name = fn_name.to_string();
593                        }
594                    }
595                    "module_name" => {
596                        if let Ok(mod_name) = node.utf8_text(content.as_bytes()) {
597                            module_name = mod_name.to_string();
598                            module = Some(mod_name.to_string());
599                        }
600                    }
601                    "type_name" => {
602                        if let Ok(type_name_str) = node.utf8_text(content.as_bytes()) {
603                            type_name = type_name_str.to_string();
604                        }
605                    }
606                    "macro_name" => {
607                        if let Ok(macro_name) = node.utf8_text(content.as_bytes()) {
608                            name = macro_name.to_string();
609                        }
610                    }
611                    _ => {}
612                }
613            }
614
615            // Handle nested scoped calls (lib::User::new)
616            if !module_name.is_empty() && !type_name.is_empty() {
617                module = Some(format!("{module_name}::{type_name}"));
618            }
619
620            if !name.is_empty() {
621                calls.push(FunctionCall { name, module, line });
622            }
623        }
624
625        Ok(calls)
626    }
627
628    /// Extract type references from query matches
629    fn extract_type_references<'a>(
630        &self,
631        matches: tree_sitter::QueryMatches<'a, 'a, &'a [u8]>,
632        content: &str,
633    ) -> Result<Vec<TypeReference>, ContextCreatorError> {
634        let mut type_refs = Vec::new();
635        let type_query_captures = self.type_reference_query.capture_names();
636
637        for match_ in matches {
638            let mut names = HashMap::new();
639            let mut module = None;
640            let mut line = 0;
641
642            for capture in match_.captures {
643                let capture_name = &type_query_captures[capture.index as usize];
644                let node = capture.node;
645                line = node.start_position().row + 1;
646
647                if let Ok(text) = node.utf8_text(content.as_bytes()) {
648                    match capture_name.as_str() {
649                        "type_name" | "param_type" | "return_type" | "field_type"
650                        | "trait_name" | "imported_type" | "interface_name" | "type_alias"
651                        | "jsx_type" | "parent_class" | "type_arg" | "base_type"
652                        | "subscript_type" => {
653                            names.insert(capture_name.to_string(), text.to_string());
654                        }
655                        "module_name" => {
656                            module = Some(text.to_string());
657                        }
658                        _ => {}
659                    }
660                }
661            }
662
663            // Create type references for each captured type name
664            for (_, type_name) in names {
665                // Skip built-in types and primitives
666                if self.is_builtin_type(&type_name) {
667                    continue;
668                }
669
670                type_refs.push(TypeReference {
671                    name: type_name.clone(),
672                    module: module.clone(),
673                    line,
674                    definition_path: None,
675                    is_external: false,
676                    external_package: None,
677                });
678            }
679        }
680
681        Ok(type_refs)
682    }
683
684    /// Resolve type definitions for type references
685    /// This method attempts to find the file that defines each type
686    pub fn resolve_type_definitions(
687        &self,
688        type_refs: &mut [TypeReference],
689        current_file: &std::path::Path,
690        project_root: &std::path::Path,
691    ) -> Result<(), ContextCreatorError> {
692        use crate::core::semantic::path_validator::validate_import_path;
693
694        for type_ref in type_refs.iter_mut() {
695            // Skip if already resolved or is external
696            if type_ref.definition_path.is_some() || type_ref.is_external {
697                continue;
698            }
699
700            // Try to resolve the type definition
701            if let Some(def_path) = self.find_type_definition(
702                &type_ref.name,
703                type_ref.module.as_deref(),
704                current_file,
705                project_root,
706            )? {
707                // Validate the path for security
708                match validate_import_path(project_root, &def_path) {
709                    Ok(validated_path) => {
710                        type_ref.definition_path = Some(validated_path);
711                    }
712                    Err(_) => {
713                        // Path validation failed, mark as external for safety
714                        type_ref.is_external = true;
715                    }
716                }
717            }
718        }
719
720        Ok(())
721    }
722
723    /// Find the definition file for a given type
724    fn find_type_definition(
725        &self,
726        type_name: &str,
727        module_name: Option<&str>,
728        current_file: &std::path::Path,
729        project_root: &std::path::Path,
730    ) -> Result<Option<std::path::PathBuf>, ContextCreatorError> {
731        use std::fs;
732
733        // Get the directory of the current file
734        let current_dir = current_file.parent().unwrap_or(project_root);
735
736        // Convert type name to lowercase for file matching
737        let type_name_lower = type_name.to_lowercase();
738
739        // Get file extensions based on current file
740        let extensions = self.get_search_extensions(current_file);
741
742        // Build search patterns
743        let mut patterns = vec![
744            // Direct file name matches
745            format!("{type_name_lower}.{}", extensions[0]),
746            // Types files
747            format!("types.{}", extensions[0]),
748            // Module files
749            format!("mod.{}", extensions[0]),
750            format!("index.{}", extensions[0]),
751            // Common type definition patterns
752            format!("{type_name_lower}_types.{}", extensions[0]),
753            format!("{type_name_lower}_type.{}", extensions[0]),
754            format!("{type_name_lower}s.{}", extensions[0]), // plural form
755        ];
756
757        // Add patterns for all supported extensions
758        for ext in &extensions[1..] {
759            patterns.push(format!("{type_name_lower}.{ext}"));
760            patterns.push(format!("types.{ext}"));
761            patterns.push(format!("index.{ext}"));
762        }
763
764        // If we have a module name, add module-based patterns
765        if let Some(module) = module_name {
766            // Handle Rust module paths like "crate::models::User"
767            if module.starts_with("crate::") {
768                let relative_path = module.strip_prefix("crate::").unwrap();
769                let path_parts: Vec<&str> = relative_path.split("::").collect();
770
771                if path_parts.len() > 1 {
772                    // Convert module path to file path
773                    // crate::models::User -> models/user.rs
774                    let module_path = path_parts[..path_parts.len() - 1].join("/");
775                    let type_name_lower = path_parts.last().unwrap().to_lowercase();
776
777                    for ext in &extensions {
778                        patterns.insert(0, format!("{module_path}/{type_name_lower}.{ext}"));
779                        patterns.insert(1, format!("{module_path}/mod.{ext}"));
780                    }
781                }
782            } else if module.contains("::") {
783                // Handle other module paths like "shared::types::ApiResponse"
784                let path_parts: Vec<&str> = module.split("::").collect();
785
786                if path_parts.len() > 1 {
787                    // Convert module path to file path
788                    // shared::types::ApiResponse -> shared/types/mod.rs
789                    let module_path = path_parts[..path_parts.len() - 1].join("/");
790                    let type_name_lower = path_parts.last().unwrap().to_lowercase();
791
792                    for ext in &extensions {
793                        patterns.insert(0, format!("{module_path}/{type_name_lower}.{ext}"));
794                        patterns.insert(1, format!("{module_path}/mod.{ext}"));
795                    }
796                }
797            } else {
798                // Handle simple module names
799                let module_lower = module.to_lowercase();
800                for ext in &extensions {
801                    patterns.insert(0, format!("{module_lower}.{ext}"));
802                    patterns.insert(1, format!("{module}.{ext}")); // Also try original case
803                }
804            }
805        }
806
807        // Search directories in priority order
808        let mut search_dirs = vec![
809            project_root.join("src"), // Start with project root src for crate:: paths
810            project_root.to_path_buf(),
811            current_dir.to_path_buf(),
812        ];
813
814        // Add parent directory if it exists
815        if let Some(parent_dir) = current_dir.parent() {
816            search_dirs.push(parent_dir.to_path_buf());
817        }
818
819        // Add common project directories
820        search_dirs.extend(vec![
821            project_root.join("src/models"),
822            project_root.join("src/types"),
823            project_root.join("shared"),
824            project_root.join("shared/types"),
825            project_root.join("lib"),
826            project_root.join("domain"),
827            current_dir.join("models"),
828            current_dir.join("types"),
829        ]);
830
831        for search_dir in search_dirs {
832            if !search_dir.exists() {
833                continue;
834            }
835
836            for pattern in &patterns {
837                let candidate = search_dir.join(pattern);
838                if candidate.exists() {
839                    // Read the file to verify it contains the type definition
840                    if let Ok(content) = fs::read_to_string(&candidate) {
841                        if self.file_contains_definition(&candidate, &content, type_name)? {
842                            return Ok(Some(candidate));
843                        }
844                    }
845                }
846            }
847        }
848
849        Ok(None)
850    }
851
852    /// Check if a file contains a definition for a given type name using AST parsing
853    fn file_contains_definition(
854        &self,
855        path: &std::path::Path,
856        content: &str,
857        type_name: &str,
858    ) -> Result<bool, ContextCreatorError> {
859        // Determine the language from the file extension
860        let language = match path.extension().and_then(|s| s.to_str()) {
861            Some("rs") => Some(tree_sitter_rust::language()),
862            Some("py") => Some(tree_sitter_python::language()),
863            Some("ts") | Some("tsx") => Some(tree_sitter_typescript::language_typescript()),
864            Some("js") | Some("jsx") => Some(tree_sitter_javascript::language()),
865            _ => None,
866        };
867
868        if let Some(language) = language {
869            let mut parser = tree_sitter::Parser::new();
870            if parser.set_language(language).is_err() {
871                return Ok(false);
872            }
873
874            if let Some(tree) = parser.parse(content, None) {
875                // Language-specific queries for type definitions
876                let query_text = match path.extension().and_then(|s| s.to_str()) {
877                    Some("rs") => {
878                        r#"
879                        [
880                          (struct_item name: (type_identifier) @name)
881                          (enum_item name: (type_identifier) @name)
882                          (trait_item name: (type_identifier) @name)
883                          (type_item name: (type_identifier) @name)
884                          (union_item name: (type_identifier) @name)
885                        ]
886                    "#
887                    }
888                    Some("py") => {
889                        r#"
890                        [
891                          (class_definition name: (identifier) @name)
892                          (function_definition name: (identifier) @name)
893                        ]
894                    "#
895                    }
896                    Some("ts") | Some("tsx") => {
897                        r#"
898                        [
899                          (interface_declaration name: (type_identifier) @name)
900                          (type_alias_declaration name: (type_identifier) @name)
901                          (class_declaration name: (type_identifier) @name)
902                          (enum_declaration name: (identifier) @name)
903                        ]
904                    "#
905                    }
906                    Some("js") | Some("jsx") => {
907                        r#"
908                        [
909                          (class_declaration name: (identifier) @name)
910                          (function_declaration name: (identifier) @name)
911                        ]
912                    "#
913                    }
914                    _ => return Ok(false),
915                };
916
917                if let Ok(query) = tree_sitter::Query::new(language, query_text) {
918                    let mut cursor = tree_sitter::QueryCursor::new();
919                    let matches = cursor.matches(&query, tree.root_node(), content.as_bytes());
920
921                    // Check each match to see if the captured name matches our target type
922                    for m in matches {
923                        for capture in m.captures {
924                            if let Ok(captured_text) = capture.node.utf8_text(content.as_bytes()) {
925                                if captured_text == type_name {
926                                    return Ok(true);
927                                }
928                            }
929                        }
930                    }
931                }
932            }
933        }
934
935        Ok(false)
936    }
937
938    /// Get appropriate file extensions for searching based on current file
939    fn get_search_extensions(&self, current_file: &std::path::Path) -> Vec<&'static str> {
940        match current_file.extension().and_then(|s| s.to_str()) {
941            Some("rs") => vec!["rs"],
942            Some("py") => vec!["py"],
943            Some("ts") | Some("tsx") => vec!["ts", "tsx", "js", "jsx"],
944            Some("js") | Some("jsx") => vec!["js", "jsx", "ts", "tsx"],
945            _ => vec!["rs", "py", "ts", "js"], // Default fallback
946        }
947    }
948
949    /// Parse Rust use tree structure
950    #[allow(dead_code)]
951    fn parse_rust_use_tree(
952        &self,
953        node: tree_sitter::Node,
954        content: &str,
955    ) -> (String, Vec<String>, bool) {
956        // Implementation would recursively parse the use tree structure
957        // For now, simplified implementation
958        if let Ok(text) = node.utf8_text(content.as_bytes()) {
959            let is_relative =
960                text.contains("self::") || text.contains("super::") || text.contains("crate::");
961            (text.to_string(), Vec::new(), is_relative)
962        } else {
963            (String::new(), Vec::new(), false)
964        }
965    }
966
967    /// Parse Rust module declaration structure
968    fn parse_rust_module_declaration(
969        &self,
970        node: tree_sitter::Node,
971        content: &str,
972    ) -> (String, Vec<String>, bool) {
973        // Parse module declaration like "mod config;"
974        if let Ok(text) = node.utf8_text(content.as_bytes()) {
975            // Look for the module name after "mod"
976            if let Some(mod_start) = text.find("mod ") {
977                let after_mod = &text[mod_start + 4..];
978                if let Some(end_pos) = after_mod.find(';') {
979                    let module_name = after_mod[..end_pos].trim();
980                    return (module_name.to_string(), Vec::new(), true);
981                } else if let Some(end_pos) = after_mod.find(' ') {
982                    let module_name = after_mod[..end_pos].trim();
983                    return (module_name.to_string(), Vec::new(), true);
984                }
985            }
986        }
987        (String::new(), Vec::new(), false)
988    }
989
990    /// Parse Rust use declaration structure
991    fn parse_rust_use_declaration(
992        &self,
993        node: tree_sitter::Node,
994        content: &str,
995    ) -> (String, Vec<String>, bool) {
996        // Parse the entire use declaration
997        if let Ok(text) = node.utf8_text(content.as_bytes()) {
998            // Extract module path and imported items from use declaration
999            // Example: "use model::{Account, DatabaseFactory, Rule};"
1000            let clean_text = text
1001                .trim()
1002                .trim_start_matches("use ")
1003                .trim_end_matches(';')
1004                .trim();
1005
1006            let is_relative = clean_text.contains("self::")
1007                || clean_text.contains("super::")
1008                || clean_text.contains("crate::");
1009
1010            if clean_text.contains('{') && clean_text.contains('}') {
1011                // Handle scoped imports like "model::{Account, DatabaseFactory}"
1012                if let Some(colon_pos) = clean_text.find("::") {
1013                    let module = clean_text[..colon_pos].to_string();
1014
1015                    // Extract items from braces
1016                    if let Some(start) = clean_text.find('{') {
1017                        if let Some(end) = clean_text.find('}') {
1018                            let items_str = &clean_text[start + 1..end];
1019                            let items: Vec<String> = items_str
1020                                .split(',')
1021                                .map(|s| s.trim().to_string())
1022                                .filter(|s| !s.is_empty())
1023                                .collect();
1024                            return (module, items, is_relative);
1025                        }
1026                    }
1027                }
1028            } else {
1029                // Handle simple imports like "use std::collections::HashMap;"
1030                return (clean_text.to_string(), Vec::new(), is_relative);
1031            }
1032
1033            (clean_text.to_string(), Vec::new(), is_relative)
1034        } else {
1035            (String::new(), Vec::new(), false)
1036        }
1037    }
1038
1039    /// Check if an import is secure (doesn't attempt path traversal or system access)
1040    fn is_secure_import(&self, module: &str) -> bool {
1041        // Reject empty modules
1042        if module.is_empty() {
1043            return false;
1044        }
1045
1046        // Check for absolute paths that could be system paths
1047        if module.starts_with('/') {
1048            // Unix absolute paths like /etc/passwd
1049            if module.contains("/etc/") || module.contains("/sys/") || module.contains("/proc/") {
1050                return false;
1051            }
1052        }
1053
1054        // Check for Windows absolute paths
1055        if module.len() >= 2 && module.chars().nth(1) == Some(':') {
1056            // Windows paths like C:\Windows\System32
1057            if module.to_lowercase().contains("windows")
1058                || module.to_lowercase().contains("system32")
1059            {
1060                return false;
1061            }
1062        }
1063
1064        // Check for excessive path traversal
1065        let dot_dot_count = module.matches("..").count();
1066        if dot_dot_count > 3 {
1067            // More than 3 levels of .. is suspicious
1068            return false;
1069        }
1070
1071        // Check for known dangerous patterns
1072        let dangerous_patterns = [
1073            "/etc/passwd",
1074            "/etc/shadow",
1075            "/root/",
1076            "C:\\Windows\\",
1077            "C:\\System32\\",
1078            "../../../../etc/",
1079            "..\\..\\..\\..\\windows\\",
1080            "file:///",
1081            "~/../../../",
1082            "%USERPROFILE%",
1083            "$HOME/../../../",
1084        ];
1085
1086        for pattern in &dangerous_patterns {
1087            if module.contains(pattern) {
1088                return false;
1089            }
1090        }
1091
1092        // Check for suspicious characters that might indicate injection
1093        if module.contains('\0') || module.contains('\x00') {
1094            return false;
1095        }
1096
1097        // Allow the import if it passes all checks
1098        true
1099    }
1100
1101    /// Check if a type name is a built-in type
1102    fn is_builtin_type(&self, type_name: &str) -> bool {
1103        matches!(
1104            type_name,
1105            "i8" | "i16"
1106                | "i32"
1107                | "i64"
1108                | "i128"
1109                | "u8"
1110                | "u16"
1111                | "u32"
1112                | "u64"
1113                | "u128"
1114                | "f32"
1115                | "f64"
1116                | "bool"
1117                | "char"
1118                | "str"
1119                | "String"
1120                | "Vec"
1121                | "Option"
1122                | "Result"
1123                | "Box"
1124                | "Rc"
1125                | "Arc"
1126                | "HashMap"
1127                | "HashSet"
1128                | "number"
1129                | "string"
1130                | "boolean"
1131                | "object"
1132                | "int"
1133                | "float"
1134                | "list"
1135                | "dict"
1136                | "tuple"
1137                | "set"
1138        )
1139    }
1140}
1141
1142#[cfg(test)]
1143mod tests {
1144    use super::*;
1145
1146    #[test]
1147    fn test_rust_query_creation() {
1148        let engine = QueryEngine::new(tree_sitter_rust::language(), "rust");
1149        assert!(engine.is_ok());
1150    }
1151
1152    #[test]
1153    fn test_python_query_creation() {
1154        let engine = QueryEngine::new(tree_sitter_python::language(), "python");
1155        if let Err(e) = &engine {
1156            println!("Python QueryEngine error: {e}");
1157        }
1158        assert!(engine.is_ok());
1159    }
1160
1161    #[test]
1162    fn test_javascript_query_creation() {
1163        let engine = QueryEngine::new(tree_sitter_javascript::language(), "javascript");
1164        if let Err(e) = &engine {
1165            println!("JavaScript QueryEngine error: {e}");
1166        }
1167        assert!(engine.is_ok());
1168    }
1169
1170    #[test]
1171    fn test_typescript_query_creation() {
1172        let engine = QueryEngine::new(tree_sitter_typescript::language_typescript(), "typescript");
1173        if let Err(e) = &engine {
1174            println!("TypeScript QueryEngine error: {e}");
1175        }
1176        assert!(engine.is_ok());
1177    }
1178
1179    #[test]
1180    fn test_builtin_type_detection() {
1181        let engine = QueryEngine::new(tree_sitter_rust::language(), "rust").unwrap();
1182
1183        assert!(engine.is_builtin_type("String"));
1184        assert!(engine.is_builtin_type("Vec"));
1185        assert!(engine.is_builtin_type("i32"));
1186        assert!(!engine.is_builtin_type("MyCustomType"));
1187    }
1188}