use expect_test::{Expect, expect}; use ide_db::{FileRange, MiniCore, base_db::SourceDatabase}; use syntax::TextRange; use crate::{ HoverConfig, HoverDocFormat, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, fixture, }; use hir::setup_tracing; const HOVER_BASE_CONFIG: HoverConfig<'_> = HoverConfig { links_in_hover: false, memory_layout: Some(MemoryLayoutHoverConfig { size: Some(MemoryLayoutHoverRenderKind::Both), offset: Some(MemoryLayoutHoverRenderKind::Both), alignment: Some(MemoryLayoutHoverRenderKind::Both), padding: Some(MemoryLayoutHoverRenderKind::Both), niches: true, }), documentation: true, format: HoverDocFormat::Markdown, keywords: true, max_trait_assoc_items_count: None, max_fields_count: Some(5), max_enum_variants_count: Some(5), max_subst_ty_len: super::SubstTyLen::Unlimited, show_drop_glue: true, minicore: MiniCore::default(), }; fn check_hover_no_result(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( &HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap(); assert!(hover.is_none(), "hover not expected but found: {:?}", hover.unwrap()); } #[track_caller] fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let _tracing = setup_tracing(); let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( &HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap() .unwrap(); let content = analysis.db.file_text(position.file_id); let hovered_element = &content.text(&analysis.db)[hover.range]; let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); expect.assert_eq(&actual) } #[track_caller] fn check_hover_fields_limit( fields_count: impl Into>, #[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect, ) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( &HoverConfig { links_in_hover: true, max_fields_count: fields_count.into(), ..HOVER_BASE_CONFIG }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap() .unwrap(); let content = analysis.db.file_text(position.file_id).text(&analysis.db); let hovered_element = &content[hover.range]; let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); expect.assert_eq(&actual) } #[track_caller] fn check_hover_enum_variants_limit( variants_count: impl Into>, #[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect, ) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( &HoverConfig { links_in_hover: true, max_enum_variants_count: variants_count.into(), ..HOVER_BASE_CONFIG }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap() .unwrap(); let content = analysis.db.file_text(position.file_id).text(&analysis.db); let hovered_element = &content[hover.range]; let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); expect.assert_eq(&actual) } #[track_caller] fn check_assoc_count( count: usize, #[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect, ) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( &HoverConfig { links_in_hover: true, max_trait_assoc_items_count: Some(count), ..HOVER_BASE_CONFIG }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap() .unwrap(); let content = analysis.db.file_text(position.file_id).text(&analysis.db); let hovered_element = &content[hover.range]; let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); expect.assert_eq(&actual) } fn check_hover_no_links(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( &HOVER_BASE_CONFIG, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap() .unwrap(); let content = analysis.db.file_text(position.file_id).text(&analysis.db); let hovered_element = &content[hover.range]; let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); expect.assert_eq(&actual) } fn check_hover_no_memory_layout(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( &HoverConfig { memory_layout: None, ..HOVER_BASE_CONFIG }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap() .unwrap(); let content = analysis.db.file_text(position.file_id).text(&analysis.db); let hovered_element = &content[hover.range]; let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); expect.assert_eq(&actual) } fn check_hover_no_markdown(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( &HoverConfig { links_in_hover: true, format: HoverDocFormat::PlainText, ..HOVER_BASE_CONFIG }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap() .unwrap(); let content = analysis.db.file_text(position.file_id).text(&analysis.db); let hovered_element = &content[hover.range]; let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); expect.assert_eq(&actual) } fn check_actions(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, file_id, position) = fixture::range_or_position(ra_fixture); let mut hover = analysis .hover( &HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, FileRange { file_id, range: position.range_or_empty() }, ) .unwrap() .unwrap(); // stub out ranges into minicore as they can change every now and then hover.info.actions.iter_mut().for_each(|action| match action { super::HoverAction::GoToType(act) => act.iter_mut().for_each(|data| { if data.nav.file_id == file_id { return; } data.nav.full_range = TextRange::empty(span::TextSize::new(!0)); if let Some(range) = &mut data.nav.focus_range { *range = TextRange::empty(span::TextSize::new(!0)); } }), _ => (), }); expect.assert_debug_eq(&hover.info.actions) } fn check_hover_range(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, range) = fixture::range(ra_fixture); let hover = analysis.hover(&HOVER_BASE_CONFIG, range).unwrap().unwrap(); expect.assert_eq(hover.info.markup.as_str()) } fn check_hover_range_actions(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, range) = fixture::range(ra_fixture); let mut hover = analysis .hover(&HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, range) .unwrap() .unwrap(); // stub out ranges into minicore as they can change every now and then hover.info.actions.iter_mut().for_each(|action| match action { super::HoverAction::GoToType(act) => act.iter_mut().for_each(|data| { if data.nav.file_id == range.file_id { return; } data.nav.full_range = TextRange::empty(span::TextSize::new(!0)); if let Some(range) = &mut data.nav.focus_range { *range = TextRange::empty(span::TextSize::new(!0)); } }), _ => (), }); expect.assert_debug_eq(&hover.info.actions); } fn check_hover_range_no_results(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, range) = fixture::range(ra_fixture); let hover = analysis.hover(&HOVER_BASE_CONFIG, range).unwrap(); assert!(hover.is_none()); } #[test] fn hover_descend_macros_avoids_duplicates() { check( r#" macro_rules! dupe_use { ($local:ident) => { { $local; $local; } } } fn foo() { let local = 0; dupe_use!(local$0); } "#, expect![[r#" *local* ```rust let local: i32 ``` "#]], ); } #[test] fn hover_shows_all_macro_descends() { check( r#" macro_rules! m { ($name:ident) => { /// Outer fn $name() {} mod module { /// Inner fn $name() {} } }; } m!(ab$0c); "#, expect![[r#" *abc* ```rust ra_test_fixture ``` ```rust fn abc() ``` --- Outer --- ```rust ra_test_fixture::module ``` ```rust fn abc() ``` --- Inner "#]], ); } #[test] fn hover_remove_markdown_if_configured() { check_hover_no_markdown( r#" pub fn foo() -> u32 { 1 } fn main() { let foo_test = foo$0(); } "#, expect![[r#" *foo* ra_test_fixture pub fn foo() -> u32 "#]], ); } #[test] fn hover_closure() { check( r#" //- minicore: copy, add, builtin_impls fn main() { let x = 2; let y = $0|z| x + z; } "#, expect![[r#" *|* ```rust impl Fn(i32) -> i32 ``` --- size = 8, align = 8, niches = 1 ## Captures * `x` by immutable borrow "#]], ); check( r#" //- minicore: copy fn foo(x: impl Fn(i32) -> i32) { } fn main() { foo($0|x: i32| x) } "#, expect![[r#" *|* ```rust impl Fn(i32) -> i32 ``` --- size = 0, align = 1 ## Captures This closure captures nothing "#]], ); check( r#" //- minicore: copy struct Z { f: i32 } struct Y(&'static mut Z) struct X { f1: Y, f2: (Y, Y), } fn main() { let x: X; let y = $0|| { x.f1; &mut x.f2.0 .0.f; }; } "#, expect![[r#" *|* ```rust impl FnOnce() ``` --- size = 16 (0x10), align = 8, niches = 1 ## Captures * `x.f1` by move * `(*x.f2.0.0).f` by mutable borrow "#]], ); check( r#" //- minicore: copy, option fn do_char(c: char) {} fn main() { let x = None; let y = |$0| { match x { Some(c) => do_char(c), None => x = None, } }; } "#, expect![[r#" *|* ```rust impl FnMut() ``` --- size = 8, align = 8, niches = 1 ## Captures * `x` by mutable borrow "#]], ); } #[test] fn hover_ranged_closure() { check_hover_range( r#" //- minicore: fn struct S; struct S2; fn main() { let x = &S; let y = ($0|| {x; S2}$0).call(); } "#, expect![[r#" ```rust impl FnOnce() -> S2 ``` --- size = 8, align = 8, niches = 1 Coerced to: &impl FnOnce() -> S2 ## Captures * `x` by move"#]], ); check_hover_range_actions( r#" //- minicore: fn struct S; struct S2; fn main() { let x = &S; let y = ($0|| {x; S2}$0).call(); } "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::S2", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 10..20, focus_range: 17..19, name: "S2", kind: Struct, description: "struct S2", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..9, focus_range: 7..8, name: "S", kind: Struct, description: "struct S", }, }, HoverGotoTypeData { mod_path: "core::ops::function::FnOnce", nav: NavigationTarget { file_id: FileId( 1, ), full_range: 4294967295..4294967295, focus_range: 4294967295..4294967295, name: "FnOnce", kind: Trait, container_name: "function", description: "pub trait FnOnce\nwhere\n Args: Tuple,", }, }, ], ), ] "#]], ); } #[test] fn hover_shows_long_type_of_an_expression() { check( r#" struct Scan { a: A, b: B, c: C } struct Iter { inner: I } enum Option { Some(T), None } struct OtherStruct { i: T } fn scan(a: A, b: B, c: C) -> Iter, B, C>> { Iter { inner: Scan { a, b, c } } } fn main() { let num: i32 = 55; let closure = |memo: &mut u32, value: &u32, _another: &mut u32| -> Option { Option::Some(*memo + value) }; let number = 5u32; let mut iter$0 = scan(OtherStruct { i: num }, closure, number); } "#, expect![[r#" *iter* ```rust let mut iter: Iter>, impl Fn(&mut u32, &u32, &mut u32) -> Option, u32>> ``` --- size = 8, align = 4, no Drop "#]], ); } #[test] fn hover_shows_fn_signature() { // Single file with result check( r#" pub fn foo() -> u32 { 1 } fn main() { let foo_test = fo$0o(); } "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust pub fn foo() -> u32 ``` "#]], ); // Use literal `crate` in path check( r#" pub struct X; fn foo() -> crate::X { X } fn main() { f$0oo(); } "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust fn foo() -> crate::X ``` "#]], ); // Check `super` in path check( r#" pub struct X; mod m { pub fn foo() -> super::X { super::X } } fn main() { m::f$0oo(); } "#, expect![[r#" *foo* ```rust ra_test_fixture::m ``` ```rust pub fn foo() -> super::X ``` "#]], ); } #[test] fn hover_omits_unnamed_where_preds() { check( r#" pub fn foo(bar: impl T) { } fn main() { fo$0o(); } "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust pub fn foo(bar: impl T) ``` "#]], ); check( r#" pub fn foo>(bar: impl T, baz: V) { } fn main() { fo$0o(); } "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust pub fn foo(bar: impl T, baz: V) where V: AsRef, ``` "#]], ); } #[test] fn hover_shows_fn_signature_with_type_params() { check( r#" pub fn foo<'a, T: AsRef>(b: &'a T) -> &'a str { } fn main() { let foo_test = fo$0o(); } "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust pub fn foo<'a, T>(b: &'a T) -> &'a str where T: AsRef, ``` "#]], ); } #[test] fn hover_shows_fn_signature_on_fn_name() { check( r#" pub fn foo$0(a: u32, b: u32) -> u32 {} fn main() { } "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust pub fn foo(a: u32, b: u32) -> u32 ``` "#]], ); } #[test] fn hover_shows_fn_doc() { check( r#" /// # Example /// ``` /// # use std::path::Path; /// # /// foo(Path::new("hello, world!")) /// ``` pub fn foo$0(_: &Path) {} fn main() { } "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust pub fn foo(_: &Path) ``` --- # Example ``` # use std::path::Path; # foo(Path::new("hello, world!")) ``` "#]], ); } #[test] fn hover_shows_fn_doc_attr_raw_string() { check( r##" #[doc = r#"Raw string doc attr"#] pub fn foo$0(_: &Path) {} fn main() { } "##, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust pub fn foo(_: &Path) ``` --- Raw string doc attr "#]], ); } #[test] fn hover_field_offset() { // Hovering over the field when instantiating check( r#" struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 } "#, expect![[r#" *field_a* ```rust ra_test_fixture::Foo ``` ```rust field_a: u8 ``` --- size = 1, align = 1, offset = 6, no Drop "#]], ); } #[test] fn hover_shows_struct_field_info() { // Hovering over the field when instantiating check( r#" struct Foo { pub field_a: u32 } fn main() { let foo = Foo { field_a$0: 0, }; } "#, expect![[r#" *field_a* ```rust ra_test_fixture::Foo ``` ```rust pub field_a: u32 ``` "#]], ); // Hovering over the field in the definition check( r#" struct Foo { pub field_a$0: u32 } fn main() { let foo = Foo { field_a: 0 }; } "#, expect![[r#" *field_a* ```rust ra_test_fixture::Foo ``` ```rust pub field_a: u32 ``` --- size = 4, align = 4, offset = 0, no Drop "#]], ); } #[test] fn hover_shows_tuple_struct_field_info() { check( r#" struct Foo(pub u32) fn main() { let foo = Foo { 0$0: 0, }; } "#, expect![[r#" *0* ```rust ra_test_fixture::Foo ``` ```rust pub 0: u32 ``` "#]], ); check( r#" struct Foo(pub u32) fn foo(foo: Foo) { foo.0$0; } "#, expect![[r#" *0* ```rust ra_test_fixture::Foo ``` ```rust pub 0: u32 ``` "#]], ); } #[test] fn hover_tuple_struct() { check( r#" struct Foo$0(pub u32) where u32: Copy; "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo(pub u32) where u32: Copy, ``` --- size = 4, align = 4, largest padding = 0, no Drop "#]], ); } #[test] fn hover_record_struct() { check( r#" struct Foo$0 { field: u32 } "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo { field: u32, } ``` --- size = 4, align = 4, largest padding = 0, no Drop "#]], ); check( r#" struct Foo$0 where u32: Copy { field: u32 } "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo where u32: Copy, { field: u32, } ``` --- size = 4, align = 4, largest padding = 0, no Drop "#]], ); } #[test] fn hover_record_struct_limit() { check_hover_fields_limit( 3, r#" struct Foo$0 { a: u32, b: i32, c: i32 } "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo { a: u32, b: i32, c: i32, } ``` --- size = 12 (0xC), align = 4, largest padding = 0, no Drop "#]], ); check_hover_fields_limit( 3, r#" struct Foo$0 { a: u32 } "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo { a: u32, } ``` --- size = 4, align = 4, largest padding = 0, no Drop "#]], ); check_hover_fields_limit( 3, r#" struct Foo$0 { a: u32, b: i32, c: i32, d: u32 } "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo { a: u32, b: i32, c: i32, /* … */ } ``` --- size = 16 (0x10), align = 4, largest padding = 0, no Drop "#]], ); check_hover_fields_limit( None, r#" struct Foo$0 { a: u32, b: i32, c: i32 } "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo ``` --- size = 12 (0xC), align = 4, largest padding = 0, no Drop "#]], ); check_hover_fields_limit( 0, r#" struct Foo$0 { a: u32, b: i32, c: i32 } "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo { /* … */ } ``` --- size = 12 (0xC), align = 4, largest padding = 0, no Drop "#]], ); // No extra spaces within `{}` when there are no fields check_hover_fields_limit( 5, r#" struct Foo$0 {} "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo {} ``` --- size = 0, align = 1, no Drop "#]], ); } #[test] fn hover_record_variant_limit() { check_hover_fields_limit( 3, r#" enum Foo { A$0 { a: u32, b: i32, c: i32 } } "#, expect![[r#" *A* ```rust ra_test_fixture::Foo ``` ```rust A { a: u32, b: i32, c: i32, } ``` --- size = 12 (0xC), align = 4, no Drop "#]], ); check_hover_fields_limit( 3, r#" enum Foo { A$0 { a: u32 } } "#, expect![[r#" *A* ```rust ra_test_fixture::Foo ``` ```rust A { a: u32, } ``` --- size = 4, align = 4, no Drop "#]], ); check_hover_fields_limit( 3, r#" enum Foo { A$0 { a: u32, b: i32, c: i32, d: u32 } } "#, expect![[r#" *A* ```rust ra_test_fixture::Foo ``` ```rust A { a: u32, b: i32, c: i32, /* … */ } ``` --- size = 16 (0x10), align = 4, no Drop "#]], ); check_hover_fields_limit( None, r#" enum Foo { A$0 { a: u32, b: i32, c: i32 } } "#, expect![[r#" *A* ```rust ra_test_fixture::Foo ``` ```rust A ``` --- size = 12 (0xC), align = 4, no Drop "#]], ); check_hover_fields_limit( 0, r#" enum Foo { A$0 { a: u32, b: i32, c: i32 } } "#, expect![[r#" *A* ```rust ra_test_fixture::Foo ``` ```rust A { /* … */ } ``` --- size = 12 (0xC), align = 4, no Drop "#]], ); } #[test] fn hover_enum_limit() { check_hover_enum_variants_limit( 5, r#"enum Foo$0 { A, B }"#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust enum Foo { A, B, } ``` --- size = 1, align = 1, niches = 254, no Drop "#]], ); check_hover_enum_variants_limit( 1, r#"enum Foo$0 { A, B }"#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust enum Foo { A, /* … */ } ``` --- size = 1, align = 1, niches = 254, no Drop "#]], ); check_hover_enum_variants_limit( 0, r#"enum Foo$0 { A, B }"#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust enum Foo { /* … */ } ``` --- size = 1, align = 1, niches = 254, no Drop "#]], ); check_hover_enum_variants_limit( None, r#"enum Foo$0 { A, B }"#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust enum Foo ``` --- size = 1, align = 1, niches = 254, no Drop "#]], ); check_hover_enum_variants_limit( 7, r#"enum Enum$0 { Variant {}, Variant2 { field: i32 }, Variant3 { field: i32, field2: i32 }, Variant4(), Variant5(i32), Variant6(i32, i32), Variant7, Variant8, }"#, expect![[r#" *Enum* ```rust ra_test_fixture ``` ```rust enum Enum { Variant {}, Variant2 { /* … */ }, Variant3 { /* … */ }, Variant4(), Variant5( /* … */ ), Variant6( /* … */ ), Variant7, /* … */ } ``` --- size = 12 (0xC), align = 4, niches = a lot, no Drop "#]], ); } #[test] fn hover_union_limit() { check_hover_fields_limit( 5, r#"union Foo$0 { a: u32, b: i32 }"#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust union Foo { a: u32, b: i32, } ``` --- size = 4, align = 4, no Drop "#]], ); check_hover_fields_limit( 1, r#"union Foo$0 { a: u32, b: i32 }"#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust union Foo { a: u32, /* … */ } ``` --- size = 4, align = 4, no Drop "#]], ); check_hover_fields_limit( 0, r#"union Foo$0 { a: u32, b: i32 }"#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust union Foo { /* … */ } ``` --- size = 4, align = 4, no Drop "#]], ); check_hover_fields_limit( None, r#"union Foo$0 { a: u32, b: i32 }"#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust union Foo ``` --- size = 4, align = 4, no Drop "#]], ); } #[test] fn hover_unit_struct() { check( r#" struct Foo$0 where u32: Copy; "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo where u32: Copy, ``` --- size = 0, align = 1, no Drop "#]], ); } #[test] fn hover_type_alias() { check( r#" type Fo$0o: Trait = S where T: Trait; "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust type Foo: Trait = S where T: Trait, ``` --- no Drop "#]], ); } #[test] fn hover_const_static() { check( r#"const foo$0: u32 = 123;"#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust const foo: u32 = 123 (0x7B) ``` "#]], ); check( r#" const foo$0: u32 = { let x = foo(); x + 100 };"#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust const foo: u32 = { let x = foo(); x + 100 } ``` "#]], ); check( r#"static foo$0: u32 = 456;"#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust static foo: u32 = 456 (0x1C8) ``` "#]], ); check( r#"const FOO$0: i32 = -2147483648;"#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: i32 = -2147483648 (0x80000000) ``` "#]], ); check( r#" const FOO: i32 = -2147483648; const BAR$0: bool = FOO > 0; "#, expect![[r#" *BAR* ```rust ra_test_fixture ``` ```rust const BAR: bool = false ``` "#]], ); } #[test] fn hover_unsigned_max_const() { check( r#"const $0A: u128 = -1_i128 as u128;"#, expect![[r#" *A* ```rust ra_test_fixture ``` ```rust const A: u128 = 340282366920938463463374607431768211455 (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) ``` "#]], ); } #[test] fn hover_eval_complex_constants() { check( r#" struct X { f1: (), f2: i32 } const foo$0: (i8, X, i64) = (1, X { f2: 5 - 1, f1: () }, 1 - 2); "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust const foo: (i8, X, i64) = (1, X { f1: (), f2: 4 }, -1) ``` "#]], ); } #[test] fn hover_default_generic_types() { check( r#" struct Test { k: K, t: T } fn main() { let zz$0 = Test { t: 23u8, k: 33 }; }"#, expect![[r#" *zz* ```rust let zz: Test ``` --- size = 8, align = 4, no Drop "#]], ); check_hover_range( r#" struct Test { k: K, t: T } fn main() { let $0zz$0 = Test { t: 23u8, k: 33 }; }"#, expect![[r#" ```rust Test ```"#]], ); } #[test] fn hover_some() { check( r#" enum Option { Some(T) } use Option::Some; fn main() { So$0me(12); } "#, expect![[r#" *Some* ```rust ra_test_fixture::Option ``` ```rust Some(T) ``` "#]], ); check( r#" enum Option { Some(T) } use Option::Some; fn main() { let b$0ar = Some(12); } "#, expect![[r#" *bar* ```rust let bar: Option ``` --- size = 4, align = 4, no Drop "#]], ); } #[test] fn hover_enum_variant() { check( r#" enum Option { Some(T) /// The None variant Non$0e } "#, expect![[r#" *None* ```rust ra_test_fixture::Option ``` ```rust None ``` --- no Drop --- The None variant "#]], ); check( r#" enum Option { /// The Some variant Some(T) } fn main() { let s = Option::Som$0e(12); } "#, expect![[r#" *Some* ```rust ra_test_fixture::Option ``` ```rust Some(T) ``` --- The Some variant "#]], ); } #[test] fn hover_for_local_variable() { check( r#"fn func(foo: i32) { fo$0o; }"#, expect![[r#" *foo* ```rust foo: i32 ``` "#]], ) } #[test] fn hover_for_local_variable_pat() { check( r#"fn func(fo$0o: i32) {}"#, expect![[r#" *foo* ```rust foo: i32 ``` --- size = 4, align = 4, no Drop "#]], ) } #[test] fn hover_local_var_edge() { check( r#"fn func(foo: i32) { if true { $0foo; }; }"#, expect![[r#" *foo* ```rust foo: i32 ``` "#]], ) } #[test] fn hover_for_param_edge() { check( r#"fn func($0foo: i32) {}"#, expect![[r#" *foo* ```rust foo: i32 ``` --- size = 4, align = 4, no Drop "#]], ) } #[test] fn hover_for_param_with_multiple_traits() { check( r#" //- minicore: sized trait Deref { type Target: ?Sized; } trait DerefMut { type Target: ?Sized; } fn f(_x$0: impl Deref + DerefMut) {}"#, expect![[r#" *_x* ```rust _x: impl Deref + DerefMut ``` --- type param may need Drop "#]], ) } #[test] fn test_hover_infer_associated_method_result() { check( r#" struct Thing { x: u32 } impl Thing { fn new() -> Thing { Thing { x: 0 } } } fn main() { let foo_$0test = Thing::new(); } "#, expect![[r#" *foo_test* ```rust let foo_test: Thing ``` --- size = 4, align = 4, no Drop "#]], ) } #[test] fn test_hover_infer_associated_method_exact() { check( r#" mod wrapper { pub struct Thing { x: u32 } impl Thing { pub fn new() -> Thing { Thing { x: 0 } } } } fn main() { let foo_test = wrapper::Thing::new$0(); } "#, expect![[r#" *new* ```rust ra_test_fixture::wrapper::Thing ``` ```rust pub fn new() -> Thing ``` "#]], ) } #[test] fn test_hover_infer_associated_const_in_pattern() { check( r#" struct X; impl X { const C: u32 = 1; } fn main() { match 1 { X::C$0 => {}, 2 => {}, _ => {} }; } "#, expect![[r#" *C* ```rust ra_test_fixture::X ``` ```rust const C: u32 = 1 ``` "#]], ) } #[test] fn test_hover_self() { check( r#" struct Thing { x: u32 } impl Thing { fn new() -> Self { Self$0 { x: 0 } } } "#, expect![[r#" *Self* ```rust ra_test_fixture ``` ```rust struct Thing { x: u32, } ``` --- size = 4, align = 4 "#]], ); check_hover_fields_limit( None, r#" struct Thing { x: u32 } impl Thing { fn new() -> Self$0 { Self { x: 0 } } } "#, expect![[r#" *Self* ```rust ra_test_fixture ``` ```rust struct Thing ``` --- size = 4, align = 4 "#]], ); check( r#" struct Thing { x: u32 } impl Thing { fn new() -> Self$0 { Self { x: 0 } } } "#, expect![[r#" *Self* ```rust ra_test_fixture ``` ```rust struct Thing { x: u32, } ``` --- size = 4, align = 4 "#]], ); check( r#" enum Thing { A } impl Thing { pub fn new() -> Self$0 { Thing::A } } "#, expect![[r#" *Self* ```rust ra_test_fixture ``` ```rust enum Thing { A, } ``` --- size = 0, align = 1 "#]], ); check( r#" enum Thing { A } impl Thing { pub fn thing(a: Self$0) {} } "#, expect![[r#" *Self* ```rust ra_test_fixture ``` ```rust enum Thing { A, } ``` --- size = 0, align = 1 "#]], ); check( r#" impl usize { pub fn thing(a: Self$0) {} } "#, expect![[r#" *Self* ```rust ra_test_fixture ``` ```rust usize ``` --- size = 8, align = 8 "#]], ); check( r#" impl fn() -> usize { pub fn thing(a: Self$0) {} } "#, expect![[r#" *Self* ```rust ra_test_fixture ``` ```rust fn() -> usize ``` --- size = 8, align = 8, niches = 1 "#]], ); check( r#" pub struct Foo where Self$0:; "#, expect![[r#" *Self* ```rust ra_test_fixture ``` ```rust pub struct Foo ``` --- size = 0, align = 1, no Drop "#]], ); } #[test] fn test_hover_shadowing_pat() { check( r#" fn x() {} fn y() { let x = 0i32; x$0; } "#, expect![[r#" *x* ```rust let x: i32 ``` "#]], ) } #[test] fn test_hover_macro_invocation() { check( r#" macro_rules! foo { (a) => {}; () => {} } fn f() { fo$0o!(); } "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust macro_rules! foo // matched arm #1 ``` "#]], ) } #[test] fn test_hover_macro2_invocation() { check( r#" /// foo bar /// /// foo bar baz macro foo() {} fn f() { fo$0o!(); } "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust macro foo // matched arm #0 ``` --- foo bar foo bar baz "#]], ) } #[test] fn test_hover_tuple_field() { check( r#"struct TS(String, i32$0);"#, expect![[r#" *i32* ```rust i32 ``` "#]], ) } #[test] fn test_hover_through_macro() { check( r#" macro_rules! id { ($($tt:tt)*) => { $($tt)* } } fn foo() {} id! { fn bar() { fo$0o(); } } "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust fn foo() ``` "#]], ); } #[test] fn test_hover_through_attr() { check( r#" //- proc_macros: identity #[proc_macros::identity] fn foo$0() {} "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust fn foo() ``` "#]], ); } #[test] fn test_hover_through_expr_in_macro() { check( r#" macro_rules! id { ($($tt:tt)*) => { $($tt)* } } fn foo(bar:u32) { let a = id!(ba$0r); } "#, expect![[r#" *bar* ```rust bar: u32 ``` "#]], ); } #[test] fn test_hover_through_expr_in_macro_recursive() { check( r#" macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } } macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } fn foo(bar:u32) { let a = id!(ba$0r); } "#, expect![[r#" *bar* ```rust bar: u32 ``` "#]], ); } #[test] fn test_hover_through_func_in_macro_recursive() { check( r#" macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } } macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } fn bar() -> u32 { 0 } fn foo() { let a = id!([0u32, bar$0()] ); } "#, expect![[r#" *bar* ```rust ra_test_fixture ``` ```rust fn bar() -> u32 ``` "#]], ); } #[test] fn test_hover_through_assert_macro() { check( r#" #[rustc_builtin_macro] macro_rules! assert {} fn bar() -> bool { true } fn foo() { assert!(ba$0r()); } "#, expect![[r#" *bar* ```rust ra_test_fixture ``` ```rust fn bar() -> bool ``` "#]], ); } #[test] fn test_hover_multiple_actions() { check_actions( r#" struct Bar; struct Foo { bar: Bar } fn foo(Foo { b$0ar }: &Foo) {} "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..11, focus_range: 7..10, name: "Bar", kind: Struct, description: "struct Bar", }, }, ], ), ] "#]], ) } #[test] fn test_hover_show_type_def_for_subst() { check_actions( r#" fn f(t: T) { } struct S; fn test() { let a = S; f$0(a); } "#, expect![[r#" [ Reference( FilePositionWrapper { file_id: FileId( 0, ), offset: 3, }, ), GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 20..29, focus_range: 27..28, name: "S", kind: Struct, description: "struct S", }, }, ], ), ] "#]], ); } #[test] fn test_hover_show_type_def_for_func_param() { check_actions( r#" struct Bar; fn f(b: Bar) { } fn test() { let b = Bar; f$0(b); } "#, expect![[r#" [ Reference( FilePositionWrapper { file_id: FileId( 0, ), offset: 15, }, ), GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..11, focus_range: 7..10, name: "Bar", kind: Struct, description: "struct Bar", }, }, ], ), ] "#]], ); } #[test] fn test_hover_show_type_def_for_trait_bound() { check_actions( r#" trait Bar {} fn f(b: T) { } fn test() { f$0(); } "#, expect![[r#" [ Reference( FilePositionWrapper { file_id: FileId( 0, ), offset: 16, }, ), GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..12, focus_range: 6..9, name: "Bar", kind: Trait, description: "trait Bar", }, }, ], ), ] "#]], ); } #[test] fn test_hover_non_ascii_space_doc() { check( " /// <- `\u{3000}` here fn foo() { } fn bar() { fo$0o(); } ", expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust fn foo() ``` --- \<- ` ` here "#]], ); } #[test] fn test_hover_function_show_qualifiers() { check( r#"async fn foo$0() {}"#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust async fn foo() ``` "#]], ); check( r#"pub const unsafe fn foo$0() {}"#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust pub const unsafe fn foo() ``` "#]], ); // Top level `pub(crate)` will be displayed as no visibility. check( r#"mod m { pub(crate) async unsafe extern "C" fn foo$0() {} }"#, expect![[r#" *foo* ```rust ra_test_fixture::m ``` ```rust pub(crate) async unsafe extern "C" fn foo() ``` "#]], ); } #[test] fn test_hover_function_show_types() { check( r#"fn foo$0(a: i32, b:i32) -> i32 { 0 }"#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust fn foo(a: i32, b: i32) -> i32 ``` "#]], ); } #[test] fn test_hover_function_associated_type_params() { check( r#" trait Foo { type Bar; } impl Foo for i32 { type Bar = i64; } fn foo(arg: ::Bar) {} fn main() { foo$0; } "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust fn foo(arg: ::Bar) ``` "#]], ); check( r#" trait Foo { type Bar; } impl Foo for i32 { type Bar = i32; } fn foo(arg: <>::Bar as Foo>::Bar) {} fn main() { foo$0; } "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust fn foo(arg: <>::Bar as Foo>::Bar) ``` "#]], ); } #[test] fn test_hover_function_pointer_show_identifiers() { check( r#"type foo$0 = fn(a: i32, b: i32) -> i32;"#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust type foo = fn(a: i32, b: i32) -> i32 ``` --- size = 8, align = 8, niches = 1, no Drop "#]], ); } #[test] fn test_hover_function_pointer_no_identifier() { check( r#"type foo$0 = fn(i32, _: i32) -> i32;"#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust type foo = fn(i32, i32) -> i32 ``` --- size = 8, align = 8, niches = 1, no Drop "#]], ); } #[test] fn test_hover_trait_show_qualifiers() { check_actions( r"unsafe trait foo$0() {}", expect![[r#" [ Implementation( FilePositionWrapper { file_id: FileId( 0, ), offset: 13, }, ), ] "#]], ); } #[test] fn test_hover_extern_crate() { check( r#" //- /main.rs crate:main deps:std //! Crate docs /// Decl docs! extern crate st$0d; //- /std/lib.rs crate:std //! Standard library for this test //! //! Printed? //! abc123 "#, expect![[r#" *std* ```rust main ``` ```rust extern crate std ``` --- Decl docs! Standard library for this test Printed? abc123 "#]], ); check( r#" //- /main.rs crate:main deps:std //! Crate docs /// Decl docs! extern crate std as ab$0c; //- /std/lib.rs crate:std //! Standard library for this test //! //! Printed? //! abc123 "#, expect![[r#" *abc* ```rust main ``` ```rust extern crate std as abc ``` --- Decl docs! Standard library for this test Printed? abc123 "#]], ); } #[test] fn test_hover_mod_with_same_name_as_function() { check( r#" use self::m$0y::Bar; mod my { pub struct Bar; } fn my() {} "#, expect![[r#" *my* ```rust ra_test_fixture ``` ```rust mod my ``` "#]], ); } #[test] fn test_hover_struct_doc_comment() { check( r#" /// This is an example /// multiline doc /// /// # Example /// /// ``` /// let five = 5; /// /// assert_eq!(6, my_crate::add_one(5)); /// ``` struct Bar; fn foo() { let bar = Ba$0r; } "#, expect![[r#" *Bar* ```rust ra_test_fixture ``` ```rust struct Bar ``` --- This is an example multiline doc # Example ``` let five = 5; assert_eq!(6, my_crate::add_one(5)); ``` "#]], ); } #[test] fn test_hover_struct_doc_attr() { check( r#" #[doc = "bar docs"] struct Bar; fn foo() { let bar = Ba$0r; } "#, expect![[r#" *Bar* ```rust ra_test_fixture ``` ```rust struct Bar ``` --- bar docs "#]], ); } #[test] fn test_hover_struct_doc_attr_multiple_and_mixed() { check( r#" /// bar docs 0 #[doc = "bar docs 1"] #[doc = "bar docs 2"] struct Bar; fn foo() { let bar = Ba$0r; } "#, expect![[r#" *Bar* ```rust ra_test_fixture ``` ```rust struct Bar ``` --- bar docs 0 bar docs 1 bar docs 2 "#]], ); } #[test] fn test_hover_external_url() { check( r#" pub struct Foo; /// [external](https://www.google.com) pub struct B$0ar "#, expect![[r#" *Bar* ```rust ra_test_fixture ``` ```rust pub struct Bar ``` --- size = 0, align = 1, no Drop --- [external](https://www.google.com) "#]], ); } // Check that we don't rewrite links which we can't identify #[test] fn test_hover_unknown_target() { check( r#" pub struct Foo; /// [baz](Baz) pub struct B$0ar "#, expect![[r#" *Bar* ```rust ra_test_fixture ``` ```rust pub struct Bar ``` --- size = 0, align = 1, no Drop --- [baz](Baz) "#]], ); } #[test] fn test_hover_no_links() { check_hover_no_links( r#" /// Test cases: /// case 1. bare URL: https://www.example.com/ /// case 2. inline URL with title: [example](https://www.example.com/) /// case 3. code reference: [`Result`] /// case 4. code reference but miss footnote: [`String`] /// case 5. autolink: /// case 6. email address: /// case 7. reference: [example][example] /// case 8. collapsed link: [example][] /// case 9. shortcut link: [example] /// case 10. inline without URL: [example]() /// case 11. reference: [foo][foo] /// case 12. reference: [foo][bar] /// case 13. collapsed link: [foo][] /// case 14. shortcut link: [foo] /// case 15. inline without URL: [foo]() /// case 16. just escaped text: \[foo] /// case 17. inline link: [Foo](foo::Foo) /// /// [`Result`]: ../../std/result/enum.Result.html /// [^example]: https://www.example.com/ pub fn fo$0o() {} "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust pub fn foo() ``` --- Test cases: case 1. bare URL: https://www.example.com/ case 2. inline URL with title: [example](https://www.example.com/) case 3. code reference: `Result` case 4. code reference but miss footnote: `String` case 5. autolink: http://www.example.com/ case 6. email address: test@example.com case 7. reference: example case 8. collapsed link: example case 9. shortcut link: example case 10. inline without URL: example case 11. reference: foo case 12. reference: foo case 13. collapsed link: foo case 14. shortcut link: foo case 15. inline without URL: foo case 16. just escaped text: \[foo\] case 17. inline link: Foo [^example]: https://www.example.com/ "#]], ); } #[test] fn test_hover_layout_of_variant() { check( r#"enum Foo { Va$0riant1(u8, u16), Variant2(i32, u8, i64), }"#, expect![[r#" *Variant1* ```rust ra_test_fixture::Foo ``` ```rust Variant1(u8, u16) ``` --- size = 4, align = 2, no Drop "#]], ); } #[test] fn test_hover_layout_of_variant_generic() { check( r#"enum Option { Some(T), None$0 }"#, expect![[r#" *None* ```rust ra_test_fixture::Option ``` ```rust None ``` --- no Drop "#]], ); } #[test] fn test_hover_layout_generic_unused() { check( r#" //- minicore: phantom_data struct S$0(core::marker::PhantomData); "#, expect![[r#" *S* ```rust ra_test_fixture ``` ```rust struct S(PhantomData) ``` --- size = 0, align = 1, largest padding = 0, no Drop "#]], ); } #[test] fn test_hover_layout_of_enum() { check( r#"enum $0Foo { Variant1(u8, u16), Variant2(i32, u8, i64), }"#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust enum Foo { Variant1( /* … */ ), Variant2( /* … */ ), } ``` --- size = 16 (0x10), align = 8, niches = 254, no Drop "#]], ); } #[test] fn test_hover_layout_padding_info() { check( r#"struct $0Foo { x: bool, y: i64, z: u32, }"#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo { x: bool, y: i64, z: u32, } ``` --- size = 16 (0x10), align = 8, largest padding = 3, niches = 254, no Drop "#]], ); check( r#"#[repr(align(32))] struct $0Foo { x: bool, y: i64, z: u32, }"#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo { x: bool, y: i64, z: u32, } ``` --- size = 32 (0x20), align = 32 (0x20), largest padding = 19 (0x13), niches = 254, no Drop "#]], ); check( r#"#[repr(C)] struct $0Foo { x: bool, y: i64, z: u32, }"#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo { x: bool, y: i64, z: u32, } ``` --- size = 24 (0x18), align = 8, tail padding = 4, niches = 254, no Drop "#]], ); check( r#"struct $0Foo(i16, u128, u64)"#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo(i16, u128, u64) ``` --- size = 32 (0x20), align = 8, largest padding = 6, no Drop "#]], ); } #[test] fn test_hover_no_memory_layout() { check_hover_no_memory_layout( r#"struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 }"#, expect![[r#" *field_a* ```rust ra_test_fixture::Foo ``` ```rust field_a: u8 ``` --- no Drop "#]], ); check_hover_no_memory_layout( r#" //- minicore: copy, add, builtin_impls fn main() { let x = 2; let y = $0|z| x + z; } "#, expect![[r#" *|* ```rust impl Fn(i32) -> i32 ``` ## Captures * `x` by immutable borrow "#]], ); } #[test] fn test_hover_macro_generated_struct_fn_doc_comment() { cov_mark::check!(hover_macro_generated_struct_fn_doc_comment); check( r#" macro_rules! bar { () => { struct Bar; impl Bar { /// Do the foo fn foo(&self) {} } } } bar!(); fn foo() { let bar = Bar; bar.fo$0o(); } "#, expect![[r#" *foo* ```rust ra_test_fixture::Bar ``` ```rust fn foo(&self) ``` --- Do the foo "#]], ); } #[test] fn test_hover_macro_generated_struct_fn_doc_attr() { cov_mark::check!(hover_macro_generated_struct_fn_doc_attr); check( r#" macro_rules! bar { () => { struct Bar; impl Bar { #[doc = "Do the foo"] fn foo(&self) {} } } } bar!(); fn foo() { let bar = Bar; bar.fo$0o(); } "#, expect![[r#" *foo* ```rust ra_test_fixture::Bar ``` ```rust fn foo(&self) ``` --- Do the foo "#]], ); } #[test] fn test_hover_variadic_function() { check( r#" extern "C" { pub fn foo(bar: i32, ...) -> i32; } fn main() { let foo_test = unsafe { fo$0o(1, 2, 3); } } "#, expect![[r#" *foo* ```rust ra_test_fixture:: ``` ```rust pub unsafe fn foo(bar: i32, ...) -> i32 ``` "#]], ); } #[test] fn test_hover_trait_has_impl_action() { check_actions( r#"trait foo$0() {}"#, expect![[r#" [ Implementation( FilePositionWrapper { file_id: FileId( 0, ), offset: 6, }, ), ] "#]], ); } #[test] fn test_hover_struct_has_impl_action() { check_actions( r"struct foo$0() {}", expect![[r#" [ Implementation( FilePositionWrapper { file_id: FileId( 0, ), offset: 7, }, ), ] "#]], ); } #[test] fn test_hover_union_has_impl_action() { check_actions( r#"union foo$0() {}"#, expect![[r#" [ Implementation( FilePositionWrapper { file_id: FileId( 0, ), offset: 6, }, ), ] "#]], ); } #[test] fn test_hover_enum_has_impl_action() { check_actions( r"enum foo$0() { A, B }", expect![[r#" [ Implementation( FilePositionWrapper { file_id: FileId( 0, ), offset: 5, }, ), ] "#]], ); } #[test] fn test_hover_self_has_impl_action() { check_actions( r#"struct foo where Self$0:;"#, expect![[r#" [ Implementation( FilePositionWrapper { file_id: FileId( 0, ), offset: 7, }, ), ] "#]], ); } #[test] fn test_hover_test_has_action() { check_actions( r#" #[test] fn foo_$0test() {} "#, expect![[r#" [ Reference( FilePositionWrapper { file_id: FileId( 0, ), offset: 11, }, ), Runnable( Runnable { use_name_in_title: false, nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..24, focus_range: 11..19, name: "foo_test", kind: Function, }, kind: Test { test_id: Path( "foo_test", ), attr: TestAttr { ignore: false, }, }, cfg: None, update_test: UpdateTest { expect_test: false, insta: false, snapbox: false, }, }, ), ] "#]], ); } #[test] fn test_hover_test_mod_has_action() { check_actions( r#" mod tests$0 { #[test] fn foo_test() {} } "#, expect![[r#" [ Runnable( Runnable { use_name_in_title: false, nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..46, focus_range: 4..9, name: "tests", kind: Module, description: "mod tests", }, kind: TestMod { path: "tests", }, cfg: None, update_test: UpdateTest { expect_test: false, insta: false, snapbox: false, }, }, ), ] "#]], ); } #[test] fn test_hover_struct_has_goto_type_action() { check_actions( r#" struct S{ f1: u32 } fn main() { let s$0t = S{ f1:0 }; } "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..19, focus_range: 7..8, name: "S", kind: Struct, description: "struct S", }, }, ], ), ] "#]], ); } #[test] fn test_hover_generic_struct_has_goto_type_actions() { check_actions( r#" struct Arg(u32); struct S{ f1: T } fn main() { let s$0t = S{ f1:Arg(0) }; } "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Arg", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..16, focus_range: 7..10, name: "Arg", kind: Struct, description: "struct Arg(u32)", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 17..37, focus_range: 24..25, name: "S", kind: Struct, description: "struct S", }, }, ], ), ] "#]], ); } #[test] fn test_hover_generic_excludes_sized_go_to_action() { check_actions( r#" //- minicore: sized struct S(T); "#, expect![[r#" [] "#]], ); } #[test] fn test_hover_generic_struct_has_flattened_goto_type_actions() { check_actions( r#" struct Arg(u32); struct S{ f1: T } fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; } "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Arg", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..16, focus_range: 7..10, name: "Arg", kind: Struct, description: "struct Arg(u32)", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 17..37, focus_range: 24..25, name: "S", kind: Struct, description: "struct S", }, }, ], ), ] "#]], ); } #[test] fn test_hover_tuple_has_goto_type_actions() { check_actions( r#" struct A(u32); struct B(u32); mod M { pub struct C(u32); } fn main() { let s$0t = (A(1), B(2), M::C(3) ); } "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::A", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..14, focus_range: 7..8, name: "A", kind: Struct, description: "struct A(u32)", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::B", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 15..29, focus_range: 22..23, name: "B", kind: Struct, description: "struct B(u32)", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::M::C", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 42..60, focus_range: 53..54, name: "C", kind: Struct, container_name: "M", description: "pub struct C(u32)", }, }, ], ), ] "#]], ); } #[test] fn test_hover_return_impl_trait_has_goto_type_action() { check_actions( r#" trait Foo {} fn foo() -> impl Foo {} fn main() { let s$0t = foo(); } "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..12, focus_range: 6..9, name: "Foo", kind: Trait, description: "trait Foo", }, }, ], ), ] "#]], ); } #[test] fn test_hover_generic_return_impl_trait_has_goto_type_action() { check_actions( r#" trait Foo {} struct S; fn foo() -> impl Foo {} fn main() { let s$0t = foo(); } "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..15, focus_range: 6..9, name: "Foo", kind: Trait, description: "trait Foo", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 16..25, focus_range: 23..24, name: "S", kind: Struct, description: "struct S", }, }, ], ), ] "#]], ); } #[test] fn test_hover_return_impl_traits_has_goto_type_action() { check_actions( r#" trait Foo {} trait Bar {} fn foo() -> impl Foo + Bar {} fn main() { let s$0t = foo(); } "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 13..25, focus_range: 19..22, name: "Bar", kind: Trait, description: "trait Bar", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..12, focus_range: 6..9, name: "Foo", kind: Trait, description: "trait Foo", }, }, ], ), ] "#]], ); } #[test] fn test_hover_generic_return_impl_traits_has_goto_type_action() { check_actions( r#" trait Foo {} trait Bar {} struct S1 {} struct S2 {} fn foo() -> impl Foo + Bar {} fn main() { let s$0t = foo(); } "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 16..31, focus_range: 22..25, name: "Bar", kind: Trait, description: "trait Bar", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..15, focus_range: 6..9, name: "Foo", kind: Trait, description: "trait Foo", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::S1", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 32..44, focus_range: 39..41, name: "S1", kind: Struct, description: "struct S1", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::S2", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 45..57, focus_range: 52..54, name: "S2", kind: Struct, description: "struct S2", }, }, ], ), ] "#]], ); } #[test] fn test_hover_arg_impl_trait_has_goto_type_action() { check_actions( r#" trait Foo {} fn foo(ar$0g: &impl Foo) {} "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..12, focus_range: 6..9, name: "Foo", kind: Trait, description: "trait Foo", }, }, ], ), ] "#]], ); } #[test] fn test_hover_arg_impl_traits_has_goto_type_action() { check_actions( r#" trait Foo {} trait Bar {} struct S{} fn foo(ar$0g: &impl Foo + Bar) {} "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 13..28, focus_range: 19..22, name: "Bar", kind: Trait, description: "trait Bar", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..12, focus_range: 6..9, name: "Foo", kind: Trait, description: "trait Foo", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 29..39, focus_range: 36..37, name: "S", kind: Struct, description: "struct S", }, }, ], ), ] "#]], ); } #[test] fn test_hover_async_block_impl_trait_has_goto_type_action() { check_actions( r#" //- /main.rs crate:main deps:core // we don't use minicore here so that this test doesn't randomly fail // when someone edits minicore struct S; fn foo() { let fo$0o = async { S }; } //- /core.rs crate:core #![feature(lang_items)] pub mod future { #[lang = "future_trait"] pub trait Future {} } "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "core::future::Future", nav: NavigationTarget { file_id: FileId( 1, ), full_range: 4294967295..4294967295, focus_range: 4294967295..4294967295, name: "Future", kind: Trait, container_name: "future", description: "pub trait Future", }, }, HoverGotoTypeData { mod_path: "main::S", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..110, focus_range: 108..109, name: "S", kind: Struct, description: "struct S", }, }, ], ), ] "#]], ); } #[test] fn test_hover_arg_generic_impl_trait_has_goto_type_action() { check_actions( r#" trait Foo {} struct S {} fn foo(ar$0g: &impl Foo) {} "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..15, focus_range: 6..9, name: "Foo", kind: Trait, description: "trait Foo", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 16..27, focus_range: 23..24, name: "S", kind: Struct, description: "struct S", }, }, ], ), ] "#]], ); } #[test] fn test_hover_dyn_return_has_goto_type_action() { check_actions( r#" trait Foo {} struct S; impl Foo for S {} struct B{} fn foo() -> B> {} fn main() { let s$0t = foo(); } "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::B", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 48..61, focus_range: 55..56, name: "B", kind: Struct, description: "struct B", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..15, focus_range: 6..9, name: "Foo", kind: Trait, description: "trait Foo", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 16..25, focus_range: 23..24, name: "S", kind: Struct, description: "struct S", }, }, ], ), ] "#]], ); } #[test] fn test_hover_dyn_arg_has_goto_type_action() { check_actions( r#" trait Foo {} fn foo(ar$0g: &dyn Foo) {} "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..12, focus_range: 6..9, name: "Foo", kind: Trait, description: "trait Foo", }, }, ], ), ] "#]], ); } #[test] fn test_hover_generic_dyn_arg_has_goto_type_action() { check_actions( r#" trait Foo {} struct S {} fn foo(ar$0g: &dyn Foo) {} "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..15, focus_range: 6..9, name: "Foo", kind: Trait, description: "trait Foo", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 16..27, focus_range: 23..24, name: "S", kind: Struct, description: "struct S", }, }, ], ), ] "#]], ); } #[test] fn test_hover_goto_type_action_links_order() { check_actions( r#" trait ImplTrait {} trait DynTrait {} struct B {} struct S {} fn foo(a$0rg: &impl ImplTrait>>>) {} "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::B", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 43..57, focus_range: 50..51, name: "B", kind: Struct, description: "struct B", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::DynTrait", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 22..42, focus_range: 28..36, name: "DynTrait", kind: Trait, description: "trait DynTrait", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::ImplTrait", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..21, focus_range: 6..15, name: "ImplTrait", kind: Trait, description: "trait ImplTrait", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 58..69, focus_range: 65..66, name: "S", kind: Struct, description: "struct S", }, }, ], ), ] "#]], ); } #[test] fn test_hover_associated_type_has_goto_type_action() { check_actions( r#" trait Foo { type Item; fn get(self) -> Self::Item {} } struct Bar{} struct S{} impl Foo for S { type Item = Bar; } fn test() -> impl Foo { S {} } fn main() { let s$0t = test().get(); } "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..62, focus_range: 6..9, name: "Foo", kind: Trait, description: "trait Foo", }, }, ], ), ] "#]], ); } #[test] fn test_hover_const_param_has_goto_type_action() { check_actions( r#" struct Bar; struct Foo; impl Foo {} "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..11, focus_range: 7..10, name: "Bar", kind: Struct, description: "struct Bar", }, }, ], ), ] "#]], ); } #[test] fn test_hover_type_param_has_goto_type_action() { check_actions( r#" trait Foo {} fn foo(t: T$0){} "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..12, focus_range: 6..9, name: "Foo", kind: Trait, description: "trait Foo", }, }, ], ), ] "#]], ); } #[test] fn test_hover_self_has_go_to_type() { check_actions( r#" struct Foo; impl Foo { fn foo(&self$0) {} } "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..11, focus_range: 7..10, name: "Foo", kind: Struct, description: "struct Foo", }, }, ], ), ] "#]], ); } #[test] fn hover_displays_normalized_crate_names() { check( r#" //- /lib.rs crate:name-with-dashes pub mod wrapper { pub struct Thing { x: u32 } impl Thing { pub fn new() -> Thing { Thing { x: 0 } } } } //- /main.rs crate:main deps:name-with-dashes fn main() { let foo_test = name_with_dashes::wrapper::Thing::new$0(); } "#, expect![[r#" *new* ```rust name_with_dashes::wrapper::Thing ``` ```rust pub fn new() -> Thing ``` "#]], ) } #[test] fn hover_field_pat_shorthand_ref_match_ergonomics() { check( r#" struct S { f: i32, } fn main() { let s = S { f: 0 }; let S { f$0 } = &s; } "#, expect![[r#" *f* ```rust let f: &i32 ``` --- size = 8, align = 8, niches = 1, no Drop --- ```rust ra_test_fixture::S ``` ```rust f: i32 ``` --- size = 4, align = 4, offset = 0, no Drop "#]], ); } #[test] fn const_generic_order() { check( r#" struct Foo; struct S$0T(T); "#, expect![[r#" *ST* ```rust ra_test_fixture ``` ```rust struct ST(T) ``` --- size = 0, align = 1, type param may need Drop "#]], ); } #[test] fn const_generic_default_value() { check( r#" struct Foo; struct S$0T(T); "#, expect![[r#" *ST* ```rust ra_test_fixture ``` ```rust struct ST(T) ``` --- size = 0, align = 1, type param may need Drop "#]], ); } #[test] fn const_generic_default_value_2() { check( r#" struct Foo; const VAL = 1; struct S$0T(T); "#, expect![[r#" *ST* ```rust ra_test_fixture ``` ```rust struct ST(T) ``` --- size = 0, align = 1, type param may need Drop "#]], ); } #[test] fn const_generic_positive_i8_literal() { check( r#" struct Const; fn main() { let v$0alue = Const::<1>; } "#, expect![[r#" *value* ```rust let value: Const<1> ``` --- size = 0, align = 1, no Drop "#]], ); } #[test] fn const_generic_zero_i8_literal() { check( r#" struct Const; fn main() { let v$0alue = Const::<0>; } "#, expect![[r#" *value* ```rust let value: Const<0> ``` --- size = 0, align = 1, no Drop "#]], ); } #[test] fn const_generic_negative_i8_literal() { check( r#" struct Const; fn main() { let v$0alue = Const::<-1>; } "#, expect![[r#" *value* ```rust let value: Const<-1> ``` --- size = 0, align = 1, no Drop "#]], ); } #[test] fn const_generic_bool_literal() { check( r#" struct Const; fn main() { let v$0alue = Const::; } "#, expect![[r#" *value* ```rust let value: Const ``` --- size = 0, align = 1, no Drop "#]], ); } #[test] fn const_generic_char_literal() { check( r#" struct Const; fn main() { let v$0alue = Const::<'🦀'>; } "#, expect![[r#" *value* ```rust let value: Const<'🦀'> ``` --- size = 0, align = 1, no Drop "#]], ); } #[test] fn const_generic_negative_literal_macro_expansion() { // Test that negative literals work correctly in const generics // when used through macro expansion. This ensures the transcriber // doesn't wrap negative literals in parentheses, which would create // invalid syntax like Foo::<(-1)> instead of Foo::<-1>. check( r#" struct Foo { pub value: i16, } impl Foo { pub fn new(value: i16) -> Self { Self { value } } } macro_rules! create_foo { ($val:expr) => { Foo::<$val>::new($val) }; } fn main() { let v$0alue = create_foo!(-1); } "#, expect![[r#" *value* ```rust let value: Foo<-1> ``` --- size = 2, align = 2, no Drop "#]], ); } #[test] fn hover_self_param_shows_type() { check( r#" struct Foo {} impl Foo { fn bar(&sel$0f) {} } "#, expect![[r#" *self* ```rust self: &Foo ``` --- size = 8, align = 8, niches = 1, no Drop "#]], ); } #[test] fn hover_self_param_shows_type_for_arbitrary_self_type() { check( r#" struct Arc(T); struct Foo {} impl Foo { fn bar(sel$0f: Arc) {} } "#, expect![[r#" *self* ```rust self: Arc ``` --- size = 0, align = 1, no Drop "#]], ); } #[test] fn hover_doc_outer_inner() { check( r#" /// Be quick; mod Foo$0 { //! time is mana /// This comment belongs to the function fn foo() {} } "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust mod Foo ``` --- Be quick; time is mana "#]], ); } #[test] fn hover_doc_outer_inner_attribute() { check( r#" #[doc = "Be quick;"] mod Foo$0 { #![doc = "time is mana"] #[doc = "This comment belongs to the function"] fn foo() {} } "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust mod Foo ``` --- Be quick; time is mana "#]], ); } #[test] fn hover_doc_block_style_indent_end() { check( r#" /** foo ```rust let x = 3; ``` */ fn foo$0() {} "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust fn foo() ``` --- foo ```rust let x = 3; ``` "#]], ); } #[test] fn hover_comments_dont_highlight_parent() { cov_mark::check!(no_highlight_on_comment_hover); check_hover_no_result( r#" fn no_hover() { // no$0hover } "#, ); } #[test] fn hover_label() { check( r#" fn foo() { 'label$0: loop {} } "#, expect![[r#" *'label* ```rust 'label ``` "#]], ); } #[test] fn hover_lifetime() { check( r#"fn foo<'lifetime>(_: &'lifetime$0 ()) {}"#, expect![[r#" *'lifetime* ```rust ra_test_fixture::foo ``` ```rust 'lifetime ``` "#]], ); check( r#"fn foo(_: &'static$0 ()) {}"#, expect![[r#" *'static* ```rust 'static ``` "#]], ); } #[test] fn hover_type_param() { check( r#" //- minicore: sized struct Foo(T); trait TraitA {} trait TraitB {} impl Foo where T: Sized {} "#, expect![[r#" *T* ```rust ra_test_fixture::Foo ``` ```rust T: TraitA + TraitB ``` "#]], ); check( r#" //- minicore: sized struct Foo(T); impl Foo {} "#, expect![[r#" *T* ```rust ra_test_fixture::Foo ``` ```rust T ``` "#]], ); check( r#" //- minicore: sized struct Foo(T); impl Foo {} "#, expect![[r#" *T* ```rust ra_test_fixture::Foo ``` ```rust T: 'static ``` "#]], ); } #[test] fn hover_type_param_sized_bounds() { // implicit `: Sized` bound check( r#" //- minicore: sized trait Trait {} struct Foo(T); impl Foo {} "#, expect![[r#" *T* ```rust ra_test_fixture::Foo ``` ```rust T: Trait ``` "#]], ); check( r#" //- minicore: sized trait Trait {} struct Foo(T); impl Foo {} "#, expect![[r#" *T* ```rust ra_test_fixture::Foo ``` ```rust T: Trait + ?Sized ``` "#]], ); } mod type_param_sized_bounds { use super::*; #[test] fn single_implicit() { check( r#" //- minicore: sized fn foo() {} "#, expect![[r#" *T* ```rust ra_test_fixture::foo ``` ```rust T ``` --- invariant "#]], ); } #[test] fn single_explicit() { check( r#" //- minicore: sized fn foo() {} "#, expect![[r#" *T* ```rust ra_test_fixture::foo ``` ```rust T ``` --- invariant "#]], ); } #[test] fn single_relaxed() { check( r#" //- minicore: sized fn foo() {} "#, expect![[r#" *T* ```rust ra_test_fixture::foo ``` ```rust T: ?Sized ``` --- invariant "#]], ); } #[test] fn multiple_implicit() { check( r#" //- minicore: sized trait Trait {} fn foo() {} "#, expect![[r#" *T* ```rust ra_test_fixture::foo ``` ```rust T: Trait ``` --- invariant "#]], ); } #[test] fn multiple_explicit() { check( r#" //- minicore: sized trait Trait {} fn foo() {} "#, expect![[r#" *T* ```rust ra_test_fixture::foo ``` ```rust T: Trait ``` --- invariant "#]], ); } #[test] fn multiple_relaxed() { check( r#" //- minicore: sized trait Trait {} fn foo() {} "#, expect![[r#" *T* ```rust ra_test_fixture::foo ``` ```rust T: Trait + ?Sized ``` --- invariant "#]], ); } #[test] fn mixed() { check( r#" //- minicore: sized fn foo() {} "#, expect![[r#" *T* ```rust ra_test_fixture::foo ``` ```rust T ``` --- invariant "#]], ); } #[test] fn mixed2() { check( r#" //- minicore: sized trait Trait {} fn foo() {} "#, expect![[r#" *T* ```rust ra_test_fixture::foo ``` ```rust T: Trait ``` --- invariant "#]], ); } } #[test] fn hover_const_generic_type_alias() { check( r#" struct Foo; type Fo$0o2 = Foo<2>; "#, expect![[r#" *Foo2* ```rust ra_test_fixture ``` ```rust type Foo2 = Foo<> ``` --- size = 0, align = 1, no Drop "#]], ); } #[test] fn hover_const_param() { check( r#" struct Foo; impl Foo {} "#, expect![[r#" *LEN* ```rust ra_test_fixture::Foo ``` ```rust const LEN: usize ``` "#]], ); } #[test] fn hover_const_eval_discriminant() { // Don't show hex for <10 check( r#" #[repr(u8)] enum E { /// This is a doc A$0 = 1 << 3, } "#, expect![[r#" *A* ```rust ra_test_fixture::E ``` ```rust A = 8 ``` --- size = 1, align = 1, no Drop --- This is a doc "#]], ); // Show hex for >10 check( r#" #[repr(u8)] enum E { /// This is a doc A$0 = (1 << 3) + (1 << 2), } "#, expect![[r#" *A* ```rust ra_test_fixture::E ``` ```rust A = 12 (0xC) ``` --- size = 1, align = 1, no Drop --- This is a doc "#]], ); // enums in const eval check( r#" #[repr(u8)] enum E { A = 1, /// This is a doc B$0 = E::A as u8 + 1, } "#, expect![[r#" *B* ```rust ra_test_fixture::E ``` ```rust B = 2 ``` --- size = 1, align = 1, no Drop --- This is a doc "#]], ); // unspecified variant should increment by one check( r#" #[repr(u8)] enum E { A = 4, /// This is a doc B$0, } "#, expect![[r#" *B* ```rust ra_test_fixture::E ``` ```rust B = 5 ``` --- size = 1, align = 1, no Drop --- This is a doc "#]], ); } #[test] fn hover_const_eval() { check( r#" trait T { const B: bool = false; } impl T for <()> { /// true const B: bool = true; } fn main() { <()>::B$0; } "#, expect![[r#" *B* ```rust ra_test_fixture ``` ```rust const B: bool = true ``` --- true "#]], ); check( r#" struct A { i: i32 }; trait T { const AA: A = A { i: 1 }; } impl T for i32 { const AA: A = A { i: 2 + 3 } } fn main() { ::AA$0; } "#, expect![[r#" *AA* ```rust ra_test_fixture ``` ```rust const AA: A = A { i: 5 } ``` "#]], ); check( r#" trait T { /// false const B: bool = false; } impl T for () { /// true const B: bool = true; } fn main() { T::B$0; } "#, expect![[r#" *B* ```rust ra_test_fixture::T ``` ```rust const B: bool = false ``` --- false "#]], ); check( r#" trait T { /// false const B: bool = false; } impl T for () { } fn main() { <()>::B$0; } "#, expect![[r#" *B* ```rust ra_test_fixture::T ``` ```rust const B: bool = false ``` --- `Self` = `()` --- false "#]], ); check( r#" trait T { /// false const B: bool = false; } impl T for () { /// true const B: bool = true; } impl T for i32 {} fn main() { ::B$0; } "#, expect![[r#" *B* ```rust ra_test_fixture::T ``` ```rust const B: bool = false ``` --- `Self` = `i32` --- false "#]], ); // show hex for <10 check( r#" /// This is a doc const FOO$0: usize = 1 << 3; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: usize = 8 ``` --- This is a doc "#]], ); check( r#" /// This is a doc const FOO$0: usize = (1 << 3) + (1 << 2); "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: usize = 12 (0xC) ``` --- This is a doc "#]], ); // show original body when const eval fails check( r#" /// This is a doc const FOO$0: usize = 2 - 3; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: usize = 2 - 3 ``` --- This is a doc "#]], ); // don't show hex for negatives check( r#" /// This is a doc const FOO$0: i32 = 2 - 3; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: i32 = -1 (0xFFFFFFFF) ``` --- This is a doc "#]], ); check( r#" /// This is a doc const FOO$0: &str = "bar"; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: &str = "bar" ``` --- This is a doc "#]], ); // show char literal check( r#" /// This is a doc const FOO$0: char = 'a'; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: char = 'a' ``` --- This is a doc "#]], ); // show escaped char literal check( r#" /// This is a doc const FOO$0: char = '\x61'; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: char = 'a' ``` --- This is a doc "#]], ); // show byte literal check( r#" /// This is a doc const FOO$0: u8 = b'a'; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: u8 = 97 (0x61) ``` --- This is a doc "#]], ); // show escaped byte literal check( r#" /// This is a doc const FOO$0: u8 = b'\x61'; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: u8 = 97 (0x61) ``` --- This is a doc "#]], ); // show float literal check( r#" /// This is a doc const FOO$0: f64 = 1.0234; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: f64 = 1.0234 ``` --- This is a doc "#]], ); //show float typecasted from int check( r#" /// This is a doc const FOO$0: f32 = 1f32; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: f32 = 1.0 ``` --- This is a doc "#]], ); // Don't show `` in const hover check( r#" /// This is a doc const FOO$0: &i32 = &2; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: &i32 = &2 ``` --- This is a doc "#]], ); //show f64 typecasted from float check( r#" /// This is a doc const FOO$0: f64 = 1.0f64; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: f64 = 1.0 ``` --- This is a doc "#]], ); } #[test] fn hover_const_eval_floating_point() { check( r#" extern "rust-intrinsic" { pub fn expf64(x: f64) -> f64; } const FOO$0: f64 = expf64(1.2); "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: f64 = 3.3201169227365472 ``` "#]], ); // check `f32` isn't double rounded via `f64` check( r#" /// This is a doc const FOO$0: f32 = 1.9999999403953552_f32; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: f32 = 1.9999999 ``` --- This is a doc "#]], ); // Check `f16` and `f128` check( r#" /// This is a doc const FOO$0: f16 = -1.0f16; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: f16 = -1.0 ``` --- This is a doc "#]], ); check( r#" /// This is a doc const FOO$0: f128 = -1.0f128; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: f128 = -1.0 ``` --- This is a doc "#]], ); } #[test] fn hover_const_eval_enum() { check( r#" enum Enum { V1, V2, } const VX: Enum = Enum::V1; const FOO$0: Enum = VX; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: Enum = V1 ``` "#]], ); check( r#" //- minicore: option const FOO$0: Option = Some(2); "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: Option = Some(2) ``` "#]], ); check( r#" //- minicore: option const FOO$0: Option<&i32> = Some(2).as_ref(); "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: Option<&i32> = Some(&2) ``` "#]], ); } #[test] fn hover_const_eval_dyn_trait() { check( r#" //- minicore: fmt, coerce_unsized, builtin_impls, dispatch_from_dyn use core::fmt::Debug; const FOO$0: &dyn Debug = &2i32; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: &dyn Debug = &2 ``` "#]], ); } #[test] fn hover_const_eval_slice() { check( r#" //- minicore: slice, index, coerce_unsized const FOO$0: &[i32] = &[1, 2, 3 + 4]; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: &[i32] = &[1, 2, 7] ``` "#]], ); check( r#" //- minicore: slice, index, coerce_unsized const FOO$0: &[i32; 5] = &[12; 5]; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: &[i32; {const}] = &[12, 12, 12, 12, 12] ``` "#]], ); check( r#" //- minicore: slice, index, coerce_unsized const FOO$0: (&i32, &[i32], &i32) = { let a: &[i32] = &[1, 2, 3]; (&a[0], a, &a[0]) } "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: (&i32, &[i32], &i32) = (&1, &[1, 2, 3], &1) ``` "#]], ); check( r#" //- minicore: slice, index, coerce_unsized struct Tree(&[Tree]); const FOO$0: Tree = { let x = &[Tree(&[]), Tree(&[Tree(&[])])]; Tree(&[Tree(x), Tree(x)]) } "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: Tree = Tree(&[Tree(&[Tree(&[]), Tree(&[Tree(&[])])]), Tree(&[Tree(&[]), Tree(&[Tree(&[])])])]) ``` "#]], ); // FIXME: Show the data of unsized structs check( r#" //- minicore: slice, index, coerce_unsized, transmute #[repr(transparent)] struct S(T); const FOO$0: &S<[u8]> = core::mem::transmute::<&[u8], _>(&[1, 2, 3]); "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: &S<[u8]> = &S ``` "#]], ); } #[test] fn hover_const_eval_str() { check( r#" const FOO$0: &str = "foo"; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: &str = "foo" ``` "#]], ); check( r#" struct X { a: &'static str, b: &'static str, } const FOO$0: X = X { a: "axiom", b: "buy N large", }; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: X = X { a: "axiom", b: "buy N large" } ``` "#]], ); check( r#" const FOO$0: (&str, &str) = { let x = "foo"; (x, x) }; "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: (&str, &str) = ("foo", "foo") ``` "#]], ); } // FIXME(next-solver): this fails to normalize the const, probably due to the solver // refusing to give the impl because of the error type. #[test] fn hover_const_eval_in_generic_trait() { // Doesn't compile, but we shouldn't crash. check( r#" trait Trait { const FOO: bool = false; } struct S(T); impl Trait for S { const FOO: bool = true; } fn test() { S::FOO$0; } "#, expect![[r#" *FOO* ```rust ra_test_fixture::Trait ``` ```rust const FOO: bool = false ``` --- `Self` = `S<{unknown}>` "#]], ); } #[test] fn hover_const_pat() { check( r#" /// This is a doc const FOO: usize = 3; fn foo() { match 5 { FOO$0 => (), _ => () } } "#, expect![[r#" *FOO* ```rust ra_test_fixture ``` ```rust const FOO: usize = 3 ``` --- This is a doc "#]], ); check( r#" enum E { /// This is a doc A = 3, } fn foo(e: E) { match e { E::A$0 => (), _ => () } } "#, expect![[r#" *A* ```rust ra_test_fixture::E ``` ```rust A = 3 ``` --- This is a doc "#]], ); } #[test] fn hover_const_value() { check( r#" pub enum AA { BB, } const CONST: AA = AA::BB; pub fn the_function() -> AA { CON$0ST } "#, expect![[r#" *CONST* ```rust ra_test_fixture ``` ```rust const CONST: AA = BB ``` "#]], ); } #[test] fn array_repeat_exp() { check( r#" fn main() { let til$0e4 = [0_u32; (4 * 8 * 8) / 32]; } "#, expect![[r#" *tile4* ```rust let tile4: [u32; 8] ``` --- size = 32 (0x20), align = 4, no Drop "#]], ); } #[test] fn hover_mod_def() { check( r#" //- /main.rs mod foo$0; //- /foo.rs //! For the horde! "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust mod foo ``` --- For the horde! "#]], ); } #[test] fn hover_self_in_use() { check( r#" //! This should not appear mod foo { /// But this should appear pub mod bar {} } use foo::bar::{self$0}; "#, expect![[r#" *self* ```rust ra_test_fixture::foo ``` ```rust pub mod bar ``` --- But this should appear "#]], ) } #[test] fn hover_keyword() { check( r#" //- /main.rs crate:main deps:std fn f() { retur$0n; } //- /libstd.rs crate:std /// Docs for return_keyword mod return_keyword {} "#, expect![[r#" *return* ```rust return ``` --- Docs for return_keyword "#]], ); } #[test] fn hover_keyword_doc() { check( r#" //- /main.rs crate:main deps:std fn foo() { let bar = mov$0e || {}; } //- /libstd.rs crate:std #[doc(keyword = "move")] /// [closure] /// [closures][closure] /// [threads] /// /// /// [closure]: ../book/ch13-01-closures.html /// [threads]: ../book/ch16-01-threads.html#using-move-closures-with-threads mod move_keyword {} "#, expect![[r#" *move* ```rust move ``` --- [closure](https://doc.rust-lang.org/stable/book/ch13-01-closures.html) [closures](https://doc.rust-lang.org/stable/book/ch13-01-closures.html) [threads](https://doc.rust-lang.org/stable/book/ch16-01-threads.html#using-move-closures-with-threads) "#]], ); } #[test] fn hover_keyword_as_primitive() { check( r#" //- /main.rs crate:main deps:std type F = f$0n(i32) -> i32; //- /libstd.rs crate:std /// Docs for prim_fn mod prim_fn {} "#, expect![[r#" *fn* ```rust fn ``` --- Docs for prim_fn "#]], ); } #[test] fn hover_builtin() { check( r#" //- /main.rs crate:main deps:std const _: &str$0 = ""; } //- /libstd.rs crate:std /// Docs for prim_str /// [`foo`](../std/keyword.foo.html) mod prim_str {} "#, expect![[r#" *str* ```rust str ``` --- Docs for prim_str [`foo`](https://doc.rust-lang.org/nightly/std/keyword.foo.html) "#]], ); } #[test] fn hover_macro_expanded_function() { check( r#" struct S<'a, T>(&'a T); trait Clone {} macro_rules! foo { () => { fn bar<'t, T: Clone + 't>(s: &mut S<'t, T>, t: u32) -> *mut u32 where 't: 't + 't, for<'a> T: Clone + 'a { 0 as _ } }; } foo!(); fn main() { bar$0; } "#, expect![[r#" *bar* ```rust ra_test_fixture ``` ```rust fn bar<'t, T>(s: &mut S<'t, T>, t: u32) -> *mut u32 where T: Clone + 't, 't: 't + 't, for<'a> T: Clone + 'a, ``` "#]], ) } #[test] fn hover_intra_doc_links() { check( r#" pub mod theitem { /// This is the item. Cool! pub struct TheItem; } /// Gives you a [`TheItem$0`]. /// /// [`TheItem`]: theitem::TheItem pub fn gimme() -> theitem::TheItem { theitem::TheItem } "#, expect![[r#" *[`TheItem`]* ```rust ra_test_fixture::theitem ``` ```rust pub struct TheItem ``` --- This is the item. Cool! "#]], ); } #[test] fn test_hover_trait_assoc_typealias() { check( r#" fn main() {} trait T1 { type Bar; type Baz; } struct Foo; mod t2 { pub trait T2 { type Bar; } } use t2::T2; impl T2 for Foo { type Bar = String; } impl T1 for Foo { type Bar = ::Ba$0r; // ^^^ unresolvedReference } "#, expect![[r#" *Bar* ```rust ra_test_fixture::t2::T2 ``` ```rust pub type Bar ``` "#]], ); } #[test] fn hover_generic_assoc() { check( r#" fn foo() where T::Assoc$0: {} trait A { type Assoc; }"#, expect![[r#" *Assoc* ```rust ra_test_fixture::A ``` ```rust type Assoc ``` "#]], ); check( r#" fn foo() { let _: ::Assoc$0; } trait A { type Assoc; }"#, expect![[r#" *Assoc* ```rust ra_test_fixture::A ``` ```rust type Assoc ``` "#]], ); check( r#" trait A where Self::Assoc$0: , { type Assoc; }"#, expect![[r#" *Assoc* ```rust ra_test_fixture::A ``` ```rust type Assoc ``` "#]], ); } #[test] fn string_shadowed_with_inner_items() { check( r#" //- /main.rs crate:main deps:alloc /// Custom `String` type. struct String; fn f() { let _: String$0; fn inner() {} } //- /alloc.rs crate:alloc #[prelude_import] pub use string::*; mod string { /// This is `alloc::String`. pub struct String; } "#, expect![[r#" *String* ```rust main ``` ```rust struct String ``` --- Custom `String` type. "#]], ) } #[test] fn function_doesnt_shadow_crate_in_use_tree() { check( r#" //- /main.rs crate:main deps:foo use foo$0::{foo}; //- /foo.rs crate:foo pub fn foo() {} "#, expect![[r#" *foo* ```rust extern crate foo ``` "#]], ) } #[test] fn hover_feature() { let (analysis, position) = fixture::position(r#"#![feature(intrinsics$0)]"#); analysis .hover( &HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap() .unwrap(); } #[test] fn hover_lint() { check( r#"#![allow(arithmetic_overflow$0)]"#, expect![[r#" *arithmetic_overflow* ``` arithmetic_overflow ``` --- arithmetic operation overflows "#]], ); check( r#"#![expect(arithmetic_overflow$0)]"#, expect![[r#" *arithmetic_overflow* ``` arithmetic_overflow ``` --- arithmetic operation overflows "#]], ); } #[test] fn hover_clippy_lint() { check( r#"#![allow(clippy::almost_swapped$0)]"#, expect![[r#" *almost_swapped* ``` clippy::almost_swapped ``` --- Checks for `foo = bar; bar = foo` sequences. "#]], ); check( r#"#![expect(clippy::almost_swapped$0)]"#, expect![[r#" *almost_swapped* ``` clippy::almost_swapped ``` --- Checks for `foo = bar; bar = foo` sequences. "#]], ); } #[test] fn hover_attr_path_qualifier() { check( r#" //- /foo.rs crate:foo //- /lib.rs crate:main.rs deps:foo #[fo$0o::bar()] struct Foo; "#, expect![[r#" *foo* ```rust extern crate foo ``` "#]], ) } #[test] fn hover_rename() { check( r#" use self as foo$0; "#, expect![[r#" *foo* ```rust extern crate ra_test_fixture ``` "#]], ); check( r#" mod bar {} use bar::{self as foo$0}; "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust mod bar ``` "#]], ); check( r#" mod bar { use super as foo$0; } "#, expect![[r#" *foo* ```rust extern crate ra_test_fixture ``` "#]], ); check( r#" use crate as foo$0; "#, expect![[r#" *foo* ```rust extern crate ra_test_fixture ``` "#]], ); } #[test] fn hover_attribute_in_macro() { check( r#" //- minicore:derive macro_rules! identity { ($struct:item) => { $struct }; } #[rustc_builtin_macro] pub macro Copy {} identity!{ #[derive(Copy$0)] struct Foo; } "#, expect![[r#" *Copy* ```rust ra_test_fixture ``` ```rust macro Copy ``` "#]], ); } #[test] fn hover_derive_input() { check( r#" //- minicore:derive #[rustc_builtin_macro] pub macro Copy {} #[derive(Copy$0)] struct Foo; "#, expect![[r#" *Copy* ```rust ra_test_fixture ``` ```rust macro Copy ``` "#]], ); check( r#" //- minicore:derive mod foo { #[rustc_builtin_macro] pub macro Copy {} } #[derive(foo::Copy$0)] struct Foo; "#, expect![[r#" *Copy* ```rust ra_test_fixture::foo ``` ```rust macro Copy ``` "#]], ); } #[test] fn hover_range_math() { check_hover_range( r#" fn f() { let expr = $01 + 2 * 3$0 } "#, expect![[r#" ```rust i32 ```"#]], ); check_hover_range( r#" fn f() { let expr = 1 $0+ 2 * $03 } "#, expect![[r#" ```rust i32 ```"#]], ); check_hover_range( r#" fn f() { let expr = 1 + $02 * 3$0 } "#, expect![[r#" ```rust i32 ```"#]], ); } #[test] fn hover_range_arrays() { check_hover_range( r#" fn f() { let expr = $0[1, 2, 3, 4]$0 } "#, expect![[r#" ```rust [i32; 4] ```"#]], ); check_hover_range( r#" fn f() { let expr = [1, 2, $03, 4]$0 } "#, expect![[r#" ```rust [i32; 4] ```"#]], ); check_hover_range( r#" fn f() { let expr = [1, 2, $03$0, 4] } "#, expect![[r#" ```rust i32 ```"#]], ); } #[test] fn hover_range_functions() { check_hover_range( r#" fn f(a: &[T]) { } fn b() { $0f$0(&[1, 2, 3, 4, 5]); } "#, expect![[r#" ```rust fn f(&[i32]) ```"#]], ); check_hover_range( r#" fn f(a: &[T]) { } fn b() { f($0&[1, 2, 3, 4, 5]$0); } "#, expect![[r#" ```rust &[i32; 5] ```"#]], ); } #[test] fn hover_range_shows_nothing_when_invalid() { check_hover_range_no_results( r#" fn f(a: &[T]) { } fn b()$0 { f(&[1, 2, 3, 4, 5]); }$0 "#, ); check_hover_range_no_results( r#" fn f$0(a: &[T]) { } fn b() { f(&[1, 2, 3,$0 4, 5]); } "#, ); check_hover_range_no_results( r#" fn $0f() { let expr = [1, 2, 3, 4]$0 } "#, ); } #[test] fn hover_range_shows_unit_for_statements() { check_hover_range( r#" fn f(a: &[T]) { } fn b() { $0f(&[1, 2, 3, 4, 5]); }$0 "#, expect![[r#" ```rust () ```"#]], ); check_hover_range( r#" fn f() { let expr$0 = $0[1, 2, 3, 4] } "#, expect![[r#" ```rust () ```"#]], ); } #[test] fn hover_range_for_pat() { check_hover_range( r#" fn foo() { let $0x$0 = 0; } "#, expect![[r#" ```rust i32 ```"#]], ); check_hover_range( r#" fn foo() { let $0x$0 = ""; } "#, expect![[r#" ```rust &str ```"#]], ); } #[test] fn hover_range_shows_coercions_if_applicable_expr() { check_hover_range( r#" fn foo() { let x: &u32 = $0&&&&&0$0; } "#, expect![[r#" ```text Type: &&&&&u32 Coerced to: &u32 ``` "#]], ); check_hover_range( r#" fn foo() { let x: *const u32 = $0&0$0; } "#, expect![[r#" ```text Type: &u32 Coerced to: *const u32 ``` "#]], ); } #[test] fn hover_range_shows_type_actions() { check_actions( r#" struct Foo; fn foo() { let x: &Foo = $0&&&&&Foo$0; } "#, expect![[r#" [ GoToType( [ HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 0..11, focus_range: 7..10, name: "Foo", kind: Struct, description: "struct Foo", }, }, ], ), ] "#]], ); } #[test] fn hover_try_expr_res() { check_hover_range( r#" //- minicore: try, from, result struct FooError; fn foo() -> Result<(), FooError> { Ok($0Result::<(), FooError>::Ok(())?$0) } "#, expect![[r#" ```rust () ```"#]], ); check_hover_range( r#" //- minicore: try, from, result struct FooError; struct BarError; fn foo() -> Result<(), FooError> { Ok($0Result::<(), BarError>::Ok(())?$0) } "#, expect![[r#" ```text Try Error Type: BarError Propagated as: FooError ``` "#]], ); } #[test] fn hover_try_expr() { check_hover_range( r#" //- minicore: try struct NotResult(T, U); struct Short; struct Looooong; fn foo() -> NotResult<(), Looooong> { $0NotResult((), Short)?$0; } "#, expect![[r#" ```text Try Target Type: NotResult<(), Short> Propagated as: NotResult<(), Looooong> ``` "#]], ); check_hover_range( r#" //- minicore: try struct NotResult(T, U); struct Short; struct Looooong; fn foo() -> NotResult<(), Short> { $0NotResult((), Looooong)?$0; } "#, expect![[r#" ```text Try Target Type: NotResult<(), Looooong> Propagated as: NotResult<(), Short> ``` "#]], ); } #[test] fn hover_try_expr_option() { cov_mark::check!(hover_try_expr_opt_opt); check_hover_range( r#" //- minicore: option, try fn foo() -> Option<()> { $0Some(0)?$0; None } "#, expect![[r#" ```rust i32 ```"#]], ); } #[test] fn hover_deref_expr() { check_hover_range( r#" //- minicore: deref use core::ops::Deref; struct DerefExample { value: T } impl Deref for DerefExample { type Target = T; fn deref(&self) -> &Self::Target { &self.value } } fn foo() { let x = DerefExample { value: 0 }; let y: i32 = $0*x$0; } "#, expect![[r#" ```text Dereferenced from: DerefExample To type: i32 ``` "#]], ); } #[test] fn hover_deref_expr_with_coercion() { check_hover_range( r#" //- minicore: deref use core::ops::Deref; struct DerefExample { value: T } impl Deref for DerefExample { type Target = T; fn deref(&self) -> &Self::Target { &self.value } } fn foo() { let x = DerefExample { value: &&&&&0 }; let y: &i32 = $0*x$0; } "#, expect![[r#" ```text Dereferenced from: DerefExample<&&&&&i32> To type: &&&&&i32 Coerced to: &i32 ``` "#]], ); } #[test] fn hover_intra_in_macro() { check( r#" macro_rules! foo_macro { ($(#[$attr:meta])* $name:ident) => { $(#[$attr])* pub struct $name; } } foo_macro!( /// Doc comment for [`Foo$0`] Foo ); "#, expect![[r#" *[`Foo`]* ```rust ra_test_fixture ``` ```rust pub struct Foo ``` --- Doc comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/struct.Foo.html) "#]], ); } #[test] fn hover_intra_in_attr() { check( r#" #[doc = "Doc comment for [`Foo$0`]"] pub struct Foo(i32); "#, expect![[r#" *[`Foo`]* ```rust ra_test_fixture ``` ```rust pub struct Foo(i32) ``` --- Doc comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/struct.Foo.html) "#]], ); } #[test] fn hover_intra_inner_attr() { check( r#" /// outer comment for [`Foo`] #[doc = "Doc outer comment for [`Foo`]"] pub fn Foo { //! inner comment for [`Foo$0`] #![doc = "Doc inner comment for [`Foo`]"] } "#, expect![[r#" *[`Foo`]* ```rust ra_test_fixture ``` ```rust pub fn Foo() ``` --- outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html) Doc outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html) inner comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html) Doc inner comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html) "#]], ); check( r#" /// outer comment for [`Foo`] #[doc = "Doc outer comment for [`Foo`]"] pub mod Foo { //! inner comment for [`super::Foo$0`] #![doc = "Doc inner comment for [`super::Foo`]"] } "#, expect![[r#" *[`super::Foo`]* ```rust ra_test_fixture ``` ```rust pub mod Foo ``` --- outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html) Doc outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html) inner comment for [`super::Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html) Doc inner comment for [`super::Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html) "#]], ); } #[test] fn hover_intra_outer_attr() { check( r#" /// outer comment for [`Foo$0`] #[doc = "Doc outer comment for [`Foo`]"] pub fn Foo() { //! inner comment for [`Foo`] #![doc = "Doc inner comment for [`Foo`]"] } "#, expect![[r#" *[`Foo`]* ```rust ra_test_fixture ``` ```rust pub fn Foo() ``` --- outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html) Doc outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html) inner comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html) Doc inner comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html) "#]], ); check( r#" /// outer comment for [`Foo$0`] #[doc = "Doc outer comment for [`Foo`]"] pub mod Foo { //! inner comment for [`super::Foo`] #![doc = "Doc inner comment for [`super::Foo`]"] } "#, expect![[r#" *[`Foo`]* ```rust ra_test_fixture ``` ```rust pub mod Foo ``` --- outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html) Doc outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html) inner comment for [`super::Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html) Doc inner comment for [`super::Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html) "#]], ); } #[test] fn hover_intra_generics() { check( r#" /// Doc comment for [`Foo$0`] pub struct Foo(T); "#, expect![[r#" *[`Foo`]* ```rust ra_test_fixture ``` ```rust pub struct Foo(T) ``` --- Doc comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/struct.Foo.html) "#]], ); } #[test] fn hover_inert_attr() { check( r#" #[doc$0 = ""] pub struct Foo; "#, expect![[r##" *doc* ```rust #[doc] ``` --- Valid forms are: * \#\[doc(hidden|inline|...)\] * \#\[doc = string\] "##]], ); check( r#" #[allow$0()] pub struct Foo; "#, expect![[r##" *allow* ```rust #[allow] ``` --- Valid forms are: * \#\[allow(lint1, lint2, ..., /\*opt\*/ reason = "...")\] "##]], ); } #[test] fn hover_dollar_crate() { // $crate should be resolved to the right crate name. check( r#" //- /main.rs crate:main deps:dep dep::m!(KONST$0); //- /dep.rs crate:dep #[macro_export] macro_rules! m { ( $name:ident ) => { const $name: $crate::Type = $crate::Type; }; } pub struct Type; "#, expect![[r#" *KONST* ```rust main ``` ```rust const KONST: dep::Type = Type ``` "#]], ); } #[test] fn hover_record_variant() { check( r#" enum Enum { RecordV$0 { field: u32 } } "#, expect![[r#" *RecordV* ```rust ra_test_fixture::Enum ``` ```rust RecordV { field: u32, } ``` --- size = 4, align = 4, no Drop "#]], ); } #[test] fn hover_record_variant_field() { check( r#" enum Enum { RecordV { field$0: u32 } } "#, expect![[r#" *field* ```rust ra_test_fixture::Enum::RecordV ``` ```rust field: u32 ``` --- size = 4, align = 4, no Drop "#]], ); } #[test] fn hover_trait_impl_assoc_item_def_doc_forwarding() { check( r#" trait T { /// Trait docs fn func() {} } impl T for () { fn func$0() {} } "#, expect![[r#" *func* ```rust ra_test_fixture ``` ```rust fn func() ``` --- Trait docs "#]], ); } #[test] fn hover_trait_show_assoc_items() { check_assoc_count( 0, r#" trait T {} impl T$0 for () {} "#, expect![[r#" *T* ```rust ra_test_fixture ``` ```rust trait T {} ``` "#]], ); check_assoc_count( 1, r#" trait T {} impl T$0 for () {} "#, expect![[r#" *T* ```rust ra_test_fixture ``` ```rust trait T {} ``` "#]], ); check_assoc_count( 0, r#" trait T { fn func() {} const FLAG: i32 = 34; type Bar; } impl T$0 for () {} "#, expect![[r#" *T* ```rust ra_test_fixture ``` ```rust trait T { /* … */ } ``` "#]], ); check_assoc_count( 2, r#" trait T { fn func() {} const FLAG: i32 = 34; type Bar; } impl T$0 for () {} "#, expect![[r#" *T* ```rust ra_test_fixture ``` ```rust trait T { fn func(); const FLAG: i32; /* … */ } ``` "#]], ); check_assoc_count( 3, r#" trait T { fn func() {} const FLAG: i32 = 34; type Bar; } impl T$0 for () {} "#, expect![[r#" *T* ```rust ra_test_fixture ``` ```rust trait T { fn func(); const FLAG: i32; type Bar; } ``` "#]], ); check_assoc_count( 4, r#" trait T { fn func() {} const FLAG: i32 = 34; type Bar; } impl T$0 for () {} "#, expect![[r#" *T* ```rust ra_test_fixture ``` ```rust trait T { fn func(); const FLAG: i32; type Bar; } ``` "#]], ); } #[test] fn hover_ranged_macro_call() { check_hover_range( r#" macro_rules! __rust_force_expr { ($e:expr) => { $e }; } macro_rules! vec { ($elem:expr) => { __rust_force_expr!($elem) }; } struct Struct; impl Struct { fn foo(self) {} } fn f() { $0vec![Struct]$0; } "#, expect![[r#" ```rust Struct ```"#]], ); } #[test] fn hover_deref() { check( r#" //- minicore: deref struct Struct(usize); impl core::ops::Deref for Struct { type Target = usize; fn deref(&self) -> &Self::Target { &self.0 } } fn f() { $0*Struct(0); } "#, expect![[r#" *** ```rust ra_test_fixture::Struct ``` ```rust fn deref(&self) -> &Self::Target ``` "#]], ); } #[test] fn static_const_macro_expanded_body() { check( r#" macro_rules! m { () => { pub const V: i8 = { let e = 123; f(e) // Prevent const eval from evaluating this constant, we want to print the body's code. }; }; } m!(); fn main() { $0V; } "#, expect![[r#" *V* ```rust ra_test_fixture ``` ```rust pub const V: i8 = { let e = 123; f(e) } ``` "#]], ); check( r#" macro_rules! m { () => { pub static V: i8 = { let e = 123; }; }; } m!(); fn main() { $0V; } "#, expect![[r#" *V* ```rust ra_test_fixture ``` ```rust pub static V: i8 = { let e = 123; } ``` "#]], ); } #[test] fn hover_rest_pat() { check( r#" struct Struct {a: u32, b: u32, c: u8, d: u16}; fn main() { let Struct {a, c, .$0.} = Struct {a: 1, b: 2, c: 3, d: 4}; } "#, expect![[r#" *..* ```rust .., b: u32, d: u16 ``` "#]], ); check( r#" struct Struct {a: u32, b: u32, c: u8, d: u16}; fn main() { let Struct {a, b, c, d, .$0.} = Struct {a: 1, b: 2, c: 3, d: 4}; } "#, expect![[r#" *..* ```rust .. ``` "#]], ); } #[test] fn hover_underscore_pat() { check( r#" fn main() { let _$0 = 0; } "#, expect![[r#" *_* ```rust i32 ``` "#]], ); check( r#" fn main() { let (_$0,) = (0,); } "#, expect![[r#" *_* ```rust i32 ``` "#]], ); } #[test] fn hover_underscore_expr() { check( r#" fn main() { _$0 = 0; } "#, expect![[r#" *_* ```rust i32 ``` "#]], ); check( r#" fn main() { (_$0,) = (0,); } "#, expect![[r#" *_* ```rust i32 ``` "#]], ); } #[test] fn hover_underscore_type() { check( r#" fn main() { let x: _$0 = 0; } "#, expect![[r#" *_* ```rust i32 ``` "#]], ); check( r#" fn main() { let x: (_$0,) = (0,); } "#, expect![[r#" *_* ```rust i32 ``` "#]], ); } #[test] fn hover_call_parens() { check( r#" fn foo() -> i32 {} fn main() { foo($0); } "#, expect![[r#" *)* ```rust i32 ``` "#]], ); check( r#" struct S; impl S { fn foo(self) -> i32 {} } fn main() { S.foo($0); } "#, expect![[r#" *)* ```rust i32 ``` "#]], ); } #[test] fn assoc_fn_in_block_local_impl() { check( r#" struct S; mod m { const _: () = { impl crate::S { pub(crate) fn foo() {} } }; } fn test() { S::foo$0(); } "#, expect![[r#" *foo* ```rust ra_test_fixture::m::S ``` ```rust pub(crate) fn foo() ``` "#]], ); check( r#" struct S; mod m { const _: () = { const _: () = { impl crate::S { pub(crate) fn foo() {} } }; }; } fn test() { S::foo$0(); } "#, expect![[r#" *foo* ```rust ra_test_fixture::m::S ``` ```rust pub(crate) fn foo() ``` "#]], ); check( r#" struct S; mod m { mod inner { const _: () = { impl crate::S { pub(super) fn foo() {} } }; } fn test() { crate::S::foo$0(); } } "#, expect![[r#" *foo* ```rust ra_test_fixture::m::inner::S ``` ```rust pub(super) fn foo() ``` "#]], ); } #[test] fn assoc_const_in_block_local_impl() { check( r#" struct S; mod m { const _: () = { impl crate::S { pub(crate) const A: () = (); } }; } fn test() { S::A$0; } "#, expect![[r#" *A* ```rust ra_test_fixture::m::S ``` ```rust pub(crate) const A: () = () ``` "#]], ); check( r#" struct S; mod m { const _: () = { const _: () = { impl crate::S { pub(crate) const A: () = (); } }; }; } fn test() { S::A$0; } "#, expect![[r#" *A* ```rust ra_test_fixture::m::S ``` ```rust pub(crate) const A: () = () ``` "#]], ); check( r#" struct S; mod m { mod inner { const _: () = { impl crate::S { pub(super) const A: () = (); } }; } fn test() { crate::S::A$0; } } "#, expect![[r#" *A* ```rust ra_test_fixture::m::inner::S ``` ```rust pub(super) const A: () = () ``` "#]], ); } #[test] fn field_as_method_call_fallback() { check( r#" struct S { f: u32 } fn test() { S { f: 0 }.f$0(); } "#, expect![[r#" *f* ```rust ra_test_fixture::S ``` ```rust f: u32 ``` "#]], ); } #[test] fn generic_params_disabled_by_cfg() { check( r#" struct S<#[cfg(never)] T>; fn test() { let s$0: S = S; } "#, expect![[r#" *s* ```rust let s: S ``` --- size = 0, align = 1, no Drop "#]], ); } #[test] fn format_args_arg() { check( r#" //- minicore: fmt fn test() { let foo = 0; format_args!("{}", foo$0); } "#, expect![[r#" *foo* ```rust let foo: i32 ``` "#]], ); } #[test] fn format_args_implicit() { check( r#" //- minicore: fmt fn test() { let aaaaa = "foo"; format_args!("{aaaaa$0}"); } "#, expect![[r#" *aaaaa* ```rust let aaaaa: &str ``` "#]], ); } #[test] fn format_args_implicit2() { check( r#" //- minicore: fmt fn test() { let aaaaa = "foo"; format_args!("{$0aaaaa}"); } "#, expect![[r#" *aaaaa* ```rust let aaaaa: &str ``` "#]], ); } #[test] fn format_args_implicit_raw() { check( r#" //- minicore: fmt fn test() { let aaaaa = "foo"; format_args!(r"{$0aaaaa}"); } "#, expect![[r#" *aaaaa* ```rust let aaaaa: &str ``` "#]], ); } #[test] fn format_args_implicit_nested() { check( r#" //- minicore: fmt macro_rules! foo { ($($tt:tt)*) => { format_args!($($tt)*) } } fn test() { let aaaaa = "foo"; foo!(r"{$0aaaaa}"); } "#, expect![[r#" *aaaaa* ```rust let aaaaa: &str ``` "#]], ); } #[test] fn method_call_without_parens() { check( r#" struct S; impl S { fn foo(&self, t: T) {} } fn main() { S.foo$0; } "#, expect![[r#" *foo* ```rust ra_test_fixture::S ``` ```rust fn foo(&self, t: T) ``` "#]], ); } #[test] fn string_literal() { check( r#" fn main() { $0"🦀\u{1f980}\\\x41"; } "#, expect![[r#" *"🦀\u{1f980}\\\x41"* ```rust &'static str ``` --- value of literal: ` 🦀🦀\A ` "#]], ); check( r#" fn main() { $0r"🦀\u{1f980}\\\x41"; } "#, expect![[r#" *r"🦀\u{1f980}\\\x41"* ```rust &'static str ``` --- value of literal: ` 🦀\u{1f980}\\\x41 ` "#]], ); check( r#" fn main() { $0r"🦀\u{1f980}\\\x41 fsdghs"; } "#, expect![[r#" *r"🦀\u{1f980}\\\x41 fsdghs"* ```rust &'static str ``` --- value of literal (truncated up to newline): ` 🦀\u{1f980}\\\x41 ` "#]], ); } #[test] fn cstring_literal() { check( r#" fn main() { $0c"🦀\u{1f980}\\\x41"; } "#, expect![[r#" *c"🦀\u{1f980}\\\x41"* ```rust &'static {unknown} ``` --- value of literal: ` 🦀🦀\A ` "#]], ); } #[test] fn rawstring_literal() { check( r#" fn main() { $0r"`[^`]*`"; }"#, expect![[r#" *r"`[^`]*`"* ```rust &'static str ``` --- value of literal: ```` `[^`]*` ```` "#]], ); check( r#" fn main() { $0r"`"; }"#, expect![[r#" *r"`"* ```rust &'static str ``` --- value of literal: `` ` `` "#]], ); check( r#" fn main() { $0r" "; }"#, expect![[r#" *r" "* ```rust &'static str ``` --- value of literal: ` ` "#]], ); check( r#" fn main() { $0r" Hello World "; }"#, expect![[r#" *r" Hello World "* ```rust &'static str ``` --- value of literal: ` Hello World ` "#]], ) } #[test] fn byte_string_literal() { check( r#" fn main() { $0b"\xF0\x9F\xA6\x80\\"; } "#, expect![[r#" *b"\xF0\x9F\xA6\x80\\"* ```rust &'static [u8; 5] ``` --- value of literal: ` [240, 159, 166, 128, 92] ` "#]], ); check( r#" fn main() { $0br"\xF0\x9F\xA6\x80\\"; } "#, expect![[r#" *br"\xF0\x9F\xA6\x80\\"* ```rust &'static [u8; 18] ``` --- value of literal: ` [92, 120, 70, 48, 92, 120, 57, 70, 92, 120, 65, 54, 92, 120, 56, 48, 92, 92] ` "#]], ); } #[test] fn byte_literal() { check( r#" fn main() { $0b'\xF0'; } "#, expect![[r#" *b'\xF0'* ```rust u8 ``` --- value of literal: ` 0xF0 ` "#]], ); check( r#" fn main() { $0b'\\'; } "#, expect![[r#" *b'\\'* ```rust u8 ``` --- value of literal: ` 0x5C ` "#]], ); } #[test] fn char_literal() { check( r#" fn main() { $0'\x41'; } "#, expect![[r#" *'\x41'* ```rust char ``` --- value of literal: ` A ` "#]], ); check( r#" fn main() { $0'\\'; } "#, expect![[r#" *'\\'* ```rust char ``` --- value of literal: ` \ ` "#]], ); check( r#" fn main() { $0'\u{1f980}'; } "#, expect![[r#" *'\u{1f980}'* ```rust char ``` --- value of literal: ` 🦀 ` "#]], ); } #[test] fn float_literal() { check( r#" fn main() { $01.0; } "#, expect![[r#" *1.0* ```rust f64 ``` --- value of literal: ` 1 (bits: 0x3FF0000000000000) ` "#]], ); check( r#" fn main() { $01.0f16; } "#, expect![[r#" *1.0f16* ```rust f16 ``` --- value of literal: ` 1 (bits: 0x3C00) ` "#]], ); check( r#" fn main() { $01.0f32; } "#, expect![[r#" *1.0f32* ```rust f32 ``` --- value of literal: ` 1 (bits: 0x3F800000) ` "#]], ); check( r#" fn main() { $01.0f128; } "#, expect![[r#" *1.0f128* ```rust f128 ``` --- value of literal: ` 1 (bits: 0x3FFF0000000000000000000000000000) ` "#]], ); check( r#" fn main() { $0134e12; } "#, expect![[r#" *134e12* ```rust f64 ``` --- value of literal: ` 134000000000000 (bits: 0x42DE77D399980000) ` "#]], ); check( r#" fn main() { $01523527134274733643531312.0; } "#, expect![[r#" *1523527134274733643531312.0* ```rust f64 ``` --- value of literal: ` 1523527134274733600000000 (bits: 0x44F429E9249F629B) ` "#]], ); check( r#" fn main() { $00.1ea123; } "#, expect![[r#" *0.1ea123* ```rust f64 ``` --- invalid literal: invalid float literal "#]], ); } #[test] fn int_literal() { check( r#" fn main() { $034325236457856836345234; } "#, expect![[r#" *34325236457856836345234* ```rust i32 ``` --- value of literal: ` 34325236457856836345234 (0x744C659178614489D92|0b111010001001100011001011001000101111000011000010100010010001001110110010010) ` "#]], ); check( r#" fn main() { $0134_123424_21; } "#, expect![[r#" *134_123424_21* ```rust i32 ``` --- value of literal: ` 13412342421 (0x31F701A95|0b1100011111011100000001101010010101) ` "#]], ); check( r#" fn main() { $00x12423423; } "#, expect![[r#" *0x12423423* ```rust i32 ``` --- value of literal: ` 306328611 (0x12423423|0b10010010000100011010000100011) ` "#]], ); check( r#" fn main() { $00b1111_1111; } "#, expect![[r#" *0b1111_1111* ```rust i32 ``` --- value of literal: ` 255 (0xFF|0b11111111) ` "#]], ); check( r#" fn main() { $00o12345; } "#, expect![[r#" *0o12345* ```rust i32 ``` --- value of literal: ` 5349 (0x14E5|0b1010011100101) ` "#]], ); check( r#" fn main() { $00xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_F; } "#, expect![[r#" *0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_F* ```rust i32 ``` --- invalid literal: number too large to fit in target type "#]], ); } #[test] fn notable_local() { check( r#" #[doc(notable_trait)] trait Notable { type Assoc; type Assoc2; } impl Notable for u32 { type Assoc = &str; type Assoc2 = char; } fn main(notable$0: u32) {} "#, expect![[r#" *notable* ```rust notable: u32 ``` --- Implements notable traits: `Notable` --- size = 4, align = 4, no Drop "#]], ); } #[test] fn notable_foreign() { check( r#" //- minicore: future, iterator struct S; #[doc(notable_trait)] trait Notable {} impl Notable for S$0 {} impl core::future::Future for S { type Output = u32; } impl Iterator for S { type Item = S; } "#, expect![[r#" *S* ```rust ra_test_fixture ``` ```rust struct S ``` "#]], ); } #[test] fn extern_items() { check( r#" extern "C" { static STATIC$0: (); } "#, expect![[r#" *STATIC* ```rust ra_test_fixture:: ``` ```rust static STATIC: () ``` "#]], ); check( r#" extern "C" { fn fun$0(); } "#, expect![[r#" *fun* ```rust ra_test_fixture:: ``` ```rust unsafe fn fun() ``` "#]], ); check( r#" extern "C" { type Ty$0; } "#, expect![[r#" *Ty* ```rust ra_test_fixture:: ``` ```rust type Ty ``` --- size = 0, align = 1, no Drop "#]], ); } #[test] fn notable_ranged() { check_hover_range( r#" //- minicore: future, iterator struct S; #[doc(notable_trait)] trait Notable {} impl Notable for S {} impl core::future::Future for S { type Output = u32; } impl Iterator for S { type Item = S; } fn main() { $0S$0; } "#, expect![[r#" ```rust S ``` --- Implements notable traits: `Future`, `Iterator`, `Notable`"#]], ); } #[test] fn notable_actions() { check_actions( r#" //- minicore: future, iterator struct S; struct S2; #[doc(notable_trait)] trait Notable {} impl Notable for S$0 {} impl core::future::Future for S { type Output = u32; } impl Iterator for S { type Item = S2; } "#, expect![[r#" [ Implementation( FilePositionWrapper { file_id: FileId( 0, ), offset: 7, }, ), GoToType( [ HoverGotoTypeData { mod_path: "core::future::Future", nav: NavigationTarget { file_id: FileId( 1, ), full_range: 4294967295..4294967295, focus_range: 4294967295..4294967295, name: "Future", kind: Trait, container_name: "future", description: "pub trait Future", }, }, HoverGotoTypeData { mod_path: "core::iter::traits::iterator::Iterator", nav: NavigationTarget { file_id: FileId( 1, ), full_range: 4294967295..4294967295, focus_range: 4294967295..4294967295, name: "Iterator", kind: Trait, container_name: "iterator", description: "pub trait Iterator", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::Notable", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 21..59, focus_range: 49..56, name: "Notable", kind: Trait, description: "trait Notable", }, }, HoverGotoTypeData { mod_path: "ra_test_fixture::S2", nav: NavigationTarget { file_id: FileId( 0, ), full_range: 10..20, focus_range: 17..19, name: "S2", kind: Struct, description: "struct S2", }, }, ], ), ] "#]], ); } #[test] fn hover_lifetime_regression_16963() { check( r#" struct Pedro$0<'a> { hola: &'a str } "#, expect![[r#" *Pedro* ```rust ra_test_fixture ``` ```rust struct Pedro<'a> { hola: &'a str, } ``` --- size = 16 (0x10), align = 8, largest padding = 0, niches = 1, no Drop "#]], ) } #[test] fn hover_impl_trait_arg_self() { check( r#" trait T {} fn main(a$0: impl T) {} "#, expect![[r#" *a* ```rust a: impl T + ?Sized ``` --- type param may need Drop "#]], ); } #[test] fn hover_struct_default_arg_self() { check( r#" struct T {} fn main(a$0: T) {} "#, expect![[r#" *a* ```rust a: T ``` --- size = 0, align = 1, no Drop "#]], ); } #[test] fn hover_fn_with_impl_trait_arg() { check( r#" trait Foo {} impl Foo for bool {} fn bar(_: impl Foo) {} fn test() { let f = bar::<3>; f$0(true); } "#, expect![[r#" *f* ```rust let f: fn bar<3>(bool) ``` "#]], ); } #[test] fn issue_17871() { check( r#" trait T { fn f(); } struct S {} impl T for S { fn f() {} } fn main() { let x$0 = S::f::; } "#, expect![[r#" *x* ```rust let x: fn f() ``` --- size = 0, align = 1, no Drop "#]], ); } #[test] fn raw_keyword_different_editions() { check( r#" //- /lib1.rs crate:with_edition_2015 edition:2015 pub fn dyn() {} //- /lib2.rs crate:with_edition_2018 edition:2018 deps:with_edition_2015 new_source_root:local fn foo() { with_edition_2015::r#dyn$0(); } "#, expect![[r#" *r#dyn* ```rust with_edition_2015 ``` ```rust pub fn r#dyn() ``` "#]], ); check( r#" //- /lib1.rs crate:with_edition_2018 edition:2018 pub fn r#dyn() {} //- /lib2.rs crate:with_edition_2015 edition:2015 deps:with_edition_2018 new_source_root:local fn foo() { with_edition_2018::dyn$0(); } "#, expect![[r#" *dyn* ```rust with_edition_2018 ``` ```rust pub fn dyn() ``` "#]], ); check( r#" //- /lib1.rs crate:escaping_needlessly edition:2015 pub fn r#dyn() {} //- /lib2.rs crate:dependent edition:2015 deps:escaping_needlessly new_source_root:local fn foo() { escaping_needlessly::dyn$0(); } "#, expect![[r#" *dyn* ```rust escaping_needlessly ``` ```rust pub fn dyn() ``` "#]], ); } #[test] fn test_hover_function_with_pat_param() { check( r#"fn test_1$0((start_range, end_range): (u32, u32), a: i32) {}"#, expect![[r#" *test_1* ```rust ra_test_fixture ``` ```rust fn test_1((start_range, end_range): (u32, u32), a: i32) ``` "#]], ); // Test case with tuple pattern and mutable parameters check( r#"fn test_2$0((mut x, y): (i32, i32)) {}"#, expect![[r#" *test_2* ```rust ra_test_fixture ``` ```rust fn test_2((mut x, y): (i32, i32)) ``` "#]], ); // Test case with a pattern in a reference type check( r#"fn test_3$0(&(a, b): &(i32, i32)) {}"#, expect![[r#" *test_3* ```rust ra_test_fixture ``` ```rust fn test_3(&(a, b): &(i32, i32)) ``` "#]], ); // Test case with complex pattern (struct destructuring) check( r#"struct Point { x: i32, y: i32 } fn test_4$0(Point { x, y }: Point) {}"#, expect![[r#" *test_4* ```rust ra_test_fixture ``` ```rust fn test_4(Point { x, y }: Point) ``` "#]], ); // Test case with a nested pattern check( r#"fn test_5$0(((a, b), c): ((i32, i32), i32)) {}"#, expect![[r#" *test_5* ```rust ra_test_fixture ``` ```rust fn test_5(((a, b), c): ((i32, i32), i32)) ``` "#]], ); // Test case with an unused variable in the pattern check( r#"fn test_6$0((_, y): (i32, i64)) {}"#, expect![[r#" *test_6* ```rust ra_test_fixture ``` ```rust fn test_6((_, y): (i32, i64)) ``` "#]], ); // Test case with a complex pattern involving both tuple and struct check( r#"struct Foo { a: i32, b: i32 } fn test_7$0((x, Foo { a, b }): (i32, Foo)) {}"#, expect![[r#" *test_7* ```rust ra_test_fixture ``` ```rust fn test_7((x, Foo { a, b }): (i32, Foo)) ``` "#]], ); // Test case with Enum and Or pattern check( r#"enum MyEnum { A(i32), B(i32) } fn test_8$0((MyEnum::A(x) | MyEnum::B(x)): MyEnum) {}"#, expect![[r#" *test_8* ```rust ra_test_fixture ``` ```rust fn test_8((MyEnum::A(x) | MyEnum::B(x)): MyEnum) ``` "#]], ); // Test case with a pattern as a function parameter check( r#"struct Foo { a: i32, b: i32 } fn test_9$0(Foo { a, b }: Foo) {}"#, expect![[r#" *test_9* ```rust ra_test_fixture ``` ```rust fn test_9(Foo { a, b }: Foo) ``` "#]], ); // Test case with a pattern as a function parameter with a different name check( r#"struct Foo { a: i32, b: i32 } fn test_10$0(Foo { a, b: b1 }: Foo) {}"#, expect![[r#" *test_10* ```rust ra_test_fixture ``` ```rust fn test_10(Foo { a, b: b1 }: Foo) ``` "#]], ); // Test case with a pattern as a function parameter with annotations check( r#"struct Foo { a: i32, b: i32 } fn test_10$0(Foo { a, b: mut b }: Foo) {}"#, expect![[r#" *test_10* ```rust ra_test_fixture ``` ```rust fn test_10(Foo { a, b: mut b }: Foo) ``` "#]], ); } #[test] fn test_hover_function_with_too_long_param() { check( r#" fn fn_$0( attrs: impl IntoIterator, visibility: Option, fn_name: ast::Name, type_params: Option, where_clause: Option, params: ast::ParamList, body: ast::BlockExpr, ret_type: Option, is_async: bool, is_const: bool, is_unsafe: bool, is_gen: bool, ) -> ast::Fn {} "#, expect![[r#" *fn_* ```rust ra_test_fixture ``` ```rust fn fn_( attrs: impl IntoIterator, visibility: Option, fn_name: ast::Name, type_params: Option, where_clause: Option, params: ast::ParamList, body: ast::BlockExpr, ret_type: Option, is_async: bool, is_const: bool, is_unsafe: bool, is_gen: bool ) -> ast::Fn ``` "#]], ); check( r#" fn fn_$0( &self, attrs: impl IntoIterator, visibility: Option, fn_name: ast::Name, type_params: Option, where_clause: Option, params: ast::ParamList, body: ast::BlockExpr, ret_type: Option, is_async: bool, is_const: bool, is_unsafe: bool, is_gen: bool, ... ) -> ast::Fn {} "#, expect![[r#" *fn_* ```rust ra_test_fixture ``` ```rust fn fn_( &self, attrs: impl IntoIterator, visibility: Option, fn_name: ast::Name, type_params: Option, where_clause: Option, params: ast::ParamList, body: ast::BlockExpr, ret_type: Option, is_async: bool, is_const: bool, is_unsafe: bool, is_gen: bool, ... ) -> ast::Fn ``` "#]], ); } #[test] fn hover_path_inside_block_scope() { check( r#" mod m { const _: () = { mod m2 { const C$0: () = (); } }; } "#, expect![[r#" *C* ```rust ra_test_fixture::m::m2 ``` ```rust const C: () = () ``` "#]], ); } #[test] fn regression_18238() { check( r#" macro_rules! foo { ($name:ident) => { pub static $name = Foo::new(|| { $crate; }); }; } foo!(BAR_$0); "#, expect![[r#" *BAR_* ```rust ra_test_fixture ``` ```rust pub static BAR_: {error} = Foo::new(||{ crate; }) ``` "#]], ); } #[test] fn type_alias_without_docs() { // Simple. check( r#" /// Docs for B struct B; type A$0 = B; "#, expect![[r#" *A* ```rust ra_test_fixture ``` ```rust type A = B ``` --- size = 0, align = 1, no Drop --- *This is the documentation for* `struct B` Docs for B "#]], ); // Nested. check( r#" /// Docs for C struct C; type B = C; type A$0 = B; "#, expect![[r#" *A* ```rust ra_test_fixture ``` ```rust type A = B ``` --- size = 0, align = 1, no Drop --- *This is the documentation for* `struct C` Docs for C "#]], ); // Showing the docs for aliased struct instead of intermediate type. check( r#" /// Docs for C struct C; /// Docs for B type B = C; type A$0 = B; "#, expect![[r#" *A* ```rust ra_test_fixture ``` ```rust type A = B ``` --- size = 0, align = 1, no Drop --- *This is the documentation for* `struct C` Docs for C "#]], ); // No docs found. check( r#" struct C; type B = C; type A$0 = B; "#, expect![[r#" *A* ```rust ra_test_fixture ``` ```rust type A = B ``` --- size = 0, align = 1, no Drop "#]], ); // Multiple nested crate. check( r#" //- /lib.rs crate:c /// Docs for C pub struct C; //- /lib.rs crate:b deps:c pub use c::C; pub type B = C; //- /lib.rs crate:a deps:b pub use b::B; pub type A = B; //- /main.rs crate:main deps:a use a::A$0; "#, expect![[r#" *A* ```rust a ``` ```rust pub type A = B ``` --- *This is the documentation for* `pub struct C` Docs for C "#]], ); } #[test] fn dyn_compat() { check( r#" trait Compat$0 {} "#, expect![[r#" *Compat* ```rust ra_test_fixture ``` ```rust trait Compat ``` --- Is dyn-compatible "#]], ); check( r#" trait UnCompat$0 { fn f() {} } "#, expect![[r#" *UnCompat* ```rust ra_test_fixture ``` ```rust trait UnCompat ``` --- Is not dyn-compatible due to having a method `f` that is not dispatchable due to missing a receiver "#]], ); check( r#" trait UnCompat { fn f() {} } fn f "#, expect![[r#" *UnCompat* ```rust ra_test_fixture ``` ```rust trait UnCompat ``` "#]], ); } #[test] fn issue_18613() { check( r#" fn main() { struct S(); let x$0 = S::<()>; }"#, expect![[r#" *x* ```rust let x: fn S<()>() -> S<()> ``` --- size = 0, align = 1, no Drop "#]], ); check( r#" pub struct Global; pub struct Box(T, A); impl Box { pub fn new(x: T) -> Self { loop {} } } pub struct String; fn main() { let box_value$0 = Box::new(); } "#, expect![[r#" *box_value* ```rust let box_value: fn Box(String, Global) -> Box ``` --- size = 0, align = 1, no Drop "#]], ); check( r#" //- minicore: eq pub struct RandomState; pub struct HashMap(K, V, S); impl HashMap { pub fn new() -> HashMap { loop {} } } impl PartialEq for HashMap { fn eq(&self, other: &HashMap) -> bool { false } } fn main() { let s$0 = HashMap::<_, u64>::ne; } "#, expect![[r#" *s* ```rust let s: fn ne>(&HashMap<{unknown}, u64>, &HashMap<{unknown}, u64>) -> bool ``` --- size = 0, align = 1, no Drop "#]], ); } #[test] fn subst_fn() { check( r#" struct Foo(T); impl Foo { fn foo(v: T, u: U) {} } fn bar() { Foo::fo$0o(123, false); } "#, expect![[r#" *foo* ```rust ra_test_fixture::Foo ``` ```rust impl Foo fn foo(v: T, u: U) ``` --- `T` = `i32`, `U` = `bool` "#]], ); check( r#" fn foo(v: T) {} fn bar() { fo$0o(123); } "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust fn foo(v: T) ``` --- `T` = `i32` "#]], ); } #[test] fn subst_record_constructor() { check( r#" struct Foo { field: T } fn bar() { let v = $0Foo { field: 123 }; } "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo { field: T, } ``` --- `T` = `i32` "#]], ); check( r#" struct Foo { field: T } fn bar() { let v = Foo { field: 123 }; let $0Foo { field: _ } = v; } "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo { field: T, } ``` --- `T` = `i32` "#]], ); } #[test] fn subst_method_call() { check( r#" struct Foo(T); impl Foo { fn bar(self, v: T) {} } fn baz() { Foo(123).bar$0("hello"); } "#, expect![[r#" *bar* ```rust ra_test_fixture::Foo ``` ```rust impl Foo fn bar(self, v: T) ``` --- `U` = `i32`, `T` = `&str` "#]], ); } #[test] fn subst_type_alias_do_not_work() { // It is very hard to support subst for type aliases properly in all places because they are eagerly evaluated. // We can show the user the subst for the underlying type instead but that'll be very confusing. check( r#" struct Foo { a: T, b: U } type Alias = Foo; fn foo() { let _ = Alias$0 { a: true, b: 123 }; } "#, expect![[r#" *Alias* ```rust ra_test_fixture ``` ```rust type Alias = Foo ``` "#]], ); } #[test] fn subst_self() { check( r#" trait Trait { fn foo(&self, v: U) {} } struct Struct(T); impl Trait for Struct {} fn bar() { Struct(123).foo$0(true); } "#, expect![[r#" *foo* ```rust ra_test_fixture::Trait ``` ```rust trait Trait fn foo(&self, v: U) ``` --- `Self` = `Struct`, `T` = `i64`, `U` = `bool` "#]], ); } #[test] fn subst_with_lifetimes_and_consts() { check( r#" struct Foo<'a, const N: usize, T>(&[T; N]); impl<'a, T, const N: usize> Foo<'a, N, T> { fn foo<'b, const Z: u32, U>(&self, v: U) {} } fn bar() { Foo(&[1i8]).fo$0o::<456, _>(""); } "#, expect![[r#" *foo* ```rust ra_test_fixture::Foo ``` ```rust impl<'a, T, const N: usize> Foo<'a, N, T> fn foo<'b, const Z: u32, U>(&self, v: U) ``` --- `T` = `i8`, `U` = `&str` "#]], ); } #[test] fn subst_field() { check( r#" struct Foo { field: T } fn bar() { let v = Foo { $0field: 123 }; } "#, expect![[r#" *field* ```rust ra_test_fixture::Foo ``` ```rust field: T ``` --- `T` = `i32` "#]], ); check( r#" struct Foo { field: T } fn bar() { let field = 123; let v = Foo { field$0 }; } "#, expect![[r#" *field* ```rust let field: i32 ``` --- ```rust ra_test_fixture::Foo ``` ```rust field: T ``` --- `T` = `i32` "#]], ); check( r#" struct Foo { field: T } fn bar() { let v = Foo { field: 123 }; let Foo { field$0 } = v; } "#, expect![[r#" *field* ```rust let field: i32 ``` --- size = 4, align = 4, no Drop --- ```rust ra_test_fixture::Foo ``` ```rust field: T ``` --- type param may need Drop --- `T` = `i32` "#]], ); check( r#" struct Foo { field: T } fn bar() { let v = Foo { field: 123 }; let Foo { field$0: _ } = v; } "#, expect![[r#" *field* ```rust ra_test_fixture::Foo ``` ```rust field: T ``` --- `T` = `i32` "#]], ); check( r#" struct Foo { field: T } fn bar() { let v = Foo { field: 123 }; let _ = (&v).$0field; } "#, expect![[r#" *field* ```rust ra_test_fixture::Foo ``` ```rust field: T ``` --- `T` = `i32` "#]], ); check( r#" struct Foo(T); fn bar() { let v = Foo(123); let _ = v.$00; } "#, expect![[r#" *0* ```rust ra_test_fixture::Foo ``` ```rust 0: T ``` --- `T` = `i32` "#]], ); } #[test] fn i128_max() { check( r#" //- /core.rs library crate:core #![rustc_coherence_is_core] impl u128 { pub const MAX: Self = 340_282_366_920_938_463_463_374_607_431_768_211_455u128; } impl i128 { pub const MAX: Self = (u128::MAX >> 1) as Self; } //- /foo.rs crate:foo deps:core fn foo() { let _ = i128::MAX$0; } "#, expect![ r#" *MAX* ```rust core ``` ```rust pub const MAX: Self = 170141183460469231731687303715884105727 (0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) ``` "# ], ); } #[test] fn test_runnables_with_snapshot_tests() { check_actions( r#" //- /lib.rs crate:foo deps:expect_test,insta,snapbox use expect_test::expect; use insta::assert_debug_snapshot; use snapbox::Assert; #[test] fn test$0() { let actual = "new25"; expect!["new25"].assert_eq(&actual); Assert::new() .action_env("SNAPSHOTS") .eq(actual, snapbox::str!["new25"]); assert_debug_snapshot!(actual); } //- /lib.rs crate:expect_test struct Expect; impl Expect { fn assert_eq(&self, actual: &str) {} } #[macro_export] macro_rules! expect { ($e:expr) => Expect; // dummy } //- /lib.rs crate:insta #[macro_export] macro_rules! assert_debug_snapshot { ($e:expr) => {}; // dummy } //- /lib.rs crate:snapbox pub struct Assert; impl Assert { pub fn new() -> Self { Assert } pub fn action_env(&self, env: &str) -> &Self { self } pub fn eq(&self, actual: &str, expected: &str) {} } #[macro_export] macro_rules! str { ($e:expr) => ""; // dummy } "#, expect![[r#" [ Reference( FilePositionWrapper { file_id: FileId( 0, ), offset: 92, }, ), Runnable( Runnable { use_name_in_title: false, nav: NavigationTarget { file_id: FileId( 0, ), full_range: 81..301, focus_range: 92..96, name: "test", kind: Function, }, kind: Test { test_id: Path( "test", ), attr: TestAttr { ignore: false, }, }, cfg: None, update_test: UpdateTest { expect_test: true, insta: true, snapbox: true, }, }, ), ] "#]], ); } #[test] fn test_runnables_with_snapshot_tests_indirect_dep() { check_actions( r#" //- /lib.rs crate:foo deps:utils use utils::expect_test::expect; #[test] fn test$0() { let actual = "new25"; expect!["new25"].assert_eq(&actual); } //- /expect-test/lib.rs crate:expect_test struct Expect; impl Expect { fn assert_eq(&self, actual: &str) {} } #[macro_export] macro_rules! expect { ($e:expr) => Expect; // dummy } //- /utils/lib.rs crate:utils deps:expect_test pub use expect_test; "#, expect![[r#" [ Reference( FilePositionWrapper { file_id: FileId( 0, ), offset: 44, }, ), Runnable( Runnable { use_name_in_title: false, nav: NavigationTarget { file_id: FileId( 0, ), full_range: 33..121, focus_range: 44..48, name: "test", kind: Function, }, kind: Test { test_id: Path( "test", ), attr: TestAttr { ignore: false, }, }, cfg: None, update_test: UpdateTest { expect_test: true, insta: false, snapbox: false, }, }, ), ] "#]], ); } #[test] fn drop_glue() { check( r#" struct NoDrop$0; "#, expect![[r#" *NoDrop* ```rust ra_test_fixture ``` ```rust struct NoDrop ``` --- size = 0, align = 1, no Drop "#]], ); check( r#" //- minicore: drop struct NeedsDrop$0; impl Drop for NeedsDrop { fn drop(&mut self) {} } "#, expect![[r#" *NeedsDrop* ```rust ra_test_fixture ``` ```rust struct NeedsDrop ``` --- size = 0, align = 1, impl Drop "#]], ); check( r#" //- minicore: manually_drop, drop struct NeedsDrop; impl Drop for NeedsDrop { fn drop(&mut self) {} } type NoDrop$0 = core::mem::ManuallyDrop; "#, expect![[r#" *NoDrop* ```rust ra_test_fixture ``` ```rust type NoDrop = core::mem::ManuallyDrop ``` --- size = 0, align = 1, no Drop "#]], ); check( r#" //- minicore: drop struct NeedsDrop; impl Drop for NeedsDrop { fn drop(&mut self) {} } struct DropField$0 { _x: i32, _y: NeedsDrop, } "#, expect![[r#" *DropField* ```rust ra_test_fixture ``` ```rust struct DropField { _x: i32, _y: NeedsDrop, } ``` --- size = 4, align = 4, largest padding = 0, needs Drop "#]], ); check( r#" //- minicore: sized type Foo$0 = impl Sized; "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust type Foo = impl Sized ``` --- no Drop "#]], ); check( r#" //- minicore: drop struct NeedsDrop; impl Drop for NeedsDrop { fn drop(&mut self) {} } enum Enum { A$0(&'static str), B(NeedsDrop) } "#, expect![[r#" *A* ```rust ra_test_fixture::Enum ``` ```rust A(&'static str) ``` --- size = 16 (0x10), align = 8, niches = 1, no Drop "#]], ); check( r#" struct Foo$0(T); "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo(T) ``` --- type param may need Drop "#]], ); check( r#" //- minicore: copy struct Foo$0(T); "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo(T) where T: Copy, ``` --- no Drop "#]], ); check( r#" //- minicore: copy trait Trait { type Assoc: Copy; } struct Foo$0(T::Assoc); "#, expect![[r#" *Foo* ```rust ra_test_fixture ``` ```rust struct Foo(::Assoc) where T: Trait, ``` --- no Drop "#]], ); check( r#" #[rustc_coherence_is_core] #[lang = "manually_drop"] #[repr(transparent)] pub struct ManuallyDrop$0 { value: T, } "#, expect![[r#" *ManuallyDrop* ```rust ra_test_fixture ``` ```rust pub struct ManuallyDrop where T: ?Sized, { value: T, } ``` --- no Drop "#]], ); } #[test] fn projection_const() { // This uses two crates, which have *no* relation between them, to test another thing: // `render_const_scalar()` used to just use the last crate for the trait env, which will // fail in this scenario. check( r#" //- /foo.rs crate:foo pub trait PublicFlags { type Internal; } pub struct NoteDialects(::Internal); impl NoteDialects { pub const CLAP$0: Self = Self(InternalBitFlags); } pub struct InternalBitFlags; impl PublicFlags for NoteDialects { type Internal = InternalBitFlags; } //- /bar.rs crate:bar "#, expect![[r#" *CLAP* ```rust foo::NoteDialects ``` ```rust pub const CLAP: Self = NoteDialects(InternalBitFlags) ``` "#]], ); } #[test] fn bounds_from_container_do_not_panic() { check( r#" //- minicore: copy struct Foo(T); impl Foo { fn foo(&self, _u: U) {} } fn bar(v: &Foo) { v.$0foo(1u32); } "#, expect![[r#" *foo* ```rust ra_test_fixture::Foo ``` ```rust impl Foo fn foo(&self, _u: U) where U: Copy, // Bounds from impl: T: Copy, ``` --- `T` = `i32`, `U` = `u32` "#]], ); } #[test] fn extra_lifetime_param_on_trait_method_subst() { check( r#" struct AudioFormat; trait ValueEnum { fn to_possible_value(&self); } impl ValueEnum for AudioFormat { fn to_possible_value<'a>(&'a self) {} } fn main() { ValueEnum::to_possible_value$0(&AudioFormat); } "#, expect![[r#" *to_possible_value* ```rust ra_test_fixture::AudioFormat ``` ```rust fn to_possible_value<'a>(&'a self) ``` "#]], ); } #[test] fn keyword_inside_link() { check( r#" enum Foo { MacroExpansion, } /// I return a [macro expansion](Foo::MacroExpansion). fn bar$0() -> Foo { Foo::MacroExpansion } "#, expect![[r#" *bar* ```rust ra_test_fixture ``` ```rust fn bar() -> Foo ``` --- I return a [macro expansion](https://docs.rs/ra_test_fixture/*/ra_test_fixture/enum.Foo.html#variant.MacroExpansion). "#]], ); } #[test] fn regression_20190() { check( r#" struct Foo; /// [`foo` bar](Foo). fn has_docs$0() {} "#, expect![[r#" *has_docs* ```rust ra_test_fixture ``` ```rust fn has_docs() ``` --- [`foo` bar](https://docs.rs/ra_test_fixture/*/ra_test_fixture/struct.Foo.html). "#]], ); } #[test] fn regression_20225() { check( r#" //- minicore: coerce_unsized trait Trait { type Type<'a, T: ?Sized + 'a>; } enum Borrowed {} impl Trait for Borrowed { type Type<'a, T: ?Sized + 'a> = &'a T; } enum Enum<'a, T: Trait + 'a> { Variant1(T::Type<'a, [Enum<'a, T>]>), Variant2, } impl Enum<'_, Borrowed> { const CONSTANT$0: Self = Self::Variant1(&[Self::Variant2]); } "#, expect![[r#" *CONSTANT* ```rust ra_test_fixture::Enum ``` ```rust const CONSTANT: Self = Variant1(&[Variant2]) ``` "#]], ); } #[test] fn unknown_should_not_implement_notable_traits() { check( r#" //- minicore: future, iterator fn foo() { let x$0; } "#, expect![[r#" *x* ```rust let x: {unknown} ``` --- no Drop "#]], ); } #[test] fn hover_trait_impl_shows_generic_args() { // Single generic arg check( r#" trait Foo { fn foo(&self) {} } impl Foo<()> for T { fn fo$0o(&self) {} } fn bar() { ().foo(); } "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust impl Foo<()> for T fn foo(&self) ``` "#]], ); // Multiple generic args check( r#" trait Foo { fn foo(&self) {} } impl Foo for T { fn fo$0o(&self) {} } "#, expect![[r#" *foo* ```rust ra_test_fixture ``` ```rust impl Foo for T fn foo(&self) ``` "#]], ); } #[test] fn doc_link_enum_self_variant() { check( r#" /// - [`VariantOne$0`](Self::One) pub enum MyEnum { One, Two, } "#, expect![[r#" *[`VariantOne`](Self::One)* ```rust ra_test_fixture::MyEnum ``` ```rust One = 0 ``` "#]], ); } #[test] fn doc_link_trait_self() { check( r#" /// - [`do_something$0`](Self::do_something) pub trait MyTrait { fn do_something(&self); } "#, expect![[r#" *[`do_something`](Self::do_something)* ```rust ra_test_fixture::MyTrait ``` ```rust pub trait MyTrait pub fn do_something(&self) ``` "#]], ); check( r#" pub trait MyTrait { /// - [`do_something$0`](Self::do_something) fn do_something(&self); } "#, expect![[r#" *[`do_something`](Self::do_something)* ```rust ra_test_fixture::MyTrait ``` ```rust pub trait MyTrait pub fn do_something(&self) ``` --- * [`do_something`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/trait.MyTrait.html#tymethod.do_something) "#]], ); }