ricecoder_lsp/semantic/
generic_analyzer.rs1use crate::providers::{ProviderResult, SemanticAnalyzerProvider, SemanticAnalyzerRegistry};
7use crate::semantic::{fallback_analyzer::FallbackAnalyzer, SemanticAnalyzer};
8use crate::types::{Position, SemanticInfo, Symbol};
9
10pub struct GenericSemanticAnalyzer {
12 registry: SemanticAnalyzerRegistry,
13 fallback: FallbackAnalyzer,
14}
15
16impl GenericSemanticAnalyzer {
17 pub fn new() -> Self {
19 Self {
20 registry: SemanticAnalyzerRegistry::new(),
21 fallback: FallbackAnalyzer::new(),
22 }
23 }
24
25 pub fn register_provider(&mut self, provider: Box<dyn SemanticAnalyzerProvider>) {
27 self.registry.register(provider);
28 }
29
30 pub fn registry(&self) -> &SemanticAnalyzerRegistry {
32 &self.registry
33 }
34
35 pub fn registry_mut(&mut self) -> &mut SemanticAnalyzerRegistry {
37 &mut self.registry
38 }
39
40 pub fn analyze(&self, code: &str, language: &str) -> ProviderResult<SemanticInfo> {
42 if let Some(provider) = self.registry.get(language) {
43 provider.analyze(code)
44 } else {
45 tracing::debug!(
47 "No provider found for language '{}', using fallback",
48 language
49 );
50 self.fallback
51 .analyze(code)
52 .map_err(|e| crate::providers::ProviderError::Error(e.to_string()))
53 }
54 }
55
56 pub fn extract_symbols(&self, code: &str, language: &str) -> ProviderResult<Vec<Symbol>> {
58 if let Some(provider) = self.registry.get(language) {
59 provider.extract_symbols(code)
60 } else {
61 tracing::debug!(
63 "No provider found for language '{}', using fallback",
64 language
65 );
66 self.fallback
67 .extract_symbols(code)
68 .map_err(|e| crate::providers::ProviderError::Error(e.to_string()))
69 }
70 }
71
72 pub fn get_hover_info(
74 &self,
75 code: &str,
76 language: &str,
77 position: Position,
78 ) -> ProviderResult<Option<String>> {
79 if let Some(provider) = self.registry.get(language) {
80 provider.get_hover_info(code, position)
81 } else {
82 tracing::debug!(
84 "No provider found for language '{}', using fallback",
85 language
86 );
87 self.fallback
88 .get_hover_info(code, position)
89 .map_err(|e| crate::providers::ProviderError::Error(e.to_string()))
90 }
91 }
92
93 pub fn has_provider(&self, language: &str) -> bool {
95 self.registry.has_provider(language)
96 }
97
98 pub fn languages(&self) -> Vec<&str> {
100 self.registry.languages()
101 }
102}
103
104impl Default for GenericSemanticAnalyzer {
105 fn default() -> Self {
106 Self::new()
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 struct MockProvider;
115
116 impl SemanticAnalyzerProvider for MockProvider {
117 fn language(&self) -> &str {
118 "mock"
119 }
120
121 fn analyze(&self, _code: &str) -> ProviderResult<SemanticInfo> {
122 Ok(SemanticInfo {
123 symbols: vec![],
124 imports: vec![],
125 definitions: vec![],
126 references: vec![],
127 })
128 }
129
130 fn extract_symbols(&self, _code: &str) -> ProviderResult<Vec<Symbol>> {
131 Ok(vec![])
132 }
133
134 fn get_hover_info(
135 &self,
136 _code: &str,
137 _position: Position,
138 ) -> ProviderResult<Option<String>> {
139 Ok(Some("mock info".to_string()))
140 }
141 }
142
143 #[test]
144 fn test_generic_analyzer_with_provider() {
145 let mut analyzer = GenericSemanticAnalyzer::new();
146 analyzer.register_provider(Box::new(MockProvider));
147
148 assert!(analyzer.has_provider("mock"));
149 assert!(analyzer.analyze("test", "mock").is_ok());
150 }
151
152 #[test]
153 fn test_generic_analyzer_fallback() {
154 let analyzer = GenericSemanticAnalyzer::new();
155
156 assert!(!analyzer.has_provider("unknown"));
158 assert!(analyzer.analyze("test", "unknown").is_ok());
159 }
160
161 #[test]
162 fn test_generic_analyzer_languages() {
163 let mut analyzer = GenericSemanticAnalyzer::new();
164 analyzer.register_provider(Box::new(MockProvider));
165
166 let languages = analyzer.languages();
167 assert!(languages.contains(&"mock"));
168 }
169}