aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r--crates/ra_ide/src/change.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_path.rs18
-rw-r--r--crates/ra_ide/src/completion/complete_postfix.rs2
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs21
-rw-r--r--crates/ra_ide/src/display.rs2
-rw-r--r--crates/ra_ide/src/expand_macro.rs13
-rw-r--r--crates/ra_ide/src/extend_selection.rs2
-rw-r--r--crates/ra_ide/src/goto_definition.rs110
-rw-r--r--crates/ra_ide/src/hover.rs80
-rw-r--r--crates/ra_ide/src/inlay_hints.rs11
-rw-r--r--crates/ra_ide/src/marks.rs9
-rw-r--r--crates/ra_ide/src/references/classify.rs9
-rw-r--r--crates/ra_ide/src/snapshots/highlighting.html4
-rw-r--r--crates/ra_ide/src/snapshots/rainbow_highlighting.html1
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs65
15 files changed, 194 insertions, 155 deletions
diff --git a/crates/ra_ide/src/change.rs b/crates/ra_ide/src/change.rs
index 4a76d1dd8..387a9cafb 100644
--- a/crates/ra_ide/src/change.rs
+++ b/crates/ra_ide/src/change.rs
@@ -270,7 +270,6 @@ impl RootDatabase {
270 270
271 self.query(hir::db::AstIdMapQuery).sweep(sweep); 271 self.query(hir::db::AstIdMapQuery).sweep(sweep);
272 272
273 self.query(hir::db::RawItemsWithSourceMapQuery).sweep(sweep);
274 self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep); 273 self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep);
275 274
276 self.query(hir::db::ExprScopesQuery).sweep(sweep); 275 self.query(hir::db::ExprScopesQuery).sweep(sweep);
@@ -309,7 +308,6 @@ impl RootDatabase {
309 hir::db::StructDataQuery 308 hir::db::StructDataQuery
310 hir::db::EnumDataQuery 309 hir::db::EnumDataQuery
311 hir::db::TraitDataQuery 310 hir::db::TraitDataQuery
312 hir::db::RawItemsWithSourceMapQuery
313 hir::db::RawItemsQuery 311 hir::db::RawItemsQuery
314 hir::db::CrateDefMapQuery 312 hir::db::CrateDefMapQuery
315 hir::db::GenericParamsQuery 313 hir::db::GenericParamsQuery
diff --git a/crates/ra_ide/src/completion/complete_path.rs b/crates/ra_ide/src/completion/complete_path.rs
index 28f94e0a7..cc1f7c830 100644
--- a/crates/ra_ide/src/completion/complete_path.rs
+++ b/crates/ra_ide/src/completion/complete_path.rs
@@ -1,7 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use either::Either; 3use hir::{Adt, PathResolution, ScopeDef};
4use hir::{Adt, HasSource, PathResolution};
5use ra_syntax::AstNode; 4use ra_syntax::AstNode;
6use test_utils::tested_by; 5use test_utils::tested_by;
7 6
@@ -19,17 +18,15 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
19 match def { 18 match def {
20 hir::ModuleDef::Module(module) => { 19 hir::ModuleDef::Module(module) => {
21 let module_scope = module.scope(ctx.db); 20 let module_scope = module.scope(ctx.db);
22 for (name, def, import) in module_scope { 21 for (name, def) in module_scope {
23 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::BuiltinType(..)) = def { 22 if ctx.use_item_syntax.is_some() {
24 if ctx.use_item_syntax.is_some() { 23 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::BuiltinType(..)) = def {
25 tested_by!(dont_complete_primitive_in_use); 24 tested_by!(dont_complete_primitive_in_use);
26 continue; 25 continue;
27 } 26 }
28 } 27 if let ScopeDef::Unknown = def {
29 if Some(module) == ctx.module { 28 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() {
30 if let Some(import) = import { 29 if &name_ref.syntax().text() == name.to_string().as_str() {
31 if let Either::Left(use_tree) = import.source(ctx.db).value {
32 if use_tree.syntax().text_range().contains_inclusive(ctx.offset) {
33 // for `use self::foo<|>`, don't suggest `foo` as a completion 30 // for `use self::foo<|>`, don't suggest `foo` as a completion
34 tested_by!(dont_complete_current_use); 31 tested_by!(dont_complete_current_use);
35 continue; 32 continue;
@@ -37,6 +34,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
37 } 34 }
38 } 35 }
39 } 36 }
37
40 acc.add_resolution(ctx, name.to_string(), &def); 38 acc.add_resolution(ctx, name.to_string(), &def);
41 } 39 }
42 } 40 }
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs
index 646a30c76..5470dc291 100644
--- a/crates/ra_ide/src/completion/complete_postfix.rs
+++ b/crates/ra_ide/src/completion/complete_postfix.rs
@@ -12,7 +12,7 @@ use crate::{
12}; 12};
13 13
14pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { 14pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
15 if ctx.db.feature_flags.get("completion.enable-postfix") == false { 15 if !ctx.db.feature_flags.get("completion.enable-postfix") {
16 return; 16 return;
17 } 17 }
18 18
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index 981da2b79..48d69f7e5 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -19,6 +19,7 @@ pub(crate) struct CompletionContext<'a> {
19 pub(super) offset: TextUnit, 19 pub(super) offset: TextUnit,
20 pub(super) token: SyntaxToken, 20 pub(super) token: SyntaxToken,
21 pub(super) module: Option<hir::Module>, 21 pub(super) module: Option<hir::Module>,
22 pub(super) name_ref_syntax: Option<ast::NameRef>,
22 pub(super) function_syntax: Option<ast::FnDef>, 23 pub(super) function_syntax: Option<ast::FnDef>,
23 pub(super) use_item_syntax: Option<ast::UseItem>, 24 pub(super) use_item_syntax: Option<ast::UseItem>,
24 pub(super) record_lit_syntax: Option<ast::RecordLit>, 25 pub(super) record_lit_syntax: Option<ast::RecordLit>,
@@ -69,6 +70,7 @@ impl<'a> CompletionContext<'a> {
69 token, 70 token,
70 offset: position.offset, 71 offset: position.offset,
71 module, 72 module,
73 name_ref_syntax: None,
72 function_syntax: None, 74 function_syntax: None,
73 use_item_syntax: None, 75 use_item_syntax: None,
74 record_lit_syntax: None, 76 record_lit_syntax: None,
@@ -142,6 +144,8 @@ impl<'a> CompletionContext<'a> {
142 } 144 }
143 145
144 fn classify_name_ref(&mut self, original_file: SourceFile, name_ref: ast::NameRef) { 146 fn classify_name_ref(&mut self, original_file: SourceFile, name_ref: ast::NameRef) {
147 self.name_ref_syntax =
148 find_node_at_offset(original_file.syntax(), name_ref.syntax().text_range().start());
145 let name_range = name_ref.syntax().text_range(); 149 let name_range = name_ref.syntax().text_range();
146 if name_ref.syntax().parent().and_then(ast::RecordField::cast).is_some() { 150 if name_ref.syntax().parent().and_then(ast::RecordField::cast).is_some() {
147 self.record_lit_syntax = find_node_at_offset(original_file.syntax(), self.offset); 151 self.record_lit_syntax = find_node_at_offset(original_file.syntax(), self.offset);
@@ -239,16 +243,15 @@ impl<'a> CompletionContext<'a> {
239 .expr() 243 .expr()
240 .map(|e| e.syntax().text_range()) 244 .map(|e| e.syntax().text_range())
241 .and_then(|r| find_node_with_range(original_file.syntax(), r)); 245 .and_then(|r| find_node_with_range(original_file.syntax(), r));
242 self.dot_receiver_is_ambiguous_float_literal = if let Some(ast::Expr::Literal(l)) = 246 self.dot_receiver_is_ambiguous_float_literal =
243 &self.dot_receiver 247 if let Some(ast::Expr::Literal(l)) = &self.dot_receiver {
244 { 248 match l.kind() {
245 match l.kind() { 249 ast::LiteralKind::FloatNumber { .. } => l.token().text().ends_with('.'),
246 ast::LiteralKind::FloatNumber { suffix: _ } => l.token().text().ends_with('.'), 250 _ => false,
247 _ => false, 251 }
252 } else {
253 false
248 } 254 }
249 } else {
250 false
251 }
252 } 255 }
253 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) { 256 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
254 // As above 257 // As above
diff --git a/crates/ra_ide/src/display.rs b/crates/ra_ide/src/display.rs
index 30617412a..fbe89841b 100644
--- a/crates/ra_ide/src/display.rs
+++ b/crates/ra_ide/src/display.rs
@@ -15,7 +15,7 @@ pub use function_signature::FunctionSignature;
15pub use navigation_target::NavigationTarget; 15pub use navigation_target::NavigationTarget;
16pub use structure::{file_structure, StructureNode}; 16pub use structure::{file_structure, StructureNode};
17 17
18pub(crate) use navigation_target::{description_from_symbol, docs_from_symbol, ToNav}; 18pub(crate) use navigation_target::ToNav;
19pub(crate) use short_label::ShortLabel; 19pub(crate) use short_label::ShortLabel;
20 20
21pub(crate) fn function_label(node: &ast::FnDef) -> String { 21pub(crate) fn function_label(node: &ast::FnDef) -> String {
diff --git a/crates/ra_ide/src/expand_macro.rs b/crates/ra_ide/src/expand_macro.rs
index 862c03304..bdbc31704 100644
--- a/crates/ra_ide/src/expand_macro.rs
+++ b/crates/ra_ide/src/expand_macro.rs
@@ -86,21 +86,18 @@ fn insert_whitespaces(syn: SyntaxNode) -> String {
86 let mut is_next = |f: fn(SyntaxKind) -> bool, default| -> bool { 86 let mut is_next = |f: fn(SyntaxKind) -> bool, default| -> bool {
87 token_iter.peek().map(|it| f(it.kind())).unwrap_or(default) 87 token_iter.peek().map(|it| f(it.kind())).unwrap_or(default)
88 }; 88 };
89 let is_last = |f: fn(SyntaxKind) -> bool, default| -> bool { 89 let is_last =
90 last.map(|it| f(it)).unwrap_or(default) 90 |f: fn(SyntaxKind) -> bool, default| -> bool { last.map(f).unwrap_or(default) };
91 };
92 91
93 res += &match token.kind() { 92 res += &match token.kind() {
94 k @ _ if is_text(k) && is_next(|it| !it.is_punct(), true) => { 93 k if is_text(k) && is_next(|it| !it.is_punct(), true) => token.text().to_string() + " ",
95 token.text().to_string() + " "
96 }
97 L_CURLY if is_next(|it| it != R_CURLY, true) => { 94 L_CURLY if is_next(|it| it != R_CURLY, true) => {
98 indent += 1; 95 indent += 1;
99 let leading_space = if is_last(|it| is_text(it), false) { " " } else { "" }; 96 let leading_space = if is_last(is_text, false) { " " } else { "" };
100 format!("{}{{\n{}", leading_space, " ".repeat(indent)) 97 format!("{}{{\n{}", leading_space, " ".repeat(indent))
101 } 98 }
102 R_CURLY if is_last(|it| it != L_CURLY, true) => { 99 R_CURLY if is_last(|it| it != L_CURLY, true) => {
103 indent = indent.checked_sub(1).unwrap_or(0); 100 indent = indent.saturating_sub(1);
104 format!("\n{}}}", " ".repeat(indent)) 101 format!("\n{}}}", " ".repeat(indent))
105 } 102 }
106 R_CURLY => format!("}}\n{}", " ".repeat(indent)), 103 R_CURLY => format!("}}\n{}", " ".repeat(indent)),
diff --git a/crates/ra_ide/src/extend_selection.rs b/crates/ra_ide/src/extend_selection.rs
index c096ca6ae..1ec41a117 100644
--- a/crates/ra_ide/src/extend_selection.rs
+++ b/crates/ra_ide/src/extend_selection.rs
@@ -138,7 +138,7 @@ fn extend_ws(root: &SyntaxNode, ws: SyntaxToken, offset: TextUnit) -> TextRange
138 ws.text_range() 138 ws.text_range()
139} 139}
140 140
141fn pick_best<'a>(l: SyntaxToken, r: SyntaxToken) -> SyntaxToken { 141fn pick_best(l: SyntaxToken, r: SyntaxToken) -> SyntaxToken {
142 return if priority(&r) > priority(&l) { r } else { l }; 142 return if priority(&r) > priority(&l) { r } else { l };
143 fn priority(n: &SyntaxToken) -> usize { 143 fn priority(n: &SyntaxToken) -> usize {
144 match n.kind() { 144 match n.kind() {
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index 184555792..79d332e8c 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -258,7 +258,7 @@ mod tests {
258 } 258 }
259 259
260 #[test] 260 #[test]
261 fn goto_definition_works_in_items() { 261 fn goto_def_in_items() {
262 check_goto( 262 check_goto(
263 " 263 "
264 //- /lib.rs 264 //- /lib.rs
@@ -271,7 +271,7 @@ mod tests {
271 } 271 }
272 272
273 #[test] 273 #[test]
274 fn goto_definition_works_at_start_of_item() { 274 fn goto_def_at_start_of_item() {
275 check_goto( 275 check_goto(
276 " 276 "
277 //- /lib.rs 277 //- /lib.rs
@@ -305,7 +305,7 @@ mod tests {
305 } 305 }
306 306
307 #[test] 307 #[test]
308 fn goto_definition_works_for_module_declaration() { 308 fn goto_def_for_module_declaration() {
309 check_goto( 309 check_goto(
310 " 310 "
311 //- /lib.rs 311 //- /lib.rs
@@ -332,8 +332,8 @@ mod tests {
332 } 332 }
333 333
334 #[test] 334 #[test]
335 fn goto_definition_works_for_macros() { 335 fn goto_def_for_macros() {
336 covers!(goto_definition_works_for_macros); 336 covers!(goto_def_for_macros);
337 check_goto( 337 check_goto(
338 " 338 "
339 //- /lib.rs 339 //- /lib.rs
@@ -349,8 +349,8 @@ mod tests {
349 } 349 }
350 350
351 #[test] 351 #[test]
352 fn goto_definition_works_for_macros_from_other_crates() { 352 fn goto_def_for_macros_from_other_crates() {
353 covers!(goto_definition_works_for_macros); 353 covers!(goto_def_for_macros);
354 check_goto( 354 check_goto(
355 " 355 "
356 //- /lib.rs 356 //- /lib.rs
@@ -369,7 +369,7 @@ mod tests {
369 } 369 }
370 370
371 #[test] 371 #[test]
372 fn goto_definition_works_for_macros_in_use_tree() { 372 fn goto_def_for_macros_in_use_tree() {
373 check_goto( 373 check_goto(
374 " 374 "
375 //- /lib.rs 375 //- /lib.rs
@@ -385,7 +385,7 @@ mod tests {
385 } 385 }
386 386
387 #[test] 387 #[test]
388 fn goto_definition_works_for_macro_defined_fn_with_arg() { 388 fn goto_def_for_macro_defined_fn_with_arg() {
389 check_goto( 389 check_goto(
390 " 390 "
391 //- /lib.rs 391 //- /lib.rs
@@ -405,7 +405,7 @@ mod tests {
405 } 405 }
406 406
407 #[test] 407 #[test]
408 fn goto_definition_works_for_macro_defined_fn_no_arg() { 408 fn goto_def_for_macro_defined_fn_no_arg() {
409 check_goto( 409 check_goto(
410 " 410 "
411 //- /lib.rs 411 //- /lib.rs
@@ -425,8 +425,44 @@ mod tests {
425 } 425 }
426 426
427 #[test] 427 #[test]
428 fn goto_definition_works_for_methods() { 428 fn goto_definition_works_for_macro_inside_pattern() {
429 covers!(goto_definition_works_for_methods); 429 check_goto(
430 "
431 //- /lib.rs
432 macro_rules! foo {() => {0}}
433
434 fn bar() {
435 match (0,1) {
436 (<|>foo!(), _) => {}
437 }
438 }
439 ",
440 "foo MACRO_CALL FileId(1) [0; 28) [13; 16)",
441 "macro_rules! foo {() => {0}}|foo",
442 );
443 }
444
445 #[test]
446 fn goto_definition_works_for_macro_inside_match_arm_lhs() {
447 check_goto(
448 "
449 //- /lib.rs
450 macro_rules! foo {() => {0}}
451
452 fn bar() {
453 match 0 {
454 <|>foo!() => {}
455 }
456 }
457 ",
458 "foo MACRO_CALL FileId(1) [0; 28) [13; 16)",
459 "macro_rules! foo {() => {0}}|foo",
460 );
461 }
462
463 #[test]
464 fn goto_def_for_methods() {
465 covers!(goto_def_for_methods);
430 check_goto( 466 check_goto(
431 " 467 "
432 //- /lib.rs 468 //- /lib.rs
@@ -445,8 +481,8 @@ mod tests {
445 } 481 }
446 482
447 #[test] 483 #[test]
448 fn goto_definition_works_for_fields() { 484 fn goto_def_for_fields() {
449 covers!(goto_definition_works_for_fields); 485 covers!(goto_def_for_fields);
450 check_goto( 486 check_goto(
451 " 487 "
452 //- /lib.rs 488 //- /lib.rs
@@ -464,8 +500,8 @@ mod tests {
464 } 500 }
465 501
466 #[test] 502 #[test]
467 fn goto_definition_works_for_record_fields() { 503 fn goto_def_for_record_fields() {
468 covers!(goto_definition_works_for_record_fields); 504 covers!(goto_def_for_record_fields);
469 check_goto( 505 check_goto(
470 " 506 "
471 //- /lib.rs 507 //- /lib.rs
@@ -502,7 +538,7 @@ mod tests {
502 } 538 }
503 539
504 #[test] 540 #[test]
505 fn goto_definition_works_for_ufcs_inherent_methods() { 541 fn goto_def_for_ufcs_inherent_methods() {
506 check_goto( 542 check_goto(
507 " 543 "
508 //- /lib.rs 544 //- /lib.rs
@@ -521,7 +557,7 @@ mod tests {
521 } 557 }
522 558
523 #[test] 559 #[test]
524 fn goto_definition_works_for_ufcs_trait_methods_through_traits() { 560 fn goto_def_for_ufcs_trait_methods_through_traits() {
525 check_goto( 561 check_goto(
526 " 562 "
527 //- /lib.rs 563 //- /lib.rs
@@ -539,7 +575,7 @@ mod tests {
539 } 575 }
540 576
541 #[test] 577 #[test]
542 fn goto_definition_works_for_ufcs_trait_methods_through_self() { 578 fn goto_def_for_ufcs_trait_methods_through_self() {
543 check_goto( 579 check_goto(
544 " 580 "
545 //- /lib.rs 581 //- /lib.rs
@@ -654,7 +690,7 @@ mod tests {
654 } 690 }
655 691
656 #[test] 692 #[test]
657 fn goto_definition_works_when_used_on_definition_name_itself() { 693 fn goto_def_when_used_on_definition_name_itself() {
658 check_goto( 694 check_goto(
659 " 695 "
660 //- /lib.rs 696 //- /lib.rs
@@ -858,4 +894,38 @@ mod tests {
858 "y", 894 "y",
859 ); 895 );
860 } 896 }
897
898 #[test]
899 fn goto_def_in_local_fn() {
900 check_goto(
901 "
902 //- /lib.rs
903 fn main() {
904 fn foo() {
905 let x = 92;
906 <|>x;
907 }
908 }
909 ",
910 "x BIND_PAT FileId(1) [39; 40)",
911 "x",
912 );
913 }
914
915 #[test]
916 fn goto_def_for_field_init_shorthand() {
917 covers!(goto_def_for_field_init_shorthand);
918 check_goto(
919 "
920 //- /lib.rs
921 struct Foo { x: i32 }
922 fn main() {
923 let x = 92;
924 Foo { x<|> };
925 }
926 ",
927 "x RECORD_FIELD_DEF FileId(1) [13; 19) [13; 14)",
928 "x: i32|x",
929 )
930 }
861} 931}
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index a227bf546..35e39f965 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -12,10 +12,7 @@ use ra_syntax::{
12 12
13use crate::{ 13use crate::{
14 db::RootDatabase, 14 db::RootDatabase,
15 display::{ 15 display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel},
16 description_from_symbol, docs_from_symbol, macro_label, rust_code_markup,
17 rust_code_markup_with_doc, ShortLabel,
18 },
19 expand::descend_into_macros, 16 expand::descend_into_macros,
20 references::{classify_name, classify_name_ref, NameKind, NameKind::*}, 17 references::{classify_name, classify_name_ref, NameKind, NameKind::*},
21 FilePosition, FileRange, RangeInfo, 18 FilePosition, FileRange, RangeInfo,
@@ -95,11 +92,7 @@ fn hover_text(docs: Option<String>, desc: Option<String>) -> Option<String> {
95 } 92 }
96} 93}
97 94
98fn hover_text_from_name_kind( 95fn hover_text_from_name_kind(db: &RootDatabase, name_kind: NameKind) -> Option<String> {
99 db: &RootDatabase,
100 name_kind: NameKind,
101 no_fallback: &mut bool,
102) -> Option<String> {
103 return match name_kind { 96 return match name_kind {
104 Macro(it) => { 97 Macro(it) => {
105 let src = it.source(db); 98 let src = it.source(db);
@@ -135,11 +128,7 @@ fn hover_text_from_name_kind(
135 hir::ModuleDef::TypeAlias(it) => from_def_source(db, it), 128 hir::ModuleDef::TypeAlias(it) => from_def_source(db, it),
136 hir::ModuleDef::BuiltinType(it) => Some(it.to_string()), 129 hir::ModuleDef::BuiltinType(it) => Some(it.to_string()),
137 }, 130 },
138 Local(_) => { 131 Local(_) => None,
139 // Hover for these shows type names
140 *no_fallback = true;
141 None
142 }
143 TypeParam(_) | SelfType(_) => { 132 TypeParam(_) | SelfType(_) => {
144 // FIXME: Hover for generic param 133 // FIXME: Hover for generic param
145 None 134 None
@@ -163,60 +152,35 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
163 152
164 let mut res = HoverResult::new(); 153 let mut res = HoverResult::new();
165 154
166 let mut range = match_ast! { 155 if let Some((range, name_kind)) = match_ast! {
167 match (token.value.parent()) { 156 match (token.value.parent()) {
168 ast::NameRef(name_ref) => { 157 ast::NameRef(name_ref) => {
169 let mut no_fallback = false; 158 classify_name_ref(db, token.with_value(&name_ref)).map(|d| (name_ref.syntax().text_range(), d.kind))
170 if let Some(name_kind) =
171 classify_name_ref(db, token.with_value(&name_ref)).map(|d| d.kind)
172 {
173 res.extend(hover_text_from_name_kind(db, name_kind, &mut no_fallback))
174 }
175
176 if res.is_empty() && !no_fallback {
177 // Fallback index based approach:
178 let symbols = crate::symbol_index::index_resolve(db, &name_ref);
179 for sym in symbols {
180 let docs = docs_from_symbol(db, &sym);
181 let desc = description_from_symbol(db, &sym);
182 res.extend(hover_text(docs, desc));
183 }
184 }
185
186 if !res.is_empty() {
187 Some(name_ref.syntax().text_range())
188 } else {
189 None
190 }
191 }, 159 },
192 ast::Name(name) => { 160 ast::Name(name) => {
193 if let Some(name_kind) = classify_name(db, token.with_value(&name)).map(|d| d.kind) { 161 classify_name(db, token.with_value(&name)).map(|d| (name.syntax().text_range(), d.kind))
194 res.extend(hover_text_from_name_kind(db, name_kind, &mut true));
195 }
196
197 if !res.is_empty() {
198 Some(name.syntax().text_range())
199 } else {
200 None
201 }
202 }, 162 },
203 _ => None, 163 _ => None,
204 } 164 }
205 }; 165 } {
166 res.extend(hover_text_from_name_kind(db, name_kind));
206 167
207 if range.is_none() { 168 if !res.is_empty() {
208 let node = token.value.ancestors().find(|n| { 169 return Some(RangeInfo::new(range, res));
209 ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some() 170 }
210 })?; 171 }
211 let frange = FileRange { file_id: position.file_id, range: node.text_range() };
212 res.extend(type_of(db, frange).map(rust_code_markup));
213 range = Some(node.text_range());
214 };
215 172
216 let range = range?; 173 let node = token
174 .value
175 .ancestors()
176 .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some())?;
177 let frange = FileRange { file_id: position.file_id, range: node.text_range() };
178 res.extend(type_of(db, frange).map(rust_code_markup));
217 if res.is_empty() { 179 if res.is_empty() {
218 return None; 180 return None;
219 } 181 }
182 let range = node.text_range();
183
220 Some(RangeInfo::new(range, res)) 184 Some(RangeInfo::new(range, res))
221} 185}
222 186
@@ -314,7 +278,7 @@ mod tests {
314 &["pub fn foo() -> u32"], 278 &["pub fn foo() -> u32"],
315 ); 279 );
316 280
317 // Multiple results 281 // Multiple candidates but results are ambiguous.
318 check_hover_result( 282 check_hover_result(
319 r#" 283 r#"
320 //- /a.rs 284 //- /a.rs
@@ -335,7 +299,7 @@ mod tests {
335 let foo_test = fo<|>o(); 299 let foo_test = fo<|>o();
336 } 300 }
337 "#, 301 "#,
338 &["pub fn foo() -> &str", "pub fn foo() -> u32", "pub fn foo(a: u32, b: u32)"], 302 &["{unknown}"],
339 ); 303 );
340 } 304 }
341 305
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 3154df457..c5e406977 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -1,12 +1,15 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use crate::{db::RootDatabase, FileId};
4use hir::{HirDisplay, SourceAnalyzer}; 3use hir::{HirDisplay, SourceAnalyzer};
4use once_cell::unsync::Lazy;
5use ra_prof::profile;
5use ra_syntax::{ 6use ra_syntax::{
6 ast::{self, AstNode, TypeAscriptionOwner}, 7 ast::{self, AstNode, TypeAscriptionOwner},
7 match_ast, SmolStr, SourceFile, SyntaxKind, SyntaxNode, TextRange, 8 match_ast, SmolStr, SourceFile, SyntaxKind, SyntaxNode, TextRange,
8}; 9};
9 10
11use crate::{db::RootDatabase, FileId};
12
10#[derive(Debug, PartialEq, Eq)] 13#[derive(Debug, PartialEq, Eq)]
11pub enum InlayKind { 14pub enum InlayKind {
12 TypeHint, 15 TypeHint,
@@ -27,7 +30,7 @@ pub(crate) fn inlay_hints(
27) -> Vec<InlayHint> { 30) -> Vec<InlayHint> {
28 file.syntax() 31 file.syntax()
29 .descendants() 32 .descendants()
30 .map(|node| get_inlay_hints(db, file_id, &node, max_inlay_hint_length).unwrap_or_default()) 33 .flat_map(|node| get_inlay_hints(db, file_id, &node, max_inlay_hint_length))
31 .flatten() 34 .flatten()
32 .collect() 35 .collect()
33} 36}
@@ -38,7 +41,9 @@ fn get_inlay_hints(
38 node: &SyntaxNode, 41 node: &SyntaxNode,
39 max_inlay_hint_length: Option<usize>, 42 max_inlay_hint_length: Option<usize>,
40) -> Option<Vec<InlayHint>> { 43) -> Option<Vec<InlayHint>> {
41 let analyzer = SourceAnalyzer::new(db, hir::InFile::new(file_id.into(), node), None); 44 let _p = profile("get_inlay_hints");
45 let analyzer =
46 Lazy::new(|| SourceAnalyzer::new(db, hir::InFile::new(file_id.into(), node), None));
42 match_ast! { 47 match_ast! {
43 match node { 48 match node {
44 ast::LetStmt(it) => { 49 ast::LetStmt(it) => {
diff --git a/crates/ra_ide/src/marks.rs b/crates/ra_ide/src/marks.rs
index 848ae4dc7..077a44473 100644
--- a/crates/ra_ide/src/marks.rs
+++ b/crates/ra_ide/src/marks.rs
@@ -3,10 +3,11 @@
3test_utils::marks!( 3test_utils::marks!(
4 inserts_angle_brackets_for_generics 4 inserts_angle_brackets_for_generics
5 inserts_parens_for_function_calls 5 inserts_parens_for_function_calls
6 goto_definition_works_for_macros 6 goto_def_for_macros
7 goto_definition_works_for_methods 7 goto_def_for_methods
8 goto_definition_works_for_fields 8 goto_def_for_fields
9 goto_definition_works_for_record_fields 9 goto_def_for_record_fields
10 goto_def_for_field_init_shorthand
10 call_info_bad_offset 11 call_info_bad_offset
11 dont_complete_current_use 12 dont_complete_current_use
12 dont_complete_primitive_in_use 13 dont_complete_primitive_in_use
diff --git a/crates/ra_ide/src/references/classify.rs b/crates/ra_ide/src/references/classify.rs
index c1f091ec0..3483a7176 100644
--- a/crates/ra_ide/src/references/classify.rs
+++ b/crates/ra_ide/src/references/classify.rs
@@ -134,21 +134,22 @@ pub(crate) fn classify_name_ref(
134 let analyzer = SourceAnalyzer::new(db, name_ref.map(|it| it.syntax()), None); 134 let analyzer = SourceAnalyzer::new(db, name_ref.map(|it| it.syntax()), None);
135 135
136 if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { 136 if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
137 tested_by!(goto_definition_works_for_methods); 137 tested_by!(goto_def_for_methods);
138 if let Some(func) = analyzer.resolve_method_call(&method_call) { 138 if let Some(func) = analyzer.resolve_method_call(&method_call) {
139 return Some(from_assoc_item(db, func.into())); 139 return Some(from_assoc_item(db, func.into()));
140 } 140 }
141 } 141 }
142 142
143 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { 143 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
144 tested_by!(goto_definition_works_for_fields); 144 tested_by!(goto_def_for_fields);
145 if let Some(field) = analyzer.resolve_field(&field_expr) { 145 if let Some(field) = analyzer.resolve_field(&field_expr) {
146 return Some(from_struct_field(db, field)); 146 return Some(from_struct_field(db, field));
147 } 147 }
148 } 148 }
149 149
150 if let Some(record_field) = ast::RecordField::cast(parent.clone()) { 150 if let Some(record_field) = ast::RecordField::cast(parent.clone()) {
151 tested_by!(goto_definition_works_for_record_fields); 151 tested_by!(goto_def_for_record_fields);
152 tested_by!(goto_def_for_field_init_shorthand);
152 if let Some(field_def) = analyzer.resolve_record_field(&record_field) { 153 if let Some(field_def) = analyzer.resolve_record_field(&record_field) {
153 return Some(from_struct_field(db, field_def)); 154 return Some(from_struct_field(db, field_def));
154 } 155 }
@@ -160,7 +161,7 @@ pub(crate) fn classify_name_ref(
160 let visibility = None; 161 let visibility = None;
161 162
162 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { 163 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
163 tested_by!(goto_definition_works_for_macros); 164 tested_by!(goto_def_for_macros);
164 if let Some(macro_def) = analyzer.resolve_macro_call(db, name_ref.with_value(&macro_call)) { 165 if let Some(macro_def) = analyzer.resolve_macro_call(db, name_ref.with_value(&macro_call)) {
165 let kind = NameKind::Macro(macro_def); 166 let kind = NameKind::Macro(macro_def);
166 return Some(NameDefinition { kind, container, visibility }); 167 return Some(NameDefinition { kind, container, visibility });
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html
index 2157139f6..a097cf8e8 100644
--- a/crates/ra_ide/src/snapshots/highlighting.html
+++ b/crates/ra_ide/src/snapshots/highlighting.html
@@ -5,6 +5,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
5 5
6.comment { color: #7F9F7F; } 6.comment { color: #7F9F7F; }
7.string { color: #CC9393; } 7.string { color: #CC9393; }
8.field { color: #94BFF3; }
8.function { color: #93E0E3; } 9.function { color: #93E0E3; }
9.parameter { color: #94BFF3; } 10.parameter { color: #94BFF3; }
10.text { color: #DCDCCC; } 11.text { color: #DCDCCC; }
@@ -39,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
39 40
40 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">vec</span> = <span class="text">Vec</span>::<span class="text">new</span>(); 41 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">vec</span> = <span class="text">Vec</span>::<span class="text">new</span>();
41 <span class="keyword.control">if</span> <span class="keyword">true</span> { 42 <span class="keyword.control">if</span> <span class="keyword">true</span> {
42 <span class="variable.mut">vec</span>.<span class="text">push</span>(<span class="type">Foo</span> { <span class="field">x</span>: <span class="literal.numeric">0</span>, <span class="field">y</span>: <span class="literal.numeric">1</span> }); 43 <span class="keyword">let</span> <span class="variable">x</span> = <span class="literal.numeric">92</span>;
44 <span class="variable.mut">vec</span>.<span class="text">push</span>(<span class="type">Foo</span> { <span class="field">x</span>, <span class="field">y</span>: <span class="literal.numeric">1</span> });
43 } 45 }
44 <span class="keyword.unsafe">unsafe</span> { <span class="variable.mut">vec</span>.<span class="text">set_len</span>(<span class="literal.numeric">0</span>); } 46 <span class="keyword.unsafe">unsafe</span> { <span class="variable.mut">vec</span>.<span class="text">set_len</span>(<span class="literal.numeric">0</span>); }
45 47
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
index 871a52cf6..110556c09 100644
--- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html
+++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
@@ -5,6 +5,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
5 5
6.comment { color: #7F9F7F; } 6.comment { color: #7F9F7F; }
7.string { color: #CC9393; } 7.string { color: #CC9393; }
8.field { color: #94BFF3; }
8.function { color: #93E0E3; } 9.function { color: #93E0E3; }
9.parameter { color: #94BFF3; } 10.parameter { color: #94BFF3; }
10.text { color: #DCDCCC; } 11.text { color: #DCDCCC; }
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 15e75709c..0228ee7e9 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -17,31 +17,31 @@ use crate::{
17}; 17};
18 18
19pub mod tags { 19pub mod tags {
20 pub(crate) const FIELD: &'static str = "field"; 20 pub(crate) const FIELD: &str = "field";
21 pub(crate) const FUNCTION: &'static str = "function"; 21 pub(crate) const FUNCTION: &str = "function";
22 pub(crate) const MODULE: &'static str = "module"; 22 pub(crate) const MODULE: &str = "module";
23 pub(crate) const TYPE: &'static str = "type"; 23 pub(crate) const TYPE: &str = "type";
24 pub(crate) const CONSTANT: &'static str = "constant"; 24 pub(crate) const CONSTANT: &str = "constant";
25 pub(crate) const MACRO: &'static str = "macro"; 25 pub(crate) const MACRO: &str = "macro";
26 pub(crate) const VARIABLE: &'static str = "variable"; 26 pub(crate) const VARIABLE: &str = "variable";
27 pub(crate) const VARIABLE_MUT: &'static str = "variable.mut"; 27 pub(crate) const VARIABLE_MUT: &str = "variable.mut";
28 pub(crate) const TEXT: &'static str = "text"; 28 pub(crate) const TEXT: &str = "text";
29 29
30 pub(crate) const TYPE_BUILTIN: &'static str = "type.builtin"; 30 pub(crate) const TYPE_BUILTIN: &str = "type.builtin";
31 pub(crate) const TYPE_SELF: &'static str = "type.self"; 31 pub(crate) const TYPE_SELF: &str = "type.self";
32 pub(crate) const TYPE_PARAM: &'static str = "type.param"; 32 pub(crate) const TYPE_PARAM: &str = "type.param";
33 pub(crate) const TYPE_LIFETIME: &'static str = "type.lifetime"; 33 pub(crate) const TYPE_LIFETIME: &str = "type.lifetime";
34 34
35 pub(crate) const LITERAL_BYTE: &'static str = "literal.byte"; 35 pub(crate) const LITERAL_BYTE: &str = "literal.byte";
36 pub(crate) const LITERAL_NUMERIC: &'static str = "literal.numeric"; 36 pub(crate) const LITERAL_NUMERIC: &str = "literal.numeric";
37 pub(crate) const LITERAL_CHAR: &'static str = "literal.char"; 37 pub(crate) const LITERAL_CHAR: &str = "literal.char";
38 pub(crate) const LITERAL_COMMENT: &'static str = "comment"; 38 pub(crate) const LITERAL_COMMENT: &str = "comment";
39 pub(crate) const LITERAL_STRING: &'static str = "string"; 39 pub(crate) const LITERAL_STRING: &str = "string";
40 pub(crate) const LITERAL_ATTRIBUTE: &'static str = "attribute"; 40 pub(crate) const LITERAL_ATTRIBUTE: &str = "attribute";
41 41
42 pub(crate) const KEYWORD_UNSAFE: &'static str = "keyword.unsafe"; 42 pub(crate) const KEYWORD_UNSAFE: &str = "keyword.unsafe";
43 pub(crate) const KEYWORD_CONTROL: &'static str = "keyword.control"; 43 pub(crate) const KEYWORD_CONTROL: &str = "keyword.control";
44 pub(crate) const KEYWORD: &'static str = "keyword"; 44 pub(crate) const KEYWORD: &str = "keyword";
45} 45}
46 46
47#[derive(Debug)] 47#[derive(Debug)]
@@ -102,11 +102,10 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
102 COMMENT => tags::LITERAL_COMMENT, 102 COMMENT => tags::LITERAL_COMMENT,
103 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => tags::LITERAL_STRING, 103 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => tags::LITERAL_STRING,
104 ATTR => tags::LITERAL_ATTRIBUTE, 104 ATTR => tags::LITERAL_ATTRIBUTE,
105 // Special-case field init shorthand
106 NAME_REF if node.parent().and_then(ast::RecordField::cast).is_some() => tags::FIELD,
107 NAME_REF if node.ancestors().any(|it| it.kind() == ATTR) => continue,
105 NAME_REF => { 108 NAME_REF => {
106 if node.ancestors().any(|it| it.kind() == ATTR) {
107 continue;
108 }
109
110 let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap(); 109 let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap();
111 let name_kind = 110 let name_kind =
112 classify_name_ref(db, InFile::new(file_id.into(), &name_ref)).map(|d| d.kind); 111 classify_name_ref(db, InFile::new(file_id.into(), &name_ref)).map(|d| d.kind);
@@ -259,9 +258,7 @@ fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str {
259 SelfType(_) => tags::TYPE_SELF, 258 SelfType(_) => tags::TYPE_SELF,
260 TypeParam(_) => tags::TYPE_PARAM, 259 TypeParam(_) => tags::TYPE_PARAM,
261 Local(local) => { 260 Local(local) => {
262 if local.is_mut(db) { 261 if local.is_mut(db) || local.ty(db).is_mutable_reference() {
263 tags::VARIABLE_MUT
264 } else if local.ty(db).is_mutable_reference() {
265 tags::VARIABLE_MUT 262 tags::VARIABLE_MUT
266 } else { 263 } else {
267 tags::VARIABLE 264 tags::VARIABLE
@@ -282,6 +279,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
282 279
283.comment { color: #7F9F7F; } 280.comment { color: #7F9F7F; }
284.string { color: #CC9393; } 281.string { color: #CC9393; }
282.field { color: #94BFF3; }
285.function { color: #93E0E3; } 283.function { color: #93E0E3; }
286.parameter { color: #94BFF3; } 284.parameter { color: #94BFF3; }
287.text { color: #DCDCCC; } 285.text { color: #DCDCCC; }
@@ -327,7 +325,8 @@ fn main() {
327 325
328 let mut vec = Vec::new(); 326 let mut vec = Vec::new();
329 if true { 327 if true {
330 vec.push(Foo { x: 0, y: 1 }); 328 let x = 92;
329 vec.push(Foo { x, y: 1 });
331 } 330 }
332 unsafe { vec.set_len(0); } 331 unsafe { vec.set_len(0); }
333 332