use std::collections::HashMap;
use std::path::PathBuf;
use crate::tree::red::SyntaxNode;
use crate::tree::walk::{Visitor, WalkOptions, WalkResult};
use crate::types::Span;
#[must_use]
pub fn collect_definitions<K: Eq + std::hash::Hash>(
roots: &[(PathBuf, SyntaxNode)],
extract: impl Fn(&SyntaxNode, &SyntaxNode) -> Option<(String, K, Span)>,
) -> HashMap<(String, K), (PathBuf, u32, u32)> {
let mut map = HashMap::new();
for (path, root) in roots {
let mut visitor = CollectDefinitionsVisitor {
path: path.clone(),
root: root.clone(),
map: &mut map,
extract: &extract,
};
let _ = root.walk(&mut visitor, &WalkOptions::nodes_only());
}
map
}
struct CollectDefinitionsVisitor<'a, K, F> {
path: PathBuf,
root: SyntaxNode,
map: &'a mut HashMap<(String, K), (PathBuf, u32, u32)>,
extract: &'a F,
}
impl<K: Eq + std::hash::Hash, F: Fn(&SyntaxNode, &SyntaxNode) -> Option<(String, K, Span)>> Visitor
for CollectDefinitionsVisitor<'_, K, F>
{
fn enter_node(&mut self, node: &SyntaxNode) -> WalkResult {
if let Some((name, kind, span)) = (self.extract)(node, &self.root) {
self.map
.entry((name, kind))
.or_insert_with(|| (self.path.clone(), span.start, span.end));
}
WalkResult::Continue(())
}
}