aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/completion/complete_path.rs
blob: aeb226847fb5b9ed559c55eb4a70dd6c11cf50c4 (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
use crate::{
    completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext},
};

use hir::Docs;

pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
    let (path, module) = match (&ctx.path_prefix, &ctx.module) {
        (Some(path), Some(module)) => (path.clone(), module),
        _ => return,
    };
    let def_id = match module.resolve_path(ctx.db, &path).take_types() {
        Some(it) => it,
        None => return,
    };
    match def_id.resolve(ctx.db) {
        hir::Def::Module(module) => {
            let module_scope = module.scope(ctx.db);
            for (name, res) in module_scope.entries() {
                CompletionItem::new(
                    CompletionKind::Reference,
                    ctx.source_range(),
                    name.to_string(),
                )
                .from_resolution(ctx, res)
                .add_to(acc);
            }
        }
        hir::Def::Enum(e) => {
            e.variants(ctx.db)
                .into_iter()
                .for_each(|(variant_name, variant)| {
                    CompletionItem::new(
                        CompletionKind::Reference,
                        ctx.source_range(),
                        variant_name.to_string(),
                    )
                    .kind(CompletionItemKind::EnumVariant)
                    .set_documentation(variant.docs(ctx.db))
                    .add_to(acc)
                });
        }
        _ => return,
    };
}

#[cfg(test)]
mod tests {
    use crate::completion::CompletionKind;
    use crate::completion::completion_item::check_completion;

    fn check_reference_completion(code: &str, expected_completions: &str) {
        check_completion(code, expected_completions, CompletionKind::Reference);
    }

    #[test]
    fn completes_use_item_starting_with_self() {
        check_reference_completion(
            "use_item_starting_with_self",
            r"
            use self::m::<|>;

            mod m {
                struct Bar;
            }
            ",
        );
    }

    #[test]
    fn completes_use_item_starting_with_crate() {
        check_reference_completion(
            "use_item_starting_with_crate",
            "
            //- /lib.rs
            mod foo;
            struct Spam;
            //- /foo.rs
            use crate::Sp<|>
            ",
        );
    }

    #[test]
    fn completes_nested_use_tree() {
        check_reference_completion(
            "nested_use_tree",
            "
            //- /lib.rs
            mod foo;
            struct Spam;
            //- /foo.rs
            use crate::{Sp<|>};
            ",
        );
    }

    #[test]
    fn completes_deeply_nested_use_tree() {
        check_reference_completion(
            "deeply_nested_use_tree",
            "
            //- /lib.rs
            mod foo;
            pub mod bar {
                pub mod baz {
                    pub struct Spam;
                }
            }
            //- /foo.rs
            use crate::{bar::{baz::Sp<|>}};
            ",
        );
    }

    #[test]
    fn completes_enum_variant() {
        check_reference_completion(
            "reference_completion",
            "
            //- /lib.rs
            enum E { Foo, Bar(i32) }
            fn foo() { let _ = E::<|> }
            ",
        );
    }
}