context_creator/core/semantic/
mod.rs

1//! Semantic analysis module for context-creator
2//!
3//! This module provides language-agnostic semantic analysis capabilities including:
4//! - Import/dependency tracing
5//! - Function call analysis
6//! - Type dependency tracking
7
8#![allow(clippy::new_without_default)]
9
10pub mod analyzer;
11pub mod cache;
12pub mod cycle_detector;
13pub mod dependency_types;
14pub mod function_call_index;
15pub mod graph_builder;
16pub mod graph_traverser;
17pub mod languages;
18pub mod parallel_analyzer;
19pub mod parser_pool;
20pub mod path_validator;
21pub mod query_engine;
22pub mod resolver;
23pub mod type_resolver;
24
25#[cfg(test)]
26mod rust_function_call_test;
27
28// Re-export commonly used types
29pub use cache::AstCacheV2;
30
31#[cfg(test)]
32mod javascript_test;
33#[cfg(test)]
34mod python_test;
35#[cfg(test)]
36mod test;
37
38pub use analyzer::{LanguageAnalyzer, SemanticContext, SemanticResult};
39pub use resolver::{ModuleResolver, ResolvedPath};
40
41// Create an alias for get_resolver_for_file
42pub use self::get_resolver_for_file as get_module_resolver_for_file;
43
44use crate::utils::error::ContextCreatorError;
45use std::path::Path;
46
47/// Semantic analysis options
48#[derive(Debug, Clone)]
49pub struct SemanticOptions {
50    /// Enable import tracing
51    pub trace_imports: bool,
52    /// Include function callers
53    pub include_callers: bool,
54    /// Include type dependencies
55    pub include_types: bool,
56    /// Maximum depth for dependency traversal
57    pub semantic_depth: usize,
58}
59
60impl SemanticOptions {
61    /// Create SemanticOptions from CLI config
62    pub fn from_config(config: &crate::cli::Config) -> Self {
63        Self {
64            trace_imports: config.trace_imports,
65            include_callers: config.include_callers,
66            include_types: config.include_types,
67            semantic_depth: config.semantic_depth,
68        }
69    }
70
71    /// Check if any semantic analysis is enabled
72    pub fn is_enabled(&self) -> bool {
73        self.trace_imports || self.include_callers || self.include_types
74    }
75}
76
77/// Get the appropriate language analyzer for a file
78pub fn get_analyzer_for_file(
79    path: &Path,
80) -> Result<Option<Box<dyn LanguageAnalyzer>>, ContextCreatorError> {
81    let extension = path.extension().and_then(|ext| ext.to_str()).unwrap_or("");
82
83    let analyzer: Option<Box<dyn LanguageAnalyzer>> = match extension {
84        "rs" => Some(Box::new(languages::rust::RustAnalyzer::new())),
85        "py" => Some(Box::new(languages::python::PythonAnalyzer::new())),
86        "js" | "jsx" => Some(Box::new(languages::javascript::JavaScriptAnalyzer::new())),
87        "ts" | "tsx" => Some(Box::new(languages::typescript::TypeScriptAnalyzer::new())),
88        "go" => Some(Box::new(languages::go::GoAnalyzer::new())),
89        "java" => Some(Box::new(languages::java::JavaAnalyzer::new())),
90        "cpp" | "cc" | "cxx" | "hpp" | "h" => Some(Box::new(languages::cpp::CppAnalyzer::new())),
91        "c" => Some(Box::new(languages::c::CAnalyzer::new())),
92        "cs" => Some(Box::new(languages::csharp::CSharpAnalyzer::new())),
93        "rb" => Some(Box::new(languages::ruby::RubyAnalyzer::new())),
94        "php" => Some(Box::new(languages::php::PhpAnalyzer::new())),
95        "swift" => Some(Box::new(languages::swift::SwiftAnalyzer::new())),
96        "kt" | "kts" => Some(Box::new(languages::kotlin::KotlinAnalyzer::new())),
97        "scala" | "sc" => Some(Box::new(languages::scala::ScalaAnalyzer::new())),
98        "dart" => Some(Box::new(languages::dart::DartAnalyzer::new())),
99        "lua" => Some(Box::new(languages::lua::LuaAnalyzer::new())),
100        "r" | "R" => Some(Box::new(languages::r::RAnalyzer::new())),
101        "jl" => Some(Box::new(languages::julia::JuliaAnalyzer::new())),
102        "ex" | "exs" => Some(Box::new(languages::elixir::ElixirAnalyzer::new())),
103        "elm" => Some(Box::new(languages::elm::ElmAnalyzer::new())),
104        _ => None,
105    };
106
107    Ok(analyzer)
108}
109
110/// Get the appropriate module resolver for a file
111pub fn get_resolver_for_file(
112    path: &Path,
113) -> Result<Option<Box<dyn ModuleResolver>>, ContextCreatorError> {
114    let extension = path.extension().and_then(|ext| ext.to_str()).unwrap_or("");
115
116    let resolver: Option<Box<dyn ModuleResolver>> = match extension {
117        "rs" => Some(Box::new(languages::rust::RustModuleResolver)),
118        "py" => Some(Box::new(languages::python::PythonModuleResolver)),
119        "js" | "jsx" => Some(Box::new(languages::javascript::JavaScriptModuleResolver)),
120        "ts" | "tsx" => Some(Box::new(languages::typescript::TypeScriptModuleResolver)),
121        _ => None,
122    };
123
124    Ok(resolver)
125}