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/call_info.rs43
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs15
-rw-r--r--crates/ra_ide/src/goto_definition.rs243
-rw-r--r--crates/ra_ide/src/hover.rs19
-rw-r--r--crates/ra_ide/src/inlay_hints.rs26
-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.rs11
10 files changed, 278 insertions, 102 deletions
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs
index b3c323d38..2c2b6fa48 100644
--- a/crates/ra_ide/src/call_info.rs
+++ b/crates/ra_ide/src/call_info.rs
@@ -1,24 +1,26 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_db::SourceDatabase; 3use hir::db::AstDatabase;
4use ra_syntax::{ 4use ra_syntax::{
5 algo::ancestors_at_offset,
6 ast::{self, ArgListOwner}, 5 ast::{self, ArgListOwner},
7 match_ast, AstNode, SyntaxNode, TextUnit, 6 match_ast, AstNode, SyntaxNode,
8}; 7};
9use test_utils::tested_by; 8use test_utils::tested_by;
10 9
11use crate::{db::RootDatabase, CallInfo, FilePosition, FunctionSignature}; 10use crate::{
11 db::RootDatabase, expand::descend_into_macros, CallInfo, FilePosition, FunctionSignature,
12};
12 13
13/// Computes parameter information for the given call expression. 14/// Computes parameter information for the given call expression.
14pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> { 15pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
15 let parse = db.parse(position.file_id); 16 let file = db.parse_or_expand(position.file_id.into())?;
16 let syntax = parse.tree().syntax().clone(); 17 let token = file.token_at_offset(position.offset).next()?;
18 let token = descend_into_macros(db, position.file_id, token);
17 19
18 // Find the calling expression and it's NameRef 20 // Find the calling expression and it's NameRef
19 let calling_node = FnCallNode::with_node(&syntax, position.offset)?; 21 let calling_node = FnCallNode::with_node(&token.value.parent())?;
20 let name_ref = calling_node.name_ref()?; 22 let name_ref = calling_node.name_ref()?;
21 let name_ref = hir::InFile::new(position.file_id.into(), name_ref.syntax()); 23 let name_ref = token.with_value(name_ref.syntax());
22 24
23 let analyzer = hir::SourceAnalyzer::new(db, name_ref, None); 25 let analyzer = hir::SourceAnalyzer::new(db, name_ref, None);
24 let (mut call_info, has_self) = match &calling_node { 26 let (mut call_info, has_self) = match &calling_node {
@@ -93,8 +95,8 @@ enum FnCallNode {
93} 95}
94 96
95impl FnCallNode { 97impl FnCallNode {
96 fn with_node(syntax: &SyntaxNode, offset: TextUnit) -> Option<FnCallNode> { 98 fn with_node(syntax: &SyntaxNode) -> Option<FnCallNode> {
97 ancestors_at_offset(syntax, offset).find_map(|node| { 99 syntax.ancestors().find_map(|node| {
98 match_ast! { 100 match_ast! {
99 match node { 101 match node {
100 ast::CallExpr(it) => { Some(FnCallNode::CallExpr(it)) }, 102 ast::CallExpr(it) => { Some(FnCallNode::CallExpr(it)) },
@@ -589,4 +591,25 @@ fn f() {
589 assert_eq!(info.label(), "foo!()"); 591 assert_eq!(info.label(), "foo!()");
590 assert_eq!(info.doc().map(|it| it.into()), Some("empty macro".to_string())); 592 assert_eq!(info.doc().map(|it| it.into()), Some("empty macro".to_string()));
591 } 593 }
594
595 #[test]
596 fn fn_signature_for_call_in_macro() {
597 let info = call_info(
598 r#"
599 macro_rules! id {
600 ($($tt:tt)*) => { $($tt)* }
601 }
602 fn foo() {
603
604 }
605 id! {
606 fn bar() {
607 foo(<|>);
608 }
609 }
610 "#,
611 );
612
613 assert_eq!(info.label(), "fn foo()");
614 }
592} 615}
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs
index 6a6b49afd..b9ae67828 100644
--- a/crates/ra_ide/src/display/navigation_target.rs
+++ b/crates/ra_ide/src/display/navigation_target.rs
@@ -328,22 +328,23 @@ impl ToNav for hir::AssocItem {
328impl ToNav for hir::Local { 328impl ToNav for hir::Local {
329 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 329 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
330 let src = self.source(db); 330 let src = self.source(db);
331 let (full_range, focus_range) = match src.value { 331 let node = match &src.value {
332 Either::Left(it) => { 332 Either::Left(bind_pat) => {
333 (it.syntax().text_range(), it.name().map(|it| it.syntax().text_range())) 333 bind_pat.name().map_or_else(|| bind_pat.syntax().clone(), |it| it.syntax().clone())
334 } 334 }
335 Either::Right(it) => (it.syntax().text_range(), Some(it.self_kw_token().text_range())), 335 Either::Right(it) => it.syntax().clone(),
336 }; 336 };
337 let full_range = original_range(db, src.with_value(&node));
337 let name = match self.name(db) { 338 let name = match self.name(db) {
338 Some(it) => it.to_string().into(), 339 Some(it) => it.to_string().into(),
339 None => "".into(), 340 None => "".into(),
340 }; 341 };
341 NavigationTarget { 342 NavigationTarget {
342 file_id: src.file_id.original_file(db), 343 file_id: full_range.file_id,
343 name, 344 name,
344 kind: BIND_PAT, 345 kind: BIND_PAT,
345 full_range, 346 full_range: full_range.range,
346 focus_range, 347 focus_range: None,
347 container_name: None, 348 container_name: None,
348 description: None, 349 description: None,
349 docs: None, 350 docs: None,
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index bee8e9df2..9b5744789 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -225,35 +225,40 @@ mod tests {
225 225
226 use crate::mock_analysis::analysis_and_position; 226 use crate::mock_analysis::analysis_and_position;
227 227
228 fn check_goto(fixture: &str, expected: &str) { 228 fn check_goto(fixture: &str, expected: &str, expected_range: &str) {
229 let (analysis, pos) = analysis_and_position(fixture); 229 let (analysis, pos) = analysis_and_position(fixture);
230 230
231 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; 231 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info;
232 assert_eq!(navs.len(), 1); 232 assert_eq!(navs.len(), 1);
233 let nav = navs.pop().unwrap();
234 nav.assert_match(expected);
235 }
236
237 fn check_goto_with_range_content(fixture: &str, expected: &str, expected_range: &str) {
238 let (analysis, pos) = analysis_and_position(fixture);
239 233
240 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info;
241 assert_eq!(navs.len(), 1);
242 let nav = navs.pop().unwrap(); 234 let nav = navs.pop().unwrap();
243 let file_text = analysis.file_text(pos.file_id).unwrap(); 235 let file_text = analysis.file_text(nav.file_id()).unwrap();
236
237 let mut actual = file_text[nav.full_range()].to_string();
238 if let Some(focus) = nav.focus_range() {
239 actual += "|";
240 actual += &file_text[focus];
241 }
244 242
245 let actual_full_range = &file_text[nav.full_range()]; 243 if !expected_range.contains("...") {
246 let actual_range = &file_text[nav.range()]; 244 test_utils::assert_eq_text!(&actual, expected_range);
245 } else {
246 let mut parts = expected_range.split("...");
247 let prefix = parts.next().unwrap();
248 let suffix = parts.next().unwrap();
249 assert!(
250 actual.starts_with(prefix) && actual.ends_with(suffix),
251 "\nExpected: {}\n Actual: {}\n",
252 expected_range,
253 actual
254 );
255 }
247 256
248 test_utils::assert_eq_text!(
249 &format!("{}|{}", actual_full_range, actual_range),
250 expected_range
251 );
252 nav.assert_match(expected); 257 nav.assert_match(expected);
253 } 258 }
254 259
255 #[test] 260 #[test]
256 fn goto_definition_works_in_items() { 261 fn goto_def_in_items() {
257 check_goto( 262 check_goto(
258 " 263 "
259 //- /lib.rs 264 //- /lib.rs
@@ -261,11 +266,12 @@ mod tests {
261 enum E { X(Foo<|>) } 266 enum E { X(Foo<|>) }
262 ", 267 ",
263 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", 268 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
269 "struct Foo;|Foo",
264 ); 270 );
265 } 271 }
266 272
267 #[test] 273 #[test]
268 fn goto_definition_works_at_start_of_item() { 274 fn goto_def_at_start_of_item() {
269 check_goto( 275 check_goto(
270 " 276 "
271 //- /lib.rs 277 //- /lib.rs
@@ -273,6 +279,7 @@ mod tests {
273 enum E { X(<|>Foo) } 279 enum E { X(<|>Foo) }
274 ", 280 ",
275 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", 281 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
282 "struct Foo;|Foo",
276 ); 283 );
277 } 284 }
278 285
@@ -285,61 +292,65 @@ mod tests {
285 mod a; 292 mod a;
286 mod b; 293 mod b;
287 enum E { X(Foo<|>) } 294 enum E { X(Foo<|>) }
295
288 //- /a.rs 296 //- /a.rs
289 struct Foo; 297 struct Foo;
298
290 //- /b.rs 299 //- /b.rs
291 struct Foo; 300 struct Foo;
292 ", 301 ",
293 "Foo STRUCT_DEF FileId(2) [0; 11) [7; 10)", 302 "Foo STRUCT_DEF FileId(2) [0; 11) [7; 10)",
303 "struct Foo;|Foo",
294 ); 304 );
295 } 305 }
296 306
297 #[test] 307 #[test]
298 fn goto_definition_works_for_module_declaration() { 308 fn goto_def_for_module_declaration() {
299 check_goto( 309 check_goto(
300 " 310 "
301 //- /lib.rs 311 //- /lib.rs
302 mod <|>foo; 312 mod <|>foo;
313
303 //- /foo.rs 314 //- /foo.rs
304 // empty 315 // empty
305 ", 316 ",
306 "foo SOURCE_FILE FileId(2) [0; 10)", 317 "foo SOURCE_FILE FileId(2) [0; 10)",
318 "// empty\n\n",
307 ); 319 );
308 320
309 check_goto( 321 check_goto(
310 " 322 "
311 //- /lib.rs 323 //- /lib.rs
312 mod <|>foo; 324 mod <|>foo;
325
313 //- /foo/mod.rs 326 //- /foo/mod.rs
314 // empty 327 // empty
315 ", 328 ",
316 "foo SOURCE_FILE FileId(2) [0; 10)", 329 "foo SOURCE_FILE FileId(2) [0; 10)",
330 "// empty\n\n",
317 ); 331 );
318 } 332 }
319 333
320 #[test] 334 #[test]
321 fn goto_definition_works_for_macros() { 335 fn goto_def_for_macros() {
322 covers!(goto_definition_works_for_macros); 336 covers!(goto_def_for_macros);
323 check_goto( 337 check_goto(
324 " 338 "
325 //- /lib.rs 339 //- /lib.rs
326 macro_rules! foo { 340 macro_rules! foo { () => { () } }
327 () => {
328 {}
329 };
330 }
331 341
332 fn bar() { 342 fn bar() {
333 <|>foo!(); 343 <|>foo!();
334 } 344 }
335 ", 345 ",
336 "foo MACRO_CALL FileId(1) [0; 50) [13; 16)", 346 "foo MACRO_CALL FileId(1) [0; 33) [13; 16)",
347 "macro_rules! foo { () => { () } }|foo",
337 ); 348 );
338 } 349 }
339 350
340 #[test] 351 #[test]
341 fn goto_definition_works_for_macros_from_other_crates() { 352 fn goto_def_for_macros_from_other_crates() {
342 covers!(goto_definition_works_for_macros); 353 covers!(goto_def_for_macros);
343 check_goto( 354 check_goto(
344 " 355 "
345 //- /lib.rs 356 //- /lib.rs
@@ -350,18 +361,15 @@ mod tests {
350 361
351 //- /foo/lib.rs 362 //- /foo/lib.rs
352 #[macro_export] 363 #[macro_export]
353 macro_rules! foo { 364 macro_rules! foo { () => { () } }
354 () => {
355 {}
356 };
357 }
358 ", 365 ",
359 "foo MACRO_CALL FileId(2) [0; 66) [29; 32)", 366 "foo MACRO_CALL FileId(2) [0; 49) [29; 32)",
367 "#[macro_export]\nmacro_rules! foo { () => { () } }|foo",
360 ); 368 );
361 } 369 }
362 370
363 #[test] 371 #[test]
364 fn goto_definition_works_for_macros_in_use_tree() { 372 fn goto_def_for_macros_in_use_tree() {
365 check_goto( 373 check_goto(
366 " 374 "
367 //- /lib.rs 375 //- /lib.rs
@@ -369,19 +377,16 @@ mod tests {
369 377
370 //- /foo/lib.rs 378 //- /foo/lib.rs
371 #[macro_export] 379 #[macro_export]
372 macro_rules! foo { 380 macro_rules! foo { () => { () } }
373 () => {
374 {}
375 };
376 }
377 ", 381 ",
378 "foo MACRO_CALL FileId(2) [0; 66) [29; 32)", 382 "foo MACRO_CALL FileId(2) [0; 49) [29; 32)",
383 "#[macro_export]\nmacro_rules! foo { () => { () } }|foo",
379 ); 384 );
380 } 385 }
381 386
382 #[test] 387 #[test]
383 fn goto_definition_works_for_macro_defined_fn_with_arg() { 388 fn goto_def_for_macro_defined_fn_with_arg() {
384 check_goto_with_range_content( 389 check_goto(
385 " 390 "
386 //- /lib.rs 391 //- /lib.rs
387 macro_rules! define_fn { 392 macro_rules! define_fn {
@@ -400,8 +405,8 @@ mod tests {
400 } 405 }
401 406
402 #[test] 407 #[test]
403 fn goto_definition_works_for_macro_defined_fn_no_arg() { 408 fn goto_def_for_macro_defined_fn_no_arg() {
404 check_goto_with_range_content( 409 check_goto(
405 " 410 "
406 //- /lib.rs 411 //- /lib.rs
407 macro_rules! define_fn { 412 macro_rules! define_fn {
@@ -420,27 +425,28 @@ mod tests {
420 } 425 }
421 426
422 #[test] 427 #[test]
423 fn goto_definition_works_for_methods() { 428 fn goto_def_for_methods() {
424 covers!(goto_definition_works_for_methods); 429 covers!(goto_def_for_methods);
425 check_goto( 430 check_goto(
426 " 431 "
427 //- /lib.rs 432 //- /lib.rs
428 struct Foo; 433 struct Foo;
429 impl Foo { 434 impl Foo {
430 fn frobnicate(&self) { } 435 fn frobnicate(&self) { }
431 } 436 }
432 437
433 fn bar(foo: &Foo) { 438 fn bar(foo: &Foo) {
434 foo.frobnicate<|>(); 439 foo.frobnicate<|>();
435 } 440 }
436 ", 441 ",
437 "frobnicate FN_DEF FileId(1) [27; 52) [30; 40)", 442 "frobnicate FN_DEF FileId(1) [27; 51) [30; 40)",
443 "fn frobnicate(&self) { }|frobnicate",
438 ); 444 );
439 } 445 }
440 446
441 #[test] 447 #[test]
442 fn goto_definition_works_for_fields() { 448 fn goto_def_for_fields() {
443 covers!(goto_definition_works_for_fields); 449 covers!(goto_def_for_fields);
444 check_goto( 450 check_goto(
445 " 451 "
446 //- /lib.rs 452 //- /lib.rs
@@ -453,12 +459,13 @@ mod tests {
453 } 459 }
454 ", 460 ",
455 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)", 461 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)",
462 "spam: u32|spam",
456 ); 463 );
457 } 464 }
458 465
459 #[test] 466 #[test]
460 fn goto_definition_works_for_record_fields() { 467 fn goto_def_for_record_fields() {
461 covers!(goto_definition_works_for_record_fields); 468 covers!(goto_def_for_record_fields);
462 check_goto( 469 check_goto(
463 " 470 "
464 //- /lib.rs 471 //- /lib.rs
@@ -473,6 +480,7 @@ mod tests {
473 } 480 }
474 ", 481 ",
475 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)", 482 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)",
483 "spam: u32|spam",
476 ); 484 );
477 } 485 }
478 486
@@ -489,29 +497,31 @@ mod tests {
489 } 497 }
490 ", 498 ",
491 "TUPLE_FIELD_DEF FileId(1) [11; 14)", 499 "TUPLE_FIELD_DEF FileId(1) [11; 14)",
500 "u32",
492 ); 501 );
493 } 502 }
494 503
495 #[test] 504 #[test]
496 fn goto_definition_works_for_ufcs_inherent_methods() { 505 fn goto_def_for_ufcs_inherent_methods() {
497 check_goto( 506 check_goto(
498 " 507 "
499 //- /lib.rs 508 //- /lib.rs
500 struct Foo; 509 struct Foo;
501 impl Foo { 510 impl Foo {
502 fn frobnicate() { } 511 fn frobnicate() { }
503 } 512 }
504 513
505 fn bar(foo: &Foo) { 514 fn bar(foo: &Foo) {
506 Foo::frobnicate<|>(); 515 Foo::frobnicate<|>();
507 } 516 }
508 ", 517 ",
509 "frobnicate FN_DEF FileId(1) [27; 47) [30; 40)", 518 "frobnicate FN_DEF FileId(1) [27; 46) [30; 40)",
519 "fn frobnicate() { }|frobnicate",
510 ); 520 );
511 } 521 }
512 522
513 #[test] 523 #[test]
514 fn goto_definition_works_for_ufcs_trait_methods_through_traits() { 524 fn goto_def_for_ufcs_trait_methods_through_traits() {
515 check_goto( 525 check_goto(
516 " 526 "
517 //- /lib.rs 527 //- /lib.rs
@@ -524,11 +534,12 @@ mod tests {
524 } 534 }
525 ", 535 ",
526 "frobnicate FN_DEF FileId(1) [16; 32) [19; 29)", 536 "frobnicate FN_DEF FileId(1) [16; 32) [19; 29)",
537 "fn frobnicate();|frobnicate",
527 ); 538 );
528 } 539 }
529 540
530 #[test] 541 #[test]
531 fn goto_definition_works_for_ufcs_trait_methods_through_self() { 542 fn goto_def_for_ufcs_trait_methods_through_self() {
532 check_goto( 543 check_goto(
533 " 544 "
534 //- /lib.rs 545 //- /lib.rs
@@ -543,6 +554,7 @@ mod tests {
543 } 554 }
544 ", 555 ",
545 "frobnicate FN_DEF FileId(1) [30; 46) [33; 43)", 556 "frobnicate FN_DEF FileId(1) [30; 46) [33; 43)",
557 "fn frobnicate();|frobnicate",
546 ); 558 );
547 } 559 }
548 560
@@ -559,6 +571,7 @@ mod tests {
559 } 571 }
560 ", 572 ",
561 "impl IMPL_BLOCK FileId(1) [12; 73)", 573 "impl IMPL_BLOCK FileId(1) [12; 73)",
574 "impl Foo {...}",
562 ); 575 );
563 576
564 check_goto( 577 check_goto(
@@ -572,6 +585,7 @@ mod tests {
572 } 585 }
573 ", 586 ",
574 "impl IMPL_BLOCK FileId(1) [12; 73)", 587 "impl IMPL_BLOCK FileId(1) [12; 73)",
588 "impl Foo {...}",
575 ); 589 );
576 590
577 check_goto( 591 check_goto(
@@ -585,6 +599,7 @@ mod tests {
585 } 599 }
586 ", 600 ",
587 "impl IMPL_BLOCK FileId(1) [15; 75)", 601 "impl IMPL_BLOCK FileId(1) [15; 75)",
602 "impl Foo {...}",
588 ); 603 );
589 604
590 check_goto( 605 check_goto(
@@ -597,6 +612,7 @@ mod tests {
597 } 612 }
598 ", 613 ",
599 "impl IMPL_BLOCK FileId(1) [15; 62)", 614 "impl IMPL_BLOCK FileId(1) [15; 62)",
615 "impl Foo {...}",
600 ); 616 );
601 } 617 }
602 618
@@ -616,6 +632,7 @@ mod tests {
616 } 632 }
617 ", 633 ",
618 "impl IMPL_BLOCK FileId(1) [49; 115)", 634 "impl IMPL_BLOCK FileId(1) [49; 115)",
635 "impl Make for Foo {...}",
619 ); 636 );
620 637
621 check_goto( 638 check_goto(
@@ -632,17 +649,19 @@ mod tests {
632 } 649 }
633 ", 650 ",
634 "impl IMPL_BLOCK FileId(1) [49; 115)", 651 "impl IMPL_BLOCK FileId(1) [49; 115)",
652 "impl Make for Foo {...}",
635 ); 653 );
636 } 654 }
637 655
638 #[test] 656 #[test]
639 fn goto_definition_works_when_used_on_definition_name_itself() { 657 fn goto_def_when_used_on_definition_name_itself() {
640 check_goto( 658 check_goto(
641 " 659 "
642 //- /lib.rs 660 //- /lib.rs
643 struct Foo<|> { value: u32 } 661 struct Foo<|> { value: u32 }
644 ", 662 ",
645 "Foo STRUCT_DEF FileId(1) [0; 25) [7; 10)", 663 "Foo STRUCT_DEF FileId(1) [0; 25) [7; 10)",
664 "struct Foo { value: u32 }|Foo",
646 ); 665 );
647 666
648 check_goto( 667 check_goto(
@@ -653,15 +672,16 @@ mod tests {
653 } 672 }
654 "#, 673 "#,
655 "field RECORD_FIELD_DEF FileId(1) [17; 30) [17; 22)", 674 "field RECORD_FIELD_DEF FileId(1) [17; 30) [17; 22)",
675 "field: string|field",
656 ); 676 );
657 677
658 check_goto( 678 check_goto(
659 " 679 "
660 //- /lib.rs 680 //- /lib.rs
661 fn foo_test<|>() { 681 fn foo_test<|>() { }
662 }
663 ", 682 ",
664 "foo_test FN_DEF FileId(1) [0; 17) [3; 11)", 683 "foo_test FN_DEF FileId(1) [0; 17) [3; 11)",
684 "fn foo_test() { }|foo_test",
665 ); 685 );
666 686
667 check_goto( 687 check_goto(
@@ -672,6 +692,7 @@ mod tests {
672 } 692 }
673 ", 693 ",
674 "Foo ENUM_DEF FileId(1) [0; 25) [5; 8)", 694 "Foo ENUM_DEF FileId(1) [0; 25) [5; 8)",
695 "enum Foo {...}|Foo",
675 ); 696 );
676 697
677 check_goto( 698 check_goto(
@@ -684,22 +705,25 @@ mod tests {
684 } 705 }
685 ", 706 ",
686 "Variant2 ENUM_VARIANT FileId(1) [29; 37) [29; 37)", 707 "Variant2 ENUM_VARIANT FileId(1) [29; 37) [29; 37)",
708 "Variant2|Variant2",
687 ); 709 );
688 710
689 check_goto( 711 check_goto(
690 r#" 712 r#"
691 //- /lib.rs 713 //- /lib.rs
692 static inner<|>: &str = ""; 714 static INNER<|>: &str = "";
693 "#, 715 "#,
694 "inner STATIC_DEF FileId(1) [0; 24) [7; 12)", 716 "INNER STATIC_DEF FileId(1) [0; 24) [7; 12)",
717 "static INNER: &str = \"\";|INNER",
695 ); 718 );
696 719
697 check_goto( 720 check_goto(
698 r#" 721 r#"
699 //- /lib.rs 722 //- /lib.rs
700 const inner<|>: &str = ""; 723 const INNER<|>: &str = "";
701 "#, 724 "#,
702 "inner CONST_DEF FileId(1) [0; 23) [6; 11)", 725 "INNER CONST_DEF FileId(1) [0; 23) [6; 11)",
726 "const INNER: &str = \"\";|INNER",
703 ); 727 );
704 728
705 check_goto( 729 check_goto(
@@ -708,24 +732,25 @@ mod tests {
708 type Thing<|> = Option<()>; 732 type Thing<|> = Option<()>;
709 "#, 733 "#,
710 "Thing TYPE_ALIAS_DEF FileId(1) [0; 24) [5; 10)", 734 "Thing TYPE_ALIAS_DEF FileId(1) [0; 24) [5; 10)",
735 "type Thing = Option<()>;|Thing",
711 ); 736 );
712 737
713 check_goto( 738 check_goto(
714 r#" 739 r#"
715 //- /lib.rs 740 //- /lib.rs
716 trait Foo<|> { 741 trait Foo<|> { }
717 }
718 "#, 742 "#,
719 "Foo TRAIT_DEF FileId(1) [0; 13) [6; 9)", 743 "Foo TRAIT_DEF FileId(1) [0; 13) [6; 9)",
744 "trait Foo { }|Foo",
720 ); 745 );
721 746
722 check_goto( 747 check_goto(
723 r#" 748 r#"
724 //- /lib.rs 749 //- /lib.rs
725 mod bar<|> { 750 mod bar<|> { }
726 }
727 "#, 751 "#,
728 "bar MODULE FileId(1) [0; 11) [4; 7)", 752 "bar MODULE FileId(1) [0; 11) [4; 7)",
753 "mod bar { }|bar",
729 ); 754 );
730 } 755 }
731 756
@@ -746,6 +771,7 @@ mod tests {
746 mod confuse_index { fn foo(); } 771 mod confuse_index { fn foo(); }
747 ", 772 ",
748 "foo FN_DEF FileId(1) [52; 63) [55; 58)", 773 "foo FN_DEF FileId(1) [52; 63) [55; 58)",
774 "fn foo() {}|foo",
749 ); 775 );
750 } 776 }
751 777
@@ -774,6 +800,7 @@ mod tests {
774 } 800 }
775 ", 801 ",
776 "foo FN_DEF FileId(1) [398; 415) [401; 404)", 802 "foo FN_DEF FileId(1) [398; 415) [401; 404)",
803 "fn foo() -> i8 {}|foo",
777 ); 804 );
778 } 805 }
779 806
@@ -787,6 +814,82 @@ mod tests {
787 } 814 }
788 ", 815 ",
789 "T TYPE_PARAM FileId(1) [11; 12)", 816 "T TYPE_PARAM FileId(1) [11; 12)",
817 "T",
790 ); 818 );
791 } 819 }
820
821 #[test]
822 fn goto_within_macro() {
823 check_goto(
824 "
825 //- /lib.rs
826 macro_rules! id {
827 ($($tt:tt)*) => ($($tt)*)
828 }
829
830 fn foo() {
831 let x = 1;
832 id!({
833 let y = <|>x;
834 let z = y;
835 });
836 }
837 ",
838 "x BIND_PAT FileId(1) [69; 70)",
839 "x",
840 );
841
842 check_goto(
843 "
844 //- /lib.rs
845 macro_rules! id {
846 ($($tt:tt)*) => ($($tt)*)
847 }
848
849 fn foo() {
850 let x = 1;
851 id!({
852 let y = x;
853 let z = <|>y;
854 });
855 }
856 ",
857 "y BIND_PAT FileId(1) [98; 99)",
858 "y",
859 );
860 }
861
862 #[test]
863 fn goto_def_in_local_fn() {
864 check_goto(
865 "
866 //- /lib.rs
867 fn main() {
868 fn foo() {
869 let x = 92;
870 <|>x;
871 }
872 }
873 ",
874 "x BIND_PAT FileId(1) [39; 40)",
875 "x",
876 );
877 }
878
879 #[test]
880 fn goto_def_for_field_init_shorthand() {
881 covers!(goto_def_for_field_init_shorthand);
882 check_goto(
883 "
884 //- /lib.rs
885 struct Foo { x: i32 }
886 fn main() {
887 let x = 92;
888 Foo { x<|> };
889 }
890 ",
891 "x RECORD_FIELD_DEF FileId(1) [13; 19) [13; 14)",
892 "x: i32|x",
893 )
894 }
792} 895}
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index 51e320128..a227bf546 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -250,7 +250,7 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
250 } else { 250 } else {
251 return None; 251 return None;
252 }; 252 };
253 Some(ty.display(db).to_string()) 253 Some(ty.display_truncated(db, None).to_string())
254} 254}
255 255
256#[cfg(test)] 256#[cfg(test)]
@@ -425,6 +425,23 @@ mod tests {
425 } 425 }
426 426
427 #[test] 427 #[test]
428 fn hover_omits_default_generic_types() {
429 check_hover_result(
430 r#"
431//- /main.rs
432struct Test<K, T = u8> {
433 k: K,
434 t: T,
435}
436
437fn main() {
438 let zz<|> = Test { t: 23, k: 33 };
439}"#,
440 &["Test<i32>"],
441 );
442 }
443
444 #[test]
428 fn hover_some() { 445 fn hover_some() {
429 let (analysis, position) = single_file_with_position( 446 let (analysis, position) = single_file_with_position(
430 " 447 "
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 3730121af..3154df457 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -160,6 +160,32 @@ mod tests {
160 use crate::mock_analysis::single_file; 160 use crate::mock_analysis::single_file;
161 161
162 #[test] 162 #[test]
163 fn default_generic_types_should_not_be_displayed() {
164 let (analysis, file_id) = single_file(
165 r#"
166struct Test<K, T = u8> {
167 k: K,
168 t: T,
169}
170
171fn main() {
172 let zz = Test { t: 23, k: 33 };
173}"#,
174 );
175
176 assert_debug_snapshot!(analysis.inlay_hints(file_id, None).unwrap(), @r###"
177 [
178 InlayHint {
179 range: [69; 71),
180 kind: TypeHint,
181 label: "Test<i32>",
182 },
183 ]
184 "###
185 );
186 }
187
188 #[test]
163 fn let_statement() { 189 fn let_statement() {
164 let (analysis, file_id) = single_file( 190 let (analysis, file_id) = single_file(
165 r#" 191 r#"
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..657c7b21a 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -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);
@@ -282,6 +281,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
282 281
283.comment { color: #7F9F7F; } 282.comment { color: #7F9F7F; }
284.string { color: #CC9393; } 283.string { color: #CC9393; }
284.field { color: #94BFF3; }
285.function { color: #93E0E3; } 285.function { color: #93E0E3; }
286.parameter { color: #94BFF3; } 286.parameter { color: #94BFF3; }
287.text { color: #DCDCCC; } 287.text { color: #DCDCCC; }
@@ -327,7 +327,8 @@ fn main() {
327 327
328 let mut vec = Vec::new(); 328 let mut vec = Vec::new();
329 if true { 329 if true {
330 vec.push(Foo { x: 0, y: 1 }); 330 let x = 92;
331 vec.push(Foo { x, y: 1 });
331 } 332 }
332 unsafe { vec.set_len(0); } 333 unsafe { vec.set_len(0); }
333 334