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

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

#[cfg(test)]
mod tests {
    use crate::completion::{CompletionKind, 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(
            r"
            use self::m::<|>;

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

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

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

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

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