pilota_build/middle/
resolver.rs1use 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}