use expect_test::{expect, Expect};
use ide_db::{base_db::SourceDatabase, FileRange};
use syntax::TextRange;

use crate::{
    fixture, HoverConfig, HoverDocFormat, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
};

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),
        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,
};

fn check_hover_no_result(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(ra_fixture: &str, expect: Expect) {
    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[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<Option<usize>>,
    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);
    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<Option<usize>>,
    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);
    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, 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);
    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(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);
    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(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);
    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(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);
    let hovered_element = &content[hover.range];

    let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup);
    expect.assert_eq(&actual)
}

fn check_actions(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(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(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(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
fn main() {
    let x = 2;
    let y = $0|z| x + z;
}
"#,
        expect![[r#"
            *|*
            ```rust
            {closure#0}
            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
            {closure#0}
            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
            {closure#0}
            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
            {closure#0}
            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
            {closure#0}
            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<Args>\nwhere\n    Args: Tuple,",
                            },
                        },
                    ],
                ),
            ]
        "#]],
    );
}

#[test]
fn hover_shows_long_type_of_an_expression() {
    check(
        r#"
struct Scan<A, B, C> { a: A, b: B, c: C }
struct Iter<I> { inner: I }
enum Option<T> { Some(T), None }

struct OtherStruct<T> { i: T }

fn scan<A, B, C>(a: A, b: B, c: C) -> Iter<Scan<OtherStruct<A>, 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<u32> {
        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<Scan<OtherStruct<OtherStruct<i32>>, impl Fn(&mut u32, &u32, &mut u32) -> Option<u32>, u32>>
            ```

            ---

            size = 8, align = 4
        "#]],
    );
}

#[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<V: AsRef<str>>(bar: impl T, baz: V) { }

fn main() { fo$0o(); }
        "#,
        expect![[r#"
            *foo*

            ```rust
            ra_test_fixture
            ```

            ```rust
            pub fn foo<V>(bar: impl T, baz: V)
            where
                V: AsRef<str>,
            ```
        "#]],
    );
}

#[test]
fn hover_shows_fn_signature_with_type_params() {
    check(
        r#"
pub fn foo<'a, T: AsRef<str>>(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<str>,
            ```
        "#]],
    );
}

#[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
        "#]],
    );
}

#[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
        "#]],
    );
}

#[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
        "#]],
    );
}

#[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
        "#]],
    );
    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
        "#]],
    );
}

#[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
        "#]],
    );
    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
        "#]],
    );
    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
        "#]],
    );
    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
        "#]],
    );
    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
        "#]],
    );

    // 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
        "#]],
    );
}

#[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
        "#]],
    );
    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
        "#]],
    );
    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
        "#]],
    );
    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
        "#]],
    );
    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
        "#]],
    );
}

#[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
        "#]],
    );
    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
        "#]],
    );
    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
        "#]],
    );
    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
        "#]],
    );
    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 = 4294967288
        "#]],
    );
}

#[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
        "#]],
    );
    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
        "#]],
    );
    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
        "#]],
    );
    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
        "#]],
    );
}

#[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
        "#]],
    );
}

#[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,
            ```
        "#]],
    );
}

#[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, T = u8> { k: K, t: T }

fn main() {
    let zz$0 = Test { t: 23u8, k: 33 };
}"#,
        expect![[r#"
            *zz*

            ```rust
            let zz: Test<i32>
            ```

            ---

            size = 8, align = 4
        "#]],
    );
    check_hover_range(
        r#"
struct Test<K, T = u8> { k: K, t: T }

fn main() {
    let $0zz$0 = Test { t: 23u8, k: 33 };
}"#,
        expect![[r#"
            ```rust
            Test<i32, u8>
            ```"#]],
    );
}

#[test]
fn hover_some() {
    check(
        r#"
enum Option<T> { 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<T> { Some(T) }
use Option::Some;

fn main() { let b$0ar = Some(12); }
"#,
        expect![[r#"
            *bar*

            ```rust
            let bar: Option<i32>
            ```

            ---

            size = 4, align = 4
        "#]],
    );
}

#[test]
fn hover_enum_variant() {
    check(
        r#"
enum Option<T> {
    Some(T)
    /// The None variant
    Non$0e
}
"#,
        expect![[r#"
            *None*

            ```rust
            ra_test_fixture::Option
            ```

            ```rust
            None
            ```

            ---

            The None variant
        "#]],
    );

    check(
        r#"
enum Option<T> {
    /// 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
        "#]],
    )
}

#[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
        "#]],
    )
}

#[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<Target=u8> + DerefMut<Target=u8>) {}"#,
        expect![[r#"
            *_x*

            ```rust
            _x: impl Deref<Target = u8> + DerefMut<Target = u8>
            ```
        "#]],
    )
}

#[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
        "#]],
    )
}

#[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,
            }
            ```
        "#]],
    );
    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
            ```
        "#]],
    );
    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,
            }
            ```
        "#]],
    );
    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,
            }
            ```
        "#]],
    );
    check(
        r#"
enum Thing { A }
impl Thing {
    pub fn thing(a: Self$0) {}
}
"#,
        expect![[r#"
            *Self*

            ```rust
            ra_test_fixture
            ```

            ```rust
            enum Thing {
                A,
            }
            ```
        "#]],
    );
    check(
        r#"
impl usize {
    pub fn thing(a: Self$0) {}
}
"#,
        expect![[r#"
            *Self*

            ```rust
            ra_test_fixture
            ```

            ```rust
            usize
            ```
        "#]],
    );
    check(
        r#"
impl fn() -> usize {
    pub fn thing(a: Self$0) {}
}
"#,
        expect![[r#"
            *Self*

            ```rust
            ra_test_fixture
            ```

            ```rust
            fn() -> usize
            ```
        "#]],
    );
}

#[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_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: <i32 as Foo>::Bar) {}
fn main() { foo$0; }
"#,
        expect![[r#"
            *foo*

            ```rust
            ra_test_fixture
            ```

            ```rust
            fn foo(arg: <i32 as Foo>::Bar)
            ```
        "#]],
    );

    check(
        r#"
trait Foo<T> { type Bar<U>; }
impl Foo<i64> for i32 { type Bar<U> = i32; }
fn foo(arg: <<i32 as Foo<i64>>::Bar<i8> as Foo<i64>>::Bar<i8>) {}
fn main() { foo$0; }
"#,
        expect![[r#"
            *foo*

            ```rust
            ra_test_fixture
            ```

            ```rust
            fn foo(arg: <<i32 as Foo<i64>>::Bar<i8> as Foo<i64>>::Bar<i8>)
            ```
        "#]],
    );
}

#[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
        "#]],
    );
}

#[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
        "#]],
    );
}

#[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

            ---

            [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

            ---

            [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: <http://www.example.com/>
/// case 6.  email address: <test@example.com>
/// 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
        "#]],
    );
}

#[test]
fn test_hover_layout_of_variant_generic() {
    check(
        r#"enum Option<T> {
    Some(T),
    None$0
}"#,
        expect![[r#"
            *None*

            ```rust
            ra_test_fixture::Option
            ```

            ```rust
            None
            ```
        "#]],
    );
}

#[test]
fn test_hover_layout_generic_unused() {
    check(
        r#"
//- minicore: phantom_data
struct S$0<T>(core::marker::PhantomData<T>);
"#,
        expect![[r#"
            *S*

            ```rust
            ra_test_fixture
            ```

            ```rust
            struct S<T>(PhantomData<T>)
            ```

            ---

            size = 0, align = 1
        "#]],
    );
}

#[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
        "#]],
    );
}

#[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
            ```
        "#]],
    );

    check_hover_no_memory_layout(
        r#"
//- minicore: copy
fn main() {
    let x = 2;
    let y = $0|z| x + z;
}
"#,
        expect![[r#"
            *|*
            ```rust
            {closure#0}
            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::<extern>
            ```

            ```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,
                    },
                ),
            ]
        "#]],
    );
}

#[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,
                        },
                    ),
                ]
            "#]],
    );
}

