1#![warn(rust_2018_idioms)]
2
3#[macro_use]
4extern crate derive_new;
5#[macro_use]
6extern crate log;
7
8extern crate rls_data as data;
9extern crate rls_span as span;
10
11mod analysis;
12mod listings;
13mod loader;
14mod lowering;
15mod raw;
16mod symbol_query;
17#[cfg(test)]
18mod test;
19mod util;
20
21use analysis::Analysis;
22pub use analysis::{Def, Ident, IdentKind, Ref};
23pub use loader::{AnalysisLoader, CargoAnalysisLoader, SearchDirectory, Target};
24pub use raw::{
25 deserialize_crate_data, name_space_for_def_kind, read_analysis_from_files, read_crate_data,
26 Crate, CrateId, DefKind,
27};
28pub use symbol_query::SymbolQuery;
29
30use std::collections::HashMap;
31use std::fmt::Debug;
32use std::path::{Path, PathBuf};
33use std::sync::Mutex;
34use std::time::{Instant, SystemTime};
35use std::u64;
36
37pub struct AnalysisHost<L: AnalysisLoader = CargoAnalysisLoader> {
38 analysis: Mutex<Option<Analysis>>,
39 master_crate_map: Mutex<HashMap<CrateId, u32>>,
40 loader: Mutex<L>,
41}
42
43pub type AResult<T> = Result<T, AError>;
44
45#[derive(Debug, Copy, Clone, PartialEq, Eq)]
46pub enum AError {
47 MutexPoison,
48 Unclassified,
49}
50
51#[derive(Debug, Clone)]
52pub struct SymbolResult {
53 pub id: Id,
54 pub name: String,
55 pub kind: raw::DefKind,
56 pub span: Span,
57 pub parent: Option<Id>,
58}
59
60impl SymbolResult {
61 fn new(id: Id, def: &Def) -> SymbolResult {
62 SymbolResult {
63 id,
64 name: def.name.clone(),
65 span: def.span.clone(),
66 kind: def.kind,
67 parent: def.parent,
68 }
69 }
70}
71
72pub type Span = span::Span<span::ZeroIndexed>;
73
74#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, new)]
78pub struct Id(u64);
79
80impl Id {
81 fn from_crate_and_local(crate_id: u32, local_id: u32) -> Id {
82 Id((u64::from(crate_id) << 32) | u64::from(local_id))
85 }
86}
87
88pub const NULL: Id = Id(u64::MAX);
90
91macro_rules! clone_field {
92 ($field: ident) => {
93 |x| x.$field.clone()
94 };
95}
96
97macro_rules! def_span {
98 ($analysis: expr, $id: expr) => {
99 $analysis.with_defs_and_then($id, |def| Some(def.span.clone()))
100 };
101}
102
103impl AnalysisHost<CargoAnalysisLoader> {
104 pub fn new(target: Target) -> AnalysisHost {
105 AnalysisHost {
106 analysis: Mutex::new(None),
107 master_crate_map: Mutex::new(HashMap::new()),
108 loader: Mutex::new(CargoAnalysisLoader::new(target)),
109 }
110 }
111}
112
113impl<L: AnalysisLoader> AnalysisHost<L> {
114 pub fn new_with_loader(loader: L) -> Self {
115 Self {
116 analysis: Mutex::new(None),
117 master_crate_map: Mutex::new(HashMap::new()),
118 loader: Mutex::new(loader),
119 }
120 }
121
122 pub fn reload_from_analysis(
126 &self,
127 analysis: Vec<data::Analysis>,
128 path_prefix: &Path,
129 base_dir: &Path,
130 blacklist: &[impl AsRef<str> + Debug],
131 ) -> AResult<()> {
132 self.reload_with_blacklist(path_prefix, base_dir, blacklist)?;
133
134 let crates: Vec<_> = analysis
135 .into_iter()
136 .map(|analysis| raw::Crate::new(analysis, SystemTime::now(), None, None))
137 .collect();
138
139 lowering::lower(crates, base_dir, self, |host, per_crate, id| {
140 let mut a = host.analysis.lock()?;
141 a.as_mut().unwrap().update(id, per_crate);
142 Ok(())
143 })
144 }
145
146 pub fn reload(&self, path_prefix: &Path, base_dir: &Path) -> AResult<()> {
147 self.reload_with_blacklist(path_prefix, base_dir, &[] as &[&str])
148 }
149
150 pub fn reload_with_blacklist(
151 &self,
152 path_prefix: &Path,
153 base_dir: &Path,
154 blacklist: &[impl AsRef<str> + Debug],
155 ) -> AResult<()> {
156 trace!("reload_with_blacklist {:?} {:?} {:?}", path_prefix, base_dir, blacklist);
157 let empty = self.analysis.lock()?.is_none();
158 if empty || self.loader.lock()?.needs_hard_reload(path_prefix) {
159 return self.hard_reload_with_blacklist(path_prefix, base_dir, blacklist);
160 }
161
162 let timestamps = self.analysis.lock()?.as_ref().unwrap().timestamps();
163 let raw_analysis = {
164 let loader = self.loader.lock()?;
165 read_analysis_from_files(&*loader, timestamps, blacklist)
166 };
167
168 lowering::lower(raw_analysis, base_dir, self, |host, per_crate, id| {
169 let mut a = host.analysis.lock()?;
170 a.as_mut().unwrap().update(id, per_crate);
171 Ok(())
172 })
173 }
174
175 pub fn hard_reload(&self, path_prefix: &Path, base_dir: &Path) -> AResult<()> {
177 self.hard_reload_with_blacklist(path_prefix, base_dir, &[] as &[&str])
178 }
179
180 pub fn hard_reload_with_blacklist(
181 &self,
182 path_prefix: &Path,
183 base_dir: &Path,
184 blacklist: &[impl AsRef<str> + Debug],
185 ) -> AResult<()> {
186 trace!("hard_reload {:?} {:?}", path_prefix, base_dir);
187 let mut fresh_host = self.loader.lock()?.fresh_host();
190 fresh_host.analysis = Mutex::new(Some(Analysis::new()));
191
192 {
193 let mut fresh_loader = fresh_host.loader.lock().unwrap();
194 fresh_loader.set_path_prefix(path_prefix); let raw_analysis = read_analysis_from_files(&*fresh_loader, HashMap::new(), blacklist);
197 lowering::lower(raw_analysis, base_dir, &fresh_host, |host, per_crate, id| {
198 let mut a = host.analysis.lock()?;
199 a.as_mut().unwrap().update(id, per_crate);
200 Ok(())
201 })?;
202 }
203
204 macro_rules! swap_mutex_fields {
211 ($($name:ident),*) => {
212 $(let mut $name = self.$name.lock()?;)*
214 $(*$name = fresh_host.$name.into_inner().unwrap();)*
216 };
217 }
218
219 swap_mutex_fields!(analysis, master_crate_map, loader);
220
221 Ok(())
222 }
223
224 pub fn has_def(&self, id: Id) -> bool {
227 match self.analysis.lock() {
228 Ok(a) => a.as_ref().unwrap().has_def(id),
229 _ => false,
230 }
231 }
232
233 pub fn get_def(&self, id: Id) -> AResult<Def> {
234 self.with_analysis(|a| a.with_defs(id, Clone::clone))
235 }
236
237 pub fn goto_def(&self, span: &Span) -> AResult<Span> {
238 self.with_analysis(|a| a.def_id_for_span(span).and_then(|id| def_span!(a, id)))
239 }
240
241 pub fn for_each_child_def<F, T>(&self, id: Id, f: F) -> AResult<Vec<T>>
242 where
243 F: FnMut(Id, &Def) -> T,
244 {
245 self.with_analysis(|a| a.for_each_child(id, f))
246 }
247
248 pub fn def_parents(&self, id: Id) -> AResult<Vec<(Id, String)>> {
249 self.with_analysis(|a| {
250 let mut result = vec![];
251 let mut next = id;
252 loop {
253 match a.with_defs_and_then(next, |def| {
254 def.parent.and_then(|p| a.with_defs(p, |def| (p, def.name.clone())))
255 }) {
256 Some((id, name)) => {
257 result.insert(0, (id, name));
258 next = id;
259 }
260 None => {
261 return Some(result);
262 }
263 }
264 }
265 })
266 }
267
268 pub fn def_roots(&self) -> AResult<Vec<(Id, String)>> {
271 self.with_analysis(|a| {
272 Some(
273 a.per_crate
274 .iter()
275 .filter_map(|(crate_id, data)| {
276 data.root_id.map(|id| (id, crate_id.name.clone()))
277 })
278 .collect(),
279 )
280 })
281 }
282
283 pub fn id(&self, span: &Span) -> AResult<Id> {
284 self.with_analysis(|a| a.def_id_for_span(span))
285 }
286
287 pub fn crate_local_id(&self, span: &Span) -> AResult<Id> {
289 self.with_analysis(|a| a.local_def_id_for_span(span))
290 }
291
292 pub fn find_all_refs(
299 &self,
300 span: &Span,
301 include_decl: bool,
302 force_unique_spans: bool,
303 ) -> AResult<Vec<Span>> {
304 let t_start = Instant::now();
305 let result = self.with_analysis(|a| {
306 a.def_id_for_span(span).map(|id| {
307 if force_unique_spans && a.aliased_imports.contains(&id) {
308 return vec![];
309 }
310 let decl = if include_decl { def_span!(a, id) } else { None };
311 let refs = a.with_ref_spans(id, |refs| {
312 if force_unique_spans {
313 for r in refs.iter() {
314 match a.ref_for_span(r) {
315 Some(Ref::Id(_)) => {}
316 _ => return None,
317 }
318 }
319 }
320 Some(refs.clone())
321 });
322 refs.map(|refs| decl.into_iter().chain(refs.into_iter()).collect::<Vec<_>>())
323 .unwrap_or_else(|| vec![])
324 })
325 });
326
327 let time = t_start.elapsed();
328 info!(
329 "find_all_refs: {}s",
330 time.as_secs() as f64 + f64::from(time.subsec_nanos()) / 1_000_000_000.0
331 );
332 result
333 }
334
335 pub fn show_type(&self, span: &Span) -> AResult<String> {
336 self.with_analysis(|a| {
337 a.def_id_for_span(span)
338 .and_then(|id| a.with_defs(id, clone_field!(value)))
339 .or_else(|| a.with_globs(span, clone_field!(value)))
340 })
341 }
342
343 pub fn docs(&self, span: &Span) -> AResult<String> {
344 self.with_analysis(|a| {
345 a.def_id_for_span(span).and_then(|id| a.with_defs(id, clone_field!(docs)))
346 })
347 }
348
349 pub fn matching_defs(&self, stem: &str) -> AResult<Vec<Def>> {
351 self.query_defs(SymbolQuery::prefix(stem))
352 }
353
354 pub fn query_defs(&self, query: SymbolQuery) -> AResult<Vec<Def>> {
355 let t_start = Instant::now();
356 let result = self.with_analysis(move |a| {
357 let defs = a.query_defs(query);
358 info!("query_defs {:?}", &defs);
359 Some(defs)
360 });
361
362 let time = t_start.elapsed();
363 info!(
364 "query_defs: {}",
365 time.as_secs() as f64 + f64::from(time.subsec_nanos()) / 1_000_000_000.0
366 );
367
368 result
369 }
370
371 pub fn search(&self, name: &str) -> AResult<Vec<Span>> {
374 let t_start = Instant::now();
375 let result = self.with_analysis(|a| {
376 Some(a.with_def_names(name, |defs| {
377 info!("defs: {:?}", defs);
378 defs.iter()
379 .flat_map(|id| {
380 a.with_ref_spans(*id, |refs| {
381 Some(
382 def_span!(a, *id)
383 .into_iter()
384 .chain(refs.iter().cloned())
385 .collect::<Vec<_>>(),
386 )
387 })
388 .or_else(|| def_span!(a, *id).map(|s| vec![s]))
389 .unwrap_or_else(Vec::new)
390 .into_iter()
391 })
392 .collect::<Vec<Span>>()
393 }))
394 });
395
396 let time = t_start.elapsed();
397 info!(
398 "search: {}s",
399 time.as_secs() as f64 + f64::from(time.subsec_nanos()) / 1_000_000_000.0
400 );
401 result
402 }
403
404 pub fn find_all_refs_by_id(&self, id: Id) -> AResult<Vec<Span>> {
407 let t_start = Instant::now();
408 let result = self.with_analysis(|a| {
409 a.with_ref_spans(id, |refs| {
410 Some(def_span!(a, id).into_iter().chain(refs.iter().cloned()).collect::<Vec<_>>())
411 })
412 .or_else(|| def_span!(a, id).map(|s| vec![s]))
413 });
414
415 let time = t_start.elapsed();
416 info!(
417 "find_all_refs_by_id: {}s",
418 time.as_secs() as f64 + f64::from(time.subsec_nanos()) / 1_000_000_000.0
419 );
420 result
421 }
422
423 pub fn find_impls(&self, id: Id) -> AResult<Vec<Span>> {
424 self.with_analysis(|a| Some(a.for_all_crates(|c| c.impls.get(&id).cloned())))
425 }
426
427 pub fn search_for_id(&self, name: &str) -> AResult<Vec<Id>> {
429 self.with_analysis(|a| Some(a.with_def_names(name, Clone::clone)))
430 }
431
432 #[cfg(feature = "idents")]
434 pub fn idents(&self, span: &Span) -> AResult<Vec<Ident>> {
435 self.with_analysis(|a| Some(a.idents(span)))
436 }
437
438 pub fn symbols(&self, file_name: &Path) -> AResult<Vec<SymbolResult>> {
439 self.with_analysis(|a| {
440 a.with_defs_per_file(file_name, |ids| {
441 ids.iter()
442 .map(|id| a.with_defs(*id, |def| SymbolResult::new(*id, def)).unwrap())
443 .collect()
444 })
445 })
446 }
447
448 pub fn doc_url(&self, span: &Span) -> AResult<String> {
449 self.with_analysis(|a| {
451 a.def_id_for_span(span).and_then(|id| {
452 a.with_defs_and_then(id, |def| AnalysisHost::<L>::mk_doc_url(def, a))
453 })
454 })
455 }
456
457 pub fn src_url(&self, span: &Span) -> AResult<String> {
459 let path_prefix = self.loader.lock().unwrap().abs_path_prefix();
461
462 self.with_analysis(|a| {
463 a.def_id_for_span(span).and_then(|id| {
464 a.with_defs_and_then(id, |def| {
465 AnalysisHost::<L>::mk_src_url(def, path_prefix.as_ref(), a)
466 })
467 })
468 })
469 }
470
471 fn with_analysis<F, T>(&self, f: F) -> AResult<T>
472 where
473 F: FnOnce(&Analysis) -> Option<T>,
474 {
475 let a = self.analysis.lock()?;
476 if let Some(ref a) = *a {
477 f(a).ok_or(AError::Unclassified)
478 } else {
479 Err(AError::Unclassified)
480 }
481 }
482
483 fn mk_doc_url(def: &Def, analysis: &Analysis) -> Option<String> {
484 if !def.distro_crate {
485 return None;
486 }
487
488 if def.parent.is_none() && def.qualname.contains('<') {
489 debug!("mk_doc_url, bailing, found generic qualname: `{}`", def.qualname);
490 return None;
491 }
492
493 match def.parent {
494 Some(p) => analysis.with_defs(p, |parent| match def.kind {
495 DefKind::Field
496 | DefKind::Method
497 | DefKind::Tuple
498 | DefKind::TupleVariant
499 | DefKind::StructVariant => {
500 let ns = name_space_for_def_kind(def.kind);
501 let mut res = AnalysisHost::<L>::mk_doc_url(parent, analysis)
502 .unwrap_or_else(|| "".into());
503 res.push_str(&format!("#{}.{}", def.name, ns));
504 res
505 }
506 DefKind::Mod => {
507 let parent_qualpath = parent.qualname.replace("::", "/");
508 format!(
509 "{}/{}/{}/",
510 analysis.doc_url_base,
511 parent_qualpath.trim_end_matches('/'),
512 def.name,
513 )
514 }
515 _ => {
516 let parent_qualpath = parent.qualname.replace("::", "/");
517 let ns = name_space_for_def_kind(def.kind);
518 format!(
519 "{}/{}/{}.{}.html",
520 analysis.doc_url_base, parent_qualpath, def.name, ns,
521 )
522 }
523 }),
524 None => {
525 let qualpath = def.qualname.replace("::", "/");
526 let ns = name_space_for_def_kind(def.kind);
527 Some(format!("{}/{}.{}.html", analysis.doc_url_base, qualpath, ns,))
528 }
529 }
530 }
531
532 fn mk_src_url(def: &Def, path_prefix: Option<&PathBuf>, analysis: &Analysis) -> Option<String> {
533 if !def.distro_crate {
534 return None;
535 }
536
537 let file_path = &def.span.file;
538 let file_path = file_path.strip_prefix(path_prefix?).ok()?;
539
540 Some(format!(
541 "{}/{}#L{}-L{}",
542 analysis.src_url_base,
543 file_path.to_str().unwrap(),
544 def.span.range.row_start.one_indexed().0,
545 def.span.range.row_end.one_indexed().0
546 ))
547 }
548}
549
550impl ::std::fmt::Display for Id {
551 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
552 ::std::fmt::Display::fmt(&self.0, f)
553 }
554}
555
556impl ::std::error::Error for AError {}
557
558impl ::std::fmt::Display for AError {
559 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
560 let description = match self {
561 AError::MutexPoison => "poison error in a mutex (usually a secondary error)",
562 AError::Unclassified => "unknown error",
563 };
564 write!(f, "{}", description)
565 }
566}
567
568impl<T> From<::std::sync::PoisonError<T>> for AError {
569 fn from(_: ::std::sync::PoisonError<T>) -> AError {
570 AError::MutexPoison
571 }
572}