Skip to content
This repository was archived by the owner on Mar 1, 2019. It is now read-only.

Commit 1d6bf96

Browse files
committed
Support multiple crate types/versions
1 parent e9e5926 commit 1d6bf96

File tree

8 files changed

+213
-185
lines changed

8 files changed

+213
-185
lines changed

benches/std_api_crate.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
// Copyright 2017 The RLS Project Developers.
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
19
#![feature(test)]
210

311
extern crate rls_analysis;
@@ -27,19 +35,13 @@ impl AnalysisLoader for TestAnalysisLoader {
2735
AnalysisHost::new_with_loader(self.clone())
2836
}
2937

30-
fn set_path_prefix(&self, _path_prefix: &Path) {}
38+
fn set_path_prefix(&mut self, _path_prefix: &Path) {}
3139

3240
fn abs_path_prefix(&self) -> Option<PathBuf> {
3341
panic!();
3442
}
3543

36-
fn iter_paths<F, T>(&self, f: F) -> Vec<T>
37-
where
38-
F: Fn(&Path) -> Vec<T>,
39-
{
40-
let paths = &[&self.path];
41-
paths.iter().flat_map(|p| f(p).into_iter()).collect()
42-
}
44+
fn search_directories(&self) -> Vec<PathBuf> { vec![self.path.clone()] }
4345
}
4446

