aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_db/src/traits/tests.rs
blob: 84bb255059e6baf4e5df87dd9c7cb205eaa06cfa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use crate::RootDatabase;
use base_db::{fixture::ChangeFixture, FilePosition};
use expect_test::{expect, Expect};
use hir::Semantics;
use syntax::ast::{self, AstNode};
use test_utils::RangeOrOffset;

/// Creates analysis from a multi-file fixture, returns positions marked with $0.
pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
    let change_fixture = ChangeFixture::parse(ra_fixture);
    let mut database = RootDatabase::default();
    database.apply_change(change_fixture.change);
    let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)");
    let offset = match range_or_offset {
        RangeOrOffset::Range(_) => panic!(),
        RangeOrOffset::Offset(it) => it,
    };
    (database, FilePosition { file_id, offset })
}

fn check_trait(ra_fixture: &str, expect: Expect) {
    let (db, position) = position(ra_fixture);
    let sema = Semantics::new(&db);
    let file = sema.parse(position.file_id);
    let impl_block: ast::Impl =
        sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
    let trait_ = crate::traits::resolve_target_trait(&sema, &impl_block);
    let actual = match trait_ {
        Some(trait_) => trait_.name(&db).to_string(),
        None => String::new(),
    };
    expect.assert_eq(&actual);
}

fn check_missing_assoc(ra_fixture: &str, expect: Expect) {
    let (db, position) = position(ra_fixture);
    let sema = Semantics::new(&db);
    let file = sema.parse(position.file_id);
    let impl_block: ast::Impl =
        sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
    let items = crate::traits::get_missing_assoc_items(&sema, &impl_block);
    let actual = items
        .into_iter()
        .map(|item| item.name(&db).unwrap().to_string())
        .collect::<Vec<_>>()
        .join("\n");
    expect.assert_eq(&actual);
}

#[test]
fn resolve_trait() {
    check_trait(
        r#"
pub trait Foo {
    fn bar();
}
impl Foo for u8 {
    $0
}
            "#,
        expect![["Foo"]],
    );
    check_trait(
        r#"
pub trait Foo {
    fn bar();
}
impl Foo for u8 {
    fn bar() {
        fn baz() {
            $0
        }
        baz();
    }
}
            "#,
        expect![["Foo"]],
    );
    check_trait(
        r#"
pub trait Foo {
    fn bar();
}
pub struct Bar;
impl Bar {
    $0
}
            "#,
        expect![[""]],
    );
}

#[test]
fn missing_assoc_items() {
    check_missing_assoc(
        r#"
pub trait Foo {
    const FOO: u8;
    fn bar();
}
impl Foo for u8 {
    $0
}"#,
        expect![[r#"
                FOO
                bar"#]],
    );

    check_missing_assoc(
        r#"
pub trait Foo {
    const FOO: u8;
    fn bar();
}
impl Foo for u8 {
    const FOO: u8 = 10;
    $0
}"#,
        expect![[r#"
                bar"#]],
    );

    check_missing_assoc(
        r#"
pub trait Foo {
    const FOO: u8;
    fn bar();
}
impl Foo for u8 {
    const FOO: u8 = 10;
    fn bar() {$0}
}"#,
        expect![[r#""#]],
    );

    check_missing_assoc(
        r#"
pub struct Foo;
impl Foo {
    fn bar() {$0}
}"#,
        expect![[r#""#]],
    );
}