diff options
-rw-r--r-- | crates/cfg/src/lib.rs | 17 | ||||
-rw-r--r-- | crates/ide/src/hover.rs | 185 | ||||
-rw-r--r-- | crates/ide/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/extract_function.rs | 26 | ||||
-rw-r--r-- | crates/project_model/src/cargo_workspace.rs | 17 | ||||
-rw-r--r-- | crates/project_model/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/project_model/src/workspace.rs | 124 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 17 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 16 | ||||
-rw-r--r-- | docs/user/generated_config.adoc | 20 | ||||
-rw-r--r-- | editors/code/package.json | 25 |
11 files changed, 282 insertions, 170 deletions
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs index 03b8dd767..916d39a0b 100644 --- a/crates/cfg/src/lib.rs +++ b/crates/cfg/src/lib.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | //! cfg defines conditional compiling options, `cfg` attibute parser and evaluator | 1 | //! cfg defines conditional compiling options, `cfg` attribute parser and evaluator |
2 | 2 | ||
3 | mod cfg_expr; | 3 | mod cfg_expr; |
4 | mod dnf; | 4 | mod dnf; |
@@ -52,6 +52,7 @@ impl CfgOptions { | |||
52 | } | 52 | } |
53 | } | 53 | } |
54 | 54 | ||
55 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
55 | pub struct CfgDiff { | 56 | pub struct CfgDiff { |
56 | // Invariants: No duplicates, no atom that's both in `enable` and `disable`. | 57 | // Invariants: No duplicates, no atom that's both in `enable` and `disable`. |
57 | enable: Vec<CfgAtom>, | 58 | enable: Vec<CfgAtom>, |
@@ -59,6 +60,20 @@ pub struct CfgDiff { | |||
59 | } | 60 | } |
60 | 61 | ||
61 | impl CfgDiff { | 62 | impl CfgDiff { |
63 | /// Create a new CfgDiff. Will return None if the same item appears more than once in the set | ||
64 | /// of both. | ||
65 | pub fn new(enable: Vec<CfgAtom>, disable: Vec<CfgAtom>) -> Option<CfgDiff> { | ||
66 | let mut occupied = FxHashSet::default(); | ||
67 | for item in enable.iter().chain(disable.iter()) { | ||
68 | if !occupied.insert(item) { | ||
69 | // was present | ||
70 | return None; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | Some(CfgDiff { enable, disable }) | ||
75 | } | ||
76 | |||
62 | /// Returns the total number of atoms changed by this diff. | 77 | /// Returns the total number of atoms changed by this diff. |
63 | pub fn len(&self) -> usize { | 78 | pub fn len(&self) -> usize { |
64 | self.enable.len() + self.disable.len() | 79 | self.enable.len() + self.disable.len() |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 2e1359eef..0c1da8774 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -1,8 +1,5 @@ | |||
1 | use either::Either; | 1 | use either::Either; |
2 | use hir::{ | 2 | use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay}; |
3 | AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, InFile, Module, | ||
4 | ModuleDef, Semantics, | ||
5 | }; | ||
6 | use ide_db::{ | 3 | use ide_db::{ |
7 | base_db::SourceDatabase, | 4 | base_db::SourceDatabase, |
8 | defs::{Definition, NameClass, NameRefClass}, | 5 | defs::{Definition, NameClass, NameRefClass}, |
@@ -40,6 +37,7 @@ pub struct HoverConfig { | |||
40 | pub goto_type_def: bool, | 37 | pub goto_type_def: bool, |
41 | pub links_in_hover: bool, | 38 | pub links_in_hover: bool, |
42 | pub markdown: bool, | 39 | pub markdown: bool, |
40 | pub documentation: bool, | ||
43 | } | 41 | } |
44 | 42 | ||
45 | impl HoverConfig { | 43 | impl HoverConfig { |
@@ -51,14 +49,15 @@ impl HoverConfig { | |||
51 | goto_type_def: false, | 49 | goto_type_def: false, |
52 | links_in_hover: true, | 50 | links_in_hover: true, |
53 | markdown: true, | 51 | markdown: true, |
52 | documentation: true, | ||
54 | }; | 53 | }; |
55 | 54 | ||
56 | pub fn any(&self) -> bool { | 55 | pub fn any_actions(&self) -> bool { |
57 | self.implementations || self.references || self.runnable() || self.goto_type_def | 56 | self.implementations || self.references || self.runnable() || self.goto_type_def |
58 | } | 57 | } |
59 | 58 | ||
60 | pub fn none(&self) -> bool { | 59 | pub fn no_actions(&self) -> bool { |
61 | !self.any() | 60 | !self.any_actions() |
62 | } | 61 | } |
63 | 62 | ||
64 | pub fn runnable(&self) -> bool { | 63 | pub fn runnable(&self) -> bool { |
@@ -97,9 +96,10 @@ pub(crate) fn hover( | |||
97 | db: &RootDatabase, | 96 | db: &RootDatabase, |
98 | position: FilePosition, | 97 | position: FilePosition, |
99 | links_in_hover: bool, | 98 | links_in_hover: bool, |
99 | documentation: bool, | ||
100 | markdown: bool, | 100 | markdown: bool, |
101 | ) -> Option<RangeInfo<HoverResult>> { | 101 | ) -> Option<RangeInfo<HoverResult>> { |
102 | let sema = Semantics::new(db); | 102 | let sema = hir::Semantics::new(db); |
103 | let file = sema.parse(position.file_id).syntax().clone(); | 103 | let file = sema.parse(position.file_id).syntax().clone(); |
104 | let token = pick_best(file.token_at_offset(position.offset))?; | 104 | let token = pick_best(file.token_at_offset(position.offset))?; |
105 | let token = sema.descend_into_macros(token); | 105 | let token = sema.descend_into_macros(token); |
@@ -131,7 +131,7 @@ pub(crate) fn hover( | |||
131 | let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?; | 131 | let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?; |
132 | let (idl_range, link, ns) = | 132 | let (idl_range, link, ns) = |
133 | extract_definitions_from_markdown(docs.as_str()).into_iter().find_map(|(range, link, ns)| { | 133 | extract_definitions_from_markdown(docs.as_str()).into_iter().find_map(|(range, link, ns)| { |
134 | let InFile { file_id, value: range } = doc_mapping.map(range)?; | 134 | let hir::InFile { file_id, value: range } = doc_mapping.map(range)?; |
135 | if file_id == position.file_id.into() && range.contains(position.offset) { | 135 | if file_id == position.file_id.into() && range.contains(position.offset) { |
136 | Some((range, link, ns)) | 136 | Some((range, link, ns)) |
137 | } else { | 137 | } else { |
@@ -151,12 +151,14 @@ pub(crate) fn hover( | |||
151 | 151 | ||
152 | if let Some(definition) = definition { | 152 | if let Some(definition) = definition { |
153 | let famous_defs = match &definition { | 153 | let famous_defs = match &definition { |
154 | Definition::ModuleDef(ModuleDef::BuiltinType(_)) => { | 154 | Definition::ModuleDef(hir::ModuleDef::BuiltinType(_)) => { |
155 | Some(FamousDefs(&sema, sema.scope(&node).krate())) | 155 | Some(FamousDefs(&sema, sema.scope(&node).krate())) |
156 | } | 156 | } |
157 | _ => None, | 157 | _ => None, |
158 | }; | 158 | }; |
159 | if let Some(markup) = hover_for_definition(db, definition, famous_defs.as_ref()) { | 159 | if let Some(markup) = |
160 | hover_for_definition(db, definition, famous_defs.as_ref(), documentation) | ||
161 | { | ||
160 | res.markup = process_markup(sema.db, definition, &markup, links_in_hover, markdown); | 162 | res.markup = process_markup(sema.db, definition, &markup, links_in_hover, markdown); |
161 | if let Some(action) = show_implementations_action(db, definition) { | 163 | if let Some(action) = show_implementations_action(db, definition) { |
162 | res.actions.push(action); | 164 | res.actions.push(action); |
@@ -179,7 +181,8 @@ pub(crate) fn hover( | |||
179 | } | 181 | } |
180 | } | 182 | } |
181 | 183 | ||
182 | if let res @ Some(_) = hover_for_keyword(&sema, links_in_hover, markdown, &token) { | 184 | if let res @ Some(_) = hover_for_keyword(&sema, links_in_hover, markdown, documentation, &token) |
185 | { | ||
183 | return res; | 186 | return res; |
184 | } | 187 | } |
185 | 188 | ||
@@ -261,8 +264,10 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov | |||
261 | } | 264 | } |
262 | 265 | ||
263 | let adt = match def { | 266 | let adt = match def { |
264 | Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), | 267 | Definition::ModuleDef(hir::ModuleDef::Trait(it)) => { |
265 | Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), | 268 | return it.try_to_nav(db).map(to_action) |
269 | } | ||
270 | Definition::ModuleDef(hir::ModuleDef::Adt(it)) => Some(it), | ||
266 | Definition::SelfType(it) => it.self_ty(db).as_adt(), | 271 | Definition::SelfType(it) => it.self_ty(db).as_adt(), |
267 | _ => None, | 272 | _ => None, |
268 | }?; | 273 | }?; |
@@ -271,25 +276,27 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov | |||
271 | 276 | ||
272 | fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | 277 | fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { |
273 | match def { | 278 | match def { |
274 | Definition::ModuleDef(ModuleDef::Function(it)) => it.try_to_nav(db).map(|nav_target| { | 279 | Definition::ModuleDef(hir::ModuleDef::Function(it)) => { |
275 | HoverAction::Reference(FilePosition { | 280 | it.try_to_nav(db).map(|nav_target| { |
276 | file_id: nav_target.file_id, | 281 | HoverAction::Reference(FilePosition { |
277 | offset: nav_target.focus_or_full_range().start(), | 282 | file_id: nav_target.file_id, |
283 | offset: nav_target.focus_or_full_range().start(), | ||
284 | }) | ||
278 | }) | 285 | }) |
279 | }), | 286 | } |
280 | _ => None, | 287 | _ => None, |
281 | } | 288 | } |
282 | } | 289 | } |
283 | 290 | ||
284 | fn runnable_action( | 291 | fn runnable_action( |
285 | sema: &Semantics<RootDatabase>, | 292 | sema: &hir::Semantics<RootDatabase>, |
286 | def: Definition, | 293 | def: Definition, |
287 | file_id: FileId, | 294 | file_id: FileId, |
288 | ) -> Option<HoverAction> { | 295 | ) -> Option<HoverAction> { |
289 | match def { | 296 | match def { |
290 | Definition::ModuleDef(it) => match it { | 297 | Definition::ModuleDef(it) => match it { |
291 | ModuleDef::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable), | 298 | hir::ModuleDef::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable), |
292 | ModuleDef::Function(func) => { | 299 | hir::ModuleDef::Function(func) => { |
293 | let src = func.source(sema.db)?; | 300 | let src = func.source(sema.db)?; |
294 | if src.file_id != file_id.into() { | 301 | if src.file_id != file_id.into() { |
295 | cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment); | 302 | cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment); |
@@ -306,19 +313,19 @@ fn runnable_action( | |||
306 | } | 313 | } |
307 | 314 | ||
308 | fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | 315 | fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { |
309 | let mut targets: Vec<ModuleDef> = Vec::new(); | 316 | let mut targets: Vec<hir::ModuleDef> = Vec::new(); |
310 | let mut push_new_def = |item: ModuleDef| { | 317 | let mut push_new_def = |item: hir::ModuleDef| { |
311 | if !targets.contains(&item) { | 318 | if !targets.contains(&item) { |
312 | targets.push(item); | 319 | targets.push(item); |
313 | } | 320 | } |
314 | }; | 321 | }; |
315 | 322 | ||
316 | if let Definition::GenericParam(GenericParam::TypeParam(it)) = def { | 323 | if let Definition::GenericParam(hir::GenericParam::TypeParam(it)) = def { |
317 | it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); | 324 | it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); |
318 | } else { | 325 | } else { |
319 | let ty = match def { | 326 | let ty = match def { |
320 | Definition::Local(it) => it.ty(db), | 327 | Definition::Local(it) => it.ty(db), |
321 | Definition::GenericParam(GenericParam::ConstParam(it)) => it.ty(db), | 328 | Definition::GenericParam(hir::GenericParam::ConstParam(it)) => it.ty(db), |
322 | _ => return None, | 329 | _ => return None, |
323 | }; | 330 | }; |
324 | 331 | ||
@@ -348,29 +355,20 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | |||
348 | Some(HoverAction::GoToType(targets)) | 355 | Some(HoverAction::GoToType(targets)) |
349 | } | 356 | } |
350 | 357 | ||
351 | fn hover_markup( | 358 | fn hover_markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Option<Markup> { |
352 | docs: Option<String>, | 359 | let mut buf = String::new(); |
353 | desc: Option<String>, | ||
354 | mod_path: Option<String>, | ||
355 | ) -> Option<Markup> { | ||
356 | match desc { | ||
357 | Some(desc) => { | ||
358 | let mut buf = String::new(); | ||
359 | |||
360 | if let Some(mod_path) = mod_path { | ||
361 | if !mod_path.is_empty() { | ||
362 | format_to!(buf, "```rust\n{}\n```\n\n", mod_path); | ||
363 | } | ||
364 | } | ||
365 | format_to!(buf, "```rust\n{}\n```", desc); | ||
366 | 360 | ||
367 | if let Some(doc) = docs { | 361 | if let Some(mod_path) = mod_path { |
368 | format_to!(buf, "\n___\n\n{}", doc); | 362 | if !mod_path.is_empty() { |
369 | } | 363 | format_to!(buf, "```rust\n{}\n```\n\n", mod_path); |
370 | Some(buf.into()) | ||
371 | } | 364 | } |
372 | None => docs.map(Markup::from), | ||
373 | } | 365 | } |
366 | format_to!(buf, "```rust\n{}\n```", desc); | ||
367 | |||
368 | if let Some(doc) = docs { | ||
369 | format_to!(buf, "\n___\n\n{}", doc); | ||
370 | } | ||
371 | Some(buf.into()) | ||
374 | } | 372 | } |
375 | 373 | ||
376 | fn process_markup( | 374 | fn process_markup( |
@@ -396,11 +394,11 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> | |||
396 | Definition::Field(f) => Some(f.parent_def(db).name(db)), | 394 | Definition::Field(f) => Some(f.parent_def(db).name(db)), |
397 | Definition::Local(l) => l.parent(db).name(db), | 395 | Definition::Local(l) => l.parent(db).name(db), |
398 | Definition::ModuleDef(md) => match md { | 396 | Definition::ModuleDef(md) => match md { |
399 | ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { | 397 | hir::ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { |
400 | AssocItemContainer::Trait(t) => Some(t.name(db)), | 398 | hir::AssocItemContainer::Trait(t) => Some(t.name(db)), |
401 | AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)), | 399 | hir::AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)), |
402 | }, | 400 | }, |
403 | ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), | 401 | hir::ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), |
404 | _ => None, | 402 | _ => None, |
405 | }, | 403 | }, |
406 | _ => None, | 404 | _ => None, |
@@ -408,7 +406,7 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> | |||
408 | .map(|name| name.to_string()) | 406 | .map(|name| name.to_string()) |
409 | } | 407 | } |
410 | 408 | ||
411 | fn render_path(db: &RootDatabase, module: Module, item_name: Option<String>) -> String { | 409 | fn render_path(db: &RootDatabase, module: hir::Module, item_name: Option<String>) -> String { |
412 | let crate_name = | 410 | let crate_name = |
413 | db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string()); | 411 | db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string()); |
414 | let module_path = module | 412 | let module_path = module |
@@ -420,6 +418,9 @@ fn render_path(db: &RootDatabase, module: Module, item_name: Option<String>) -> | |||
420 | } | 418 | } |
421 | 419 | ||
422 | fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> { | 420 | fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> { |
421 | if let Definition::GenericParam(_) = def { | ||
422 | return None; | ||
423 | } | ||
423 | def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def))) | 424 | def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def))) |
424 | } | 425 | } |
425 | 426 | ||
@@ -427,60 +428,53 @@ fn hover_for_definition( | |||
427 | db: &RootDatabase, | 428 | db: &RootDatabase, |
428 | def: Definition, | 429 | def: Definition, |
429 | famous_defs: Option<&FamousDefs>, | 430 | famous_defs: Option<&FamousDefs>, |
431 | documentation: bool, | ||
430 | ) -> Option<Markup> { | 432 | ) -> Option<Markup> { |
431 | let mod_path = definition_mod_path(db, &def); | 433 | let mod_path = definition_mod_path(db, &def); |
432 | return match def { | 434 | let (label, docs) = match def { |
433 | Definition::Macro(it) => match &it.source(db)?.value { | 435 | Definition::Macro(it) => match &it.source(db)?.value { |
434 | Either::Left(mac) => { | 436 | Either::Left(mac) => { |
435 | let label = macro_label(mac); | 437 | let label = macro_label(mac); |
436 | from_def_source_labeled(db, it, Some(label), mod_path) | 438 | (label, it.attrs(db).docs()) |
437 | } | 439 | } |
438 | Either::Right(_) => { | 440 | Either::Right(_) => { |
439 | // FIXME | 441 | // FIXME |
440 | None | 442 | return None; |
441 | } | 443 | } |
442 | }, | 444 | }, |
443 | Definition::Field(def) => from_hir_fmt(db, def, mod_path), | 445 | Definition::Field(def) => label_and_docs(db, def), |
444 | Definition::ModuleDef(it) => match it { | 446 | Definition::ModuleDef(it) => match it { |
445 | ModuleDef::Module(it) => from_hir_fmt(db, it, mod_path), | 447 | hir::ModuleDef::Module(it) => label_and_docs(db, it), |
446 | ModuleDef::Function(it) => from_hir_fmt(db, it, mod_path), | 448 | hir::ModuleDef::Function(it) => label_and_docs(db, it), |
447 | ModuleDef::Adt(it) => from_hir_fmt(db, it, mod_path), | 449 | hir::ModuleDef::Adt(it) => label_and_docs(db, it), |
448 | ModuleDef::Variant(it) => from_hir_fmt(db, it, mod_path), | 450 | hir::ModuleDef::Variant(it) => label_and_docs(db, it), |
449 | ModuleDef::Const(it) => from_hir_fmt(db, it, mod_path), | 451 | hir::ModuleDef::Const(it) => label_and_docs(db, it), |
450 | ModuleDef::Static(it) => from_hir_fmt(db, it, mod_path), | 452 | hir::ModuleDef::Static(it) => label_and_docs(db, it), |
451 | ModuleDef::Trait(it) => from_hir_fmt(db, it, mod_path), | 453 | hir::ModuleDef::Trait(it) => label_and_docs(db, it), |
452 | ModuleDef::TypeAlias(it) => from_hir_fmt(db, it, mod_path), | 454 | hir::ModuleDef::TypeAlias(it) => label_and_docs(db, it), |
453 | ModuleDef::BuiltinType(it) => famous_defs | 455 | hir::ModuleDef::BuiltinType(it) => { |
454 | .and_then(|fd| hover_for_builtin(fd, it)) | 456 | return famous_defs |
455 | .or_else(|| Some(Markup::fenced_block(&it.name()))), | 457 | .and_then(|fd| hover_for_builtin(fd, it)) |
458 | .or_else(|| Some(Markup::fenced_block(&it.name()))) | ||
459 | } | ||
456 | }, | 460 | }, |
457 | Definition::Local(it) => hover_for_local(it, db), | 461 | Definition::Local(it) => return hover_for_local(it, db), |
458 | Definition::SelfType(impl_def) => { | 462 | Definition::SelfType(impl_def) => { |
459 | impl_def.self_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path)) | 463 | impl_def.self_ty(db).as_adt().map(|adt| label_and_docs(db, adt))? |
460 | } | 464 | } |
461 | Definition::GenericParam(it) => from_hir_fmt(db, it, None), | 465 | Definition::GenericParam(it) => label_and_docs(db, it), |
462 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), | 466 | Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))), |
463 | }; | 467 | }; |
464 | 468 | ||
465 | fn from_hir_fmt<D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> | 469 | return hover_markup(docs.filter(|_| documentation).map(Into::into), label, mod_path); |
470 | |||
471 | fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<hir::Documentation>) | ||
466 | where | 472 | where |
467 | D: HasAttrs + HirDisplay, | 473 | D: HasAttrs + HirDisplay, |
468 | { | 474 | { |
469 | let label = def.display(db).to_string(); | 475 | let label = def.display(db).to_string(); |
470 | from_def_source_labeled(db, def, Some(label), mod_path) | 476 | let docs = def.attrs(db).docs(); |
471 | } | 477 | (label, docs) |
472 | |||
473 | fn from_def_source_labeled<D>( | ||
474 | db: &RootDatabase, | ||
475 | def: D, | ||
476 | short_label: Option<String>, | ||
477 | mod_path: Option<String>, | ||
478 | ) -> Option<Markup> | ||
479 | where | ||
480 | D: HasAttrs, | ||
481 | { | ||
482 | let docs = def.attrs(db).docs().map(Into::into); | ||
483 | hover_markup(docs, short_label, mod_path) | ||
484 | } | 478 | } |
485 | } | 479 | } |
486 | 480 | ||
@@ -504,16 +498,17 @@ fn hover_for_local(it: hir::Local, db: &RootDatabase) -> Option<Markup> { | |||
504 | } | 498 | } |
505 | Either::Right(_) => format!("{}self: {}", is_mut, ty), | 499 | Either::Right(_) => format!("{}self: {}", is_mut, ty), |
506 | }; | 500 | }; |
507 | hover_markup(None, Some(desc), None) | 501 | hover_markup(None, desc, None) |
508 | } | 502 | } |
509 | 503 | ||
510 | fn hover_for_keyword( | 504 | fn hover_for_keyword( |
511 | sema: &Semantics<RootDatabase>, | 505 | sema: &hir::Semantics<RootDatabase>, |
512 | links_in_hover: bool, | 506 | links_in_hover: bool, |
513 | markdown: bool, | 507 | markdown: bool, |
508 | documentation: bool, | ||
514 | token: &SyntaxToken, | 509 | token: &SyntaxToken, |
515 | ) -> Option<RangeInfo<HoverResult>> { | 510 | ) -> Option<RangeInfo<HoverResult>> { |
516 | if !token.kind().is_keyword() { | 511 | if !token.kind().is_keyword() || !documentation { |
517 | return None; | 512 | return None; |
518 | } | 513 | } |
519 | let famous_defs = FamousDefs(sema, sema.scope(&token.parent()?).krate()); | 514 | let famous_defs = FamousDefs(sema, sema.scope(&token.parent()?).krate()); |
@@ -524,7 +519,7 @@ fn hover_for_keyword( | |||
524 | let markup = process_markup( | 519 | let markup = process_markup( |
525 | sema.db, | 520 | sema.db, |
526 | Definition::ModuleDef(doc_owner.into()), | 521 | Definition::ModuleDef(doc_owner.into()), |
527 | &hover_markup(Some(docs.into()), Some(token.text().into()), None)?, | 522 | &hover_markup(Some(docs.into()), token.text().into(), None)?, |
528 | links_in_hover, | 523 | links_in_hover, |
529 | markdown, | 524 | markdown, |
530 | ); | 525 | ); |
@@ -536,7 +531,7 @@ fn hover_for_builtin(famous_defs: &FamousDefs, builtin: hir::BuiltinType) -> Opt | |||
536 | let primitive_mod = format!("prim_{}", builtin.name()); | 531 | let primitive_mod = format!("prim_{}", builtin.name()); |
537 | let doc_owner = find_std_module(famous_defs, &primitive_mod)?; | 532 | let doc_owner = find_std_module(famous_defs, &primitive_mod)?; |
538 | let docs = doc_owner.attrs(famous_defs.0.db).docs()?; | 533 | let docs = doc_owner.attrs(famous_defs.0.db).docs()?; |
539 | hover_markup(Some(docs.into()), Some(builtin.name().to_string()), None) | 534 | hover_markup(Some(docs.into()), builtin.name().to_string(), None) |
540 | } | 535 | } |
541 | 536 | ||
542 | fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module> { | 537 | fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module> { |
@@ -570,12 +565,12 @@ mod tests { | |||
570 | 565 | ||
571 | fn check_hover_no_result(ra_fixture: &str) { | 566 | fn check_hover_no_result(ra_fixture: &str) { |
572 | let (analysis, position) = fixture::position(ra_fixture); | 567 | let (analysis, position) = fixture::position(ra_fixture); |
573 | assert!(analysis.hover(position, true, true).unwrap().is_none()); | 568 | assert!(analysis.hover(position, true, true, true).unwrap().is_none()); |
574 | } | 569 | } |
575 | 570 | ||
576 | fn check(ra_fixture: &str, expect: Expect) { | 571 | fn check(ra_fixture: &str, expect: Expect) { |
577 | let (analysis, position) = fixture::position(ra_fixture); | 572 | let (analysis, position) = fixture::position(ra_fixture); |
578 | let hover = analysis.hover(position, true, true).unwrap().unwrap(); | 573 | let hover = analysis.hover(position, true, true, true).unwrap().unwrap(); |
579 | 574 | ||
580 | let content = analysis.db.file_text(position.file_id); | 575 | let content = analysis.db.file_text(position.file_id); |
581 | let hovered_element = &content[hover.range]; | 576 | let hovered_element = &content[hover.range]; |
@@ -586,7 +581,7 @@ mod tests { | |||
586 | 581 | ||
587 | fn check_hover_no_links(ra_fixture: &str, expect: Expect) { | 582 | fn check_hover_no_links(ra_fixture: &str, expect: Expect) { |
588 | let (analysis, position) = fixture::position(ra_fixture); | 583 | let (analysis, position) = fixture::position(ra_fixture); |
589 | let hover = analysis.hover(position, false, true).unwrap().unwrap(); | 584 | let hover = analysis.hover(position, false, true, true).unwrap().unwrap(); |
590 | 585 | ||
591 | let content = analysis.db.file_text(position.file_id); | 586 | let content = analysis.db.file_text(position.file_id); |
592 | let hovered_element = &content[hover.range]; | 587 | let hovered_element = &content[hover.range]; |
@@ -597,7 +592,7 @@ mod tests { | |||
597 | 592 | ||
598 | fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { | 593 | fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { |
599 | let (analysis, position) = fixture::position(ra_fixture); | 594 | let (analysis, position) = fixture::position(ra_fixture); |
600 | let hover = analysis.hover(position, true, false).unwrap().unwrap(); | 595 | let hover = analysis.hover(position, true, true, false).unwrap().unwrap(); |
601 | 596 | ||
602 | let content = analysis.db.file_text(position.file_id); | 597 | let content = analysis.db.file_text(position.file_id); |
603 | let hovered_element = &content[hover.range]; | 598 | let hovered_element = &content[hover.range]; |
@@ -608,7 +603,7 @@ mod tests { | |||
608 | 603 | ||
609 | fn check_actions(ra_fixture: &str, expect: Expect) { | 604 | fn check_actions(ra_fixture: &str, expect: Expect) { |
610 | let (analysis, position) = fixture::position(ra_fixture); | 605 | let (analysis, position) = fixture::position(ra_fixture); |
611 | let hover = analysis.hover(position, true, true).unwrap().unwrap(); | 606 | let hover = analysis.hover(position, true, true, true).unwrap().unwrap(); |
612 | expect.assert_debug_eq(&hover.info.actions) | 607 | expect.assert_debug_eq(&hover.info.actions) |
613 | } | 608 | } |
614 | 609 | ||
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 4bd073cc3..3798f32cc 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -408,9 +408,10 @@ impl Analysis { | |||
408 | &self, | 408 | &self, |
409 | position: FilePosition, | 409 | position: FilePosition, |
410 | links_in_hover: bool, | 410 | links_in_hover: bool, |
411 | documentation: bool, | ||
411 | markdown: bool, | 412 | markdown: bool, |
412 | ) -> Cancellable<Option<RangeInfo<HoverResult>>> { | 413 | ) -> Cancellable<Option<RangeInfo<HoverResult>>> { |
413 | self.with_db(|db| hover::hover(db, position, links_in_hover, markdown)) | 414 | self.with_db(|db| hover::hover(db, position, links_in_hover, documentation, markdown)) |
414 | } | 415 | } |
415 | 416 | ||
416 | /// Return URL(s) for the documentation of the symbol under the cursor. | 417 | /// Return URL(s) for the documentation of the symbol under the cursor. |
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs index ac7f0959b..870d4f665 100644 --- a/crates/ide_assists/src/handlers/extract_function.rs +++ b/crates/ide_assists/src/handlers/extract_function.rs | |||
@@ -109,10 +109,15 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
109 | 109 | ||
110 | let new_indent = IndentLevel::from_node(&insert_after); | 110 | let new_indent = IndentLevel::from_node(&insert_after); |
111 | let old_indent = fun.body.indent_level(); | 111 | let old_indent = fun.body.indent_level(); |
112 | let body_contains_await = body_contains_await(&fun.body); | ||
112 | 113 | ||
113 | builder.replace(target_range, format_replacement(ctx, &fun, old_indent)); | 114 | builder.replace( |
115 | target_range, | ||
116 | format_replacement(ctx, &fun, old_indent, body_contains_await), | ||
117 | ); | ||
114 | 118 | ||
115 | let fn_def = format_function(ctx, module, &fun, old_indent, new_indent); | 119 | let fn_def = |
120 | format_function(ctx, module, &fun, old_indent, new_indent, body_contains_await); | ||
116 | let insert_offset = insert_after.text_range().end(); | 121 | let insert_offset = insert_after.text_range().end(); |
117 | match ctx.config.snippet_cap { | 122 | match ctx.config.snippet_cap { |
118 | Some(cap) => builder.insert_snippet(cap, insert_offset, fn_def), | 123 | Some(cap) => builder.insert_snippet(cap, insert_offset, fn_def), |
@@ -954,7 +959,12 @@ fn scope_for_fn_insertion_node(node: &SyntaxNode, anchor: Anchor) -> Option<Synt | |||
954 | last_ancestor | 959 | last_ancestor |
955 | } | 960 | } |
956 | 961 | ||
957 | fn format_replacement(ctx: &AssistContext, fun: &Function, indent: IndentLevel) -> String { | 962 | fn format_replacement( |
963 | ctx: &AssistContext, | ||
964 | fun: &Function, | ||
965 | indent: IndentLevel, | ||
966 | body_contains_await: bool, | ||
967 | ) -> String { | ||
958 | let ret_ty = fun.return_type(ctx); | 968 | let ret_ty = fun.return_type(ctx); |
959 | 969 | ||
960 | let args = fun.params.iter().map(|param| param.to_arg(ctx)); | 970 | let args = fun.params.iter().map(|param| param.to_arg(ctx)); |
@@ -994,6 +1004,9 @@ fn format_replacement(ctx: &AssistContext, fun: &Function, indent: IndentLevel) | |||
994 | } | 1004 | } |
995 | } | 1005 | } |
996 | format_to!(buf, "{}", expr); | 1006 | format_to!(buf, "{}", expr); |
1007 | if body_contains_await { | ||
1008 | buf.push_str(".await"); | ||
1009 | } | ||
997 | if fun.ret_ty.is_unit() | 1010 | if fun.ret_ty.is_unit() |
998 | && (!fun.vars_defined_in_body_and_outlive.is_empty() || !expr.is_block_like()) | 1011 | && (!fun.vars_defined_in_body_and_outlive.is_empty() || !expr.is_block_like()) |
999 | { | 1012 | { |
@@ -1122,12 +1135,13 @@ fn format_function( | |||
1122 | fun: &Function, | 1135 | fun: &Function, |
1123 | old_indent: IndentLevel, | 1136 | old_indent: IndentLevel, |
1124 | new_indent: IndentLevel, | 1137 | new_indent: IndentLevel, |
1138 | body_contains_await: bool, | ||
1125 | ) -> String { | 1139 | ) -> String { |
1126 | let mut fn_def = String::new(); | 1140 | let mut fn_def = String::new(); |
1127 | let params = make_param_list(ctx, module, fun); | 1141 | let params = make_param_list(ctx, module, fun); |
1128 | let ret_ty = make_ret_ty(ctx, module, fun); | 1142 | let ret_ty = make_ret_ty(ctx, module, fun); |
1129 | let body = make_body(ctx, old_indent, new_indent, fun); | 1143 | let body = make_body(ctx, old_indent, new_indent, fun); |
1130 | let async_kw = if body_contains_await(&fun.body) { "async " } else { "" }; | 1144 | let async_kw = if body_contains_await { "async " } else { "" }; |
1131 | match ctx.config.snippet_cap { | 1145 | match ctx.config.snippet_cap { |
1132 | Some(_) => format_to!(fn_def, "\n\n{}{}fn $0{}{}", new_indent, async_kw, fun.name, params), | 1146 | Some(_) => format_to!(fn_def, "\n\n{}{}fn $0{}{}", new_indent, async_kw, fun.name, params), |
1133 | None => format_to!(fn_def, "\n\n{}{}fn {}{}", new_indent, async_kw, fun.name, params), | 1147 | None => format_to!(fn_def, "\n\n{}{}fn {}{}", new_indent, async_kw, fun.name, params), |
@@ -3681,7 +3695,7 @@ async fn some_function() { | |||
3681 | "#, | 3695 | "#, |
3682 | r#" | 3696 | r#" |
3683 | fn main() { | 3697 | fn main() { |
3684 | fun_name(); | 3698 | fun_name().await; |
3685 | } | 3699 | } |
3686 | 3700 | ||
3687 | async fn $0fun_name() { | 3701 | async fn $0fun_name() { |
@@ -3710,7 +3724,7 @@ async fn some_function() { | |||
3710 | "#, | 3724 | "#, |
3711 | r#" | 3725 | r#" |
3712 | fn main() { | 3726 | fn main() { |
3713 | fun_name(); | 3727 | fun_name().await; |
3714 | } | 3728 | } |
3715 | 3729 | ||
3716 | async fn $0fun_name() { | 3730 | async fn $0fun_name() { |
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index ac079f83e..0935ea967 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | //! See [`CargoWorkspace`]. | 1 | //! See [`CargoWorkspace`]. |
2 | 2 | ||
3 | use std::iter; | ||
3 | use std::path::PathBuf; | 4 | use std::path::PathBuf; |
4 | use std::{convert::TryInto, ops, process::Command, sync::Arc}; | 5 | use std::{convert::TryInto, ops, process::Command, sync::Arc}; |
5 | 6 | ||
@@ -12,6 +13,7 @@ use rustc_hash::FxHashMap; | |||
12 | use serde::Deserialize; | 13 | use serde::Deserialize; |
13 | use serde_json::from_value; | 14 | use serde_json::from_value; |
14 | 15 | ||
16 | use crate::CfgOverrides; | ||
15 | use crate::{build_data::BuildDataConfig, utf8_stdout}; | 17 | use crate::{build_data::BuildDataConfig, utf8_stdout}; |
16 | 18 | ||
17 | /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo | 19 | /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo |
@@ -76,6 +78,21 @@ pub struct CargoConfig { | |||
76 | 78 | ||
77 | /// rustc private crate source | 79 | /// rustc private crate source |
78 | pub rustc_source: Option<RustcSource>, | 80 | pub rustc_source: Option<RustcSource>, |
81 | |||
82 | /// crates to disable `#[cfg(test)]` on | ||
83 | pub unset_test_crates: Vec<String>, | ||
84 | } | ||
85 | |||
86 | impl CargoConfig { | ||
87 | pub fn cfg_overrides(&self) -> CfgOverrides { | ||
88 | self.unset_test_crates | ||
89 | .iter() | ||
90 | .cloned() | ||
91 | .zip(iter::repeat_with(|| { | ||
92 | cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())]).unwrap() | ||
93 | })) | ||
94 | .collect() | ||
95 | } | ||
79 | } | 96 | } |
80 | 97 | ||
81 | pub type Package = Idx<PackageData>; | 98 | pub type Package = Idx<PackageData>; |
diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs index 8c6cf94c2..1d408dff2 100644 --- a/crates/project_model/src/lib.rs +++ b/crates/project_model/src/lib.rs | |||
@@ -41,7 +41,7 @@ pub use crate::{ | |||
41 | }, | 41 | }, |
42 | project_json::{ProjectJson, ProjectJsonData}, | 42 | project_json::{ProjectJson, ProjectJsonData}, |
43 | sysroot::Sysroot, | 43 | sysroot::Sysroot, |
44 | workspace::{PackageRoot, ProjectWorkspace}, | 44 | workspace::{CfgOverrides, PackageRoot, ProjectWorkspace}, |
45 | }; | 45 | }; |
46 | 46 | ||
47 | pub use proc_macro_api::ProcMacroClient; | 47 | pub use proc_macro_api::ProcMacroClient; |
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs index ef0f3c9e4..d8217f714 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs | |||
@@ -7,7 +7,7 @@ use std::{collections::VecDeque, fmt, fs, path::Path, process::Command}; | |||
7 | use anyhow::{format_err, Context, Result}; | 7 | use anyhow::{format_err, Context, Result}; |
8 | use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro}; | 8 | use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro}; |
9 | use cargo_workspace::DepKind; | 9 | use cargo_workspace::DepKind; |
10 | use cfg::CfgOptions; | 10 | use cfg::{CfgDiff, CfgOptions}; |
11 | use paths::{AbsPath, AbsPathBuf}; | 11 | use paths::{AbsPath, AbsPathBuf}; |
12 | use proc_macro_api::ProcMacroClient; | 12 | use proc_macro_api::ProcMacroClient; |
13 | use rustc_hash::{FxHashMap, FxHashSet}; | 13 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -22,6 +22,8 @@ use crate::{ | |||
22 | Sysroot, TargetKind, | 22 | Sysroot, TargetKind, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | pub type CfgOverrides = FxHashMap<String, CfgDiff>; | ||
26 | |||
25 | /// `PackageRoot` describes a package root folder. | 27 | /// `PackageRoot` describes a package root folder. |
26 | /// Which may be an external dependency, or a member of | 28 | /// Which may be an external dependency, or a member of |
27 | /// the current workspace. | 29 | /// the current workspace. |
@@ -46,6 +48,7 @@ pub enum ProjectWorkspace { | |||
46 | /// FIXME: make this a per-crate map, as, eg, build.rs might have a | 48 | /// FIXME: make this a per-crate map, as, eg, build.rs might have a |
47 | /// different target. | 49 | /// different target. |
48 | rustc_cfg: Vec<CfgFlag>, | 50 | rustc_cfg: Vec<CfgFlag>, |
51 | cfg_overrides: CfgOverrides, | ||
49 | }, | 52 | }, |
50 | /// Project workspace was manually specified using a `rust-project.json` file. | 53 | /// Project workspace was manually specified using a `rust-project.json` file. |
51 | Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> }, | 54 | Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> }, |
@@ -67,7 +70,7 @@ impl fmt::Debug for ProjectWorkspace { | |||
67 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 70 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
68 | // Make sure this isn't too verbose. | 71 | // Make sure this isn't too verbose. |
69 | match self { | 72 | match self { |
70 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => f | 73 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => f |
71 | .debug_struct("Cargo") | 74 | .debug_struct("Cargo") |
72 | .field("root", &cargo.workspace_root().file_name()) | 75 | .field("root", &cargo.workspace_root().file_name()) |
73 | .field("n_packages", &cargo.packages().len()) | 76 | .field("n_packages", &cargo.packages().len()) |
@@ -77,6 +80,7 @@ impl fmt::Debug for ProjectWorkspace { | |||
77 | &rustc.as_ref().map_or(0, |rc| rc.packages().len()), | 80 | &rustc.as_ref().map_or(0, |rc| rc.packages().len()), |
78 | ) | 81 | ) |
79 | .field("n_rustc_cfg", &rustc_cfg.len()) | 82 | .field("n_rustc_cfg", &rustc_cfg.len()) |
83 | .field("n_cfg_overrides", &cfg_overrides.len()) | ||
80 | .finish(), | 84 | .finish(), |
81 | ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { | 85 | ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { |
82 | let mut debug_struct = f.debug_struct("Json"); | 86 | let mut debug_struct = f.debug_struct("Json"); |
@@ -164,7 +168,9 @@ impl ProjectWorkspace { | |||
164 | }; | 168 | }; |
165 | 169 | ||
166 | let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref()); | 170 | let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref()); |
167 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } | 171 | |
172 | let cfg_overrides = config.cfg_overrides(); | ||
173 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } | ||
168 | } | 174 | } |
169 | }; | 175 | }; |
170 | 176 | ||
@@ -213,43 +219,45 @@ impl ProjectWorkspace { | |||
213 | }) | 219 | }) |
214 | })) | 220 | })) |
215 | .collect::<Vec<_>>(), | 221 | .collect::<Vec<_>>(), |
216 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _ } => cargo | 222 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _, cfg_overrides: _ } => { |
217 | .packages() | 223 | cargo |
218 | .map(|pkg| { | 224 | .packages() |
219 | let is_member = cargo[pkg].is_member; | 225 | .map(|pkg| { |
220 | let pkg_root = cargo[pkg].root().to_path_buf(); | 226 | let is_member = cargo[pkg].is_member; |
221 | 227 | let pkg_root = cargo[pkg].root().to_path_buf(); | |
222 | let mut include = vec![pkg_root.clone()]; | 228 | |
223 | include.extend( | 229 | let mut include = vec![pkg_root.clone()]; |
224 | build_data | 230 | include.extend( |
225 | .and_then(|it| it.get(cargo.workspace_root())) | 231 | build_data |
226 | .and_then(|map| map.get(&cargo[pkg].id)) | 232 | .and_then(|it| it.get(cargo.workspace_root())) |
227 | .and_then(|it| it.out_dir.clone()), | 233 | .and_then(|map| map.get(&cargo[pkg].id)) |
228 | ); | 234 | .and_then(|it| it.out_dir.clone()), |
235 | ); | ||
229 | 236 | ||
230 | let mut exclude = vec![pkg_root.join(".git")]; | 237 | let mut exclude = vec![pkg_root.join(".git")]; |
231 | if is_member { | 238 | if is_member { |
232 | exclude.push(pkg_root.join("target")); | 239 | exclude.push(pkg_root.join("target")); |
233 | } else { | 240 | } else { |
234 | exclude.push(pkg_root.join("tests")); | 241 | exclude.push(pkg_root.join("tests")); |
235 | exclude.push(pkg_root.join("examples")); | 242 | exclude.push(pkg_root.join("examples")); |
236 | exclude.push(pkg_root.join("benches")); | 243 | exclude.push(pkg_root.join("benches")); |
237 | } | 244 | } |
238 | PackageRoot { is_member, include, exclude } | 245 | PackageRoot { is_member, include, exclude } |
239 | }) | 246 | }) |
240 | .chain(sysroot.crates().map(|krate| PackageRoot { | 247 | .chain(sysroot.crates().map(|krate| PackageRoot { |
241 | is_member: false, | ||
242 | include: vec![sysroot[krate].root_dir().to_path_buf()], | ||
243 | exclude: Vec::new(), | ||
244 | })) | ||
245 | .chain(rustc.into_iter().flat_map(|rustc| { | ||
246 | rustc.packages().map(move |krate| PackageRoot { | ||
247 | is_member: false, | 248 | is_member: false, |
248 | include: vec![rustc[krate].root().to_path_buf()], | 249 | include: vec![sysroot[krate].root_dir().to_path_buf()], |
249 | exclude: Vec::new(), | 250 | exclude: Vec::new(), |
250 | }) | 251 | })) |
251 | })) | 252 | .chain(rustc.into_iter().flat_map(|rustc| { |
252 | .collect(), | 253 | rustc.packages().map(move |krate| PackageRoot { |
254 | is_member: false, | ||
255 | include: vec![rustc[krate].root().to_path_buf()], | ||
256 | exclude: Vec::new(), | ||
257 | }) | ||
258 | })) | ||
259 | .collect() | ||
260 | } | ||
253 | ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files | 261 | ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files |
254 | .into_iter() | 262 | .into_iter() |
255 | .map(|detached_file| PackageRoot { | 263 | .map(|detached_file| PackageRoot { |
@@ -299,16 +307,22 @@ impl ProjectWorkspace { | |||
299 | project, | 307 | project, |
300 | sysroot, | 308 | sysroot, |
301 | ), | 309 | ), |
302 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => cargo_to_crate_graph( | 310 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => { |
303 | rustc_cfg.clone(), | 311 | cargo_to_crate_graph( |
304 | &proc_macro_loader, | 312 | rustc_cfg.clone(), |
305 | load, | 313 | cfg_overrides, |
306 | cargo, | 314 | &proc_macro_loader, |
307 | build_data.and_then(|it| it.get(cargo.workspace_root())), | 315 | load, |
308 | sysroot, | 316 | cargo, |
309 | rustc, | 317 | build_data.and_then(|it| it.get(cargo.workspace_root())), |
310 | rustc.as_ref().zip(build_data).and_then(|(it, map)| map.get(it.workspace_root())), | 318 | sysroot, |
311 | ), | 319 | rustc, |
320 | rustc | ||
321 | .as_ref() | ||
322 | .zip(build_data) | ||
323 | .and_then(|(it, map)| map.get(it.workspace_root())), | ||
324 | ) | ||
325 | } | ||
312 | ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => { | 326 | ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => { |
313 | detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot) | 327 | detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot) |
314 | } | 328 | } |
@@ -398,6 +412,7 @@ fn project_json_to_crate_graph( | |||
398 | 412 | ||
399 | fn cargo_to_crate_graph( | 413 | fn cargo_to_crate_graph( |
400 | rustc_cfg: Vec<CfgFlag>, | 414 | rustc_cfg: Vec<CfgFlag>, |
415 | override_cfg: &CfgOverrides, | ||
401 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, | 416 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, |
402 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 417 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
403 | cargo: &CargoWorkspace, | 418 | cargo: &CargoWorkspace, |
@@ -425,6 +440,21 @@ fn cargo_to_crate_graph( | |||
425 | let mut has_private = false; | 440 | let mut has_private = false; |
426 | // Next, create crates for each package, target pair | 441 | // Next, create crates for each package, target pair |
427 | for pkg in cargo.packages() { | 442 | for pkg in cargo.packages() { |
443 | let mut cfg_options = &cfg_options; | ||
444 | let mut replaced_cfg_options; | ||
445 | if let Some(overrides) = override_cfg.get(&cargo[pkg].name) { | ||
446 | // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen | ||
447 | // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while | ||
448 | // working on rust-lang/rust as that's the only time it appears outside sysroot). | ||
449 | // | ||
450 | // A more ideal solution might be to reanalyze crates based on where the cursor is and | ||
451 | // figure out the set of cfgs that would have to apply to make it active. | ||
452 | |||
453 | replaced_cfg_options = cfg_options.clone(); | ||
454 | replaced_cfg_options.apply_diff(overrides.clone()); | ||
455 | cfg_options = &replaced_cfg_options; | ||
456 | }; | ||
457 | |||
428 | has_private |= cargo[pkg].metadata.rustc_private; | 458 | has_private |= cargo[pkg].metadata.rustc_private; |
429 | let mut lib_tgt = None; | 459 | let mut lib_tgt = None; |
430 | for &tgt in cargo[pkg].targets.iter() { | 460 | for &tgt in cargo[pkg].targets.iter() { |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 16c295639..3aeca8839 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -55,6 +55,8 @@ config_data! { | |||
55 | cargo_autoreload: bool = "true", | 55 | cargo_autoreload: bool = "true", |
56 | /// Activate all available features (`--all-features`). | 56 | /// Activate all available features (`--all-features`). |
57 | cargo_allFeatures: bool = "false", | 57 | cargo_allFeatures: bool = "false", |
58 | /// Unsets `#[cfg(test)]` for the specified crates. | ||
59 | cargo_unsetTest: Vec<String> = "[\"core\"]", | ||
58 | /// List of features to activate. | 60 | /// List of features to activate. |
59 | cargo_features: Vec<String> = "[]", | 61 | cargo_features: Vec<String> = "[]", |
60 | /// Run build scripts (`build.rs`) for more precise code analysis. | 62 | /// Run build scripts (`build.rs`) for more precise code analysis. |
@@ -144,6 +146,12 @@ config_data! { | |||
144 | /// their contents. | 146 | /// their contents. |
145 | highlighting_strings: bool = "true", | 147 | highlighting_strings: bool = "true", |
146 | 148 | ||
149 | /// Whether to show documentation on hover. | ||
150 | hover_documentation: bool = "true", | ||
151 | /// Use markdown syntax for links in hover. | ||
152 | hover_linksInHover | | ||
153 | hoverActions_linksInHover: bool = "true", | ||
154 | |||
147 | /// Whether to show `Debug` action. Only applies when | 155 | /// Whether to show `Debug` action. Only applies when |
148 | /// `#rust-analyzer.hoverActions.enable#` is set. | 156 | /// `#rust-analyzer.hoverActions.enable#` is set. |
149 | hoverActions_debug: bool = "true", | 157 | hoverActions_debug: bool = "true", |
@@ -161,8 +169,6 @@ config_data! { | |||
161 | /// Whether to show `Run` action. Only applies when | 169 | /// Whether to show `Run` action. Only applies when |
162 | /// `#rust-analyzer.hoverActions.enable#` is set. | 170 | /// `#rust-analyzer.hoverActions.enable#` is set. |
163 | hoverActions_run: bool = "true", | 171 | hoverActions_run: bool = "true", |
164 | /// Use markdown syntax for links in hover. | ||
165 | hoverActions_linksInHover: bool = "true", | ||
166 | 172 | ||
167 | /// Whether to show inlay type hints for method chains. | 173 | /// Whether to show inlay type hints for method chains. |
168 | inlayHints_chainingHints: bool = "true", | 174 | inlayHints_chainingHints: bool = "true", |
@@ -595,8 +601,10 @@ impl Config { | |||
595 | target: self.data.cargo_target.clone(), | 601 | target: self.data.cargo_target.clone(), |
596 | rustc_source, | 602 | rustc_source, |
597 | no_sysroot: self.data.cargo_noSysroot, | 603 | no_sysroot: self.data.cargo_noSysroot, |
604 | unset_test_crates: self.data.cargo_unsetTest.clone(), | ||
598 | } | 605 | } |
599 | } | 606 | } |
607 | |||
600 | pub fn rustfmt(&self) -> RustfmtConfig { | 608 | pub fn rustfmt(&self) -> RustfmtConfig { |
601 | match &self.data.rustfmt_overrideCommand { | 609 | match &self.data.rustfmt_overrideCommand { |
602 | Some(args) if !args.is_empty() => { | 610 | Some(args) if !args.is_empty() => { |
@@ -730,7 +738,7 @@ impl Config { | |||
730 | run: self.data.hoverActions_enable && self.data.hoverActions_run, | 738 | run: self.data.hoverActions_enable && self.data.hoverActions_run, |
731 | debug: self.data.hoverActions_enable && self.data.hoverActions_debug, | 739 | debug: self.data.hoverActions_enable && self.data.hoverActions_debug, |
732 | goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef, | 740 | goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef, |
733 | links_in_hover: self.data.hoverActions_linksInHover, | 741 | links_in_hover: self.data.hover_linksInHover, |
734 | markdown: try_or!( | 742 | markdown: try_or!( |
735 | self.caps | 743 | self.caps |
736 | .text_document | 744 | .text_document |
@@ -743,6 +751,7 @@ impl Config { | |||
743 | &[] | 751 | &[] |
744 | ) | 752 | ) |
745 | .contains(&MarkupKind::Markdown), | 753 | .contains(&MarkupKind::Markdown), |
754 | documentation: self.data.hover_documentation, | ||
746 | } | 755 | } |
747 | } | 756 | } |
748 | 757 | ||
@@ -852,6 +861,7 @@ macro_rules! _config_data { | |||
852 | $({ | 861 | $({ |
853 | let field = stringify!($field); | 862 | let field = stringify!($field); |
854 | let ty = stringify!($ty); | 863 | let ty = stringify!($ty); |
864 | |||
855 | (field, ty, &[$($doc),*], $default) | 865 | (field, ty, &[$($doc),*], $default) |
856 | },)* | 866 | },)* |
857 | ]) | 867 | ]) |
@@ -863,6 +873,7 @@ macro_rules! _config_data { | |||
863 | $({ | 873 | $({ |
864 | let field = stringify!($field); | 874 | let field = stringify!($field); |
865 | let ty = stringify!($ty); | 875 | let ty = stringify!($ty); |
876 | |||
866 | (field, ty, &[$($doc),*], $default) | 877 | (field, ty, &[$($doc),*], $default) |
867 | },)* | 878 | },)* |
868 | ]) | 879 | ]) |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index ccf66294f..eff1e6c93 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -862,11 +862,15 @@ pub(crate) fn handle_hover( | |||
862 | let _p = profile::span("handle_hover"); | 862 | let _p = profile::span("handle_hover"); |
863 | let position = from_proto::file_position(&snap, params.text_document_position_params)?; | 863 | let position = from_proto::file_position(&snap, params.text_document_position_params)?; |
864 | let hover_config = snap.config.hover(); | 864 | let hover_config = snap.config.hover(); |
865 | let info = | 865 | let info = match snap.analysis.hover( |
866 | match snap.analysis.hover(position, hover_config.links_in_hover, hover_config.markdown)? { | 866 | position, |
867 | None => return Ok(None), | 867 | hover_config.links_in_hover, |
868 | Some(info) => info, | 868 | hover_config.documentation, |
869 | }; | 869 | hover_config.markdown, |
870 | )? { | ||
871 | None => return Ok(None), | ||
872 | Some(info) => info, | ||
873 | }; | ||
870 | let line_index = snap.file_line_index(position.file_id)?; | 874 | let line_index = snap.file_line_index(position.file_id)?; |
871 | let range = to_proto::range(&line_index, info.range); | 875 | let range = to_proto::range(&line_index, info.range); |
872 | let hover = lsp_ext::Hover { | 876 | let hover = lsp_ext::Hover { |
@@ -1587,7 +1591,7 @@ fn prepare_hover_actions( | |||
1587 | snap: &GlobalStateSnapshot, | 1591 | snap: &GlobalStateSnapshot, |
1588 | actions: &[HoverAction], | 1592 | actions: &[HoverAction], |
1589 | ) -> Vec<lsp_ext::CommandLinkGroup> { | 1593 | ) -> Vec<lsp_ext::CommandLinkGroup> { |
1590 | if snap.config.hover().none() || !snap.config.hover_actions() { | 1594 | if snap.config.hover().no_actions() || !snap.config.hover_actions() { |
1591 | return Vec::new(); | 1595 | return Vec::new(); |
1592 | } | 1596 | } |
1593 | 1597 | ||
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 18ea77266..cc7fdd38f 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc | |||
@@ -39,6 +39,11 @@ Automatically refresh project info via `cargo metadata` on | |||
39 | -- | 39 | -- |
40 | Activate all available features (`--all-features`). | 40 | Activate all available features (`--all-features`). |
41 | -- | 41 | -- |
42 | [[rust-analyzer.cargo.unsetTest]]rust-analyzer.cargo.unsetTest (default: `["core"]`):: | ||
43 | + | ||
44 | -- | ||
45 | Unsets `#[cfg(test)]` for the specified crates. | ||
46 | -- | ||
42 | [[rust-analyzer.cargo.features]]rust-analyzer.cargo.features (default: `[]`):: | 47 | [[rust-analyzer.cargo.features]]rust-analyzer.cargo.features (default: `[]`):: |
43 | + | 48 | + |
44 | -- | 49 | -- |
@@ -210,6 +215,16 @@ In some editors (e.g. vscode) semantic tokens override other highlighting gramma | |||
210 | By disabling semantic tokens for strings, other grammars can be used to highlight | 215 | By disabling semantic tokens for strings, other grammars can be used to highlight |
211 | their contents. | 216 | their contents. |
212 | -- | 217 | -- |
218 | [[rust-analyzer.hover.documentation]]rust-analyzer.hover.documentation (default: `true`):: | ||
219 | + | ||
220 | -- | ||
221 | Whether to show documentation on hover. | ||
222 | -- | ||
223 | [[rust-analyzer.hover.linksInHover]]rust-analyzer.hover.linksInHover (default: `true`):: | ||
224 | + | ||
225 | -- | ||
226 | Use markdown syntax for links in hover. | ||
227 | -- | ||
213 | [[rust-analyzer.hoverActions.debug]]rust-analyzer.hoverActions.debug (default: `true`):: | 228 | [[rust-analyzer.hoverActions.debug]]rust-analyzer.hoverActions.debug (default: `true`):: |
214 | + | 229 | + |
215 | -- | 230 | -- |
@@ -245,11 +260,6 @@ Whether to show `References` action. Only applies when | |||
245 | Whether to show `Run` action. Only applies when | 260 | Whether to show `Run` action. Only applies when |
246 | `#rust-analyzer.hoverActions.enable#` is set. | 261 | `#rust-analyzer.hoverActions.enable#` is set. |
247 | -- | 262 | -- |
248 | [[rust-analyzer.hoverActions.linksInHover]]rust-analyzer.hoverActions.linksInHover (default: `true`):: | ||
249 | + | ||
250 | -- | ||
251 | Use markdown syntax for links in hover. | ||
252 | -- | ||
253 | [[rust-analyzer.inlayHints.chainingHints]]rust-analyzer.inlayHints.chainingHints (default: `true`):: | 263 | [[rust-analyzer.inlayHints.chainingHints]]rust-analyzer.inlayHints.chainingHints (default: `true`):: |
254 | + | 264 | + |
255 | -- | 265 | -- |
diff --git a/editors/code/package.json b/editors/code/package.json index c077bd2c0..666016ae4 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -452,6 +452,16 @@ | |||
452 | "default": false, | 452 | "default": false, |
453 | "type": "boolean" | 453 | "type": "boolean" |
454 | }, | 454 | }, |
455 | "rust-analyzer.cargo.unsetTest": { | ||
456 | "markdownDescription": "Unsets `#[cfg(test)]` for the specified crates.", | ||
457 | "default": [ | ||
458 | "core" | ||
459 | ], | ||
460 | "type": "array", | ||
461 | "items": { | ||
462 | "type": "string" | ||
463 | } | ||
464 | }, | ||
455 | "rust-analyzer.cargo.features": { | 465 | "rust-analyzer.cargo.features": { |
456 | "markdownDescription": "List of features to activate.", | 466 | "markdownDescription": "List of features to activate.", |
457 | "default": [], | 467 | "default": [], |
@@ -645,6 +655,16 @@ | |||
645 | "default": true, | 655 | "default": true, |
646 | "type": "boolean" | 656 | "type": "boolean" |
647 | }, | 657 | }, |
658 | "rust-analyzer.hover.documentation": { | ||
659 | "markdownDescription": "Whether to show documentation on hover.", | ||
660 | "default": true, | ||
661 | "type": "boolean" | ||
662 | }, | ||
663 | "rust-analyzer.hover.linksInHover": { | ||
664 | "markdownDescription": "Use markdown syntax for links in hover.", | ||
665 | "default": true, | ||
666 | "type": "boolean" | ||
667 | }, | ||
648 | "rust-analyzer.hoverActions.debug": { | 668 | "rust-analyzer.hoverActions.debug": { |
649 | "markdownDescription": "Whether to show `Debug` action. Only applies when\n`#rust-analyzer.hoverActions.enable#` is set.", | 669 | "markdownDescription": "Whether to show `Debug` action. Only applies when\n`#rust-analyzer.hoverActions.enable#` is set.", |
650 | "default": true, | 670 | "default": true, |
@@ -675,11 +695,6 @@ | |||
675 | "default": true, | 695 | "default": true, |
676 | "type": "boolean" | 696 | "type": "boolean" |
677 | }, | 697 | }, |
678 | "rust-analyzer.hoverActions.linksInHover": { | ||
679 | "markdownDescription": "Use markdown syntax for links in hover.", | ||
680 | "default": true, | ||
681 | "type": "boolean" | ||
682 | }, | ||
683 | "rust-analyzer.inlayHints.chainingHints": { | 698 | "rust-analyzer.inlayHints.chainingHints": { |
684 | "markdownDescription": "Whether to show inlay type hints for method chains.", | 699 | "markdownDescription": "Whether to show inlay type hints for method chains.", |
685 | "default": true, | 700 | "default": true, |