#[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<T>{ 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<T>",
                            },
                        },
                    ],
                ),
            ]
        "#]],
    );
}

#[test]
fn test_hover_generic_excludes_sized_go_to_action() {
    check_actions(
        r#"
//- minicore: sized
struct S<T$0>(T);
    "#,
        expect![[r#"
            []
        "#]],
    );
}

#[test]
fn test_hover_generic_struct_has_flattened_goto_type_actions() {
    check_actions(
        r#"
struct Arg(u32);
struct S<T>{ 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<T>",
                            },
                        },
                    ],
                ),
            ]
        "#]],
    );
}

#[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<T> {}
struct S;
fn foo() -> impl Foo<S> {}

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<T>",
                            },
                        },
                        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<T> {}
trait Bar<T> {}
struct S1 {}
struct S2 {}

fn foo() -> impl Foo<S1> + Bar<S2> {}

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<T>",
                            },
                        },
                        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<T>",
                            },
                        },
                        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<T> {}
struct S{}

fn foo(ar$0g: &impl Foo + Bar<S>) {}
"#,
        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<T>",
                            },
                        },
                        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
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<T> {}
struct S {}
fn foo(ar$0g: &impl Foo<S>) {}
"#,
        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<T>",
                            },
                        },
                        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<T> {}
struct S;
impl Foo<S> for S {}

