aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock10
-rw-r--r--Cargo.toml1
-rw-r--r--crates/ra_db/src/input.rs34
-rw-r--r--crates/ra_db/src/mock.rs7
-rw-r--r--crates/ra_hir/src/krate.rs48
-rw-r--r--crates/ra_hir/src/lib.rs48
-rw-r--r--crates/ra_hir/src/mock.rs24
-rw-r--r--crates/ra_hir/src/module.rs13
-rw-r--r--crates/ra_hir/src/module/nameres.rs203
-rw-r--r--crates/ra_hir/src/module/nameres/tests.rs127
-rw-r--r--crates/ra_hir/src/query_definitions.rs11
-rw-r--r--crates/ra_hir/src/source_binder.rs2
-rw-r--r--crates/ra_lsp_server/Cargo.toml1
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs24
-rw-r--r--crates/ra_lsp_server/src/project_model.rs36
-rw-r--r--crates/ra_lsp_server/src/server_world.rs39
-rw-r--r--editors/code/package-lock.json164
-rw-r--r--editors/code/package.json1
18 files changed, 475 insertions, 318 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 4f46e26fb..1f69a91b2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -697,6 +697,7 @@ dependencies = [
697 "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 697 "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
698 "test_utils 0.1.0", 698 "test_utils 0.1.0",
699 "text_unit 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 699 "text_unit 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
700 "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
700 "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 701 "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
701 "walkdir 2.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 702 "walkdir 2.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
702] 703]
@@ -1104,6 +1105,14 @@ dependencies = [
1104] 1105]
1105 1106
1106[[package]] 1107[[package]]
1108name = "threadpool"
1109version = "1.7.1"
1110source = "registry+https://github.com/rust-lang/crates.io-index"
1111dependencies = [
1112 "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
1113]
1114
1115[[package]]
1107name = "time" 1116name = "time"
1108version = "0.1.40" 1117version = "0.1.40"
1109source = "registry+https://github.com/rust-lang/crates.io-index" 1118source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1414,6 +1423,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1414"checksum text_unit 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8009d7bdbd896a7e09b595f8f9325a19047fc708653e60d0895202b82135048f" 1423"checksum text_unit 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8009d7bdbd896a7e09b595f8f9325a19047fc708653e60d0895202b82135048f"
1415"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" 1424"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
1416"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" 1425"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
1426"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
1417"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" 1427"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
1418"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" 1428"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
1419"checksum ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77" 1429"checksum ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77"
diff --git a/Cargo.toml b/Cargo.toml
index 8e4e84729..5cfc064b5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,5 @@
1[workspace] 1[workspace]
2members = [ "crates/*" ] 2members = [ "crates/*" ]
3exclude = [ "crates/rowan"]
4 3
5[profile.release] 4[profile.release]
6debug = true 5debug = true
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index 7d9faa43c..ac144b991 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -1,7 +1,7 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use rustc_hash::FxHashMap; 3use rustc_hash::{FxHashSet, FxHashMap};
4use rustc_hash::FxHashSet; 4use ra_syntax::SmolStr;
5use salsa; 5use salsa;
6 6
7use crate::file_resolver::FileResolverImp; 7use crate::file_resolver::FileResolverImp;
@@ -20,25 +20,32 @@ pub struct CrateGraph {
20#[derive(Debug, Clone, PartialEq, Eq)] 20#[derive(Debug, Clone, PartialEq, Eq)]
21struct CrateData { 21struct CrateData {
22 file_id: FileId, 22 file_id: FileId,
23 deps: Vec<Dependency>, 23 dependencies: Vec<Dependency>,
24} 24}
25 25
26impl CrateData { 26impl CrateData {
27 fn new(file_id: FileId) -> CrateData { 27 fn new(file_id: FileId) -> CrateData {
28 CrateData { 28 CrateData {
29 file_id, 29 file_id,
30 deps: Vec::new(), 30 dependencies: Vec::new(),
31 } 31 }
32 } 32 }
33 33
34 fn add_dep(&mut self, dep: CrateId) { 34 fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) {
35 self.deps.push(Dependency { crate_: dep }) 35 self.dependencies.push(Dependency { name, crate_id })
36 } 36 }
37} 37}
38 38
39#[derive(Debug, Clone, PartialEq, Eq)] 39#[derive(Debug, Clone, PartialEq, Eq)]
40pub struct Dependency { 40pub struct Dependency {
41 crate_: CrateId, 41 pub crate_id: CrateId,
42 pub name: SmolStr,
43}
44
45impl Dependency {
46 pub fn crate_id(&self) -> CrateId {
47 self.crate_id
48 }
42} 49}
43 50
44impl CrateGraph { 51impl CrateGraph {
@@ -48,8 +55,11 @@ impl CrateGraph {
48 assert!(prev.is_none()); 55 assert!(prev.is_none());
49 crate_id 56 crate_id
50 } 57 }
51 pub fn add_dep(&mut self, from: CrateId, to: CrateId) { 58 //FIXME: check that we don't have cycles here.
52 self.arena.get_mut(&from).unwrap().add_dep(to) 59 // Just a simple depth first search from `to` should work,
60 // the graph is small.
61 pub fn add_dep(&mut self, from: CrateId, name: SmolStr, to: CrateId) {
62 self.arena.get_mut(&from).unwrap().add_dep(name, to)
53 } 63 }
54 pub fn crate_root(&self, crate_id: CrateId) -> FileId { 64 pub fn crate_root(&self, crate_id: CrateId) -> FileId {
55 self.arena[&crate_id].file_id 65 self.arena[&crate_id].file_id
@@ -61,6 +71,12 @@ impl CrateGraph {
61 .find(|(_crate_id, data)| data.file_id == file_id)?; 71 .find(|(_crate_id, data)| data.file_id == file_id)?;
62 Some(crate_id) 72 Some(crate_id)
63 } 73 }
74 pub fn dependencies<'a>(
75 &'a self,
76 crate_id: CrateId,
77 ) -> impl Iterator<Item = &'a Dependency> + 'a {
78 self.arena[&crate_id].dependencies.iter()
79 }
64} 80}
65 81
66salsa::query_group! { 82salsa::query_group! {
diff --git a/crates/ra_db/src/mock.rs b/crates/ra_db/src/mock.rs
index 2840f9655..2f7551597 100644
--- a/crates/ra_db/src/mock.rs
+++ b/crates/ra_db/src/mock.rs
@@ -5,7 +5,7 @@ use relative_path::{RelativePath, RelativePathBuf};
5 5
6use crate::{FileId, FileResolver, SourceRoot, FileResolverImp}; 6use crate::{FileId, FileResolver, SourceRoot, FileResolverImp};
7 7
8#[derive(Default, Debug)] 8#[derive(Default, Debug, Clone)]
9pub struct FileMap(Vec<(FileId, RelativePathBuf)>); 9pub struct FileMap(Vec<(FileId, RelativePathBuf)>);
10 10
11impl FileMap { 11impl FileMap {
@@ -28,6 +28,11 @@ impl FileMap {
28 self.iter().map(|(id, _)| id).collect() 28 self.iter().map(|(id, _)| id).collect()
29 } 29 }
30 30
31 pub fn file_id(&self, path: &str) -> FileId {
32 assert!(path.starts_with('/'));
33 self.iter().find(|(_, p)| p == &path[1..]).unwrap().0
34 }
35
31 fn iter<'a>(&'a self) -> impl Iterator<Item = (FileId, &'a RelativePath)> + 'a { 36 fn iter<'a>(&'a self) -> impl Iterator<Item = (FileId, &'a RelativePath)> + 'a {
32 self.0 37 self.0
33 .iter() 38 .iter()
diff --git a/crates/ra_hir/src/krate.rs b/crates/ra_hir/src/krate.rs
new file mode 100644
index 000000000..1196dcef1
--- /dev/null
+++ b/crates/ra_hir/src/krate.rs
@@ -0,0 +1,48 @@
1use ra_syntax::SmolStr;
2pub use ra_db::CrateId;
3
4use crate::{HirDatabase, Module, Cancelable};
5
6/// hir::Crate describes a single crate. It's the main inteface with which
7/// crate's dependencies interact. Mostly, it should be just a proxy for the
8/// root module.
9#[derive(Debug)]
10pub struct Crate {
11 crate_id: CrateId,
12}
13
14#[derive(Debug)]
15pub struct CrateDependency {
16 pub krate: Crate,
17 pub name: SmolStr,
18}
19
20impl Crate {
21 pub(crate) fn new(crate_id: CrateId) -> Crate {
22 Crate { crate_id }
23 }
24 pub fn dependencies(&self, db: &impl HirDatabase) -> Vec<CrateDependency> {
25 let crate_graph = db.crate_graph();
26 crate_graph
27 .dependencies(self.crate_id)
28 .map(|dep| {
29 let krate = Crate::new(dep.crate_id());
30 let name = dep.name.clone();
31 CrateDependency { krate, name }
32 })
33 .collect()
34 }
35 pub fn root_module(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
36 let crate_graph = db.crate_graph();
37 let file_id = crate_graph.crate_root(self.crate_id);
38 let source_root_id = db.file_source_root(file_id);
39 let module_tree = db.module_tree(source_root_id)?;
40 // FIXME: teach module tree about crate roots instead of guessing
41 let (module_id, _) = ctry!(module_tree
42 .modules_with_sources()
43 .find(|(_, src)| src.file_id() == file_id));
44
45 let module = Module::new(db, source_root_id, module_id)?;
46 Ok(Some(module))
47 }
48}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 983ce99cb..760524f6b 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -18,12 +18,14 @@ pub mod db;
18#[cfg(test)] 18#[cfg(test)]
19mod mock; 19mod mock;
20mod query_definitions; 20mod query_definitions;
21mod function;
22mod module;
23mod path; 21mod path;
24mod arena; 22mod arena;
25pub mod source_binder; 23pub mod source_binder;
26 24
25mod krate;
26mod module;
27mod function;
28
27use std::ops::Index; 29use std::ops::Index;
28 30
29use ra_syntax::{SyntaxNodeRef, SyntaxNode}; 31use ra_syntax::{SyntaxNodeRef, SyntaxNode};
@@ -36,6 +38,7 @@ use crate::{
36 38
37pub use self::{ 39pub use self::{
38 path::{Path, PathKind}, 40 path::{Path, PathKind},
41 krate::Crate,
39 module::{Module, ModuleId, Problem, nameres::ItemMap}, 42 module::{Module, ModuleId, Problem, nameres::ItemMap},
40 function::{Function, FnScopes}, 43 function::{Function, FnScopes},
41}; 44};
@@ -110,22 +113,47 @@ pub struct SourceItemId {
110} 113}
111 114
112/// Maps item's `SyntaxNode`s to `SourceFileItemId` and back. 115/// Maps item's `SyntaxNode`s to `SourceFileItemId` and back.
113#[derive(Debug, PartialEq, Eq, Default)] 116#[derive(Debug, PartialEq, Eq)]
114pub struct SourceFileItems { 117pub struct SourceFileItems {
118 file_id: FileId,
115 arena: Arena<SyntaxNode>, 119 arena: Arena<SyntaxNode>,
116} 120}
117 121
118impl SourceFileItems { 122impl SourceFileItems {
123 fn new(file_id: FileId) -> SourceFileItems {
124 SourceFileItems {
125 file_id,
126 arena: Arena::default(),
127 }
128 }
129
119 fn alloc(&mut self, item: SyntaxNode) -> SourceFileItemId { 130 fn alloc(&mut self, item: SyntaxNode) -> SourceFileItemId {
120 self.arena.alloc(item) 131 self.arena.alloc(item)
121 } 132 }
122 pub fn id_of(&self, item: SyntaxNodeRef) -> SourceFileItemId { 133 pub fn id_of(&self, file_id: FileId, item: SyntaxNodeRef) -> SourceFileItemId {
123 let (id, _item) = self 134 assert_eq!(
124 .arena 135 self.file_id, file_id,
125 .iter() 136 "SourceFileItems: wrong file, expected {:?}, got {:?}",
126 .find(|(_id, i)| i.borrowed() == item) 137 self.file_id, file_id
127 .unwrap(); 138 );
128 id 139 self.id_of_unchecked(item)
140 }
141 fn id_of_unchecked(&self, item: SyntaxNodeRef) -> SourceFileItemId {
142 if let Some((id, _)) = self.arena.iter().find(|(_id, i)| i.borrowed() == item) {
143 return id;
144 }
145 // This should not happen. Let's try to give a sensible diagnostics.
146 if let Some((_, i)) = self.arena.iter().find(|(_id, i)| i.range() == item.range()) {
147 panic!(
148 "unequal syntax nodes with the same range:\n{:?}\n{:?}",
149 item, i
150 )
151 }
152 panic!(
153 "Can't find {:?} in SourceFileItems:\n{:?}",
154 item,
155 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
156 );
129 } 157 }
130 pub fn id_of_source_file(&self) -> SourceFileItemId { 158 pub fn id_of_source_file(&self) -> SourceFileItemId {
131 let (id, _syntax) = self.arena.iter().next().unwrap(); 159 let (id, _syntax) = self.arena.iter().next().unwrap();
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index e855df11d..b7193c4f3 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -2,7 +2,7 @@ use std::sync::Arc;
2 2
3use parking_lot::Mutex; 3use parking_lot::Mutex;
4use salsa::{self, Database}; 4use salsa::{self, Database};
5use ra_db::{LocationIntener, BaseDatabase, FilePosition, mock::FileMap, FileId, WORKSPACE}; 5use ra_db::{LocationIntener, BaseDatabase, FilePosition, mock::FileMap, FileId, WORKSPACE, CrateGraph};
6use relative_path::RelativePathBuf; 6use relative_path::RelativePathBuf;
7use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; 7use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset};
8 8
@@ -16,7 +16,24 @@ pub(crate) struct MockDatabase {
16} 16}
17 17
18impl MockDatabase { 18impl MockDatabase {
19 pub(crate) fn with_files(fixture: &str) -> (MockDatabase, FileMap) {
20 let (db, file_map, position) = MockDatabase::from_fixture(fixture);
21 assert!(position.is_none());
22 (db, file_map)
23 }
24
19 pub(crate) fn with_position(fixture: &str) -> (MockDatabase, FilePosition) { 25 pub(crate) fn with_position(fixture: &str) -> (MockDatabase, FilePosition) {
26 let (db, _, position) = MockDatabase::from_fixture(fixture);
27 let position = position.expect("expected a marker ( <|> )");
28 (db, position)
29 }
30
31 pub(crate) fn set_crate_graph(&mut self, crate_graph: CrateGraph) {
32 self.query_mut(ra_db::CrateGraphQuery)
33 .set((), Arc::new(crate_graph));
34 }
35
36 fn from_fixture(fixture: &str) -> (MockDatabase, FileMap, Option<FilePosition>) {
20 let mut db = MockDatabase::default(); 37 let mut db = MockDatabase::default();
21 38
22 let mut position = None; 39 let mut position = None;
@@ -32,11 +49,10 @@ impl MockDatabase {
32 db.add_file(&mut file_map, &entry.meta, &entry.text); 49 db.add_file(&mut file_map, &entry.meta, &entry.text);
33 } 50 }
34 } 51 }
35 let position = position.expect("expected a marker (<|>)"); 52 let source_root = file_map.clone().into_source_root();
36 let source_root = file_map.into_source_root();
37 db.query_mut(ra_db::SourceRootQuery) 53 db.query_mut(ra_db::SourceRootQuery)
38 .set(WORKSPACE, Arc::new(source_root)); 54 .set(WORKSPACE, Arc::new(source_root));
39 (db, position) 55 (db, file_map, position)
40 } 56 }
41 57
42 fn add_file(&mut self, file_map: &mut FileMap, path: &str, text: &str) -> FileId { 58 fn add_file(&mut self, file_map: &mut FileMap, path: &str, text: &str) -> FileId {
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs
index 580c737c3..c6bb76d56 100644
--- a/crates/ra_hir/src/module.rs
+++ b/crates/ra_hir/src/module.rs
@@ -12,7 +12,7 @@ use ra_db::{SourceRootId, FileId, Cancelable};
12use relative_path::RelativePathBuf; 12use relative_path::RelativePathBuf;
13 13
14use crate::{ 14use crate::{
15 DefKind, DefLoc, DefId, Path, PathKind, HirDatabase, SourceItemId, SourceFileItemId, 15 DefKind, DefLoc, DefId, Path, PathKind, HirDatabase, SourceItemId, SourceFileItemId, Crate,
16 arena::{Arena, Id}, 16 arena::{Arena, Id},
17}; 17};
18 18
@@ -64,6 +64,15 @@ impl Module {
64 }) 64 })
65 } 65 }
66 66
67 /// Returns the crate this module is part of.
68 pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> {
69 let root_id = self.module_id.crate_root(&self.tree);
70 let file_id = root_id.source(&self.tree).file_id();
71 let crate_graph = db.crate_graph();
72 let crate_id = crate_graph.crate_id_for_crate_root(file_id)?;
73 Some(Crate::new(crate_id))
74 }
75
67 /// The root of the tree this module is part of 76 /// The root of the tree this module is part of
68 pub fn crate_root(&self) -> Module { 77 pub fn crate_root(&self) -> Module {
69 let root_id = self.module_id.crate_root(&self.tree); 78 let root_id = self.module_id.crate_root(&self.tree);
@@ -280,7 +289,7 @@ impl ModuleSource {
280 ) -> ModuleSource { 289 ) -> ModuleSource {
281 assert!(!m.has_semi()); 290 assert!(!m.has_semi());
282 let file_items = db.file_items(file_id); 291 let file_items = db.file_items(file_id);
283 let item_id = file_items.id_of(m.syntax()); 292 let item_id = file_items.id_of(file_id, m.syntax());
284 ModuleSource::new(file_id, item_id) 293 ModuleSource::new(file_id, item_id)
285 } 294 }
286 295
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs
index 61a1acfe6..9afeade9e 100644
--- a/crates/ra_hir/src/module/nameres.rs
+++ b/crates/ra_hir/src/module/nameres.rs
@@ -31,7 +31,7 @@ use crate::{
31 DefId, DefLoc, DefKind, 31 DefId, DefLoc, DefKind,
32 SourceItemId, SourceFileItemId, SourceFileItems, 32 SourceItemId, SourceFileItemId, SourceFileItems,
33 Path, PathKind, 33 Path, PathKind,
34 HirDatabase, 34 HirDatabase, Crate,
35 module::{ModuleId, ModuleTree}, 35 module::{ModuleId, ModuleTree},
36}; 36};
37 37
@@ -168,7 +168,7 @@ impl InputModuleItems {
168 } 168 }
169 169
170 fn add_use_item(&mut self, file_items: &SourceFileItems, item: ast::UseItem) { 170 fn add_use_item(&mut self, file_items: &SourceFileItems, item: ast::UseItem) {
171 let file_item_id = file_items.id_of(item.syntax()); 171 let file_item_id = file_items.id_of_unchecked(item.syntax());
172 let start_offset = item.syntax().range().start(); 172 let start_offset = item.syntax().range().start();
173 Path::expand_use_item(item, |path, range| { 173 Path::expand_use_item(item, |path, range| {
174 let kind = match range { 174 let kind = match range {
@@ -188,7 +188,7 @@ impl ModuleItem {
188 let name = item.name()?.text(); 188 let name = item.name()?.text();
189 let kind = item.syntax().kind(); 189 let kind = item.syntax().kind();
190 let vis = Vis::Other; 190 let vis = Vis::Other;
191 let id = file_items.id_of(item.syntax()); 191 let id = file_items.id_of_unchecked(item.syntax());
192 let res = ModuleItem { 192 let res = ModuleItem {
193 id, 193 id,
194 name, 194 name,
@@ -200,34 +200,63 @@ impl ModuleItem {
200} 200}
201 201
202pub(crate) struct Resolver<'a, DB> { 202pub(crate) struct Resolver<'a, DB> {
203 pub(crate) db: &'a DB, 203 db: &'a DB,
204 pub(crate) input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>, 204 input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>,
205 pub(crate) source_root: SourceRootId, 205 source_root: SourceRootId,
206 pub(crate) module_tree: Arc<ModuleTree>, 206 module_tree: Arc<ModuleTree>,
207 pub(crate) result: ItemMap, 207 result: ItemMap,
208} 208}
209 209
210impl<'a, DB> Resolver<'a, DB> 210impl<'a, DB> Resolver<'a, DB>
211where 211where
212 DB: HirDatabase, 212 DB: HirDatabase,
213{ 213{
214 pub(crate) fn new(
215 db: &'a DB,
216 input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>,
217 source_root: SourceRootId,
218 module_tree: Arc<ModuleTree>,
219 ) -> Resolver<'a, DB> {
220 Resolver {
221 db,
222 input,
223 source_root,
224 module_tree,
225 result: ItemMap::default(),
226 }
227 }
228
214 pub(crate) fn resolve(mut self) -> Cancelable<ItemMap> { 229 pub(crate) fn resolve(mut self) -> Cancelable<ItemMap> {
215 for (&module_id, items) in self.input.iter() { 230 for (&module_id, items) in self.input.iter() {
216 self.populate_module(module_id, items) 231 self.populate_module(module_id, items)?;
217 } 232 }
218 233
219 for &module_id in self.input.keys() { 234 for &module_id in self.input.keys() {
220 self.db.check_canceled()?; 235 self.db.check_canceled()?;
221 self.resolve_imports(module_id); 236 self.resolve_imports(module_id)?;
222 } 237 }
223 Ok(self.result) 238 Ok(self.result)
224 } 239 }
225 240
226 fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) { 241 fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) -> Cancelable<()> {
227 let file_id = module_id.source(&self.module_tree).file_id(); 242 let file_id = module_id.source(&self.module_tree).file_id();
228 243
229 let mut module_items = ModuleScope::default(); 244 let mut module_items = ModuleScope::default();
230 245
246 // Populate extern crates prelude
247 {
248 let root_id = module_id.crate_root(&self.module_tree);
249 let file_id = root_id.source(&self.module_tree).file_id();
250 let crate_graph = self.db.crate_graph();
251 if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id) {
252 let krate = Crate::new(crate_id);
253 for dep in krate.dependencies(self.db) {
254 if let Some(module) = dep.krate.root_module(self.db)? {
255 self.add_module_item(&mut module_items, dep.name, module.module_id);
256 }
257 }
258 };
259 }
231 for import in input.imports.iter() { 260 for import in input.imports.iter() {
232 if let Some(name) = import.path.segments.iter().last() { 261 if let Some(name) = import.path.segments.iter().last() {
233 if let ImportKind::Named(import) = import.kind { 262 if let ImportKind::Named(import) = import.kind {
@@ -241,10 +270,9 @@ where
241 } 270 }
242 } 271 }
243 } 272 }
244 273 // Populate explicitelly declared items, except modules
245 for item in input.items.iter() { 274 for item in input.items.iter() {
246 if item.kind == MODULE { 275 if item.kind == MODULE {
247 // handle submodules separatelly
248 continue; 276 continue;
249 } 277 }
250 let def_loc = DefLoc { 278 let def_loc = DefLoc {
@@ -264,45 +292,50 @@ where
264 module_items.items.insert(item.name.clone(), resolution); 292 module_items.items.insert(item.name.clone(), resolution);
265 } 293 }
266 294
295 // Populate modules
267 for (name, module_id) in module_id.children(&self.module_tree) { 296 for (name, module_id) in module_id.children(&self.module_tree) {
268 let def_loc = DefLoc { 297 self.add_module_item(&mut module_items, name, module_id);
269 kind: DefKind::Module,
270 source_root_id: self.source_root,
271 module_id,
272 source_item_id: module_id.source(&self.module_tree).0,
273 };
274 let def_id = def_loc.id(self.db);
275 let resolution = Resolution {
276 def_id: Some(def_id),
277 import: None,
278 };
279 module_items.items.insert(name, resolution);
280 } 298 }
281 299
282 self.result.per_module.insert(module_id, module_items); 300 self.result.per_module.insert(module_id, module_items);
301 Ok(())
283 } 302 }
284 303
285 fn resolve_imports(&mut self, module_id: ModuleId) { 304 fn add_module_item(&self, module_items: &mut ModuleScope, name: SmolStr, module_id: ModuleId) {
305 let def_loc = DefLoc {
306 kind: DefKind::Module,
307 source_root_id: self.source_root,
308 module_id,
309 source_item_id: module_id.source(&self.module_tree).0,
310 };
311 let def_id = def_loc.id(self.db);
312 let resolution = Resolution {
313 def_id: Some(def_id),
314 import: None,
315 };
316 module_items.items.insert(name, resolution);
317 }
318
319 fn resolve_imports(&mut self, module_id: ModuleId) -> Cancelable<()> {
286 for import in self.input[&module_id].imports.iter() { 320 for import in self.input[&module_id].imports.iter() {
287 self.resolve_import(module_id, import); 321 self.resolve_import(module_id, import)?;
288 } 322 }
323 Ok(())
289 } 324 }
290 325
291 fn resolve_import(&mut self, module_id: ModuleId, import: &Import) { 326 fn resolve_import(&mut self, module_id: ModuleId, import: &Import) -> Cancelable<()> {
292 let ptr = match import.kind { 327 let ptr = match import.kind {
293 ImportKind::Glob => return, 328 ImportKind::Glob => return Ok(()),
294 ImportKind::Named(ptr) => ptr, 329 ImportKind::Named(ptr) => ptr,
295 }; 330 };
296 331
297 let mut curr = match import.path.kind { 332 let mut curr = match import.path.kind {
298 // TODO: handle extern crates 333 PathKind::Plain | PathKind::Self_ => module_id,
299 PathKind::Plain => return,
300 PathKind::Self_ => module_id,
301 PathKind::Super => { 334 PathKind::Super => {
302 match module_id.parent(&self.module_tree) { 335 match module_id.parent(&self.module_tree) {
303 Some(it) => it, 336 Some(it) => it,
304 // TODO: error 337 // TODO: error
305 None => return, 338 None => return Ok(()),
306 } 339 }
307 } 340 }
308 PathKind::Crate => module_id.crate_root(&self.module_tree), 341 PathKind::Crate => module_id.crate_root(&self.module_tree),
@@ -312,10 +345,10 @@ where
312 let is_last = i == import.path.segments.len() - 1; 345 let is_last = i == import.path.segments.len() - 1;
313 346
314 let def_id = match self.result.per_module[&curr].items.get(name) { 347 let def_id = match self.result.per_module[&curr].items.get(name) {
315 None => return, 348 None => return Ok(()),
316 Some(res) => match res.def_id { 349 Some(res) => match res.def_id {
317 Some(it) => it, 350 Some(it) => it,
318 None => return, 351 None => return Ok(()),
319 }, 352 },
320 }; 353 };
321 354
@@ -326,7 +359,7 @@ where
326 module_id, 359 module_id,
327 .. 360 ..
328 } => module_id, 361 } => module_id,
329 _ => return, 362 _ => return Ok(()),
330 } 363 }
331 } else { 364 } else {
332 self.update(module_id, |items| { 365 self.update(module_id, |items| {
@@ -338,6 +371,7 @@ where
338 }) 371 })
339 } 372 }
340 } 373 }
374 Ok(())
341 } 375 }
342 376
343 fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) { 377 fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) {
@@ -347,99 +381,4 @@ where
347} 381}
348 382
349#[cfg(test)] 383#[cfg(test)]
350mod tests { 384mod tests;
351 use std::sync::Arc;
352
353 use salsa::Database;
354 use ra_db::FilesDatabase;
355 use ra_syntax::SmolStr;
356
357 use crate::{
358 self as hir,
359 db::HirDatabase,
360 mock::MockDatabase,
361};
362
363 fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
364 let (db, pos) = MockDatabase::with_position(fixture);
365 let source_root = db.file_source_root(pos.file_id);
366 let module = hir::source_binder::module_from_position(&db, pos)
367 .unwrap()
368 .unwrap();
369 let module_id = module.module_id;
370 (db.item_map(source_root).unwrap(), module_id)
371 }
372
373 #[test]
374 fn test_item_map() {
375 let (item_map, module_id) = item_map(
376 "
377 //- /lib.rs
378 mod foo;
379
380 use crate::foo::bar::Baz;
381 <|>
382
383 //- /foo/mod.rs
384 pub mod bar;
385
386 //- /foo/bar.rs
387 pub struct Baz;
388 ",
389 );
390 let name = SmolStr::from("Baz");
391 let resolution = &item_map.per_module[&module_id].items[&name];
392 assert!(resolution.def_id.is_some());
393 }
394
395 #[test]
396 fn typing_inside_a_function_should_not_invalidate_item_map() {
397 let (mut db, pos) = MockDatabase::with_position(
398 "
399 //- /lib.rs
400 mod foo;<|>
401
402 use crate::foo::bar::Baz;
403
404 fn foo() -> i32 {
405 1 + 1
406 }
407 //- /foo/mod.rs
408 pub mod bar;
409
410 //- /foo/bar.rs
411 pub struct Baz;
412 ",
413 );
414 let source_root = db.file_source_root(pos.file_id);
415 {
416 let events = db.log_executed(|| {
417 db.item_map(source_root).unwrap();
418 });
419 assert!(format!("{:?}", events).contains("item_map"))
420 }
421
422 let new_text = "
423 mod foo;
424
425 use crate::foo::bar::Baz;
426
427 fn foo() -> i32 { 92 }
428 "
429 .to_string();
430
431 db.query_mut(ra_db::FileTextQuery)
432 .set(pos.file_id, Arc::new(new_text));
433
434 {
435 let events = db.log_executed(|| {
436 db.item_map(source_root).unwrap();
437 });
438 assert!(
439 !format!("{:?}", events).contains("_item_map"),
440 "{:#?}",
441 events
442 )
443 }
444 }
445}
diff --git a/crates/ra_hir/src/module/nameres/tests.rs b/crates/ra_hir/src/module/nameres/tests.rs
new file mode 100644
index 000000000..9ddc32dcd
--- /dev/null
+++ b/crates/ra_hir/src/module/nameres/tests.rs
@@ -0,0 +1,127 @@
1use std::sync::Arc;
2
3use salsa::Database;
4use ra_db::{FilesDatabase, CrateGraph};
5use ra_syntax::SmolStr;
6
7use crate::{
8 self as hir,
9 db::HirDatabase,
10 mock::MockDatabase,
11};
12
13fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
14 let (db, pos) = MockDatabase::with_position(fixture);
15 let source_root = db.file_source_root(pos.file_id);
16 let module = hir::source_binder::module_from_position(&db, pos)
17 .unwrap()
18 .unwrap();
19 let module_id = module.module_id;
20 (db.item_map(source_root).unwrap(), module_id)
21}
22
23#[test]
24fn item_map_smoke_test() {
25 let (item_map, module_id) = item_map(
26 "
27 //- /lib.rs
28 mod foo;
29
30 use crate::foo::bar::Baz;
31 <|>
32
33 //- /foo/mod.rs
34 pub mod bar;
35
36 //- /foo/bar.rs
37 pub struct Baz;
38 ",
39 );
40 let name = SmolStr::from("Baz");
41 let resolution = &item_map.per_module[&module_id].items[&name];
42 assert!(resolution.def_id.is_some());
43}
44
45#[test]
46fn item_map_across_crates() {
47 let (mut db, files) = MockDatabase::with_files(
48 "
49 //- /main.rs
50 use test_crate::Baz;
51
52 //- /lib.rs
53 pub struct Baz;
54 ",
55 );
56 let main_id = files.file_id("/main.rs");
57 let lib_id = files.file_id("/lib.rs");
58
59 let mut crate_graph = CrateGraph::default();
60 let main_crate = crate_graph.add_crate_root(main_id);
61 let lib_crate = crate_graph.add_crate_root(lib_id);
62 crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate);
63
64 db.set_crate_graph(crate_graph);
65
66 let source_root = db.file_source_root(main_id);
67 let module = hir::source_binder::module_from_file_id(&db, main_id)
68 .unwrap()
69 .unwrap();
70 let module_id = module.module_id;
71 let item_map = db.item_map(source_root).unwrap();
72
73 let name = SmolStr::from("Baz");
74 let resolution = &item_map.per_module[&module_id].items[&name];
75 assert!(resolution.def_id.is_some());
76}
77
78#[test]
79fn typing_inside_a_function_should_not_invalidate_item_map() {
80 let (mut db, pos) = MockDatabase::with_position(
81 "
82 //- /lib.rs
83 mod foo;<|>
84
85 use crate::foo::bar::Baz;
86
87 fn foo() -> i32 {
88 1 + 1
89 }
90 //- /foo/mod.rs
91 pub mod bar;
92
93 //- /foo/bar.rs
94 pub struct Baz;
95 ",
96 );
97 let source_root = db.file_source_root(pos.file_id);
98 {
99 let events = db.log_executed(|| {
100 db.item_map(source_root).unwrap();
101 });
102 assert!(format!("{:?}", events).contains("item_map"))
103 }
104
105 let new_text = "
106 mod foo;
107
108 use crate::foo::bar::Baz;
109
110 fn foo() -> i32 { 92 }
111 "
112 .to_string();
113
114 db.query_mut(ra_db::FileTextQuery)
115 .set(pos.file_id, Arc::new(new_text));
116
117 {
118 let events = db.log_executed(|| {
119 db.item_map(source_root).unwrap();
120 });
121 assert!(
122 !format!("{:?}", events).contains("_item_map"),
123 "{:#?}",
124 events
125 )
126 }
127}
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs
index e4d721601..37c4f9e4f 100644
--- a/crates/ra_hir/src/query_definitions.rs
+++ b/crates/ra_hir/src/query_definitions.rs
@@ -36,7 +36,7 @@ pub(super) fn fn_scopes(db: &impl HirDatabase, fn_id: FnId) -> Arc<FnScopes> {
36} 36}
37 37
38pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> { 38pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> {
39 let mut res = SourceFileItems::default(); 39 let mut res = SourceFileItems::new(file_id);
40 let source_file = db.source_file(file_id); 40 let source_file = db.source_file(file_id);
41 res.alloc(source_file.syntax().owned()); 41 res.alloc(source_file.syntax().owned());
42 let source_file = source_file.borrowed(); 42 let source_file = source_file.borrowed();
@@ -141,13 +141,8 @@ pub(super) fn item_map(
141 Ok((id, items)) 141 Ok((id, items))
142 }) 142 })
143 .collect::<Cancelable<FxHashMap<_, _>>>()?; 143 .collect::<Cancelable<FxHashMap<_, _>>>()?;
144 let resolver = Resolver { 144
145 db: db, 145 let resolver = Resolver::new(db, &input, source_root, module_tree);
146 input: &input,
147 source_root,
148 module_tree,
149 result: ItemMap::default(),
150 };
151 let res = resolver.resolve()?; 146 let res = resolver.resolve()?;
152 let elapsed = start.elapsed(); 147 let elapsed = start.elapsed();
153 log::info!("item_map: {:?}", elapsed); 148 log::info!("item_map: {:?}", elapsed);
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 479155805..0c16ccc24 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -75,7 +75,7 @@ pub fn function_from_source(
75) -> Cancelable<Option<Function>> { 75) -> Cancelable<Option<Function>> {
76 let module = ctry!(module_from_child_node(db, file_id, fn_def.syntax())?); 76 let module = ctry!(module_from_child_node(db, file_id, fn_def.syntax())?);
77 let file_items = db.file_items(file_id); 77 let file_items = db.file_items(file_id);
78 let item_id = file_items.id_of(fn_def.syntax()); 78 let item_id = file_items.id_of(file_id, fn_def.syntax());
79 let source_item_id = SourceItemId { file_id, item_id }; 79 let source_item_id = SourceItemId { file_id, item_id };
80 let def_loc = DefLoc { 80 let def_loc = DefLoc {
81 kind: DefKind::Function, 81 kind: DefKind::Function,
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index 79d86f9b2..5ee218b6b 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -6,6 +6,7 @@ authors = ["Aleksey Kladov <[email protected]>"]
6 6
7[dependencies] 7[dependencies]
8rayon = "1.0.2" 8rayon = "1.0.2"
9threadpool = "1.7.1"
9relative-path = "0.4.0" 10relative-path = "0.4.0"
10failure = "0.1.2" 11failure = "0.1.2"
11failure_derive = "0.1.2" 12failure_derive = "0.1.2"
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 0e1878906..41f70f263 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -9,7 +9,8 @@ use gen_lsp_server::{
9}; 9};
10use languageserver_types::NumberOrString; 10use languageserver_types::NumberOrString;
11use ra_analysis::{Canceled, FileId, LibraryData}; 11use ra_analysis::{Canceled, FileId, LibraryData};
12use rayon::{self, ThreadPool}; 12use rayon;
13use threadpool::ThreadPool;
13use rustc_hash::FxHashSet; 14use rustc_hash::FxHashSet;
14use serde::{de::DeserializeOwned, Serialize}; 15use serde::{de::DeserializeOwned, Serialize};
15use failure::{format_err, bail}; 16use failure::{format_err, bail};
@@ -54,11 +55,7 @@ pub fn main_loop(
54 msg_receiver: &Receiver<RawMessage>, 55 msg_receiver: &Receiver<RawMessage>,
55 msg_sender: &Sender<RawMessage>, 56 msg_sender: &Sender<RawMessage>,
56) -> Result<()> { 57) -> Result<()> {
57 let pool = rayon::ThreadPoolBuilder::new() 58 let pool = ThreadPool::new(8);
58 .num_threads(4)
59 .panic_handler(|_| log::error!("thread panicked :("))
60 .build()
61 .unwrap();
62 let (task_sender, task_receiver) = unbounded::<Task>(); 59 let (task_sender, task_receiver) = unbounded::<Task>();
63 let (fs_worker, fs_watcher) = vfs::roots_loader(); 60 let (fs_worker, fs_watcher) = vfs::roots_loader();
64 let (ws_worker, ws_watcher) = workspace_loader(); 61 let (ws_worker, ws_watcher) = workspace_loader();
@@ -155,7 +152,7 @@ fn main_loop_inner(
155 } else { 152 } else {
156 let (files, resolver) = state.events_to_files(events); 153 let (files, resolver) = state.events_to_files(events);
157 let sender = libdata_sender.clone(); 154 let sender = libdata_sender.clone();
158 pool.spawn(move || { 155 pool.execute(move || {
159 let start = ::std::time::Instant::now(); 156 let start = ::std::time::Instant::now();
160 log::info!("indexing {} ... ", root.display()); 157 log::info!("indexing {} ... ", root.display());
161 let data = LibraryData::prepare(files, resolver); 158 let data = LibraryData::prepare(files, resolver);
@@ -321,7 +318,14 @@ fn on_notification(
321 panic!("string id's not supported: {:?}", id); 318 panic!("string id's not supported: {:?}", id);
322 } 319 }
323 }; 320 };
324 pending_requests.remove(&id); 321 if pending_requests.remove(&id) {
322 let response = RawResponse::err(
323 id,
324 ErrorCode::RequestCancelled as i32,
325 "canceled by client".to_string(),
326 );
327 msg_sender.send(RawMessage::Response(response))
328 }
325 return Ok(()); 329 return Ok(());
326 } 330 }
327 Err(not) => not, 331 Err(not) => not,
@@ -402,7 +406,7 @@ impl<'a> PoolDispatcher<'a> {
402 Ok((id, params)) => { 406 Ok((id, params)) => {
403 let world = self.world.snapshot(); 407 let world = self.world.snapshot();
404 let sender = self.sender.clone(); 408 let sender = self.sender.clone();
405 self.pool.spawn(move || { 409 self.pool.execute(move || {
406 let resp = match f(world, params) { 410 let resp = match f(world, params) {
407 Ok(resp) => RawResponse::ok::<R>(id, &resp), 411 Ok(resp) => RawResponse::ok::<R>(id, &resp),
408 Err(e) => match e.downcast::<LspError>() { 412 Err(e) => match e.downcast::<LspError>() {
@@ -452,7 +456,7 @@ fn update_file_notifications_on_threadpool(
452 sender: Sender<Task>, 456 sender: Sender<Task>,
453 subscriptions: Vec<FileId>, 457 subscriptions: Vec<FileId>,
454) { 458) {
455 pool.spawn(move || { 459 pool.execute(move || {
456 for file_id in subscriptions { 460 for file_id in subscriptions {
457 match handlers::publish_diagnostics(&world, file_id) { 461 match handlers::publish_diagnostics(&world, file_id) {
458 Err(e) => { 462 Err(e) => {
diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs
index 3305d468a..cb91ada90 100644
--- a/crates/ra_lsp_server/src/project_model.rs
+++ b/crates/ra_lsp_server/src/project_model.rs
@@ -1,6 +1,5 @@
1use std::path::{Path, PathBuf}; 1use std::path::{Path, PathBuf};
2 2
3use serde_derive::Serialize;
4use cargo_metadata::{metadata_run, CargoOpt}; 3use cargo_metadata::{metadata_run, CargoOpt};
5use ra_syntax::SmolStr; 4use ra_syntax::SmolStr;
6use rustc_hash::{FxHashMap, FxHashSet}; 5use rustc_hash::{FxHashMap, FxHashSet};
@@ -11,15 +10,22 @@ use crate::{
11 thread_watcher::{ThreadWatcher, Worker}, 10 thread_watcher::{ThreadWatcher, Worker},
12}; 11};
13 12
13/// `CargoWorksapce` represents the logical structure of, well, a Cargo
14/// workspace. It pretty closely mirrors `cargo metadata` output.
15///
16/// Note that internally, rust analyzer uses a differnet structure:
17/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
18/// while this knows about `Pacakges` & `Targets`: purely cargo-related
19/// concepts.
14#[derive(Debug, Clone)] 20#[derive(Debug, Clone)]
15pub struct CargoWorkspace { 21pub struct CargoWorkspace {
16 packages: Vec<PackageData>, 22 packages: Vec<PackageData>,
17 targets: Vec<TargetData>, 23 targets: Vec<TargetData>,
18} 24}
19 25
20#[derive(Clone, Copy, Debug, Serialize)] 26#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
21pub struct Package(usize); 27pub struct Package(usize);
22#[derive(Clone, Copy, Debug, Serialize)] 28#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
23pub struct Target(usize); 29pub struct Target(usize);
24 30
25#[derive(Debug, Clone)] 31#[derive(Debug, Clone)]
@@ -28,6 +34,13 @@ struct PackageData {
28 manifest: PathBuf, 34 manifest: PathBuf,
29 targets: Vec<Target>, 35 targets: Vec<Target>,
30 is_member: bool, 36 is_member: bool,
37 dependencies: Vec<PackageDependency>,
38}
39
40#[derive(Debug, Clone)]
41pub struct PackageDependency {
42 pub pkg: Package,
43 pub name: SmolStr,
31} 44}
32 45
33#[derive(Debug, Clone)] 46#[derive(Debug, Clone)]
@@ -61,6 +74,12 @@ impl Package {
61 pub fn is_member(self, ws: &CargoWorkspace) -> bool { 74 pub fn is_member(self, ws: &CargoWorkspace) -> bool {
62 ws.pkg(self).is_member 75 ws.pkg(self).is_member
63 } 76 }
77 pub fn dependencies<'a>(
78 self,
79 ws: &'a CargoWorkspace,
80 ) -> impl Iterator<Item = &'a PackageDependency> + 'a {
81 ws.pkg(self).dependencies.iter()
82 }
64} 83}
65 84
66impl Target { 85impl Target {
@@ -106,6 +125,7 @@ impl CargoWorkspace {
106 manifest: PathBuf::from(meta_pkg.manifest_path), 125 manifest: PathBuf::from(meta_pkg.manifest_path),
107 targets: Vec::new(), 126 targets: Vec::new(),
108 is_member, 127 is_member,
128 dependencies: Vec::new(),
109 }; 129 };
110 for meta_tgt in meta_pkg.targets { 130 for meta_tgt in meta_pkg.targets {
111 let tgt = Target(targets.len()); 131 let tgt = Target(targets.len());
@@ -119,6 +139,16 @@ impl CargoWorkspace {
119 } 139 }
120 packages.push(pkg_data) 140 packages.push(pkg_data)
121 } 141 }
142 let resolve = meta.resolve.expect("metadata executed with deps");
143 for node in resolve.nodes {
144 let source = pkg_by_id[&node.id];
145 for id in node.dependencies {
146 let target = pkg_by_id[&id];
147 let name: SmolStr = packages[target.0].name.replace('-', "_").into();
148 let dep = PackageDependency { name, pkg: target };
149 packages[source.0].dependencies.push(dep);
150 }
151 }
122 152
123 Ok(CargoWorkspace { packages, targets }) 153 Ok(CargoWorkspace { packages, targets })
124 } 154 }
diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs
index c3f89ad5f..ab4c2c8aa 100644
--- a/crates/ra_lsp_server/src/server_world.rs
+++ b/crates/ra_lsp_server/src/server_world.rs
@@ -13,7 +13,7 @@ use failure::{bail, format_err};
13 13
14use crate::{ 14use crate::{
15 path_map::{PathMap, Root}, 15 path_map::{PathMap, Root},
16 project_model::CargoWorkspace, 16 project_model::{CargoWorkspace, TargetKind},
17 vfs::{FileEvent, FileEventKind}, 17 vfs::{FileEvent, FileEventKind},
18 Result, 18 Result,
19}; 19};
@@ -142,17 +142,34 @@ impl ServerWorldState {
142 } 142 }
143 pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) { 143 pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) {
144 let mut crate_graph = CrateGraph::default(); 144 let mut crate_graph = CrateGraph::default();
145 ws.iter() 145 let mut pkg_to_lib_crate = FxHashMap::default();
146 .flat_map(|ws| { 146 let mut pkg_crates = FxHashMap::default();
147 ws.packages() 147 for ws in ws.iter() {
148 .flat_map(move |pkg| pkg.targets(ws)) 148 for pkg in ws.packages() {
149 .map(move |tgt| tgt.root(ws)) 149 for tgt in pkg.targets(ws) {
150 }) 150 let root = tgt.root(ws);
151 .for_each(|root| { 151 if let Some(file_id) = self.path_map.get_id(root) {
152 if let Some(file_id) = self.path_map.get_id(root) { 152 let crate_id = crate_graph.add_crate_root(file_id);
153 crate_graph.add_crate_root(file_id); 153 if tgt.kind(ws) == TargetKind::Lib {
154 pkg_to_lib_crate.insert(pkg, crate_id);
155 }
156 pkg_crates
157 .entry(pkg)
158 .or_insert_with(Vec::new)
159 .push(crate_id);
160 }
161 }
162 }
163 for pkg in ws.packages() {
164 for dep in pkg.dependencies(ws) {
165 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
166 for &from in pkg_crates.get(&pkg).into_iter().flatten() {
167 crate_graph.add_dep(from, dep.name.clone(), to);
168 }
169 }
154 } 170 }
155 }); 171 }
172 }
156 self.workspaces = Arc::new(ws); 173 self.workspaces = Arc::new(ws);
157 let mut change = AnalysisChange::new(); 174 let mut change = AnalysisChange::new();
158 change.set_crate_graph(crate_graph); 175 change.set_crate_graph(crate_graph);
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index e74fd2a63..0b6d72917 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -437,7 +437,7 @@
437 }, 437 },
438 "css-select": { 438 "css-select": {
439 "version": "1.2.0", 439 "version": "1.2.0",
440 "resolved": "http://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", 440 "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
441 "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", 441 "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
442 "dev": true, 442 "dev": true,
443 "requires": { 443 "requires": {
@@ -473,7 +473,7 @@
473 }, 473 },
474 "deep-assign": { 474 "deep-assign": {
475 "version": "1.0.0", 475 "version": "1.0.0",
476 "resolved": "http://registry.npmjs.org/deep-assign/-/deep-assign-1.0.0.tgz", 476 "resolved": "https://registry.npmjs.org/deep-assign/-/deep-assign-1.0.0.tgz",
477 "integrity": "sha1-sJJ0O+hCfcYh6gBnzex+cN0Z83s=", 477 "integrity": "sha1-sJJ0O+hCfcYh6gBnzex+cN0Z83s=",
478 "dev": true, 478 "dev": true,
479 "requires": { 479 "requires": {
@@ -519,7 +519,7 @@
519 "dependencies": { 519 "dependencies": {
520 "domelementtype": { 520 "domelementtype": {
521 "version": "1.1.3", 521 "version": "1.1.3",
522 "resolved": "http://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", 522 "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
523 "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", 523 "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=",
524 "dev": true 524 "dev": true
525 } 525 }
@@ -553,7 +553,8 @@
553 "duplexer": { 553 "duplexer": {
554 "version": "0.1.1", 554 "version": "0.1.1",
555 "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", 555 "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
556 "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" 556 "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
557 "dev": true
557 }, 558 },
558 "duplexify": { 559 "duplexify": {
559 "version": "3.6.1", 560 "version": "3.6.1",
@@ -637,16 +638,17 @@
637 "dev": true 638 "dev": true
638 }, 639 },
639 "event-stream": { 640 "event-stream": {
640 "version": "4.0.1", 641 "version": "3.3.4",
641 "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz", 642 "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
642 "integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==", 643 "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=",
644 "dev": true,
643 "requires": { 645 "requires": {
644 "duplexer": "0.1.1", 646 "duplexer": "0.1.1",
645 "from": "0.1.7", 647 "from": "0.1.7",
646 "map-stream": "0.0.7", 648 "map-stream": "0.1.0",
647 "pause-stream": "0.0.11", 649 "pause-stream": "0.0.11",
648 "split": "1.0.1", 650 "split": "0.3.3",
649 "stream-combiner": "0.2.2", 651 "stream-combiner": "0.0.4",
650 "through": "2.3.8" 652 "through": "2.3.8"
651 } 653 }
652 }, 654 },
@@ -748,7 +750,8 @@
748 "from": { 750 "from": {
749 "version": "0.1.7", 751 "version": "0.1.7",
750 "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", 752 "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
751 "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=" 753 "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=",
754 "dev": true
752 }, 755 },
753 "fs-mkdirp-stream": { 756 "fs-mkdirp-stream": {
754 "version": "1.0.0", 757 "version": "1.0.0",
@@ -925,13 +928,13 @@
925 }, 928 },
926 "string_decoder": { 929 "string_decoder": {
927 "version": "0.10.31", 930 "version": "0.10.31",
928 "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 931 "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
929 "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", 932 "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
930 "dev": true 933 "dev": true
931 }, 934 },
932 "through2": { 935 "through2": {
933 "version": "0.6.5", 936 "version": "0.6.5",
934 "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", 937 "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
935 "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", 938 "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
936 "dev": true, 939 "dev": true,
937 "requires": { 940 "requires": {
@@ -966,45 +969,6 @@
966 "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", 969 "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=",
967 "dev": true 970 "dev": true
968 }, 971 },
969 "event-stream": {
970 "version": "3.3.4",
971 "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
972 "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=",
973 "dev": true,
974 "requires": {
975 "duplexer": "0.1.1",
976 "from": "0.1.7",
977 "map-stream": "0.1.0",
978 "pause-stream": "0.0.11",
979 "split": "0.3.3",
980 "stream-combiner": "0.0.4",
981 "through": "2.3.8"
982 }
983 },
984 "map-stream": {
985 "version": "0.1.0",
986 "resolved": "http://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
987 "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=",
988 "dev": true
989 },
990 "split": {
991 "version": "0.3.3",
992 "resolved": "http://registry.npmjs.org/split/-/split-0.3.3.tgz",
993 "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=",
994 "dev": true,
995 "requires": {
996 "through": "2.3.8"
997 }
998 },
999 "stream-combiner": {
1000 "version": "0.0.4",
1001 "resolved": "http://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
1002 "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=",
1003 "dev": true,
1004 "requires": {
1005 "duplexer": "0.1.1"
1006 }
1007 },
1008 "vinyl": { 972 "vinyl": {
1009 "version": "2.2.0", 973 "version": "2.2.0",
1010 "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", 974 "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz",
@@ -1027,7 +991,7 @@
1027 "integrity": "sha512-0QfbCH2a1k2qkTLWPqTX+QO4qNsHn3kC546YhAP3/n0h+nvtyGITDuDrYBMDZeW4WnFijmkOvBWa5HshTic1tw==", 991 "integrity": "sha512-0QfbCH2a1k2qkTLWPqTX+QO4qNsHn3kC546YhAP3/n0h+nvtyGITDuDrYBMDZeW4WnFijmkOvBWa5HshTic1tw==",
1028 "dev": true, 992 "dev": true,
1029 "requires": { 993 "requires": {
1030 "event-stream": "3.3.5", 994 "event-stream": "3.3.4",
1031 "streamifier": "0.1.1", 995 "streamifier": "0.1.1",
1032 "tar": "2.2.1", 996 "tar": "2.2.1",
1033 "through2": "2.0.5", 997 "through2": "2.0.5",
@@ -1040,21 +1004,6 @@
1040 "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", 1004 "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
1041 "dev": true 1005 "dev": true
1042 }, 1006 },
1043 "event-stream": {
1044 "version": "3.3.5",
1045 "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.5.tgz",
1046 "integrity": "sha512-vyibDcu5JL20Me1fP734QBH/kenBGLZap2n0+XXM7mvuUPzJ20Ydqj1aKcIeMdri1p+PU+4yAKugjN8KCVst+g==",
1047 "dev": true,
1048 "requires": {
1049 "duplexer": "0.1.1",
1050 "from": "0.1.7",
1051 "map-stream": "0.0.7",
1052 "pause-stream": "0.0.11",
1053 "split": "1.0.1",
1054 "stream-combiner": "0.2.2",
1055 "through": "2.3.8"
1056 }
1057 },
1058 "replace-ext": { 1007 "replace-ext": {
1059 "version": "0.0.1", 1008 "version": "0.0.1",
1060 "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", 1009 "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
@@ -1101,45 +1050,6 @@
1101 "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", 1050 "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=",
1102 "dev": true 1051 "dev": true
1103 }, 1052 },
1104 "event-stream": {
1105 "version": "3.3.4",
1106 "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
1107 "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=",
1108 "dev": true,
1109 "requires": {
1110 "duplexer": "0.1.1",
1111 "from": "0.1.7",
1112 "map-stream": "0.1.0",
1113 "pause-stream": "0.0.11",
1114 "split": "0.3.3",
1115 "stream-combiner": "0.0.4",
1116 "through": "2.3.8"
1117 }
1118 },
1119 "map-stream": {
1120 "version": "0.1.0",
1121 "resolved": "http://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
1122 "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=",
1123 "dev": true
1124 },
1125 "split": {
1126 "version": "0.3.3",
1127 "resolved": "http://registry.npmjs.org/split/-/split-0.3.3.tgz",
1128 "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=",
1129 "dev": true,
1130 "requires": {
1131 "through": "2.3.8"
1132 }
1133 },
1134 "stream-combiner": {
1135 "version": "0.0.4",
1136 "resolved": "http://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
1137 "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=",
1138 "dev": true,
1139 "requires": {
1140 "duplexer": "0.1.1"
1141 }
1142 },
1143 "vinyl": { 1053 "vinyl": {
1144 "version": "2.2.0", 1054 "version": "2.2.0",
1145 "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", 1055 "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz",
@@ -1421,7 +1331,7 @@
1421 }, 1331 },
1422 "kind-of": { 1332 "kind-of": {
1423 "version": "1.1.0", 1333 "version": "1.1.0",
1424 "resolved": "http://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", 1334 "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
1425 "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", 1335 "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=",
1426 "dev": true 1336 "dev": true
1427 }, 1337 },
@@ -1485,9 +1395,10 @@
1485 "dev": true 1395 "dev": true
1486 }, 1396 },
1487 "map-stream": { 1397 "map-stream": {
1488 "version": "0.0.7", 1398 "version": "0.1.0",
1489 "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", 1399 "resolved": "http://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
1490 "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=" 1400 "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=",
1401 "dev": true
1491 }, 1402 },
1492 "markdown-it": { 1403 "markdown-it": {
1493 "version": "8.4.2", 1404 "version": "8.4.2",
@@ -1724,13 +1635,13 @@
1724 }, 1635 },
1725 "os-homedir": { 1636 "os-homedir": {
1726 "version": "1.0.2", 1637 "version": "1.0.2",
1727 "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", 1638 "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
1728 "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", 1639 "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
1729 "dev": true 1640 "dev": true
1730 }, 1641 },
1731 "os-tmpdir": { 1642 "os-tmpdir": {
1732 "version": "1.0.2", 1643 "version": "1.0.2",
1733 "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 1644 "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
1734 "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", 1645 "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
1735 "dev": true 1646 "dev": true
1736 }, 1647 },
@@ -1746,7 +1657,7 @@
1746 }, 1657 },
1747 "parse-semver": { 1658 "parse-semver": {
1748 "version": "1.1.1", 1659 "version": "1.1.1",
1749 "resolved": "http://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", 1660 "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz",
1750 "integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=", 1661 "integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=",
1751 "dev": true, 1662 "dev": true,
1752 "requires": { 1663 "requires": {
@@ -1784,6 +1695,7 @@
1784 "version": "0.0.11", 1695 "version": "0.0.11",
1785 "resolved": "http://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", 1696 "resolved": "http://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
1786 "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", 1697 "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=",
1698 "dev": true,
1787 "requires": { 1699 "requires": {
1788 "through": "2.3.8" 1700 "through": "2.3.8"
1789 } 1701 }
@@ -2033,9 +1945,10 @@
2033 } 1945 }
2034 }, 1946 },
2035 "split": { 1947 "split": {
2036 "version": "1.0.1", 1948 "version": "0.3.3",
2037 "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", 1949 "resolved": "http://registry.npmjs.org/split/-/split-0.3.3.tgz",
2038 "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", 1950 "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=",
1951 "dev": true,
2039 "requires": { 1952 "requires": {
2040 "through": "2.3.8" 1953 "through": "2.3.8"
2041 } 1954 }
@@ -2070,12 +1983,12 @@
2070 "dev": true 1983 "dev": true
2071 }, 1984 },
2072 "stream-combiner": { 1985 "stream-combiner": {
2073 "version": "0.2.2", 1986 "version": "0.0.4",
2074 "resolved": "http://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", 1987 "resolved": "http://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
2075 "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=", 1988 "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=",
1989 "dev": true,
2076 "requires": { 1990 "requires": {
2077 "duplexer": "0.1.1", 1991 "duplexer": "0.1.1"
2078 "through": "2.3.8"
2079 } 1992 }
2080 }, 1993 },
2081 "stream-shift": { 1994 "stream-shift": {
@@ -2154,7 +2067,7 @@
2154 }, 2067 },
2155 "tar": { 2068 "tar": {
2156 "version": "2.2.1", 2069 "version": "2.2.1",
2157 "resolved": "http://registry.npmjs.org/tar/-/tar-2.2.1.tgz", 2070 "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz",
2158 "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", 2071 "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=",
2159 "dev": true, 2072 "dev": true,
2160 "requires": { 2073 "requires": {
@@ -2166,7 +2079,8 @@
2166 "through": { 2079 "through": {
2167 "version": "2.3.8", 2080 "version": "2.3.8",
2168 "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", 2081 "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
2169 "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" 2082 "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
2083 "dev": true
2170 }, 2084 },
2171 "through2": { 2085 "through2": {
2172 "version": "2.0.5", 2086 "version": "2.0.5",
@@ -2334,7 +2248,7 @@
2334 "dependencies": { 2248 "dependencies": {
2335 "underscore": { 2249 "underscore": {
2336 "version": "1.8.3", 2250 "version": "1.8.3",
2337 "resolved": "http://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", 2251 "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
2338 "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", 2252 "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=",
2339 "dev": true 2253 "dev": true
2340 } 2254 }
diff --git a/editors/code/package.json b/editors/code/package.json
index b212e159d..f196ecc60 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -31,7 +31,6 @@
31 "singleQuote": true 31 "singleQuote": true
32 }, 32 },
33 "dependencies": { 33 "dependencies": {
34 "event-stream": "^4.0.1",
35 "vscode-languageclient": "^5.1.1" 34 "vscode-languageclient": "^5.1.1"
36 }, 35 },
37 "devDependencies": { 36 "devDependencies": {