ryo_symbol/
use_resolver.rs1use std::collections::HashMap;
25
26use crate::path::SymbolPath;
27use crate::registry::SymbolRegistry;
28use crate::SymbolId;
29
30#[derive(Debug, Clone, Default)]
35pub struct ImportMap {
36 imports: HashMap<String, SymbolPath>,
39
40 glob_imports: Vec<SymbolPath>,
43
44 renames: HashMap<String, SymbolPath>,
47}
48
49impl ImportMap {
50 pub fn new() -> Self {
52 Self::default()
53 }
54
55 pub fn add_import(&mut self, local_name: impl Into<String>, full_path: SymbolPath) {
61 self.imports.insert(local_name.into(), full_path);
62 }
63
64 pub fn add_rename(&mut self, alias: impl Into<String>, full_path: SymbolPath) {
70 self.renames.insert(alias.into(), full_path);
71 }
72
73 pub fn add_glob(&mut self, module_path: SymbolPath) {
78 self.glob_imports.push(module_path);
79 }
80
81 pub fn resolve(&self, name: &str) -> Option<&SymbolPath> {
86 if let Some(path) = self.imports.get(name) {
88 return Some(path);
89 }
90 self.renames.get(name)
92 }
93
94 pub fn resolve_with_registry(&self, name: &str, registry: &SymbolRegistry) -> Option<SymbolId> {
103 if let Some(path) = self.resolve(name) {
105 return registry.lookup(path);
106 }
107
108 for glob_module in &self.glob_imports {
110 if let Ok(candidate) = glob_module.child(name) {
112 if let Some(id) = registry.lookup(&candidate) {
113 return Some(id);
114 }
115 }
116 }
117
118 None
119 }
120
121 pub fn imports(&self) -> &HashMap<String, SymbolPath> {
123 &self.imports
124 }
125
126 pub fn renames(&self) -> &HashMap<String, SymbolPath> {
128 &self.renames
129 }
130
131 pub fn glob_imports(&self) -> &[SymbolPath] {
133 &self.glob_imports
134 }
135
136 pub fn is_empty(&self) -> bool {
138 self.imports.is_empty() && self.renames.is_empty() && self.glob_imports.is_empty()
139 }
140
141 pub fn len(&self) -> usize {
143 self.imports.len() + self.renames.len()
144 }
145}
146
147#[derive(Debug, Clone, Default)]
152pub struct UseResolver {
153 import_maps: HashMap<SymbolPath, ImportMap>,
156}
157
158impl UseResolver {
159 pub fn new() -> Self {
161 Self::default()
162 }
163
164 pub fn register(&mut self, module_path: SymbolPath, import_map: ImportMap) {
166 self.import_maps.insert(module_path, import_map);
167 }
168
169 pub fn get(&self, module_path: &SymbolPath) -> Option<&ImportMap> {
171 self.import_maps.get(module_path)
172 }
173
174 pub fn get_mut(&mut self, module_path: &SymbolPath) -> Option<&mut ImportMap> {
176 self.import_maps.get_mut(module_path)
177 }
178
179 pub fn resolve(
195 &self,
196 module_path: &SymbolPath,
197 name: &str,
198 registry: &SymbolRegistry,
199 ) -> Option<SymbolId> {
200 if let Some(import_map) = self.import_maps.get(module_path) {
202 if let Some(id) = import_map.resolve_with_registry(name, registry) {
203 return Some(id);
204 }
205 }
206
207 if name.contains("::") {
209 if let Ok(path) = SymbolPath::parse(name) {
210 if let Some(id) = registry.lookup(&path) {
211 return Some(id);
212 }
213 }
214 }
215
216 if let Ok(qualified) = module_path.child(name) {
218 if let Some(id) = registry.lookup(&qualified) {
219 return Some(id);
220 }
221 }
222
223 let mut current = module_path.clone();
225 while let Some(parent) = current.parent() {
226 if let Ok(qualified) = parent.child(name) {
227 if let Some(id) = registry.lookup(&qualified) {
228 return Some(id);
229 }
230 }
231 current = parent;
232 }
233
234 if let Ok(path) = SymbolPath::parse(name) {
236 return registry.lookup(&path);
237 }
238
239 None
240 }
241
242 pub fn contains(&self, module_path: &SymbolPath) -> bool {
244 self.import_maps.contains_key(module_path)
245 }
246
247 pub fn len(&self) -> usize {
249 self.import_maps.len()
250 }
251
252 pub fn is_empty(&self) -> bool {
254 self.import_maps.is_empty()
255 }
256
257 pub fn iter(&self) -> impl Iterator<Item = (&SymbolPath, &ImportMap)> {
259 self.import_maps.iter()
260 }
261}
262
263#[cfg(test)]
264mod tests {
265 use super::*;
266 use crate::SymbolKind;
267
268 fn make_path(s: &str) -> SymbolPath {
269 SymbolPath::parse(s).unwrap()
270 }
271
272 #[test]
273 fn test_import_map_basic() {
274 let mut map = ImportMap::new();
275
276 let hashmap_path = make_path("std::collections::HashMap");
278 map.add_import("HashMap", hashmap_path.clone());
279
280 assert_eq!(map.resolve("HashMap"), Some(&hashmap_path));
282 assert_eq!(map.resolve("Vec"), None);
283 }
284
285 #[test]
286 fn test_import_map_rename() {
287 let mut map = ImportMap::new();
288
289 let hashmap_path = make_path("std::collections::HashMap");
291 map.add_rename("Map", hashmap_path.clone());
292
293 assert_eq!(map.resolve("Map"), Some(&hashmap_path));
295 assert_eq!(map.resolve("HashMap"), None);
297 }
298
299 #[test]
300 fn test_import_map_with_registry() {
301 let mut map = ImportMap::new();
302 let mut registry = SymbolRegistry::new();
303
304 let hashmap_path = make_path("std::collections::HashMap");
306 let id = registry
307 .register(hashmap_path.clone(), SymbolKind::Struct)
308 .unwrap();
309
310 map.add_import("HashMap", hashmap_path);
312
313 assert_eq!(map.resolve_with_registry("HashMap", ®istry), Some(id));
315 }
316
317 #[test]
318 fn test_import_map_glob() {
319 let mut map = ImportMap::new();
320 let mut registry = SymbolRegistry::new();
321
322 let foo_bar_path = make_path("foo::bar::Baz");
324 let id = registry.register(foo_bar_path, SymbolKind::Struct).unwrap();
325
326 map.add_glob(make_path("foo::bar"));
328
329 assert_eq!(map.resolve_with_registry("Baz", ®istry), Some(id));
331 }
332
333 #[test]
334 fn test_use_resolver_basic() {
335 let mut resolver = UseResolver::new();
336 let mut registry = SymbolRegistry::new();
337
338 let hashmap_path = make_path("std::collections::HashMap");
340 let id = registry
341 .register(hashmap_path.clone(), SymbolKind::Struct)
342 .unwrap();
343
344 let module_path = make_path("my_crate::handlers");
346 let mut import_map = ImportMap::new();
347 import_map.add_import("HashMap", hashmap_path);
348
349 resolver.register(module_path.clone(), import_map);
351
352 assert_eq!(
354 resolver.resolve(&module_path, "HashMap", ®istry),
355 Some(id)
356 );
357 }
358
359 #[test]
360 fn test_use_resolver_hierarchy_fallback() {
361 let mut resolver = UseResolver::new();
362 let mut registry = SymbolRegistry::new();
363
364 let config_path = make_path("my_crate::Config");
366 let id = registry.register(config_path, SymbolKind::Struct).unwrap();
367
368 let module_path = make_path("my_crate::handlers::create");
370
371 resolver.register(module_path.clone(), ImportMap::new());
373
374 assert_eq!(
376 resolver.resolve(&module_path, "Config", ®istry),
377 Some(id)
378 );
379 }
380
381 #[test]
382 fn test_use_resolver_qualified_path() {
383 let resolver = UseResolver::new();
384 let mut registry = SymbolRegistry::new();
385
386 let path = make_path("std::io::Read");
388 let id = registry.register(path, SymbolKind::Trait).unwrap();
389
390 let module_path = make_path("my_crate");
392 assert_eq!(
393 resolver.resolve(&module_path, "std::io::Read", ®istry),
394 Some(id)
395 );
396 }
397}