struct B<T>{}
fn foo() -> B<dyn Foo<S>> {}

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<T>",
                            },
                        },
                        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<T>",
                            },
                        },
                        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<T> {}
struct S {}
fn foo(ar$0g: &dyn Foo<S>) {}
"#,
        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<T>",
                            },
                        },
                        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<T> {}
trait DynTrait<T> {}
struct B<T> {}
struct S {}

fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
"#,
        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<T>",
                            },
                        },
                        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<T>",
                            },
                        },
                        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<T>",
                            },
                        },
                        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<const BAR: Bar>;

impl<const BAR: Bar> Foo<BAR$0> {}
"#,
        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: 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
            ---

            ```rust
            ra_test_fixture::S
            ```

            ```rust
            f: i32
            ```

            ---

            size = 4, align = 4, offset = 0
        "#]],
    );
}

#[test]
fn const_generic_order() {
    check(
        r#"
struct Foo;
struct S$0T<const C: usize = 1, T = Foo>(T);
"#,
        expect![[r#"
            *ST*

            ```rust
            ra_test_fixture
            ```

            ```rust
            struct ST<const C: usize = 1, T = Foo>(T)
            ```

            ---

            size = 0, align = 1
        "#]],
    );
}

#[test]
fn const_generic_default_value() {
    check(
        r#"
struct Foo;
struct S$0T<const C: usize = {40 + 2}, T = Foo>(T);
"#,
        expect![[r#"
            *ST*

            ```rust
            ra_test_fixture
            ```

            ```rust
            struct ST<const C: usize = {const}, T = Foo>(T)
            ```

            ---

            size = 0, align = 1
        "#]],
    );
}

#[test]
fn const_generic_default_value_2() {
    check(
        r#"
struct Foo;
const VAL = 1;
struct S$0T<const C: usize = VAL, T = Foo>(T);
"#,
        expect![[r#"
            *ST*

            ```rust
            ra_test_fixture
            ```

            ```rust
            struct ST<const C: usize = VAL, T = Foo>(T)
            ```

            ---

            size = 0, align = 1
        "#]],
    );
}

#[test]
fn const_generic_positive_i8_literal() {
    check(
        r#"
struct Const<const N: i8>;

fn main() {
    let v$0alue = Const::<1>;
}
"#,
        expect![[r#"
            *value*

            ```rust
            let value: Const<1>
            ```

            ---

            size = 0, align = 1
        "#]],
    );
}

#[test]
fn const_generic_zero_i8_literal() {
    check(
        r#"
struct Const<const N: i8>;

fn main() {
    let v$0alue = Const::<0>;
}
"#,
        expect![[r#"
            *value*

            ```rust
            let value: Const<0>
            ```

            ---

            size = 0, align = 1
        "#]],
    );
}

#[test]
fn const_generic_negative_i8_literal() {
    check(
        r#"
struct Const<const N: i8>;

fn main() {
    let v$0alue = Const::<-1>;
}
"#,
        expect![[r#"
            *value*

            ```rust
            let value: Const<-1>
            ```

            ---

            size = 0, align = 1
        "#]],
    );
}

#[test]
fn const_generic_bool_literal() {
    check(
        r#"
struct Const<const F: bool>;

fn main() {
    let v$0alue = Const::<true>;
}
"#,
        expect![[r#"
            *value*

            ```rust
            let value: Const<true>
            ```

            ---

            size = 0, align = 1
        "#]],
    );
}

#[test]
fn const_generic_char_literal() {
    check(
        r#"
struct Const<const C: char>;

fn main() {
    let v$0alue = Const::<'🦀'>;
}
"#,
        expect![[r#"
            *value*

            ```rust
            let value: Const<'🦀'>
            ```

            ---

            size = 0, align = 1
        "#]],
    );
}

#[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
        "#]],
    );
}

#[test]
fn hover_self_param_shows_type_for_arbitrary_self_type() {
    check(
        r#"
struct Arc<T>(T);
struct Foo {}
impl Foo {
    fn bar(sel$0f: Arc<Foo>) {}
}
"#,
        expect![[r#"
            *self*

            ```rust
            self: Arc<Foo>
            ```

            ---

            size = 0, align = 1
        "#]],
    );
}

#[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
            'lifetime
            ```
        "#]],
    );
    check(
        r#"fn foo(_: &'static$0 ()) {}"#,
        expect![[r#"
            *'static*

            ```rust
            'static
            ```
        "#]],
    );
}

#[test]
fn hover_type_param() {
    check(
        r#"
//- minicore: sized
struct Foo<T>(T);
trait TraitA {}
trait TraitB {}
impl<T: TraitA + TraitB> Foo<T$0> where T: Sized {}
"#,
        expect![[r#"
            *T*

            ```rust
            T: TraitA + TraitB
            ```
        "#]],
    );
    check(
        r#"
//- minicore: sized
struct Foo<T>(T);
impl<T> Foo<T$0> {}
"#,
        expect![[r#"
            *T*

            ```rust
            T
            ```
        "#]],
    );
    check(
        r#"
//- minicore: sized
struct Foo<T>(T);
impl<T: 'static> Foo<T$0> {}
"#,
        expect![[r#"
            *T*

            ```rust
            T: 'static
            ```
        "#]],
    );
}

#[test]
fn hover_type_param_sized_bounds() {
    // implicit `: Sized` bound
    check(
        r#"
//- minicore: sized
trait Trait {}
struct Foo<T>(T);
impl<T$0: Trait> Foo<T> {}
"#,
        expect![[r#"
            *T*

            ```rust
            T: Trait
            ```
        "#]],
    );
    check(
        r#"
//- minicore: sized
trait Trait {}
struct Foo<T>(T);
impl<T$0: Trait + ?Sized> Foo<T> {}
"#,
        expect![[r#"
            *T*

            ```rust
            T: Trait + ?Sized
            ```
        "#]],
    );
}

mod type_param_sized_bounds {
    use super::*;

    #[test]
    fn single_implicit() {
        check(
            r#"
//- minicore: sized
fn foo<T$0>() {}
"#,
            expect![[r#"
                *T*

                ```rust
                T
                ```

                ---

                invariant
            "#]],
        );
    }

    #[test]
    fn single_explicit() {
        check(
            r#"
//- minicore: sized
fn foo<T$0: Sized>() {}
"#,
            expect![[r#"
                *T*

                ```rust
                T
                ```

                ---

                invariant
            "#]],
        );
    }

    #[test]
    fn single_relaxed() {
        check(
            r#"
//- minicore: sized
fn foo<T$0: ?Sized>() {}
"#,
            expect![[r#"
                *T*

                ```rust
                T: ?Sized
                ```

                ---

                invariant
            "#]],
        );
    }

    #[test]
    fn multiple_implicit() {
        check(
            r#"
//- minicore: sized
trait Trait {}
fn foo<T$0: Trait>() {}
"#,
            expect![[r#"
                *T*

                ```rust
                T: Trait
                ```

                ---

                invariant
            "#]],
        );
    }

    #[test]
    fn multiple_explicit() {
        check(
            r#"
//- minicore: sized
trait Trait {}
fn foo<T$0: Trait + Sized>() {}
"#,
            expect![[r#"
                *T*

                ```rust
                T: Trait
                ```

                ---

                invariant
            "#]],
        );
    }

    #[test]
    fn multiple_relaxed() {
        check(
            r#"
//- minicore: sized
trait Trait {}
fn foo<T$0: Trait + ?Sized>() {}
"#,
            expect![[r#"
                *T*

                ```rust
                T: Trait + ?Sized
                ```

                ---

                invariant
            "#]],
        );
    }

    #[test]
    fn mixed() {
        check(
            r#"
//- minicore: sized
fn foo<T$0: ?Sized + Sized + Sized>() {}
"#,
            expect![[r#"
                *T*

                ```rust
                T
                ```

                ---

                invariant
            "#]],
        );
    }

    #[test]
    fn mixed2() {
        check(
            r#"
//- minicore: sized
trait Trait {}
fn foo<T$0: Sized + ?Sized + Sized + Trait>() {}
"#,
            expect![[r#"
                *T*

                ```rust
                T: Trait
                ```

                ---

                invariant
            "#]],
        );
    }
}

#[test]
fn hover_const_generic_type_alias() {
    check(
        r#"
struct Foo<const LEN: usize>;
type Fo$0o2 = Foo<2>;
"#,
        expect![[r#"
            *Foo2*

            ```rust
            ra_test_fixture
            ```

            ```rust
            type Foo2 = Foo<2>
            ```

            ---

            size = 0, align = 1
        "#]],
    );
}

#[test]
fn hover_const_param() {
    check(
        r#"
struct Foo<const LEN: usize>;
impl<const LEN: usize> Foo<LEN$0> {}
"#,
        expect![[r#"
            *LEN*

            ```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

            ---

            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

            ---

            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

            ---

            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

            ---

            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() {
    <i32>::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() {
    <i32>::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 `<ref-not-supported>` 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<i32> = Some(2);
"#,
        expect![[r#"
            *FOO*

            ```rust
            ra_test_fixture
            ```

            ```rust
            const FOO: Option<i32> = 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; 5] = &[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: ?Sized>(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")
            ```
        "#]],
    );
}

#[test]
fn hover_const_eval_in_generic_trait() {
    // Doesn't compile, but we shouldn't crash.
    check(
        r#"
trait Trait<T> {
    const FOO: bool = false;
}
struct S<T>(T);
impl<T> Trait<T> for S<T> {
    const FOO: bool = true;
}

fn test() {
    S::FOO$0;
}
"#,
        expect![[r#"
            *FOO*

            ```rust
            ra_test_fixture::S
            ```

            ```rust
            const FOO: bool = true
            ```
        "#]],
    );
}

#[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
        "#]],
    );
}

#[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
            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]
/// <https://doc.rust-lang.org/nightly/book/ch13-01-closures.html>
///
/// [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)
            <https://doc.rust-lang.org/nightly/book/ch13-01-closures.html>
        "#]],
    );
}

#[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 = <Foo as t2::T2>::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<T: A>() where T::Assoc$0: {}

trait A {
    type Assoc;
}"#,
        expect![[r#"
            *Assoc*

            ```rust
            ra_test_fixture::A
            ```

            ```rust
            type Assoc
            ```
        "#]],
    );
    check(
        r#"
fn foo<T: A>() {
    let _: <T>::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() {
    check(
        r#"#![feature(intrinsics$0)]"#,
        expect![[r#"
            *intrinsics*
            ```
            intrinsics
            ```
            ___

            # `intrinsics`

            The tracking issue for this feature is: None.

            Intrinsics are rarely intended to be stable directly, but are usually
            exported in some sort of stable manner. Prefer using the stable interfaces to
            the intrinsic directly when you can.

            ------------------------


            ## Intrinsics with fallback logic

            Many intrinsics can be written in pure rust, albeit inefficiently or without supporting
            some features that only exist on some backends. Backends can simply not implement those
            intrinsics without causing any code miscompilations or failures to compile.
            All intrinsic fallback bodies are automatically made cross-crate inlineable (like `#[inline]`)
            by the codegen backend, but not the MIR inliner.

            ```rust
            #![feature(intrinsics)]
            #![allow(internal_features)]

            #[rustc_intrinsic]
            const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
            ```

            Since these are just regular functions, it is perfectly ok to create the intrinsic twice:

            ```rust
            #![feature(intrinsics)]
            #![allow(internal_features)]

            #[rustc_intrinsic]
            const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}

            mod foo {
                #[rustc_intrinsic]
                const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {
                    panic!("noisy const dealloc")
                }
            }

            ```

            The behaviour on backends that override the intrinsic is exactly the same. On other
            backends, the intrinsic behaviour depends on which implementation is called, just like
            with any regular function.

            ## Intrinsics lowered to MIR instructions

            Various intrinsics have native MIR operations that they correspond to. Instead of requiring
            backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass
            will convert the calls to the MIR operation. Backends do not need to know about these intrinsics
            at all. These intrinsics only make sense without a body, and can either be declared as a "rust-intrinsic"
            or as a `#[rustc_intrinsic]`. The body is never used, as calls to the intrinsic do not exist
            anymore after MIR analyses.

            ## Intrinsics without fallback logic

            These must be implemented by all backends.

            ### `#[rustc_intrinsic]` declarations

            These are written like intrinsics with fallback bodies, but the body is irrelevant.
            Use `loop {}` for the body or call the intrinsic recursively and add
            `#[rustc_intrinsic_must_be_overridden]` to the function to ensure that backends don't
            invoke the body.

            ### Legacy extern ABI based intrinsics

            These are imported as if they were FFI functions, with the special
            `rust-intrinsic` ABI. For example, if one was in a freestanding
            context, but wished to be able to `transmute` between types, and
            perform efficient pointer arithmetic, one would import those functions
            via a declaration like

            ```rust
            #![feature(intrinsics)]
            #![allow(internal_features)]
            # fn main() {}

            extern "rust-intrinsic" {
                fn transmute<T, U>(x: T) -> U;

                fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
            }
            ```

            As with any other FFI functions, these are by default always `unsafe` to call.
            You can add `#[rustc_safe_intrinsic]` to the intrinsic to make it safe to call.

        "#]],
    )
}

#[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<T>(a: &[T]) { }
fn b() { $0f$0(&[1, 2, 3, 4, 5]); }
"#,
        expect![[r#"
            ```rust
            fn f<i32>(&[i32])
            ```"#]],
    );

    check_hover_range(
        r#"
fn f<T>(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<T>(a: &[T]) { }
fn b()$0 { f(&[1, 2, 3, 4, 5]); }$0
"#,
    );

    check_hover_range_no_results(
        r#"
fn f<T>$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<T>(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>(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>(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<T> {
    value: T
}

impl<T> Deref for DerefExample<T> {
    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
                ```
            "#]],
    );
}

#[test]
fn hover_deref_expr_with_coercion() {
    check_hover_range(
        r#"
//- minicore: deref
use core::ops::Deref;

struct DerefExample<T> {
    value: T
}

impl<T> Deref for DerefExample<T> {
    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_generics() {
    check(
        r#"
/// Doc comment for [`Foo$0<T>`]
pub struct Foo<T>(T);
"#,
        expect![[r#"
            *[`Foo<T>`]*

            ```rust
            ra_test_fixture
            ```

            ```rust
            pub struct Foo<T>(T)
            ```

            ---

            Doc comment for [`Foo<T>`](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
        "#]],
    );
}

#[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
        "#]],
    );
}

#[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_hover_no_result(
        r#"
fn main() {
    let x: _$0 = 0;
}
"#,
    );
    check_hover_no_result(
        r#"
fn main() {
    let x: (_$0,) = (0,);
}
"#,
    );
}

#[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::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::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::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::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::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::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
        "#]],
    );
}

#[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<T>(&self, t: T) {}
}

fn main() {
    S.foo$0;
}
"#,
        expect![[r#"
            *foo*

            ```rust
            ra_test_fixture::S
            ```

            ```rust
            fn foo<T>(&self, t: T)
            ```
        "#]],
    );
}

#[test]
fn string_literal() {
    check(
        r#"
fn main() {
    $0"🦀\u{1f980}\\\x41";
}
"#,
        expect![[r#"
            *"🦀\u{1f980}\\\x41"*
            ```rust
            &str
            ```
            ___

            value of literal: 🦀🦀\A
        "#]],
    );
    check(
        r#"
fn main() {
    $0r"🦀\u{1f980}\\\x41";
}
"#,
        expect![[r#"
            *r"🦀\u{1f980}\\\x41"*
            ```rust
            &str
            ```
            ___

            value of literal: 🦀\u{1f980}\\\x41
        "#]],
    );
    check(
        r#"
fn main() {
    $0r"🦀\u{1f980}\\\x41


fsdghs";
}
"#,
        expect![[r#"
            *r"🦀\u{1f980}\\\x41


            fsdghs"*
            ```rust
            &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
            &{unknown}
            ```
            ___

            value of literal: 🦀🦀\A
        "#]],
    );
}

#[test]
fn byte_string_literal() {
    check(
        r#"
fn main() {
    $0b"\xF0\x9F\xA6\x80\\";
}
"#,
        expect![[r#"
            *b"\xF0\x9F\xA6\x80\\"*
            ```rust
            &[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
            &[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\<Assoc = &str, Assoc2 = char>

            ---

            size = 4, align = 4
        "#]],
    );
}

#[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::<extern>
            ```

            ```rust
            static STATIC: ()
            ```
        "#]],
    );
    check(
        r#"
extern "C" {
    fn fun$0();
}
"#,
        expect![[r#"
            *fun*

            ```rust
            ra_test_fixture::<extern>
            ```

            ```rust
            unsafe fn fun()
            ```
        "#]],
    );
    check(
        r#"
extern "C" {
    type Ty$0;
}
"#,
        expect![[r#"
            *Ty*

            ```rust
            ra_test_fixture::<extern>
            ```

            ```rust
            type Ty
            ```

            ---

            size = 0, align = 1
        "#]],
    );
}

#[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: Notable, Future<Output = u32>, Iterator<Item = S>"#]],
    );
}

#[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: &str,
            }
            ```

            ---

            size = 16 (0x10), align = 8, niches = 1
        "#]],
    )
}

#[test]
fn hover_impl_trait_arg_self() {
    check(
        r#"
trait T<Rhs = Self> {}
fn main(a$0: impl T) {}
"#,
        expect![[r#"
            *a*

            ```rust
            a: impl T + ?Sized
            ```
        "#]],
    );
}

#[test]
fn hover_struct_default_arg_self() {
    check(
        r#"
struct T<Rhs = Self> {}
fn main(a$0: T) {}
"#,
        expect![[r#"
            *a*

            ```rust
            a: T
            ```

            ---

            size = 0, align = 1
        "#]],
    );
}

#[test]
fn hover_fn_with_impl_trait_arg() {
    check(
        r#"
trait Foo {}
impl Foo for bool {}
fn bar<const WIDTH: u8>(_: 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<A>();
}

struct S {}
impl T for S {
    fn f<A>() {}
}

fn main() {
    let x$0 = S::f::<i32>;
}
"#,
        expect![[r#"
            *x*

            ```rust
            let x: fn f<S, i32>()
            ```

            ---

            size = 0, align = 1
        "#]],
    );
}

#[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 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

            ---

            *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

            ---

            *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

            ---

            *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
        "#]],
    );

    // 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<T>() {}
}
"#,
        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<T>() {}
}
fn f<T: UnCompat$0>
"#,
        expect![[r#"
            *UnCompat*

            ```rust
            ra_test_fixture
            ```

            ```rust
            trait UnCompat
            ```
        "#]],
    );
}

#[test]
fn issue_18613() {
    check(
        r#"
fn main() {
    struct S<T, D = bool>();
    let x$0 = S::<()>;
}"#,
        expect![[r#"
            *x*

            ```rust
            let x: fn S<()>() -> S<()>
            ```

            ---

            size = 0, align = 1
        "#]],
    );

    check(
        r#"
pub struct Global;
pub struct Box<T, A = Global>(T, A);

impl<T> Box<T> {
    pub fn new(x: T) -> Self { loop {} }
}

pub struct String;

fn main() {
    let box_value$0 = Box::<String>new();
}
"#,
        expect![[r#"
            *box_value*

            ```rust
            let box_value: fn Box<String>(String, Global) -> Box<String>
            ```

            ---

            size = 0, align = 1
        "#]],
    );

    check(
        r#"
//- minicore: eq
pub struct RandomState;
pub struct HashMap<K, V, S = RandomState>(K, V, S);

impl<K, V> HashMap<K, V, RandomState> {
    pub fn new() -> HashMap<K, V, RandomState> {
        loop {}
    }
}

impl<K, V, S> PartialEq for HashMap<K, V, S> {
    fn eq(&self, other: &HashMap<K, V, S>) -> bool {
        false
    }
}

fn main() {
    let s$0 = HashMap::<_, u64>::ne;
}
"#,
        expect![[r#"
            *s*

            ```rust
            let s: fn ne<HashMap<{unknown}, u64>>(&HashMap<{unknown}, u64>, &HashMap<{unknown}, u64>) -> bool
            ```

            ---

            size = 0, align = 1
        "#]],
    );
}

#[test]
fn subst_fn() {
    check(
        r#"
struct Foo<T>(T);
impl<T> Foo<T> {
    fn foo<U>(v: T, u: U) {}
}

fn bar() {
    Foo::fo$0o(123, false);
}
        "#,
        expect![[r#"
            *foo*

            ```rust
            ra_test_fixture::Foo
            ```

            ```rust
            impl<T> Foo<T>
            fn foo<U>(v: T, u: U)
            ```

            ---

            `T` = `i32`, `U` = `bool`
        "#]],
    );
    check(
        r#"
fn foo<T>(v: T) {}

fn bar() {
    fo$0o(123);
}
        "#,
        expect![[r#"
            *foo*

            ```rust
            ra_test_fixture
            ```

            ```rust
            fn foo<T>(v: T)
            ```

            ---

            `T` = `i32`
        "#]],
    );
}

#[test]
fn subst_record_constructor() {
    check(
        r#"
struct Foo<T> { field: T }

fn bar() {
    let v = $0Foo { field: 123 };
}
        "#,
        expect![[r#"
            *Foo*

            ```rust
            ra_test_fixture
            ```

            ```rust
            struct Foo<T> {
                field: T,
            }
            ```

            ---

            `T` = `i32`
        "#]],
    );
    check(
        r#"
struct Foo<T> { field: T }

fn bar() {
    let v = Foo { field: 123 };
    let $0Foo { field: _ } = v;
}
        "#,
        expect![[r#"
            *Foo*

            ```rust
            ra_test_fixture
            ```

            ```rust
            struct Foo<T> {
                field: T,
            }
            ```

            ---

            `T` = `i32`
        "#]],
    );
}

#[test]
fn subst_method_call() {
    check(
        r#"
struct Foo<T>(T);

impl<U> Foo<U> {
    fn bar<T>(self, v: T) {}
}

fn baz() {
    Foo(123).bar$0("hello");
}
    "#,
        expect![[r#"
            *bar*

            ```rust
            ra_test_fixture::Foo
            ```

            ```rust
            impl<U> Foo<U>
            fn bar<T>(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<T, U> { a: T, b: U }
type Alias<T> = Foo<T, i32>;

fn foo() {
    let _ = Alias$0 { a: true, b: 123 };
}
    "#,
        expect![[r#"
            *Alias*

            ```rust
            ra_test_fixture
            ```

            ```rust
            type Alias<T> = Foo<T, i32>
            ```
        "#]],
    );
}

#[test]
fn subst_self() {
    check(
        r#"
trait Trait<T> {
    fn foo<U>(&self, v: U) {}
}
struct Struct<T>(T);
impl<T> Trait<i64> for Struct<T> {}

fn bar() {
    Struct(123).foo$0(true);
}
    "#,
        expect![[r#"
            *foo*

            ```rust
            ra_test_fixture::Trait
            ```

            ```rust
            trait Trait<T>
            fn foo<U>(&self, v: U)
            ```

            ---

            `Self` = `Struct<i32>`, `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<T> { 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<T> { 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<T> { 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
            ---

            ```rust
            ra_test_fixture::Foo
            ```

            ```rust
            field: T
            ```

            ---

            `T` = `i32`
        "#]],
    );
    check(
        r#"
struct Foo<T> { 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<T> { 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>(T);

fn bar() {
    let v = Foo(123);
    let _ = v.$00;
}
    "#,
        expect![[r#"
            *0*

            ```rust
            ra_test_fixture::Foo
            ```

            ```rust
            0: T
            ```

            ---

            `T` = `i32`
        "#]],
    );
}
