1use fst;
2use std::collections::{BTreeMap, HashMap, HashSet};
3use std::iter;
4use std::path::{Path, PathBuf};
5use std::time::SystemTime;
6
7use crate::raw::{CrateId, DefKind};
8use crate::{Id, Span, SymbolQuery};
9use span::{Column, Row, ZeroIndexed};
10
11pub(crate) struct Analysis {
15 pub per_crate: HashMap<CrateId, PerCrateAnalysis>,
17
18 pub(crate) aliased_imports: HashSet<Id>,
26
27 pub(crate) crate_names: HashMap<String, Vec<CrateId>>,
29
30 pub doc_url_base: String,
31 pub src_url_base: String,
32}
33
34pub struct PerCrateAnalysis {
35 pub def_id_for_span: HashMap<Span, Ref>,
38 pub defs: HashMap<Id, Def>,
39 pub defs_per_file: HashMap<PathBuf, Vec<Id>>,
40 pub children: HashMap<Id, HashSet<Id>>,
41 pub def_names: HashMap<String, Vec<Id>>,
42
43 pub def_fst: fst::Map<Vec<u8>>,
46 pub def_fst_values: Vec<Vec<Id>>,
47
48 pub ref_spans: HashMap<Id, Vec<Span>>,
49 pub globs: HashMap<Span, Glob>,
50 pub impls: HashMap<Id, Vec<Span>>,
51 pub idents: HashMap<PathBuf, IdentsByLine>,
52
53 pub root_id: Option<Id>,
54 pub timestamp: SystemTime,
55 pub path: Option<PathBuf>,
56 pub global_crate_num: u32,
60}
61
62#[derive(Debug, Clone)]
63pub enum Ref {
64 Id(Id),
66 Double(Id, Id),
69 Multi(Id, usize),
73}
74
75impl Ref {
76 pub fn some_id(&self) -> Id {
77 match *self {
78 Ref::Id(id) => id,
79 Ref::Double(id, _) => id,
80 Ref::Multi(id, _) => id,
81 }
82 }
83
84 pub fn add_id(&self, def_id: Id) -> Ref {
85 match *self {
86 Ref::Id(id) => Ref::Double(id, def_id),
87 Ref::Double(id, _) => Ref::Multi(id, 3),
88 Ref::Multi(id, n) => Ref::Multi(id, n + 1),
89 }
90 }
91}
92
93#[derive(Debug, Clone)]
94pub struct Def {
95 pub kind: DefKind,
96 pub span: Span,
97 pub name: String,
98 pub qualname: String,
99 pub distro_crate: bool,
100 pub parent: Option<Id>,
101 pub value: String,
102 pub docs: String,
103 }
105
106pub type IdentsByLine = BTreeMap<Row<ZeroIndexed>, IdentsByColumn>;
107pub type IdentsByColumn = BTreeMap<Column<ZeroIndexed>, IdentBound>;
108
109#[derive(new, Clone, Debug)]
116pub struct IdentBound {
117 pub column_end: Column<ZeroIndexed>,
118 pub id: Id,
119 pub kind: IdentKind,
120}
121
122#[derive(Copy, Clone, Debug, Eq, PartialEq)]
123pub enum IdentKind {
124 Def,
125 Ref,
126}
127
128#[derive(new, Clone, Debug)]
133pub struct Ident {
134 pub span: Span,
135 pub id: Id,
136 pub kind: IdentKind,
137}
138
139#[derive(Debug, Clone)]
140pub struct Signature {
141 pub span: Span,
142 pub text: String,
143 pub ident_start: u32,
144 pub ident_end: u32,
145 pub defs: Vec<SigElement>,
146 pub refs: Vec<SigElement>,
147}
148
149#[derive(Debug, Clone)]
150pub struct SigElement {
151 pub id: Id,
152 pub start: usize,
153 pub end: usize,
154}
155
156#[derive(Debug)]
157pub struct Glob {
158 pub value: String,
159}
160
161impl PerCrateAnalysis {
162 pub fn new(timestamp: SystemTime, path: Option<PathBuf>) -> PerCrateAnalysis {
163 let empty_fst = fst::Map::from_iter(iter::empty::<(String, u64)>()).unwrap();
164 PerCrateAnalysis {
165 def_id_for_span: HashMap::new(),
166 defs: HashMap::new(),
167 defs_per_file: HashMap::new(),
168 children: HashMap::new(),
169 def_names: HashMap::new(),
170 def_fst: empty_fst,
171 def_fst_values: Vec::new(),
172 ref_spans: HashMap::new(),
173 globs: HashMap::new(),
174 impls: HashMap::new(),
175 idents: HashMap::new(),
176 root_id: None,
177 timestamp,
178 path,
179 global_crate_num: 0,
180 }
181 }
182
183 pub(crate) fn has_congruent_def(&self, local_id: u32, span: &Span) -> bool {
186 let id = Id::from_crate_and_local(self.global_crate_num, local_id);
187 match self.defs.get(&id) {
188 Some(existing) => span == &existing.span,
189 None => false,
190 }
191 }
192
193 #[cfg(feature = "idents")]
197 fn idents(&self, span: &Span) -> Vec<Ident> {
198 self.idents
199 .get(&span.file)
200 .map(|by_line| {
201 (span.range.row_start..=span.range.row_end)
202 .flat_map(|line| {
203 let vec = by_line
204 .get(&line)
205 .iter()
206 .flat_map(|by_col| {
207 by_col.into_iter().filter_map(|(col_start, id)| {
208 if col_start <= &span.range.col_end
209 && id.column_end >= span.range.col_start
210 {
211 Some(Ident::new(
212 Span::new(
213 line,
214 line,
215 *col_start,
216 id.column_end,
217 span.file.clone(),
218 ),
219 id.id,
220 id.kind,
221 ))
222 } else {
223 None
224 }
225 })
226 })
227 .collect::<Vec<Ident>>();
228 vec.into_iter()
229 })
230 .collect::<Vec<Ident>>()
231 })
232 .unwrap_or_else(Vec::new)
233 }
234}
235
236impl Analysis {
237 pub fn new() -> Analysis {
238 Analysis {
239 per_crate: HashMap::new(),
240 aliased_imports: HashSet::new(),
241 crate_names: HashMap::new(),
242 doc_url_base: "https://doc.rust-lang.org/nightly".to_owned(),
244 src_url_base: "https://github.com/rust-lang/rust/blob/master".to_owned(),
245 }
246 }
247
248 pub fn timestamps(&self) -> HashMap<PathBuf, SystemTime> {
249 self.per_crate
250 .values()
251 .filter(|c| c.path.is_some())
252 .map(|c| (c.path.as_ref().unwrap().clone(), c.timestamp))
253 .collect()
254 }
255
256 pub fn update(&mut self, crate_id: CrateId, per_crate: PerCrateAnalysis) {
257 self.per_crate.insert(crate_id, per_crate);
258 }
259
260 pub fn has_def(&self, id: Id) -> bool {
261 self.per_crate.values().any(|c| c.defs.contains_key(&id))
262 }
263
264 pub fn for_each_crate<F, T>(&self, f: F) -> Option<T>
265 where
266 F: Fn(&PerCrateAnalysis) -> Option<T>,
267 {
268 let mut result = vec![];
269 for per_crate in self.per_crate.values() {
270 if let Some(t) = f(per_crate) {
271 result.push(t);
272 }
273 }
274
275 result.into_iter().nth(0)
284 }
285
286 pub fn for_all_crates<F, T>(&self, f: F) -> Vec<T>
287 where
288 F: Fn(&PerCrateAnalysis) -> Option<Vec<T>>,
289 {
290 let mut result = vec![];
291 for per_crate in self.per_crate.values() {
292 if let Some(this_crate) = f(per_crate) {
293 result.extend(this_crate);
294 }
295 }
296
297 result
298 }
299
300 pub fn def_id_for_span(&self, span: &Span) -> Option<Id> {
301 self.ref_for_span(span).map(|r| r.some_id())
302 }
303
304 pub fn ref_for_span(&self, span: &Span) -> Option<Ref> {
305 self.for_each_crate(|c| c.def_id_for_span.get(span).cloned())
306 }
307
308 pub fn local_def_id_for_span(&self, span: &Span) -> Option<Id> {
311 self.for_each_crate(|c| {
312 c.def_id_for_span.get(span).map(Ref::some_id).and_then(|id| {
313 if c.defs.contains_key(&id) {
314 Some(id)
315 } else {
316 None
317 }
318 })
319 })
320 }
321
322 pub fn with_defs<F, T>(&self, id: Id, f: F) -> Option<T>
323 where
324 F: Fn(&Def) -> T,
325 {
326 self.for_each_crate(|c| c.defs.get(&id).map(&f))
327 }
328
329 pub fn with_defs_and_then<F, T>(&self, id: Id, f: F) -> Option<T>
330 where
331 F: Fn(&Def) -> Option<T>,
332 {
333 self.for_each_crate(|c| c.defs.get(&id).and_then(&f))
334 }
335
336 pub fn with_globs<F, T>(&self, span: &Span, f: F) -> Option<T>
337 where
338 F: Fn(&Glob) -> T,
339 {
340 self.for_each_crate(|c| c.globs.get(span).map(&f))
341 }
342
343 pub fn for_each_child<F, T>(&self, id: Id, mut f: F) -> Option<Vec<T>>
344 where
345 F: FnMut(Id, &Def) -> T,
346 {
347 for per_crate in self.per_crate.values() {
348 if let Some(children) = per_crate.children.get(&id) {
349 return Some(
350 children
351 .iter()
352 .filter_map(|id| {
353 let def = per_crate.defs.get(id);
354 if def.is_none() {
355 info!("def not found for {}", id);
356 }
357 def.map(|def| f(*id, def))
358 })
359 .collect(),
360 );
361 }
362 }
363
364 Some(vec![])
365 }
366
367 pub fn with_ref_spans<F, T>(&self, id: Id, f: F) -> Option<T>
368 where
369 F: Fn(&Vec<Span>) -> Option<T>,
370 {
371 self.for_each_crate(|c| c.ref_spans.get(&id).and_then(&f))
372 }
373
374 pub fn with_defs_per_file<F, T>(&self, file: &Path, f: F) -> Option<T>
375 where
376 F: Fn(&Vec<Id>) -> T,
377 {
378 self.for_each_crate(|c| c.defs_per_file.get(file).map(&f))
379 }
380
381 #[cfg(feature = "idents")]
382 pub fn idents(&self, span: &Span) -> Vec<Ident> {
383 self.for_each_crate(|c| {
384 let result = c.idents(span);
385 if result.is_empty() {
386 None
387 } else {
388 Some(result)
389 }
390 })
391 .unwrap_or_else(Vec::new)
392 }
393
394 pub fn query_defs(&self, query: SymbolQuery) -> Vec<Def> {
395 let mut crates = Vec::with_capacity(self.per_crate.len());
396 let stream = query.build_stream(self.per_crate.values().map(|c| {
397 crates.push(c);
398 &c.def_fst
399 }));
400
401 query.search_stream(stream, |acc, e| {
402 let c = &crates[e.index];
403 let ids = &c.def_fst_values[e.value as usize];
404 acc.extend(ids.iter().flat_map(|id| c.defs.get(id)).cloned());
405 })
406 }
407
408 pub fn with_def_names<F, T>(&self, name: &str, f: F) -> Vec<T>
409 where
410 F: Fn(&Vec<Id>) -> Vec<T>,
411 {
412 self.for_all_crates(|c| c.def_names.get(name).map(&f))
413 }
414}