Skip to main content

pilota_build/middle/
resolver.rs

1use std::sync::Arc;
2
3use faststr::FastStr;
4use itertools::Itertools;
5
6use crate::{Context, DefId, IdentName, db::RirDatabase, rir::NodeKind, symbol::Symbol};
7
8pub trait PathResolver: Sync + Send {
9    fn path_for_def_id(&self, cx: &Context, def_id: DefId) -> Arc<[Symbol]> {
10        fn calc_node_path(cx: &Context, def_id: DefId, segs: &mut Vec<Symbol>) {
11            let node = cx.node(def_id).unwrap();
12
13            match node.kind {
14                NodeKind::Item(_) => {}
15                _ => calc_node_path(cx, node.parent.unwrap(), segs),
16            }
17
18            let name = match node.kind {
19                NodeKind::Item(item) => match &*item {
20                    crate::rir::Item::Mod(_) => return,
21                    _ => cx.rust_name(def_id),
22                },
23                _ => cx.rust_name(def_id),
24            };
25
26            segs.push(name);
27        }
28
29        let mut segs = Vec::from(&*self.mod_prefix(cx, def_id));
30
31        calc_node_path(cx, def_id, &mut segs);
32
33        Arc::from(segs)
34    }
35    fn mod_prefix(&self, cx: &Context, def_id: DefId) -> Arc<[Symbol]>;
36
37    fn related_path(&self, p1: &[Symbol], p2: &[Symbol]) -> FastStr;
38}
39
40pub struct DefaultPathResolver;
41
42impl PathResolver for DefaultPathResolver {
43    fn mod_prefix(&self, cx: &Context, def_id: DefId) -> Arc<[Symbol]> {
44        fn calc_item_path(cx: &Context, def_id: DefId, segs: &mut Vec<Symbol>) {
45            let node = cx.node(def_id).unwrap();
46            match node.parent {
47                Some(parent) => {
48                    tracing::debug!("the parent of {:?} is {:?} ", def_id, parent);
49                    calc_item_path(cx, parent, segs)
50                }
51                _ => {
52                    let file = cx.file(node.file_id).unwrap();
53                    let package = &file.package;
54                    if package.len() != 1 || !package.first().unwrap().0.is_empty() {
55                        segs.extend(package.iter().map(|s| (&*s.0).mod_ident().into()))
56                    }
57                }
58            }
59
60            if let NodeKind::Item(item) = node.kind {
61                if let crate::rir::Item::Mod(_) = &*item {
62                    segs.push(cx.rust_name(def_id));
63                }
64            }
65        }
66
67        let mut segs = Default::default();
68
69        calc_item_path(cx, def_id, &mut segs);
70
71        Arc::from(segs)
72    }
73
74    fn related_path(&self, p1: &[Symbol], p2: &[Symbol]) -> FastStr {
75        if p1 == p2 {
76            return p2.last().unwrap().clone().0;
77        }
78        let mut i = 0;
79        while i < p1.len() && i < p2.len() && p1[i] == p2[i] {
80            i += 1
81        }
82        let mut segs = vec![];
83
84        #[derive(Debug)]
85        enum Kind {
86            Super,
87            Ident(Symbol),
88        }
89
90        let path = (0..p1.len() - i)
91            .map(|_| Kind::Super)
92            .chain((i..p2.len()).map(|i| Kind::Ident(p2[i].clone())))
93            .collect::<Vec<_>>();
94
95        let _length = path.len();
96
97        for k in path.into_iter() {
98            segs.push(match k {
99                Kind::Super => "super".into(),
100                Kind::Ident(ident) => ident.to_string(),
101            });
102        }
103        segs.into_iter().join("::").into()
104    }
105}
106
107pub struct WorkspacePathResolver;
108
109impl PathResolver for WorkspacePathResolver {
110    fn mod_prefix(&self, cx: &Context, def_id: DefId) -> Arc<[Symbol]> {
111        let mut item_def_id = def_id;
112        while !matches!(cx.node(item_def_id).unwrap().kind, NodeKind::Item(_)) {
113            item_def_id = cx.node(item_def_id).unwrap().parent.unwrap()
114        }
115
116        let info = cx.workspace_info();
117        let prefix = match info.location_map.get(&item_def_id) {
118            location @ Some(super::context::DefLocation::Fixed(_, prefix)) => {
119                let mut path = Vec::with_capacity(prefix.len() + 1);
120                path.push(cx.crate_name(location.unwrap()).into());
121                path.extend(prefix.iter().cloned());
122                path
123            }
124            Some(super::context::DefLocation::Dynamic) => {
125                [cx.config.common_crate_name.clone().into()]
126                    .iter()
127                    .chain(DefaultPathResolver.mod_prefix(cx, def_id).iter())
128                    .cloned()
129                    .collect_vec()
130            }
131            None => {
132                panic!(
133                    "no location found for \"{}\" in file \"{}\"",
134                    cx.rust_name(item_def_id),
135                    cx.file(cx.node(item_def_id).unwrap().file_id)
136                        .unwrap()
137                        .package
138                        .join("/")
139                )
140            }
141        };
142
143        Arc::from(prefix)
144    }
145
146    fn related_path(&self, p1: &[Symbol], p2: &[Symbol]) -> FastStr {
147        if p2[0] == p1[0] {
148            DefaultPathResolver.related_path(p1, p2)
149        } else {
150            format!("::{}", p2.iter().map(|s| s.to_string()).join("::")).into()
151        }
152    }
153}