4547
lazy_static! {

src/analysis.rs

+11-13
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ use std::path::{Path, PathBuf};
1111
use std::time::SystemTime;
1212

1313
use {Id, Span};
14-
use raw::DefKind;
14+
use raw::{CrateId, DefKind};
1515

16+
/// This is the main database that contains all the collected symbol information,
17+
/// such as definitions, their mapping between spans, hierarchy and so on,
18+
/// organized in a per-crate fashion.
1619
#[derive(Debug)]
1720
pub struct Analysis {
18-
// The primary crate will have its data passed directly, not via a file, so
19-
// there is no path for it. Because of this key into the hashmap, this means
20-
// we can only pass the data for one crate directly.
21-
pub per_crate: HashMap<Option<PathBuf>, PerCrateAnalysis>,
21+
/// Contains lowered data with global inter-crate `Id`s per each crate.
22+
pub per_crate: HashMap<CrateId, PerCrateAnalysis>,
2223

2324
pub doc_url_base: String,
2425
pub src_url_base: String,
@@ -36,7 +37,6 @@ pub struct PerCrateAnalysis {
3637
pub globs: HashMap<Span, Glob>,
3738
pub impls: HashMap<Id, Vec<Span>>,
3839

39-
pub name: String,
4040
pub root_id: Option<Id>,
4141
pub timestamp: SystemTime,
4242
}
@@ -88,7 +88,6 @@ impl PerCrateAnalysis {
8888
ref_spans: HashMap::new(),
8989
globs: HashMap::new(),
9090
impls: HashMap::new(),
91-
name: String::new(),
9291
root_id: None,
9392
timestamp,
9493
}
@@ -105,20 +104,19 @@ impl Analysis {
105104
}
106105
}
107106

108-
pub fn timestamps(&self) -> HashMap<PathBuf, SystemTime> {
107+
pub fn timestamps(&self) -> HashMap<CrateId, SystemTime> {
109108
self.per_crate
110109
.iter()
111-
.filter_map(|(s, pc)| s.as_ref().map(|s| (s.clone(), pc.timestamp)))
110+
.map(|(id, c)| (id.clone(), c.timestamp.clone()))
112111
.collect()
113112
}
114113

115-
pub fn update(&mut self, per_crate: PerCrateAnalysis, path: Option<PathBuf>) {
116-
self.per_crate.insert(path, per_crate);
114+
pub fn update(&mut self, crate_id: CrateId, per_crate: PerCrateAnalysis) {
115+
self.per_crate.insert(crate_id, per_crate);
117116
}
118117

119118
pub fn has_def(&self, id: Id) -> bool {
120-
self.for_each_crate(|c| c.defs.get(&id).map(|_| ()))
121-
.is_some()
119+
self.per_crate.values().any(|c| c.defs.contains_key(&id))
122120
}
123121

124122
pub fn for_each_crate<F, T>(&self, f: F) -> Option<T>

src/lib.rs

+62-57
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ mod test;
2727

2828
pub use analysis::Def;
2929
use analysis::Analysis;
30-
pub use raw::{name_space_for_def_kind, read_analysis_incremental, DefKind, Target};
31-
pub use loader::{AnalysisLoader, CargoAnalysisLoader};
30+
pub use raw::{name_space_for_def_kind, read_analysis_from_files, CrateId, DefKind};
31+
pub use loader::{AnalysisLoader, CargoAnalysisLoader, Target};
3232

3333
use std::collections::HashMap;
3434
use std::path::{Path, PathBuf};
@@ -39,8 +39,8 @@ use std::u64;
3939
#[derive(Debug)]
4040
pub struct AnalysisHost<L: AnalysisLoader = CargoAnalysisLoader> {
4141
analysis: Mutex<Option<Analysis>>,
42-
master_crate_map: Mutex<HashMap<String, u32>>,
43-
loader: L,
42+
master_crate_map: Mutex<HashMap<CrateId, u32>>,
43+
loader: Mutex<L>,
4444
}
4545

4646
pub type AResult<T> = Result<T, AError>;
@@ -72,10 +72,13 @@ impl SymbolResult {
7272

7373
pub type Span = span::Span<span::ZeroIndexed>;
7474

75+
/// A common identifier for definitions, references etc. This is effectively a
76+
/// `DefId` with globally unique crate number (instead of a compiler generated
77+
/// crate-local number).
7578
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, new)]
7679
pub struct Id(u64);
7780

78-
// Used to indicate a missing index in the Id.
81+
/// Used to indicate a missing index in the Id.
7982
pub const NULL: Id = Id(u64::MAX);
8083

8184
type Blacklist<'a> = &'a [&'static str];
@@ -95,10 +98,7 @@ impl AnalysisHost<CargoAnalysisLoader> {
9598
AnalysisHost {
9699
analysis: Mutex::new(None),
97100
master_crate_map: Mutex::new(HashMap::new()),
98-
loader: CargoAnalysisLoader {
99-
path_prefix: Mutex::new(None),
100-
target,
101-
},
101+
loader: Mutex::new(CargoAnalysisLoader::new(target)),
102102
}
103103
}
104104
}
@@ -108,7 +108,7 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
108108
Self {
109109
analysis: Mutex::new(None),
110110
master_crate_map: Mutex::new(HashMap::new()),
111-
loader,
111+
loader: Mutex::new(loader),
112112
}
113113
}
114114

@@ -117,20 +117,24 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
117117
/// passing in directly.
118118
pub fn reload_from_analysis(
119119
&self,
120-
analysis: data::Analysis,
120+
analysis: Vec<data::Analysis>,
121121
path_prefix: &Path,
122122
base_dir: &Path,
123123
blacklist: Blacklist,
124124
) -> AResult<()> {
125125
self.reload_with_blacklist(path_prefix, base_dir, blacklist)?;
126126

127+
let crates: Vec<_> = analysis.into_iter()
128+
.map(|analysis| raw::Crate::new(analysis, SystemTime::now()))
129+
.collect();
130+
127131
lowering::lower(
128-
vec![raw::Crate::new(analysis, SystemTime::now(), None)],
132+
crates,
129133
base_dir,
130134
self,
131-
|host, per_crate, path| {
135+
|host, per_crate, id| {
132136
let mut a = host.analysis.lock()?;
133-
a.as_mut().unwrap().update(per_crate, path);
137+
a.as_mut().unwrap().update(id, per_crate);
134138
Ok(())
135139
},
136140
)
@@ -152,29 +156,25 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
152156
base_dir,
153157
blacklist
154158
);
155-
let empty = {
156-
let a = self.analysis.lock()?;
157-
a.is_none()
158-
};
159-
if empty || self.loader.needs_hard_reload(path_prefix) {
159+
let empty = self.analysis.lock()?.is_none();
160+
if empty || self.loader.lock()?.needs_hard_reload(path_prefix) {
160161
return self.hard_reload_with_blacklist(path_prefix, base_dir, blacklist);
161162
}
162163

163-
let timestamps = {
164-
let a = self.analysis.lock()?;
165-
a.as_ref().unwrap().timestamps()
164+
let timestamps = self.analysis.lock()?.as_ref().unwrap().timestamps();
165+
let raw_analysis = {
166+
let loader = self.loader.lock()?;
167+
read_analysis_from_files(&*loader, timestamps, blacklist)
166168
};
167169

168-
let raw_analysis = read_analysis_incremental(&self.loader, timestamps, blacklist);
169-
170-
lowering::lower(raw_analysis, base_dir, self, |host, per_crate, path| {
170+
lowering::lower(raw_analysis, base_dir, self, |host, per_crate, id| {
171171
let mut a = host.analysis.lock()?;
172-
a.as_mut().unwrap().update(per_crate, path);
172+
a.as_mut().unwrap().update(id, per_crate);
173173
Ok(())
174174
})
175175
}
176176

177-
// Reloads the entire project's analysis data.
177+
/// Reloads the entire project's analysis data.
178178
pub fn hard_reload(&self, path_prefix: &Path, base_dir: &Path) -> AResult<()> {
179179
self.hard_reload_with_blacklist(path_prefix, base_dir, &[])
180180
}
@@ -186,42 +186,42 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
186186
blacklist: Blacklist,
187187
) -> AResult<()> {
188188
trace!("hard_reload {:?} {:?}", path_prefix, base_dir);
189-
self.loader.set_path_prefix(path_prefix);
190-
let raw_analysis = read_analysis_incremental(&self.loader, HashMap::new(), blacklist);
191-
192189
// We're going to create a dummy AnalysisHost that we will fill with data,
193190
// then once we're done, we'll swap its data into self.
194-
let mut fresh_host = self.loader.fresh_host();
191+
let mut fresh_host = self.loader.lock()?.fresh_host();
195192
fresh_host.analysis = Mutex::new(Some(Analysis::new()));
196-
let lowering_result = lowering::lower(
197-
raw_analysis,
198-
base_dir,
199-
&fresh_host,
200-
|host, per_crate, path| {
201-
host.analysis
202-
.lock()
203-
.unwrap()
204-
.as_mut()
205-
.unwrap()
206-
.per_crate
207-
.insert(path, per_crate);
208-
Ok(())
209-
},
210-
);
211193

212-
if let Err(s) = lowering_result {
213-
let mut a = self.analysis.lock()?;
214-
*a = None;
215-
return Err(s);
194+
{
195+
let mut fresh_loader = fresh_host.loader.lock().unwrap();
196+
fresh_loader.set_path_prefix(path_prefix); // TODO: Needed?
197+
198+
let raw_analysis = read_analysis_from_files(&*fresh_loader,
199+
HashMap::new(),
200+
blacklist);
201+
lowering::lower(raw_analysis, base_dir, &fresh_host, |host, per_crate, id| {
202+
let mut a = host.analysis.lock()?;
203+
a.as_mut().unwrap().update(id, per_crate);
204+
Ok(())
205+
})?;
216206
}
217207

218-
{
219-
let mut mcm = self.master_crate_map.lock()?;
220-
*mcm = fresh_host.master_crate_map.into_inner().unwrap();
208+
// To guarantee a consistent state and no corruption in case an error
209+
// happens during reloading, we need to swap data with a dummy host in
210+
// a single atomic step. We can't lock and swap every member at a time,
211+
// as this can possibly lead to inconsistent state, but now this can possibly
212+
// deadlock, which isn't that good. Ideally we should have guaranteed
213+
// exclusive access to AnalysisHost as a whole to perform a reliable swap.
214+
macro_rules! swap_mutex_fields {
215+
($($name:ident),*) => {
216+
// First, we need exclusive access to every field before swapping
217+
$(let mut $name = self.$name.lock()?;)*
218+
// Then, we can swap every field
219+
$(*$name = fresh_host.$name.into_inner().unwrap();)*
220+
};
221221
}
222222

223-
let mut a = self.analysis.lock()?;
224-
*a = Some(fresh_host.analysis.into_inner().unwrap().unwrap());
223+
swap_mutex_fields!(analysis, master_crate_map, loader);
224+
225225
Ok(())
226226
}
227227

@@ -275,7 +275,12 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
275275
pub fn def_roots(&self) -> AResult<Vec<(Id, String)>> {
276276
self.with_analysis(|a| {
277277
Some(
278-
a.for_all_crates(|c| c.root_id.map(|id| vec![(id, c.name.clone())])),
278+
a.per_crate
279+
.iter()
280+
.filter_map(|(crate_id, data)| {
281+
data.root_id.map(|id| (id, crate_id.name.clone()))
282+
})
283+
.collect()
279284
)
280285
})
281286
}
@@ -448,7 +453,7 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
448453
// e.g., https://github.com/rust-lang/rust/blob/master/src/liballoc/string.rs#L261-L263
449454
pub fn src_url(&self, span: &Span) -> AResult<String> {
450455
// FIXME would be nice not to do this every time.
451-
let path_prefix = &self.loader.abs_path_prefix();
456+
let path_prefix = self.loader.lock().unwrap().abs_path_prefix();
452457

453458
self.with_analysis(|a| {
454459
a.def_id_for_span(span).and_then(|id| {

src/listings/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl DirectoryListing {
5959
path: path.components()
6060
.map(|c| c.as_os_str().to_str().unwrap().to_owned())
6161
.collect(),
62-
files: files,
62+
files,
6363
})
6464
}
6565
}

0 commit comments

Comments
 (0)