aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/code_model_impl/module.rs10
-rw-r--r--crates/ra_hir/src/db.rs7
-rw-r--r--crates/ra_hir/src/ids.rs38
-rw-r--r--crates/ra_hir/src/module_tree.rs99
-rw-r--r--crates/ra_hir/src/nameres.rs2
-rw-r--r--crates/ra_hir/src/nameres/lower.rs5
-rw-r--r--crates/ra_hir/src/query_definitions.rs12
-rw-r--r--crates/ra_hir/src/source_binder.rs28
-rw-r--r--crates/ra_ide_api/src/call_info.rs22
-rw-r--r--crates/ra_ide_api/src/marks.rs1
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs28
-rw-r--r--crates/ra_lsp_server/src/project_model/cargo_workspace.rs10
12 files changed, 145 insertions, 117 deletions
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs
index 480ec27bf..418d59c91 100644
--- a/crates/ra_hir/src/code_model_impl/module.rs
+++ b/crates/ra_hir/src/code_model_impl/module.rs
@@ -25,9 +25,10 @@ impl Module {
25 25
26 pub(crate) fn definition_source_impl(&self, db: &impl HirDatabase) -> (FileId, ModuleSource) { 26 pub(crate) fn definition_source_impl(&self, db: &impl HirDatabase) -> (FileId, ModuleSource) {
27 let module_tree = db.module_tree(self.krate); 27 let module_tree = db.module_tree(self.krate);
28 let source = self.module_id.source(&module_tree); 28 let file_id = self.module_id.file_id(&module_tree);
29 let module_source = ModuleSource::from_source_item_id(db, source); 29 let decl_id = self.module_id.decl_id(&module_tree);
30 let file_id = source.file_id.as_original_file(); 30 let module_source = ModuleSource::new(db, file_id, decl_id);
31 let file_id = file_id.as_original_file();
31 (file_id, module_source) 32 (file_id, module_source)
32 } 33 }
33 34
@@ -39,8 +40,7 @@ impl Module {
39 let link = self.module_id.parent_link(&module_tree)?; 40 let link = self.module_id.parent_link(&module_tree)?;
40 let file_id = link 41 let file_id = link
41 .owner(&module_tree) 42 .owner(&module_tree)
42 .source(&module_tree) 43 .file_id(&module_tree)
43 .file_id
44 .as_original_file(); 44 .as_original_file();
45 let src = link.source(&module_tree, db); 45 let src = link.source(&module_tree, db);
46 Some((file_id, src)) 46 Some((file_id, src))
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 5df4bd4a1..3f76b769d 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -16,6 +16,7 @@ use crate::{
16 adt::{StructData, EnumData}, 16 adt::{StructData, EnumData},
17 impl_block::ModuleImplBlocks, 17 impl_block::ModuleImplBlocks,
18 generics::{GenericParams, GenericDef}, 18 generics::{GenericParams, GenericDef},
19 ids::SourceFileItemId,
19}; 20};
20 21
21#[salsa::query_group(HirDatabaseStorage)] 22#[salsa::query_group(HirDatabaseStorage)]
@@ -51,7 +52,11 @@ pub trait HirDatabase: SourceDatabase + AsRef<HirInterner> {
51 fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>; 52 fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>;
52 53
53 #[salsa::invoke(crate::module_tree::Submodule::submodules_query)] 54 #[salsa::invoke(crate::module_tree::Submodule::submodules_query)]
54 fn submodules(&self, source: SourceItemId) -> Arc<Vec<crate::module_tree::Submodule>>; 55 fn submodules(
56 &self,
57 file_id: HirFileId,
58 delc_id: Option<SourceFileItemId>,
59 ) -> Arc<Vec<crate::module_tree::Submodule>>;
55 60
56 #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_query)] 61 #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_query)]
57 fn lower_module(&self, module: Module) -> (Arc<LoweredModule>, Arc<ImportSourceMap>); 62 fn lower_module(&self, module: Module) -> (Arc<LoweredModule>, Arc<ImportSourceMap>);
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 7dd4b540e..0e4dc6261 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -4,7 +4,7 @@ use std::{
4}; 4};
5 5
6use ra_db::{LocationIntener, FileId}; 6use ra_db::{LocationIntener, FileId};
7use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, ast}; 7use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, SyntaxNodePtr, ast};
8use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; 8use ra_arena::{Arena, RawId, ArenaId, impl_arena_id};
9 9
10use crate::{ 10use crate::{
@@ -203,7 +203,7 @@ pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone {
203 let items = ctx.db.file_items(ctx.file_id); 203 let items = ctx.db.file_items(ctx.file_id);
204 let raw = SourceItemId { 204 let raw = SourceItemId {
205 file_id: ctx.file_id, 205 file_id: ctx.file_id,
206 item_id: Some(items.id_of(ctx.file_id, ast.syntax())), 206 item_id: items.id_of(ctx.file_id, ast.syntax()),
207 }; 207 };
208 let loc = ItemLoc { 208 let loc = ItemLoc {
209 module: ctx.module, 209 module: ctx.module,
@@ -301,15 +301,14 @@ impl_arena_id!(SourceFileItemId);
301#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 301#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
302pub struct SourceItemId { 302pub struct SourceItemId {
303 pub(crate) file_id: HirFileId, 303 pub(crate) file_id: HirFileId,
304 /// None for the whole file. 304 pub(crate) item_id: SourceFileItemId,
305 pub(crate) item_id: Option<SourceFileItemId>,
306} 305}
307 306
308/// Maps items' `SyntaxNode`s to `SourceFileItemId`s and back. 307/// Maps items' `SyntaxNode`s to `SourceFileItemId`s and back.
309#[derive(Debug, PartialEq, Eq)] 308#[derive(Debug, PartialEq, Eq)]
310pub struct SourceFileItems { 309pub struct SourceFileItems {
311 file_id: HirFileId, 310 file_id: HirFileId,
312 arena: Arena<SourceFileItemId, TreeArc<SyntaxNode>>, 311 arena: Arena<SourceFileItemId, SyntaxNodePtr>,
313} 312}
314 313
315impl SourceFileItems { 314impl SourceFileItems {
@@ -329,15 +328,15 @@ impl SourceFileItems {
329 // trait does not chage ids of top-level items, which helps caching. 328 // trait does not chage ids of top-level items, which helps caching.
330 bfs(source_file.syntax(), |it| { 329 bfs(source_file.syntax(), |it| {
331 if let Some(module_item) = ast::ModuleItem::cast(it) { 330 if let Some(module_item) = ast::ModuleItem::cast(it) {
332 self.alloc(module_item.syntax().to_owned()); 331 self.alloc(module_item.syntax());
333 } else if let Some(macro_call) = ast::MacroCall::cast(it) { 332 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
334 self.alloc(macro_call.syntax().to_owned()); 333 self.alloc(macro_call.syntax());
335 } 334 }
336 }) 335 })
337 } 336 }
338 337
339 fn alloc(&mut self, item: TreeArc<SyntaxNode>) -> SourceFileItemId { 338 fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId {
340 self.arena.alloc(item) 339 self.arena.alloc(SyntaxNodePtr::new(item))
341 } 340 }
342 pub(crate) fn id_of(&self, file_id: HirFileId, item: &SyntaxNode) -> SourceFileItemId { 341 pub(crate) fn id_of(&self, file_id: HirFileId, item: &SyntaxNode) -> SourceFileItemId {
343 assert_eq!( 342 assert_eq!(
@@ -348,17 +347,8 @@ impl SourceFileItems {
348 self.id_of_unchecked(item) 347 self.id_of_unchecked(item)
349 } 348 }
350 pub(crate) fn id_of_unchecked(&self, item: &SyntaxNode) -> SourceFileItemId { 349 pub(crate) fn id_of_unchecked(&self, item: &SyntaxNode) -> SourceFileItemId {
351 if let Some((id, _)) = self.arena.iter().find(|(_id, i)| *i == item) { 350 let ptr = SyntaxNodePtr::new(item);
352 return id; 351 if let Some((id, _)) = self.arena.iter().find(|(_id, i)| **i == ptr) {
353 }
354 // This should not happen. Let's try to give a sensible diagnostics.
355 if let Some((id, i)) = self.arena.iter().find(|(_id, i)| i.range() == item.range()) {
356 // FIXME(#288): whyyy are we getting here?
357 log::error!(
358 "unequal syntax nodes with the same range:\n{:?}\n{:?}",
359 item,
360 i
361 );
362 return id; 352 return id;
363 } 353 }
364 panic!( 354 panic!(
@@ -367,15 +357,11 @@ impl SourceFileItems {
367 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(), 357 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
368 ); 358 );
369 } 359 }
370 pub fn id_of_parse(&self) -> SourceFileItemId {
371 let (id, _syntax) = self.arena.iter().next().unwrap();
372 id
373 }
374} 360}
375 361
376impl std::ops::Index<SourceFileItemId> for SourceFileItems { 362impl std::ops::Index<SourceFileItemId> for SourceFileItems {
377 type Output = SyntaxNode; 363 type Output = SyntaxNodePtr;
378 fn index(&self, idx: SourceFileItemId) -> &SyntaxNode { 364 fn index(&self, idx: SourceFileItemId) -> &SyntaxNodePtr {
379 &self.arena[idx] 365 &self.arena[idx]
380 } 366 }
381} 367}
diff --git a/crates/ra_hir/src/module_tree.rs b/crates/ra_hir/src/module_tree.rs
index d5ad9decb..d1dc3fa4b 100644
--- a/crates/ra_hir/src/module_tree.rs
+++ b/crates/ra_hir/src/module_tree.rs
@@ -11,21 +11,28 @@ use ra_syntax::{
11use ra_arena::{Arena, RawId, impl_arena_id}; 11use ra_arena::{Arena, RawId, impl_arena_id};
12use test_utils::tested_by; 12use test_utils::tested_by;
13 13
14use crate::{Name, AsName, HirDatabase, SourceItemId, HirFileId, Problem, SourceFileItems, ModuleSource}; 14use crate::{
15 Name, AsName, HirDatabase, SourceItemId, HirFileId, Problem, SourceFileItems, ModuleSource,
16 ids::SourceFileItemId,
17};
15 18
16impl ModuleSource { 19impl ModuleSource {
17 pub(crate) fn from_source_item_id( 20 pub(crate) fn new(
18 db: &impl HirDatabase, 21 db: &impl HirDatabase,
19 source_item_id: SourceItemId, 22 file_id: HirFileId,
23 decl_id: Option<SourceFileItemId>,
20 ) -> ModuleSource { 24 ) -> ModuleSource {
21 let module_syntax = db.file_item(source_item_id); 25 match decl_id {
22 if let Some(source_file) = ast::SourceFile::cast(&module_syntax) { 26 Some(item_id) => {
23 ModuleSource::SourceFile(source_file.to_owned()) 27 let module = db.file_item(SourceItemId { file_id, item_id });
24 } else if let Some(module) = ast::Module::cast(&module_syntax) { 28 let module = ast::Module::cast(&*module).unwrap();
25 assert!(module.item_list().is_some(), "expected inline module"); 29 assert!(module.item_list().is_some(), "expected inline module");
26 ModuleSource::Module(module.to_owned()) 30 ModuleSource::Module(module.to_owned())
27 } else { 31 }
28 panic!("expected file or inline module") 32 None => {
33 let source_file = db.hir_parse(file_id);
34 ModuleSource::SourceFile(source_file)
35 }
29 } 36 }
30 } 37 }
31} 38}
@@ -34,18 +41,18 @@ impl ModuleSource {
34pub struct Submodule { 41pub struct Submodule {
35 name: Name, 42 name: Name,
36 is_declaration: bool, 43 is_declaration: bool,
37 source: SourceItemId, 44 decl_id: SourceFileItemId,
38} 45}
39 46
40impl Submodule { 47impl Submodule {
41 pub(crate) fn submodules_query( 48 pub(crate) fn submodules_query(
42 db: &impl HirDatabase, 49 db: &impl HirDatabase,
43 source: SourceItemId, 50 file_id: HirFileId,
51 decl_id: Option<SourceFileItemId>,
44 ) -> Arc<Vec<Submodule>> { 52 ) -> Arc<Vec<Submodule>> {
45 db.check_canceled(); 53 db.check_canceled();
46 let file_id = source.file_id;
47 let file_items = db.file_items(file_id); 54 let file_items = db.file_items(file_id);
48 let module_source = ModuleSource::from_source_item_id(db, source); 55 let module_source = ModuleSource::new(db, file_id, decl_id);
49 let submodules = match module_source { 56 let submodules = match module_source {
50 ModuleSource::SourceFile(source_file) => { 57 ModuleSource::SourceFile(source_file) => {
51 collect_submodules(file_id, &file_items, &*source_file) 58 collect_submodules(file_id, &file_items, &*source_file)
@@ -54,6 +61,7 @@ impl Submodule {
54 collect_submodules(file_id, &file_items, module.item_list().unwrap()) 61 collect_submodules(file_id, &file_items, module.item_list().unwrap())
55 } 62 }
56 }; 63 };
64
57 return Arc::new(submodules); 65 return Arc::new(submodules);
58 66
59 fn collect_submodules( 67 fn collect_submodules(
@@ -75,10 +83,7 @@ impl Submodule {
75 let sub = Submodule { 83 let sub = Submodule {
76 name, 84 name,
77 is_declaration: module.has_semi(), 85 is_declaration: module.has_semi(),
78 source: SourceItemId { 86 decl_id: file_items.id_of(file_id, module.syntax()),
79 file_id,
80 item_id: Some(file_items.id_of(file_id, module.syntax())),
81 },
82 }; 87 };
83 Some(sub) 88 Some(sub)
84 }) 89 })
@@ -110,7 +115,9 @@ pub struct ModuleTree {
110 115
111#[derive(Debug, PartialEq, Eq, Hash)] 116#[derive(Debug, PartialEq, Eq, Hash)]
112pub struct ModuleData { 117pub struct ModuleData {
113 source: SourceItemId, 118 file_id: HirFileId,
119 /// Points to `ast::Module`, `None` for the whole file.
120 decl_id: Option<SourceFileItemId>,
114 parent: Option<LinkId>, 121 parent: Option<LinkId>,
115 children: Vec<LinkId>, 122 children: Vec<LinkId>,
116} 123}
@@ -136,8 +143,15 @@ impl ModuleTree {
136 self.mods.iter().map(|(id, _)| id) 143 self.mods.iter().map(|(id, _)| id)
137 } 144 }
138 145
139 pub(crate) fn find_module_by_source(&self, source: SourceItemId) -> Option<ModuleId> { 146 pub(crate) fn find_module_by_source(
140 let (res, _) = self.mods.iter().find(|(_, m)| m.source == source)?; 147 &self,
148 file_id: HirFileId,
149 decl_id: Option<SourceFileItemId>,
150 ) -> Option<ModuleId> {
151 let (res, _) = self
152 .mods
153 .iter()
154 .find(|(_, m)| (m.file_id, m.decl_id) == (file_id, decl_id))?;
141 Some(res) 155 Some(res)
142 } 156 }
143 157
@@ -147,11 +161,7 @@ impl ModuleTree {
147 let source_root_id = db.file_source_root(file_id); 161 let source_root_id = db.file_source_root(file_id);
148 162
149 let source_root = db.source_root(source_root_id); 163 let source_root = db.source_root(source_root_id);
150 let source = SourceItemId { 164 self.init_subtree(db, &source_root, None, file_id.into(), None);
151 file_id: file_id.into(),
152 item_id: None,
153 };
154 self.init_subtree(db, &source_root, None, source);
155 } 165 }
156 166
157 fn init_subtree( 167 fn init_subtree(
@@ -159,16 +169,21 @@ impl ModuleTree {
159 db: &impl HirDatabase, 169 db: &impl HirDatabase,
160 source_root: &SourceRoot, 170 source_root: &SourceRoot,
161 parent: Option<LinkId>, 171 parent: Option<LinkId>,
162 source: SourceItemId, 172 file_id: HirFileId,
173 decl_id: Option<SourceFileItemId>,
163 ) -> ModuleId { 174 ) -> ModuleId {
164 let id = self.alloc_mod(ModuleData { 175 let id = self.alloc_mod(ModuleData {
165 source, 176 file_id,
177 decl_id,
166 parent, 178 parent,
167 children: Vec::new(), 179 children: Vec::new(),
168 }); 180 });
169 for sub in db.submodules(source).iter() { 181 for sub in db.submodules(file_id, decl_id).iter() {
170 let link = self.alloc_link(LinkData { 182 let link = self.alloc_link(LinkData {
171 source: sub.source, 183 source: SourceItemId {
184 file_id,
185 item_id: sub.decl_id,
186 },
172 name: sub.name.clone(), 187 name: sub.name.clone(),
173 owner: id, 188 owner: id,
174 points_to: Vec::new(), 189 points_to: Vec::new(),
@@ -176,24 +191,17 @@ impl ModuleTree {
176 }); 191 });
177 192
178 let (points_to, problem) = if sub.is_declaration { 193 let (points_to, problem) = if sub.is_declaration {
179 let (points_to, problem) = resolve_submodule(db, source.file_id, &sub.name); 194 let (points_to, problem) = resolve_submodule(db, file_id, &sub.name);
180 let points_to = points_to 195 let points_to = points_to
181 .into_iter() 196 .into_iter()
182 .map(|file_id| { 197 .map(|file_id| {
183 self.init_subtree( 198 self.init_subtree(db, source_root, Some(link), file_id.into(), None)
184 db,
185 source_root,
186 Some(link),
187 SourceItemId {
188 file_id: file_id.into(),
189 item_id: None,
190 },
191 )
192 }) 199 })
193 .collect::<Vec<_>>(); 200 .collect::<Vec<_>>();
194 (points_to, problem) 201 (points_to, problem)
195 } else { 202 } else {
196 let points_to = self.init_subtree(db, source_root, Some(link), sub.source); 203 let points_to =
204 self.init_subtree(db, source_root, Some(link), file_id, Some(sub.decl_id));
197 (vec![points_to], None) 205 (vec![points_to], None)
198 }; 206 };
199 207
@@ -216,8 +224,11 @@ impl ModuleTree {
216} 224}
217 225
218impl ModuleId { 226impl ModuleId {
219 pub(crate) fn source(self, tree: &ModuleTree) -> SourceItemId { 227 pub(crate) fn file_id(self, tree: &ModuleTree) -> HirFileId {
220 tree.mods[self].source 228 tree.mods[self].file_id
229 }
230 pub(crate) fn decl_id(self, tree: &ModuleTree) -> Option<SourceFileItemId> {
231 tree.mods[self].decl_id
221 } 232 }
222 pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> { 233 pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> {
223 tree.mods[self].parent 234 tree.mods[self].parent
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 5193900e0..97ce6c946 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -215,7 +215,7 @@ where
215 // Populate extern crates prelude 215 // Populate extern crates prelude
216 { 216 {
217 let root_id = module_id.crate_root(&self.module_tree); 217 let root_id = module_id.crate_root(&self.module_tree);
218 let file_id = root_id.source(&self.module_tree).file_id; 218 let file_id = root_id.file_id(&self.module_tree);
219 let crate_graph = self.db.crate_graph(); 219 let crate_graph = self.db.crate_graph();
220 if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id.as_original_file()) 220 if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id.as_original_file())
221 { 221 {
diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs
index 1d77548f3..8df11a5f4 100644
--- a/crates/ra_hir/src/nameres/lower.rs
+++ b/crates/ra_hir/src/nameres/lower.rs
@@ -121,10 +121,7 @@ impl LoweredModule {
121 let item_id = file_items.id_of_unchecked(macro_call.syntax()); 121 let item_id = file_items.id_of_unchecked(macro_call.syntax());
122 let loc = MacroCallLoc { 122 let loc = MacroCallLoc {
123 module, 123 module,
124 source_item_id: SourceItemId { 124 source_item_id: SourceItemId { file_id, item_id },
125 file_id,
126 item_id: Some(item_id),
127 },
128 }; 125 };
129 let id = loc.id(db); 126 let id = loc.id(db);
130 let file_id = HirFileId::from(id); 127 let file_id = HirFileId::from(id);
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs
index 61c93a964..bf9ac0dfb 100644
--- a/crates/ra_hir/src/query_definitions.rs
+++ b/crates/ra_hir/src/query_definitions.rs
@@ -4,9 +4,7 @@ use std::{
4}; 4};
5 5
6use rustc_hash::FxHashMap; 6use rustc_hash::FxHashMap;
7use ra_syntax::{ 7use ra_syntax::{SyntaxNode, TreeArc};
8 AstNode, SyntaxNode, TreeArc,
9};
10use ra_db::{CrateId}; 8use ra_db::{CrateId};
11 9
12use crate::{ 10use crate::{
@@ -32,10 +30,10 @@ pub(super) fn file_item(
32 db: &impl HirDatabase, 30 db: &impl HirDatabase,
33 source_item_id: SourceItemId, 31 source_item_id: SourceItemId,
34) -> TreeArc<SyntaxNode> { 32) -> TreeArc<SyntaxNode> {
35 match source_item_id.item_id { 33 let source_file = db.hir_parse(source_item_id.file_id);
36 Some(id) => db.file_items(source_item_id.file_id)[id].to_owned(), 34 db.file_items(source_item_id.file_id)[source_item_id.item_id]
37 None => db.hir_parse(source_item_id.file_id).syntax().to_owned(), 35 .to_node(&source_file)
38 } 36 .to_owned()
39} 37}
40 38
41pub(super) fn item_map(db: &impl HirDatabase, crate_id: CrateId) -> Arc<ItemMap> { 39pub(super) fn item_map(db: &impl HirDatabase, crate_id: CrateId) -> Arc<ItemMap> {
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index c0b3f1cd4..f523f0647 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -13,18 +13,14 @@ use ra_syntax::{
13}; 13};
14 14
15use crate::{ 15use crate::{
16 HirDatabase, Function, SourceItemId, ModuleDef, 16 HirDatabase, Function, ModuleDef,
17 AsName, Module, 17 AsName, Module, HirFileId,
18 ids::LocationCtx, 18 ids::{LocationCtx, SourceFileItemId},
19}; 19};
20 20
21/// Locates the module by `FileId`. Picks topmost module in the file. 21/// Locates the module by `FileId`. Picks topmost module in the file.
22pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Option<Module> { 22pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Option<Module> {
23 let module_source = SourceItemId { 23 module_from_source(db, file_id.into(), None)
24 file_id: file_id.into(),
25 item_id: None,
26 };
27 module_from_source(db, module_source)
28} 24}
29 25
30/// Locates the child module by `mod child;` declaration. 26/// Locates the child module by `mod child;` declaration.
@@ -59,11 +55,7 @@ fn module_from_inline(
59 let file_id = file_id.into(); 55 let file_id = file_id.into();
60 let file_items = db.file_items(file_id); 56 let file_items = db.file_items(file_id);
61 let item_id = file_items.id_of(file_id, module.syntax()); 57 let item_id = file_items.id_of(file_id, module.syntax());
62 let source = SourceItemId { 58 module_from_source(db, file_id, Some(item_id))
63 file_id,
64 item_id: Some(item_id),
65 };
66 module_from_source(db, source)
67} 59}
68 60
69/// Locates the module by child syntax element within the module 61/// Locates the module by child syntax element within the module
@@ -83,13 +75,17 @@ pub fn module_from_child_node(
83 } 75 }
84} 76}
85 77
86fn module_from_source(db: &impl HirDatabase, source: SourceItemId) -> Option<Module> { 78fn module_from_source(
87 let source_root_id = db.file_source_root(source.file_id.as_original_file()); 79 db: &impl HirDatabase,
80 file_id: HirFileId,
81 decl_id: Option<SourceFileItemId>,
82) -> Option<Module> {
83 let source_root_id = db.file_source_root(file_id.as_original_file());
88 db.source_root_crates(source_root_id) 84 db.source_root_crates(source_root_id)
89 .iter() 85 .iter()
90 .find_map(|&krate| { 86 .find_map(|&krate| {
91 let module_tree = db.module_tree(krate); 87 let module_tree = db.module_tree(krate);
92 let module_id = module_tree.find_module_by_source(source)?; 88 let module_id = module_tree.find_module_by_source(file_id, decl_id)?;
93 Some(Module { krate, module_id }) 89 Some(Module { krate, module_id })
94 }) 90 })
95} 91}
diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs
index 3267fff96..f203a6bf1 100644
--- a/crates/ra_ide_api/src/call_info.rs
+++ b/crates/ra_ide_api/src/call_info.rs
@@ -1,3 +1,4 @@
1use test_utils::tested_by;
1use ra_db::SourceDatabase; 2use ra_db::SourceDatabase;
2use ra_syntax::{ 3use ra_syntax::{
3 AstNode, SyntaxNode, TextUnit, TextRange, 4 AstNode, SyntaxNode, TextUnit, TextRange,
@@ -41,7 +42,12 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
41 // where offset is in that list (or beyond). 42 // where offset is in that list (or beyond).
42 // Revisit this after we get documentation comments in. 43 // Revisit this after we get documentation comments in.
43 if let Some(ref arg_list) = calling_node.arg_list() { 44 if let Some(ref arg_list) = calling_node.arg_list() {
44 let start = arg_list.syntax().range().start(); 45 let arg_list_range = arg_list.syntax().range();
46 if !arg_list_range.contains_inclusive(position.offset) {
47 tested_by!(call_info_bad_offset);
48 return None;
49 }
50 let start = arg_list_range.start();
45 51
46 let range_search = TextRange::from_to(start, position.offset); 52 let range_search = TextRange::from_to(start, position.offset);
47 let mut commas: usize = arg_list 53 let mut commas: usize = arg_list
@@ -172,10 +178,12 @@ fn param_list(node: &ast::FnDef) -> Vec<String> {
172 178
173#[cfg(test)] 179#[cfg(test)]
174mod tests { 180mod tests {
175 use super::*; 181 use test_utils::covers;
176 182
177 use crate::mock_analysis::single_file_with_position; 183 use crate::mock_analysis::single_file_with_position;
178 184
185 use super::*;
186
179 fn call_info(text: &str) -> CallInfo { 187 fn call_info(text: &str) -> CallInfo {
180 let (analysis, position) = single_file_with_position(text); 188 let (analysis, position) = single_file_with_position(text);
181 analysis.call_info(position).unwrap().unwrap() 189 analysis.call_info(position).unwrap().unwrap()
@@ -417,4 +425,14 @@ By default this method stops actor's `Context`."#
417 ); 425 );
418 } 426 }
419 427
428 #[test]
429 fn call_info_bad_offset() {
430 covers!(call_info_bad_offset);
431 let (analysis, position) = single_file_with_position(
432 r#"fn foo(x: u32, y: u32) -> u32 {x + y}
433 fn bar() { foo <|> (3, ); }"#,
434 );
435 let call_info = analysis.call_info(position).unwrap();
436 assert!(call_info.is_none());
437 }
420} 438}
diff --git a/crates/ra_ide_api/src/marks.rs b/crates/ra_ide_api/src/marks.rs
index e33bf6c91..21ce7289d 100644
--- a/crates/ra_ide_api/src/marks.rs
+++ b/crates/ra_ide_api/src/marks.rs
@@ -2,4 +2,5 @@ test_utils::marks!(
2 inserts_parens_for_function_calls 2 inserts_parens_for_function_calls
3 goto_definition_works_for_methods 3 goto_definition_works_for_methods
4 goto_definition_works_for_fields 4 goto_definition_works_for_fields
5 call_info_bad_offset
5); 6);
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 8ea9edc84..ace3da020 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -520,21 +520,33 @@ pub fn handle_formatting(
520 let end_position = TextUnit::of_str(&file).conv_with(&file_line_index); 520 let end_position = TextUnit::of_str(&file).conv_with(&file_line_index);
521 521
522 use std::process; 522 use std::process;
523 let mut rustfmt = process::Command::new("rustfmt") 523 let mut rustfmt = process::Command::new("rustfmt");
524 rustfmt
524 .stdin(process::Stdio::piped()) 525 .stdin(process::Stdio::piped())
525 .stdout(process::Stdio::piped()) 526 .stdout(process::Stdio::piped());
526 .spawn()?; 527
528 if let Ok(path) = params.text_document.uri.to_file_path() {
529 if let Some(parent) = path.parent() {
530 rustfmt.current_dir(parent);
531 }
532 }
533 let mut rustfmt = rustfmt.spawn()?;
527 534
528 rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?; 535 rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?;
529 536
530 let output = rustfmt.wait_with_output()?; 537 let output = rustfmt.wait_with_output()?;
531 let captured_stdout = String::from_utf8(output.stdout)?; 538 let captured_stdout = String::from_utf8(output.stdout)?;
532 if !output.status.success() { 539 if !output.status.success() {
533 failure::bail!( 540 return Err(LspError::new(
534 "rustfmt exited with error code {}: {}.", 541 -32900,
535 output.status, 542 format!(
536 captured_stdout, 543 r#"rustfmt exited with:
537 ); 544 Status: {}
545 stdout: {}"#,
546 output.status, captured_stdout,
547 ),
548 )
549 .into());
538 } 550 }
539 551
540 Ok(Some(vec![TextEdit { 552 Ok(Some(vec![TextEdit {
diff --git a/crates/ra_lsp_server/src/project_model/cargo_workspace.rs b/crates/ra_lsp_server/src/project_model/cargo_workspace.rs
index 75ae78bca..8cf99d586 100644
--- a/crates/ra_lsp_server/src/project_model/cargo_workspace.rs
+++ b/crates/ra_lsp_server/src/project_model/cargo_workspace.rs
@@ -117,9 +117,13 @@ impl Target {
117 117
118impl CargoWorkspace { 118impl CargoWorkspace {
119 pub fn from_cargo_metadata(cargo_toml: &Path) -> Result<CargoWorkspace> { 119 pub fn from_cargo_metadata(cargo_toml: &Path) -> Result<CargoWorkspace> {
120 let meta = MetadataCommand::new() 120 let mut meta = MetadataCommand::new();
121 .manifest_path(cargo_toml) 121 meta.manifest_path(cargo_toml)
122 .features(CargoOpt::AllFeatures) 122 .features(CargoOpt::AllFeatures);
123 if let Some(parent) = cargo_toml.parent() {
124 meta.current_dir(parent);
125 }
126 let meta = meta
123 .exec() 127 .exec()
124 .map_err(|e| format_err!("cargo metadata failed: {}", e))?; 128 .map_err(|e| format_err!("cargo metadata failed: {}", e))?;
125 let mut pkg_by_id = FxHashMap::default(); 129 let mut pkg_by_id = FxHashMap::default();