aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/base_db/src/fixture.rs3
-rw-r--r--crates/base_db/src/input.rs13
-rw-r--r--crates/cfg/src/lib.rs20
-rw-r--r--crates/hir/src/lib.rs4
-rw-r--r--crates/ide/src/hover.rs135
-rw-r--r--crates/ide/src/lib.rs9
-rw-r--r--crates/ide_completion/src/completions/attribute.rs15
-rw-r--r--crates/ide_completion/src/completions/attribute/cfg.rs112
-rw-r--r--crates/proc_macro_test/build.rs14
-rw-r--r--crates/project_model/src/workspace.rs11
-rw-r--r--crates/rust-analyzer/src/bin/main.rs9
-rw-r--r--crates/rust-analyzer/src/config.rs87
-rw-r--r--crates/rust-analyzer/src/handlers.rs24
-rw-r--r--crates/syntax/src/ptr.rs2
14 files changed, 355 insertions, 103 deletions
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs
index 6ce377710..7d5d12e63 100644
--- a/crates/base_db/src/fixture.rs
+++ b/crates/base_db/src/fixture.rs
@@ -128,6 +128,7 @@ impl ChangeFixture {
128 file_id, 128 file_id,
129 meta.edition, 129 meta.edition,
130 Some(crate_name.clone().into()), 130 Some(crate_name.clone().into()),
131 meta.cfg.clone(),
131 meta.cfg, 132 meta.cfg,
132 meta.env, 133 meta.env,
133 Default::default(), 134 Default::default(),
@@ -157,6 +158,7 @@ impl ChangeFixture {
157 crate_root, 158 crate_root,
158 Edition::Edition2018, 159 Edition::Edition2018,
159 Some(CrateName::new("test").unwrap().into()), 160 Some(CrateName::new("test").unwrap().into()),
161 default_cfg.clone(),
160 default_cfg, 162 default_cfg,
161 Env::default(), 163 Env::default(),
162 Default::default(), 164 Default::default(),
@@ -186,6 +188,7 @@ impl ChangeFixture {
186 Edition::Edition2021, 188 Edition::Edition2021,
187 Some(CrateDisplayName::from_canonical_name("core".to_string())), 189 Some(CrateDisplayName::from_canonical_name("core".to_string())),
188 CfgOptions::default(), 190 CfgOptions::default(),
191 CfgOptions::default(),
189 Env::default(), 192 Env::default(),
190 Vec::new(), 193 Vec::new(),
191 ); 194 );
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index 23cb0c839..0c51a59a0 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -189,6 +189,7 @@ pub struct CrateData {
189 /// `Dependency` matters), this name should only be used for UI. 189 /// `Dependency` matters), this name should only be used for UI.
190 pub display_name: Option<CrateDisplayName>, 190 pub display_name: Option<CrateDisplayName>,
191 pub cfg_options: CfgOptions, 191 pub cfg_options: CfgOptions,
192 pub potential_cfg_options: CfgOptions,
192 pub env: Env, 193 pub env: Env,
193 pub dependencies: Vec<Dependency>, 194 pub dependencies: Vec<Dependency>,
194 pub proc_macro: Vec<ProcMacro>, 195 pub proc_macro: Vec<ProcMacro>,
@@ -219,6 +220,7 @@ impl CrateGraph {
219 edition: Edition, 220 edition: Edition,
220 display_name: Option<CrateDisplayName>, 221 display_name: Option<CrateDisplayName>,
221 cfg_options: CfgOptions, 222 cfg_options: CfgOptions,
223 potential_cfg_options: CfgOptions,
222 env: Env, 224 env: Env,
223 proc_macro: Vec<ProcMacro>, 225 proc_macro: Vec<ProcMacro>,
224 ) -> CrateId { 226 ) -> CrateId {
@@ -227,6 +229,7 @@ impl CrateGraph {
227 edition, 229 edition,
228 display_name, 230 display_name,
229 cfg_options, 231 cfg_options,
232 potential_cfg_options,
230 env, 233 env,
231 proc_macro, 234 proc_macro,
232 dependencies: Vec::new(), 235 dependencies: Vec::new(),
@@ -504,6 +507,7 @@ mod tests {
504 Edition2018, 507 Edition2018,
505 None, 508 None,
506 CfgOptions::default(), 509 CfgOptions::default(),
510 CfgOptions::default(),
507 Env::default(), 511 Env::default(),
508 Default::default(), 512 Default::default(),
509 ); 513 );
@@ -512,6 +516,7 @@ mod tests {
512 Edition2018, 516 Edition2018,
513 None, 517 None,
514 CfgOptions::default(), 518 CfgOptions::default(),
519 CfgOptions::default(),
515 Env::default(), 520 Env::default(),
516 Default::default(), 521 Default::default(),
517 ); 522 );
@@ -520,6 +525,7 @@ mod tests {
520 Edition2018, 525 Edition2018,
521 None, 526 None,
522 CfgOptions::default(), 527 CfgOptions::default(),
528 CfgOptions::default(),
523 Env::default(), 529 Env::default(),
524 Default::default(), 530 Default::default(),
525 ); 531 );
@@ -536,6 +542,7 @@ mod tests {
536 Edition2018, 542 Edition2018,
537 None, 543 None,
538 CfgOptions::default(), 544 CfgOptions::default(),
545 CfgOptions::default(),
539 Env::default(), 546 Env::default(),
540 Default::default(), 547 Default::default(),
541 ); 548 );
@@ -544,6 +551,7 @@ mod tests {
544 Edition2018, 551 Edition2018,
545 None, 552 None,
546 CfgOptions::default(), 553 CfgOptions::default(),
554 CfgOptions::default(),
547 Env::default(), 555 Env::default(),
548 Default::default(), 556 Default::default(),
549 ); 557 );
@@ -559,6 +567,7 @@ mod tests {
559 Edition2018, 567 Edition2018,
560 None, 568 None,
561 CfgOptions::default(), 569 CfgOptions::default(),
570 CfgOptions::default(),
562 Env::default(), 571 Env::default(),
563 Default::default(), 572 Default::default(),
564 ); 573 );
@@ -567,6 +576,7 @@ mod tests {
567 Edition2018, 576 Edition2018,
568 None, 577 None,
569 CfgOptions::default(), 578 CfgOptions::default(),
579 CfgOptions::default(),
570 Env::default(), 580 Env::default(),
571 Default::default(), 581 Default::default(),
572 ); 582 );
@@ -575,6 +585,7 @@ mod tests {
575 Edition2018, 585 Edition2018,
576 None, 586 None,
577 CfgOptions::default(), 587 CfgOptions::default(),
588 CfgOptions::default(),
578 Env::default(), 589 Env::default(),
579 Default::default(), 590 Default::default(),
580 ); 591 );
@@ -590,6 +601,7 @@ mod tests {
590 Edition2018, 601 Edition2018,
591 None, 602 None,
592 CfgOptions::default(), 603 CfgOptions::default(),
604 CfgOptions::default(),
593 Env::default(), 605 Env::default(),
594 Default::default(), 606 Default::default(),
595 ); 607 );
@@ -598,6 +610,7 @@ mod tests {
598 Edition2018, 610 Edition2018,
599 None, 611 None,
600 CfgOptions::default(), 612 CfgOptions::default(),
613 CfgOptions::default(),
601 Env::default(), 614 Env::default(),
602 Default::default(), 615 Default::default(),
603 ); 616 );
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs
index 916d39a0b..9a4baa636 100644
--- a/crates/cfg/src/lib.rs
+++ b/crates/cfg/src/lib.rs
@@ -50,6 +50,26 @@ impl CfgOptions {
50 self.enabled.remove(&atom); 50 self.enabled.remove(&atom);
51 } 51 }
52 } 52 }
53
54 pub fn get_cfg_keys(&self) -> Vec<&SmolStr> {
55 self.enabled
56 .iter()
57 .map(|x| match x {
58 CfgAtom::Flag(key) => key,
59 CfgAtom::KeyValue { key, .. } => key,
60 })
61 .collect()
62 }
63
64 pub fn get_cfg_values(&self, cfg_key: &str) -> Vec<&SmolStr> {
65 self.enabled
66 .iter()
67 .filter_map(|x| match x {
68 CfgAtom::KeyValue { key, value } if cfg_key == key => Some(value),
69 _ => None,
70 })
71 .collect()
72 }
53} 73}
54 74
55#[derive(Clone, Debug, PartialEq, Eq)] 75#[derive(Clone, Debug, PartialEq, Eq)]
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 88490fea9..30cc34403 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -233,6 +233,10 @@ impl Crate {
233 pub fn cfg(&self, db: &dyn HirDatabase) -> CfgOptions { 233 pub fn cfg(&self, db: &dyn HirDatabase) -> CfgOptions {
234 db.crate_graph()[self.id].cfg_options.clone() 234 db.crate_graph()[self.id].cfg_options.clone()
235 } 235 }
236
237 pub fn potential_cfg(&self, db: &dyn HirDatabase) -> CfgOptions {
238 db.crate_graph()[self.id].potential_cfg_options.clone()
239 }
236} 240}
237 241
238#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 242#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 0c1da8774..c6d6bb74a 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -1,5 +1,5 @@
1use either::Either; 1use either::Either;
2use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay}; 2use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics};
3use ide_db::{ 3use ide_db::{
4 base_db::SourceDatabase, 4 base_db::SourceDatabase,
5 defs::{Definition, NameClass, NameRefClass}, 5 defs::{Definition, NameClass, NameRefClass},
@@ -30,39 +30,20 @@ use crate::{
30 30
31#[derive(Clone, Debug, PartialEq, Eq)] 31#[derive(Clone, Debug, PartialEq, Eq)]
32pub struct HoverConfig { 32pub struct HoverConfig {
33 pub implementations: bool,
34 pub references: bool,
35 pub run: bool,
36 pub debug: bool,
37 pub goto_type_def: bool,
38 pub links_in_hover: bool, 33 pub links_in_hover: bool,
39 pub markdown: bool, 34 pub documentation: Option<HoverDocFormat>,
40 pub documentation: bool,
41} 35}
42 36
43impl HoverConfig { 37impl HoverConfig {
44 pub const NO_ACTIONS: Self = Self { 38 fn markdown(&self) -> bool {
45 implementations: false, 39 matches!(self.documentation, Some(HoverDocFormat::Markdown))
46 references: false,
47 run: false,
48 debug: false,
49 goto_type_def: false,
50 links_in_hover: true,
51 markdown: true,
52 documentation: true,
53 };
54
55 pub fn any_actions(&self) -> bool {
56 self.implementations || self.references || self.runnable() || self.goto_type_def
57 }
58
59 pub fn no_actions(&self) -> bool {
60 !self.any_actions()
61 } 40 }
41}
62 42
63 pub fn runnable(&self) -> bool { 43#[derive(Clone, Debug, PartialEq, Eq)]
64 self.run || self.debug 44pub enum HoverDocFormat {
65 } 45 Markdown,
46 PlainText,
66} 47}
67 48
68#[derive(Debug, Clone)] 49#[derive(Debug, Clone)]
@@ -95,9 +76,7 @@ pub struct HoverResult {
95pub(crate) fn hover( 76pub(crate) fn hover(
96 db: &RootDatabase, 77 db: &RootDatabase,
97 position: FilePosition, 78 position: FilePosition,
98 links_in_hover: bool, 79 config: &HoverConfig,
99 documentation: bool,
100 markdown: bool,
101) -> Option<RangeInfo<HoverResult>> { 80) -> Option<RangeInfo<HoverResult>> {
102 let sema = hir::Semantics::new(db); 81 let sema = hir::Semantics::new(db);
103 let file = sema.parse(position.file_id).syntax().clone(); 82 let file = sema.parse(position.file_id).syntax().clone();
@@ -156,10 +135,8 @@ pub(crate) fn hover(
156 } 135 }
157 _ => None, 136 _ => None,
158 }; 137 };
159 if let Some(markup) = 138 if let Some(markup) = hover_for_definition(db, definition, famous_defs.as_ref(), config) {
160 hover_for_definition(db, definition, famous_defs.as_ref(), documentation) 139 res.markup = process_markup(sema.db, definition, &markup, config);
161 {
162 res.markup = process_markup(sema.db, definition, &markup, links_in_hover, markdown);
163 if let Some(action) = show_implementations_action(db, definition) { 140 if let Some(action) = show_implementations_action(db, definition) {
164 res.actions.push(action); 141 res.actions.push(action);
165 } 142 }
@@ -181,8 +158,7 @@ pub(crate) fn hover(
181 } 158 }
182 } 159 }
183 160
184 if let res @ Some(_) = hover_for_keyword(&sema, links_in_hover, markdown, documentation, &token) 161 if let res @ Some(_) = hover_for_keyword(&sema, config, &token) {
185 {
186 return res; 162 return res;
187 } 163 }
188 164
@@ -201,7 +177,7 @@ pub(crate) fn hover(
201 } 177 }
202 }; 178 };
203 179
204 res.markup = if markdown { 180 res.markup = if config.markdown() {
205 Markup::fenced_block(&ty.display(db)) 181 Markup::fenced_block(&ty.display(db))
206 } else { 182 } else {
207 ty.display(db).to_string().into() 183 ty.display(db).to_string().into()
@@ -375,13 +351,12 @@ fn process_markup(
375 db: &RootDatabase, 351 db: &RootDatabase,
376 def: Definition, 352 def: Definition,
377 markup: &Markup, 353 markup: &Markup,
378 links_in_hover: bool, 354 config: &HoverConfig,
379 markdown: bool,
380) -> Markup { 355) -> Markup {
381 let markup = markup.as_str(); 356 let markup = markup.as_str();
382 let markup = if !markdown { 357 let markup = if !config.markdown() {
383 remove_markdown(markup) 358 remove_markdown(markup)
384 } else if links_in_hover { 359 } else if config.links_in_hover {
385 rewrite_links(db, markup, &def) 360 rewrite_links(db, markup, &def)
386 } else { 361 } else {
387 remove_links(markup) 362 remove_links(markup)
@@ -428,7 +403,7 @@ fn hover_for_definition(
428 db: &RootDatabase, 403 db: &RootDatabase,
429 def: Definition, 404 def: Definition,
430 famous_defs: Option<&FamousDefs>, 405 famous_defs: Option<&FamousDefs>,
431 documentation: bool, 406 config: &HoverConfig,
432) -> Option<Markup> { 407) -> Option<Markup> {
433 let mod_path = definition_mod_path(db, &def); 408 let mod_path = definition_mod_path(db, &def);
434 let (label, docs) = match def { 409 let (label, docs) = match def {
@@ -466,7 +441,11 @@ fn hover_for_definition(
466 Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))), 441 Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))),
467 }; 442 };
468 443
469 return hover_markup(docs.filter(|_| documentation).map(Into::into), label, mod_path); 444 return hover_markup(
445 docs.filter(|_| config.documentation.is_some()).map(Into::into),
446 label,
447 mod_path,
448 );
470 449
471 fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<hir::Documentation>) 450 fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<hir::Documentation>)
472 where 451 where
@@ -502,13 +481,11 @@ fn hover_for_local(it: hir::Local, db: &RootDatabase) -> Option<Markup> {
502} 481}
503 482
504fn hover_for_keyword( 483fn hover_for_keyword(
505 sema: &hir::Semantics<RootDatabase>, 484 sema: &Semantics<RootDatabase>,
506 links_in_hover: bool, 485 config: &HoverConfig,
507 markdown: bool,
508 documentation: bool,
509 token: &SyntaxToken, 486 token: &SyntaxToken,
510) -> Option<RangeInfo<HoverResult>> { 487) -> Option<RangeInfo<HoverResult>> {
511 if !token.kind().is_keyword() || !documentation { 488 if !token.kind().is_keyword() || !config.documentation.is_some() {
512 return None; 489 return None;
513 } 490 }
514 let famous_defs = FamousDefs(sema, sema.scope(&token.parent()?).krate()); 491 let famous_defs = FamousDefs(sema, sema.scope(&token.parent()?).krate());
@@ -520,8 +497,7 @@ fn hover_for_keyword(
520 sema.db, 497 sema.db,
521 Definition::ModuleDef(doc_owner.into()), 498 Definition::ModuleDef(doc_owner.into()),
522 &hover_markup(Some(docs.into()), token.text().into(), None)?, 499 &hover_markup(Some(docs.into()), token.text().into(), None)?,
523 links_in_hover, 500 config,
524 markdown,
525 ); 501 );
526 Some(RangeInfo::new(token.text_range(), HoverResult { markup, actions: Default::default() })) 502 Some(RangeInfo::new(token.text_range(), HoverResult { markup, actions: Default::default() }))
527} 503}
@@ -561,16 +537,34 @@ mod tests {
561 use expect_test::{expect, Expect}; 537 use expect_test::{expect, Expect};
562 use ide_db::base_db::FileLoader; 538 use ide_db::base_db::FileLoader;
563 539
564 use crate::fixture; 540 use crate::{fixture, hover::HoverDocFormat, HoverConfig};
565 541
566 fn check_hover_no_result(ra_fixture: &str) { 542 fn check_hover_no_result(ra_fixture: &str) {
567 let (analysis, position) = fixture::position(ra_fixture); 543 let (analysis, position) = fixture::position(ra_fixture);
568 assert!(analysis.hover(position, true, true, true).unwrap().is_none()); 544 assert!(analysis
545 .hover(
546 position,
547 &HoverConfig {
548 links_in_hover: true,
549 documentation: Some(HoverDocFormat::Markdown)
550 }
551 )
552 .unwrap()
553 .is_none());
569 } 554 }
570 555
571 fn check(ra_fixture: &str, expect: Expect) { 556 fn check(ra_fixture: &str, expect: Expect) {
572 let (analysis, position) = fixture::position(ra_fixture); 557 let (analysis, position) = fixture::position(ra_fixture);
573 let hover = analysis.hover(position, true, true, true).unwrap().unwrap(); 558 let hover = analysis
559 .hover(
560 position,
561 &HoverConfig {
562 links_in_hover: true,
563 documentation: Some(HoverDocFormat::Markdown),
564 },
565 )
566 .unwrap()
567 .unwrap();
574 568
575 let content = analysis.db.file_text(position.file_id); 569 let content = analysis.db.file_text(position.file_id);
576 let hovered_element = &content[hover.range]; 570 let hovered_element = &content[hover.range];
@@ -581,7 +575,16 @@ mod tests {
581 575
582 fn check_hover_no_links(ra_fixture: &str, expect: Expect) { 576 fn check_hover_no_links(ra_fixture: &str, expect: Expect) {
583 let (analysis, position) = fixture::position(ra_fixture); 577 let (analysis, position) = fixture::position(ra_fixture);
584 let hover = analysis.hover(position, false, true, true).unwrap().unwrap(); 578 let hover = analysis
579 .hover(
580 position,
581 &HoverConfig {
582 links_in_hover: false,
583 documentation: Some(HoverDocFormat::Markdown),
584 },
585 )
586 .unwrap()
587 .unwrap();
585 588
586 let content = analysis.db.file_text(position.file_id); 589 let content = analysis.db.file_text(position.file_id);
587 let hovered_element = &content[hover.range]; 590 let hovered_element = &content[hover.range];
@@ -592,7 +595,16 @@ mod tests {
592 595
593 fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { 596 fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) {
594 let (analysis, position) = fixture::position(ra_fixture); 597 let (analysis, position) = fixture::position(ra_fixture);
595 let hover = analysis.hover(position, true, true, false).unwrap().unwrap(); 598 let hover = analysis
599 .hover(
600 position,
601 &HoverConfig {
602 links_in_hover: true,
603 documentation: Some(HoverDocFormat::PlainText),
604 },
605 )
606 .unwrap()
607 .unwrap();
596 608
597 let content = analysis.db.file_text(position.file_id); 609 let content = analysis.db.file_text(position.file_id);
598 let hovered_element = &content[hover.range]; 610 let hovered_element = &content[hover.range];
@@ -603,7 +615,16 @@ mod tests {
603 615
604 fn check_actions(ra_fixture: &str, expect: Expect) { 616 fn check_actions(ra_fixture: &str, expect: Expect) {
605 let (analysis, position) = fixture::position(ra_fixture); 617 let (analysis, position) = fixture::position(ra_fixture);
606 let hover = analysis.hover(position, true, true, true).unwrap().unwrap(); 618 let hover = analysis
619 .hover(
620 position,
621 &HoverConfig {
622 links_in_hover: true,
623 documentation: Some(HoverDocFormat::Markdown),
624 },
625 )
626 .unwrap()
627 .unwrap();
607 expect.assert_debug_eq(&hover.info.actions) 628 expect.assert_debug_eq(&hover.info.actions)
608 } 629 }
609 630
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 3798f32cc..b978e36af 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -75,7 +75,7 @@ pub use crate::{
75 expand_macro::ExpandedMacro, 75 expand_macro::ExpandedMacro,
76 file_structure::{StructureNode, StructureNodeKind}, 76 file_structure::{StructureNode, StructureNodeKind},
77 folding_ranges::{Fold, FoldKind}, 77 folding_ranges::{Fold, FoldKind},
78 hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult}, 78 hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
79 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, 79 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
80 markup::Markup, 80 markup::Markup,
81 move_item::Direction, 81 move_item::Direction,
@@ -217,6 +217,7 @@ impl Analysis {
217 file_id, 217 file_id,
218 Edition::Edition2018, 218 Edition::Edition2018,
219 None, 219 None,
220 cfg_options.clone(),
220 cfg_options, 221 cfg_options,
221 Env::default(), 222 Env::default(),
222 Default::default(), 223 Default::default(),
@@ -407,11 +408,9 @@ impl Analysis {
407 pub fn hover( 408 pub fn hover(
408 &self, 409 &self,
409 position: FilePosition, 410 position: FilePosition,
410 links_in_hover: bool, 411 config: &HoverConfig,
411 documentation: bool,
412 markdown: bool,
413 ) -> Cancellable<Option<RangeInfo<HoverResult>>> { 412 ) -> Cancellable<Option<RangeInfo<HoverResult>>> {
414 self.with_db(|db| hover::hover(db, position, links_in_hover, documentation, markdown)) 413 self.with_db(|db| hover::hover(db, position, config))
415 } 414 }
416 415
417 /// Return URL(s) for the documentation of the symbol under the cursor. 416 /// Return URL(s) for the documentation of the symbol under the cursor.
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index 78fc30e16..cc4f4b2af 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -15,6 +15,7 @@ use crate::{
15 Completions, 15 Completions,
16}; 16};
17 17
18mod cfg;
18mod derive; 19mod derive;
19mod lint; 20mod lint;
20mod repr; 21mod repr;
@@ -30,6 +31,9 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
30 lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS); 31 lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS);
31 lint::complete_lint(acc, ctx, token_tree, CLIPPY_LINTS); 32 lint::complete_lint(acc, ctx, token_tree, CLIPPY_LINTS);
32 } 33 }
34 "cfg" => {
35 cfg::complete_cfg(acc, ctx);
36 }
33 _ => (), 37 _ => (),
34 }, 38 },
35 (None, Some(_)) => (), 39 (None, Some(_)) => (),
@@ -852,4 +856,15 @@ mod tests {
852 "#]], 856 "#]],
853 ); 857 );
854 } 858 }
859
860 #[test]
861 fn test_cfg() {
862 check(
863 r#"#[cfg(target_endian = $0"#,
864 expect![[r#"
865 at little
866 at big
867"#]],
868 );
869 }
855} 870}
diff --git a/crates/ide_completion/src/completions/attribute/cfg.rs b/crates/ide_completion/src/completions/attribute/cfg.rs
new file mode 100644
index 000000000..847e6529a
--- /dev/null
+++ b/crates/ide_completion/src/completions/attribute/cfg.rs
@@ -0,0 +1,112 @@
1//! Completion for cfg
2
3use std::iter;
4
5use syntax::SyntaxKind;
6
7use crate::{
8 completions::Completions, context::CompletionContext, item::CompletionKind, CompletionItem,
9 CompletionItemKind,
10};
11
12pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) {
13 let add_completion = |item: &&str| {
14 let mut completion =
15 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), *item);
16 completion.insert_text(format!(r#""{}""#, item));
17 completion.kind(CompletionItemKind::Attribute);
18 acc.add(completion.build());
19 };
20
21 let previous = iter::successors(ctx.original_token.prev_token(), |t| {
22 (matches!(t.kind(), SyntaxKind::EQ) || t.kind().is_trivia())
23 .then(|| t.prev_token())
24 .flatten()
25 })
26 .find(|t| matches!(t.kind(), SyntaxKind::IDENT));
27
28 match previous.as_ref().map(|p| p.text()) {
29 Some("target_arch") => KNOWN_ARCH.iter().for_each(add_completion),
30 Some("target_env") => KNOWN_ENV.iter().for_each(add_completion),
31 Some("target_os") => KNOWN_OS.iter().for_each(add_completion),
32 Some("target_vendor") => KNOWN_VENDOR.iter().for_each(add_completion),
33 Some("target_endian") => ["little", "big"].iter().for_each(add_completion),
34 Some(name) => {
35 ctx.krate.map(|krate| {
36 krate.potential_cfg(ctx.db).get_cfg_values(&name).iter().for_each(|s| {
37 let mut item = CompletionItem::new(
38 CompletionKind::Attribute,
39 ctx.source_range(),
40 s.as_str(),
41 );
42 item.insert_text(format!(r#""{}""#, s));
43
44 acc.add(item.build());
45 })
46 });
47 }
48 None => {
49 ctx.krate.map(|krate| {
50 krate.potential_cfg(ctx.db).get_cfg_keys().iter().for_each(|s| {
51 let item = CompletionItem::new(
52 CompletionKind::Attribute,
53 ctx.source_range(),
54 s.as_str(),
55 );
56 acc.add(item.build());
57 })
58 });
59 }
60 };
61}
62
63const KNOWN_ARCH: [&'static str; 19] = [
64 "aarch64",
65 "arm",
66 "avr",
67 "hexagon",
68 "mips",
69 "mips64",
70 "msp430",
71 "nvptx64",
72 "powerpc",
73 "powerpc64",
74 "riscv32",
75 "riscv64",
76 "s390x",
77 "sparc",
78 "sparc64",
79 "wasm32",
80 "wasm64",
81 "x86",
82 "x86_64",
83];
84
85const KNOWN_ENV: [&'static str; 7] =
86 ["eabihf", "gnu", "gnueabihf", "msvc", "relibc", "sgx", "uclibc"];
87
88const KNOWN_OS: [&'static str; 20] = [
89 "cuda",
90 "dragonfly",
91 "emscripten",
92 "freebsd",
93 "fuchsia",
94 "haiku",
95 "hermit",
96 "illumos",
97 "l4re",
98 "linux",
99 "netbsd",
100 "none",
101 "openbsd",
102 "psp",
103 "redox",
104 "solaris",
105 "uefi",
106 "unknown",
107 "vxworks",
108 "windows",
109];
110
111const KNOWN_VENDOR: [&'static str; 8] =
112 ["apple", "fortanix", "nvidia", "pc", "sony", "unknown", "wrs", "uwp"];
diff --git a/crates/proc_macro_test/build.rs b/crates/proc_macro_test/build.rs
index 4653a93dd..1e7aa026f 100644
--- a/crates/proc_macro_test/build.rs
+++ b/crates/proc_macro_test/build.rs
@@ -17,9 +17,16 @@ fn main() {
17 17
18 let name = "proc_macro_test_impl"; 18 let name = "proc_macro_test_impl";
19 let version = "0.0.0"; 19 let version = "0.0.0";
20 let target_dir = out_dir.join("target");
20 let output = Command::new(toolchain::cargo()) 21 let output = Command::new(toolchain::cargo())
21 .current_dir("imp") 22 .current_dir("imp")
22 .args(&["build", "-p", "proc_macro_test_impl", "--message-format", "json"]) 23 .args(&["build", "-p", "proc_macro_test_impl", "--message-format", "json"])
24 // Explicit override the target directory to avoid using the same one which the parent
25 // cargo is using, or we'll deadlock.
26 // This can happen when `CARGO_TARGET_DIR` is set or global config forces all cargo
27 // instance to use the same target directory.
28 .arg("--target-dir")
29 .arg(&target_dir)
23 .output() 30 .output()
24 .unwrap(); 31 .unwrap();
25 assert!(output.status.success()); 32 assert!(output.status.success());
@@ -39,10 +46,9 @@ fn main() {
39 } 46 }
40 } 47 }
41 48
42 let src_path = artifact_path.expect("no dylib for proc_macro_test_impl found"); 49 // This file is under `target_dir` and is already under `OUT_DIR`.
43 let dest_path = out_dir.join(src_path.file_name().unwrap()); 50 let artifact_path = artifact_path.expect("no dylib for proc_macro_test_impl found");
44 fs::copy(src_path, &dest_path).unwrap();
45 51
46 let info_path = out_dir.join("proc_macro_test_location.txt"); 52 let info_path = out_dir.join("proc_macro_test_location.txt");
47 fs::write(info_path, dest_path.to_str().unwrap()).unwrap(); 53 fs::write(info_path, artifact_path.to_str().unwrap()).unwrap();
48} 54}
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index d8217f714..e67ba2bd9 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -384,6 +384,7 @@ fn project_json_to_crate_graph(
384 file_id, 384 file_id,
385 krate.edition, 385 krate.edition,
386 krate.display_name.clone(), 386 krate.display_name.clone(),
387 cfg_options.clone(),
387 cfg_options, 388 cfg_options,
388 env, 389 env,
389 proc_macro.unwrap_or_default(), 390 proc_macro.unwrap_or_default(),
@@ -580,6 +581,7 @@ fn detached_files_to_crate_graph(
580 Edition::Edition2018, 581 Edition::Edition2018,
581 display_name, 582 display_name,
582 cfg_options.clone(), 583 cfg_options.clone(),
584 cfg_options.clone(),
583 Env::default(), 585 Env::default(),
584 Vec::new(), 586 Vec::new(),
585 ); 587 );
@@ -719,11 +721,19 @@ fn add_target_crate_root(
719 .unwrap_or_default(); 721 .unwrap_or_default();
720 722
721 let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string()); 723 let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string());
724 let mut potential_cfg_options = cfg_options.clone();
725 potential_cfg_options.extend(
726 pkg.features
727 .iter()
728 .map(|feat| CfgFlag::KeyValue { key: "feature".into(), value: feat.0.into() }),
729 );
730
722 let crate_id = crate_graph.add_crate_root( 731 let crate_id = crate_graph.add_crate_root(
723 file_id, 732 file_id,
724 edition, 733 edition,
725 Some(display_name), 734 Some(display_name),
726 cfg_options, 735 cfg_options,
736 potential_cfg_options,
727 env, 737 env,
728 proc_macro, 738 proc_macro,
729 ); 739 );
@@ -753,6 +763,7 @@ fn sysroot_to_crate_graph(
753 Edition::Edition2018, 763 Edition::Edition2018,
754 Some(display_name), 764 Some(display_name),
755 cfg_options.clone(), 765 cfg_options.clone(),
766 cfg_options.clone(),
756 env, 767 env,
757 proc_macro, 768 proc_macro,
758 ); 769 );
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index afc96505f..97246cae6 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -60,7 +60,14 @@ fn try_main() -> Result<()> {
60 } 60 }
61 } 61 }
62 62
63 setup_logging(flags.log_file.as_deref(), flags.no_log_buffering)?; 63 let mut log_file = flags.log_file.as_deref();
64
65 let env_log_file = env::var("RA_LOG_FILE").ok();
66 if let Some(env_log_file) = env_log_file.as_deref() {
67 log_file = Some(Path::new(env_log_file));
68 }
69
70 setup_logging(log_file, flags.no_log_buffering)?;
64 let verbosity = flags.verbosity(); 71 let verbosity = flags.verbosity();
65 72
66 match flags.subcommand { 73 match flags.subcommand {
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 3aeca8839..b9aa6f0aa 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -10,7 +10,10 @@
10use std::{ffi::OsString, iter, path::PathBuf}; 10use std::{ffi::OsString, iter, path::PathBuf};
11 11
12use flycheck::FlycheckConfig; 12use flycheck::FlycheckConfig;
13use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig}; 13use ide::{
14 AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, HoverDocFormat,
15 InlayHintsConfig,
16};
14use ide_db::helpers::{ 17use ide_db::helpers::{
15 insert_use::{ImportGranularity, InsertUseConfig, PrefixKind}, 18 insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
16 SnippetCap, 19 SnippetCap,
@@ -32,6 +35,9 @@ use crate::{
32// 35//
33// However, editor specific config, which the server doesn't know about, should 36// However, editor specific config, which the server doesn't know about, should
34// be specified directly in `package.json`. 37// be specified directly in `package.json`.
38//
39// To deprecate an option by replacing it with another name use `new_name | `old_name` so that we keep
40// parsing the old name.
35config_data! { 41config_data! {
36 struct ConfigData { 42 struct ConfigData {
37 /// How imports should be grouped into use statements. 43 /// How imports should be grouped into use statements.
@@ -309,6 +315,37 @@ impl LensConfig {
309 } 315 }
310} 316}
311 317
318#[derive(Clone, Debug, PartialEq, Eq)]
319pub struct HoverActionsConfig {
320 pub implementations: bool,
321 pub references: bool,
322 pub run: bool,
323 pub debug: bool,
324 pub goto_type_def: bool,
325}
326
327impl HoverActionsConfig {
328 pub const NO_ACTIONS: Self = Self {
329 implementations: false,
330 references: false,
331 run: false,
332 debug: false,
333 goto_type_def: false,
334 };
335
336 pub fn any(&self) -> bool {
337 self.implementations || self.references || self.runnable() || self.goto_type_def
338 }
339
340 pub fn none(&self) -> bool {
341 !self.any()
342 }
343
344 pub fn runnable(&self) -> bool {
345 self.run || self.debug
346 }
347}
348
312#[derive(Debug, Clone)] 349#[derive(Debug, Clone)]
313pub struct FilesConfig { 350pub struct FilesConfig {
314 pub watcher: FilesWatcher, 351 pub watcher: FilesWatcher,
@@ -527,7 +564,7 @@ impl Config {
527 pub fn code_action_group(&self) -> bool { 564 pub fn code_action_group(&self) -> bool {
528 self.experimental("codeActionGroup") 565 self.experimental("codeActionGroup")
529 } 566 }
530 pub fn hover_actions(&self) -> bool { 567 pub fn experimental_hover_actions(&self) -> bool {
531 self.experimental("hoverActions") 568 self.experimental("hoverActions")
532 } 569 }
533 pub fn server_status_notification(&self) -> bool { 570 pub fn server_status_notification(&self) -> bool {
@@ -727,31 +764,41 @@ impl Config {
727 refs: self.data.lens_enable && self.data.lens_references, 764 refs: self.data.lens_enable && self.data.lens_references,
728 } 765 }
729 } 766 }
730 pub fn highlighting_strings(&self) -> bool { 767 pub fn hover_actions(&self) -> HoverActionsConfig {
731 self.data.highlighting_strings 768 HoverActionsConfig {
732 }
733 pub fn hover(&self) -> HoverConfig {
734 HoverConfig {
735 implementations: self.data.hoverActions_enable 769 implementations: self.data.hoverActions_enable
736 && self.data.hoverActions_implementations, 770 && self.data.hoverActions_implementations,
737 references: self.data.hoverActions_enable && self.data.hoverActions_references, 771 references: self.data.hoverActions_enable && self.data.hoverActions_references,
738 run: self.data.hoverActions_enable && self.data.hoverActions_run, 772 run: self.data.hoverActions_enable && self.data.hoverActions_run,
739 debug: self.data.hoverActions_enable && self.data.hoverActions_debug, 773 debug: self.data.hoverActions_enable && self.data.hoverActions_debug,
740 goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef, 774 goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef,
775 }
776 }
777 pub fn highlighting_strings(&self) -> bool {
778 self.data.highlighting_strings
779 }
780 pub fn hover(&self) -> HoverConfig {
781 HoverConfig {
741 links_in_hover: self.data.hover_linksInHover, 782 links_in_hover: self.data.hover_linksInHover,
742 markdown: try_or!( 783 documentation: self.data.hover_documentation.then(|| {
743 self.caps 784 let is_markdown = try_or!(
744 .text_document 785 self.caps
745 .as_ref()? 786 .text_document
746 .hover 787 .as_ref()?
747 .as_ref()? 788 .hover
748 .content_format 789 .as_ref()?
749 .as_ref()? 790 .content_format
750 .as_slice(), 791 .as_ref()?
751 &[] 792 .as_slice(),
752 ) 793 &[]
753 .contains(&MarkupKind::Markdown), 794 )
754 documentation: self.data.hover_documentation, 795 .contains(&MarkupKind::Markdown);
796 if is_markdown {
797 HoverDocFormat::Markdown
798 } else {
799 HoverDocFormat::PlainText
800 }
801 }),
755 } 802 }
756 } 803 }
757 804
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index eff1e6c93..dcead5f5c 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -861,13 +861,7 @@ pub(crate) fn handle_hover(
861) -> Result<Option<lsp_ext::Hover>> { 861) -> Result<Option<lsp_ext::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 info = match snap.analysis.hover(position, &snap.config.hover())? {
865 let info = match snap.analysis.hover(
866 position,
867 hover_config.links_in_hover,
868 hover_config.documentation,
869 hover_config.markdown,
870 )? {
871 None => return Ok(None), 865 None => return Ok(None),
872 Some(info) => info, 866 Some(info) => info,
873 }; 867 };
@@ -1487,7 +1481,7 @@ fn show_impl_command_link(
1487 snap: &GlobalStateSnapshot, 1481 snap: &GlobalStateSnapshot,
1488 position: &FilePosition, 1482 position: &FilePosition,
1489) -> Option<lsp_ext::CommandLinkGroup> { 1483) -> Option<lsp_ext::CommandLinkGroup> {
1490 if snap.config.hover().implementations { 1484 if snap.config.hover_actions().implementations {
1491 if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) { 1485 if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) {
1492 let uri = to_proto::url(snap, position.file_id); 1486 let uri = to_proto::url(snap, position.file_id);
1493 let line_index = snap.file_line_index(position.file_id).ok()?; 1487 let line_index = snap.file_line_index(position.file_id).ok()?;
@@ -1513,7 +1507,7 @@ fn show_ref_command_link(
1513 snap: &GlobalStateSnapshot, 1507 snap: &GlobalStateSnapshot,
1514 position: &FilePosition, 1508 position: &FilePosition,
1515) -> Option<lsp_ext::CommandLinkGroup> { 1509) -> Option<lsp_ext::CommandLinkGroup> {
1516 if snap.config.hover().references { 1510 if snap.config.hover_actions().references {
1517 if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) { 1511 if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) {
1518 let uri = to_proto::url(snap, position.file_id); 1512 let uri = to_proto::url(snap, position.file_id);
1519 let line_index = snap.file_line_index(position.file_id).ok()?; 1513 let line_index = snap.file_line_index(position.file_id).ok()?;
@@ -1544,8 +1538,8 @@ fn runnable_action_links(
1544 runnable: Runnable, 1538 runnable: Runnable,
1545) -> Option<lsp_ext::CommandLinkGroup> { 1539) -> Option<lsp_ext::CommandLinkGroup> {
1546 let cargo_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id).ok()?; 1540 let cargo_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id).ok()?;
1547 let hover_config = snap.config.hover(); 1541 let hover_actions_config = snap.config.hover_actions();
1548 if !hover_config.runnable() || should_skip_target(&runnable, cargo_spec.as_ref()) { 1542 if !hover_actions_config.runnable() || should_skip_target(&runnable, cargo_spec.as_ref()) {
1549 return None; 1543 return None;
1550 } 1544 }
1551 1545
@@ -1553,12 +1547,12 @@ fn runnable_action_links(
1553 to_proto::runnable(snap, runnable).ok().map(|r| { 1547 to_proto::runnable(snap, runnable).ok().map(|r| {
1554 let mut group = lsp_ext::CommandLinkGroup::default(); 1548 let mut group = lsp_ext::CommandLinkGroup::default();
1555 1549
1556 if hover_config.run { 1550 if hover_actions_config.run {
1557 let run_command = to_proto::command::run_single(&r, action.run_title); 1551 let run_command = to_proto::command::run_single(&r, action.run_title);
1558 group.commands.push(to_command_link(run_command, r.label.clone())); 1552 group.commands.push(to_command_link(run_command, r.label.clone()));
1559 } 1553 }
1560 1554
1561 if hover_config.debug { 1555 if hover_actions_config.debug {
1562 let dbg_command = to_proto::command::debug_single(&r); 1556 let dbg_command = to_proto::command::debug_single(&r);
1563 group.commands.push(to_command_link(dbg_command, r.label)); 1557 group.commands.push(to_command_link(dbg_command, r.label));
1564 } 1558 }
@@ -1571,7 +1565,7 @@ fn goto_type_action_links(
1571 snap: &GlobalStateSnapshot, 1565 snap: &GlobalStateSnapshot,
1572 nav_targets: &[HoverGotoTypeData], 1566 nav_targets: &[HoverGotoTypeData],
1573) -> Option<lsp_ext::CommandLinkGroup> { 1567) -> Option<lsp_ext::CommandLinkGroup> {
1574 if !snap.config.hover().goto_type_def || nav_targets.is_empty() { 1568 if !snap.config.hover_actions().goto_type_def || nav_targets.is_empty() {
1575 return None; 1569 return None;
1576 } 1570 }
1577 1571
@@ -1591,7 +1585,7 @@ fn prepare_hover_actions(
1591 snap: &GlobalStateSnapshot, 1585 snap: &GlobalStateSnapshot,
1592 actions: &[HoverAction], 1586 actions: &[HoverAction],
1593) -> Vec<lsp_ext::CommandLinkGroup> { 1587) -> Vec<lsp_ext::CommandLinkGroup> {
1594 if snap.config.hover().no_actions() || !snap.config.hover_actions() { 1588 if snap.config.hover_actions().none() || !snap.config.experimental_hover_actions() {
1595 return Vec::new(); 1589 return Vec::new();
1596 } 1590 }
1597 1591
diff --git a/crates/syntax/src/ptr.rs b/crates/syntax/src/ptr.rs
index c077a04cb..282470bae 100644
--- a/crates/syntax/src/ptr.rs
+++ b/crates/syntax/src/ptr.rs
@@ -44,7 +44,7 @@ impl SyntaxNodePtr {
44 pub fn to_node(&self, root: &SyntaxNode) -> SyntaxNode { 44 pub fn to_node(&self, root: &SyntaxNode) -> SyntaxNode {
45 assert!(root.parent().is_none()); 45 assert!(root.parent().is_none());
46 successors(Some(root.clone()), |node| { 46 successors(Some(root.clone()), |node| {
47 node.children().find(|it| it.text_range().contains_range(self.range)) 47 node.child_or_token_at_range(self.range).and_then(|it| it.into_node())
48 }) 48 })
49 .find(|it| it.text_range() == self.range && it.kind() == self.kind) 49 .find(|it| it.text_range() == self.range && it.kind() == self.kind)
50 .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self)) 50 .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self))