2020-03-07 15:27:03 +01:00
|
|
|
//! Completion of names from the current scope, e.g. locals and imported items.
|
2019-09-30 11:58:53 +03:00
|
|
|
|
2020-11-14 01:26:31 +02:00
|
|
|
use either::Either;
|
2020-07-07 11:44:16 +02:00
|
|
|
use hir::{Adt, ModuleDef, ScopeDef, Type};
|
2020-11-28 16:30:39 +02:00
|
|
|
use ide_db::helpers::insert_use::ImportScope;
|
2020-11-14 01:26:31 +02:00
|
|
|
use ide_db::imports_locator;
|
2020-11-16 23:16:41 +02:00
|
|
|
use syntax::AstNode;
|
2020-05-20 12:59:20 +02:00
|
|
|
use test_utils::mark;
|
2020-04-17 14:28:20 +02:00
|
|
|
|
2020-11-14 01:26:31 +02:00
|
|
|
use crate::{
|
2020-11-16 23:16:41 +02:00
|
|
|
render::{render_resolution_with_import, RenderContext},
|
2020-12-04 16:03:22 +02:00
|
|
|
CompletionContext, Completions, ImportEdit,
|
2020-11-14 01:26:31 +02:00
|
|
|
};
|
2019-01-08 22:33:36 +03:00
|
|
|
|
2020-10-25 10:59:15 +03:00
|
|
|
pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
|
2020-05-04 16:48:50 +02:00
|
|
|
if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ctx.record_lit_syntax.is_some()
|
2020-04-11 23:33:17 +02:00
|
|
|
|| ctx.record_pat_syntax.is_some()
|
2020-05-04 16:48:50 +02:00
|
|
|
|| ctx.attribute_under_caret.is_some()
|
2020-09-08 02:34:11 +03:00
|
|
|
|| ctx.mod_declaration_under_caret.is_some()
|
2020-04-11 23:33:17 +02:00
|
|
|
{
|
2019-09-06 21:57:11 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-04-26 10:54:08 +02:00
|
|
|
if let Some(ty) = &ctx.expected_type {
|
|
|
|
complete_enum_variants(acc, ctx, ty);
|
|
|
|
}
|
2020-04-20 14:01:30 -04:00
|
|
|
|
|
|
|
if ctx.is_pat_binding_or_const {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-11 01:26:24 +02:00
|
|
|
ctx.scope.process_all_names(&mut |name, res| {
|
2020-04-17 14:28:20 +02:00
|
|
|
if ctx.use_item_syntax.is_some() {
|
|
|
|
if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) {
|
|
|
|
if name_ref.syntax().text() == name.to_string().as_str() {
|
2020-05-20 12:59:20 +02:00
|
|
|
mark::hit!(self_fulfilling_completion);
|
2020-04-17 14:28:20 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
acc.add_resolution(ctx, name.to_string(), &res)
|
|
|
|
});
|
2020-11-14 01:26:31 +02:00
|
|
|
|
2020-11-25 00:02:45 +02:00
|
|
|
if ctx.config.enable_experimental_completions {
|
|
|
|
fuzzy_completion(acc, ctx).unwrap_or_default()
|
|
|
|
}
|
2020-11-14 01:26:31 +02:00
|
|
|
}
|
|
|
|
|
2020-11-14 11:59:23 +02:00
|
|
|
fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) {
|
|
|
|
if let Some(Adt::Enum(enum_data)) = ty.as_adt() {
|
|
|
|
let variants = enum_data.variants(ctx.db);
|
|
|
|
|
|
|
|
let module = if let Some(module) = ctx.scope.module() {
|
|
|
|
// Compute path from the completion site if available.
|
|
|
|
module
|
|
|
|
} else {
|
|
|
|
// Otherwise fall back to the enum's definition site.
|
|
|
|
enum_data.module(ctx.db)
|
|
|
|
};
|
|
|
|
|
|
|
|
for variant in variants {
|
|
|
|
if let Some(path) = module.find_use_path(ctx.db, ModuleDef::from(variant)) {
|
|
|
|
// Variants with trivial paths are already added by the existing completion logic,
|
|
|
|
// so we should avoid adding these twice
|
|
|
|
if path.segments.len() > 1 {
|
|
|
|
acc.add_qualified_enum_variant(ctx, variant, path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-07 00:39:03 +02:00
|
|
|
// Feature: Fuzzy Completion and Autoimports
|
|
|
|
//
|
|
|
|
// When completing names in the current scope, proposes additional imports from other modules or crates,
|
|
|
|
// if they can be qualified in the scope and their name contains all symbols from the completion input
|
|
|
|
// (case-insensitive, in any order or places).
|
|
|
|
//
|
|
|
|
// ```
|
|
|
|
// fn main() {
|
|
|
|
// pda<|>
|
|
|
|
// }
|
|
|
|
// # pub mod std { pub mod marker { pub struct PhantomData { } } }
|
|
|
|
// ```
|
|
|
|
// ->
|
|
|
|
// ```
|
|
|
|
// use std::marker::PhantomData;
|
|
|
|
//
|
|
|
|
// fn main() {
|
|
|
|
// PhantomData
|
|
|
|
// }
|
|
|
|
// # pub mod std { pub mod marker { pub struct PhantomData { } } }
|
|
|
|
// ```
|
|
|
|
//
|
|
|
|
// .Fuzzy search details
|
|
|
|
//
|
|
|
|
// To avoid an excessive amount of the results returned, completion input is checked for inclusion in the identifiers only
|
|
|
|
// (i.e. in `HashMap` in the `std::collections::HashMap` path), also not in the module indentifiers.
|
|
|
|
//
|
|
|
|
// .Merge Behaviour
|
|
|
|
//
|
|
|
|
// It is possible to configure how use-trees are merged with the `importMergeBehaviour` setting.
|
|
|
|
// Mimics the corresponding behaviour of the `Auto Import` feature.
|
|
|
|
//
|
|
|
|
// .LSP and performance implications
|
|
|
|
//
|
|
|
|
// LSP 3.16 provides the way to defer the computation of some completion data, including the import edits for this feature.
|
|
|
|
// If the LSP client supports the `additionalTextEdits` (case sensitive) resolve client capability, rust-analyzer computes
|
|
|
|
// the completion edits only when a corresponding completion item is selected.
|
|
|
|
// For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones,
|
|
|
|
// which might be slow.
|
|
|
|
//
|
|
|
|
// .Feature toggle
|
|
|
|
//
|
|
|
|
// The feature can be turned off in the settings with the `rust-analyzer.completion.enableExperimental` flag.
|
2020-11-14 01:26:31 +02:00
|
|
|
fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
|
2020-11-16 21:24:54 +02:00
|
|
|
let _p = profile::span("fuzzy_completion");
|
2020-11-14 01:26:31 +02:00
|
|
|
let current_module = ctx.scope.module()?;
|
|
|
|
let anchor = ctx.name_ref_syntax.as_ref()?;
|
|
|
|
let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
|
|
|
|
|
|
|
|
let potential_import_name = ctx.token.to_string();
|
|
|
|
|
2020-11-24 02:26:16 +02:00
|
|
|
let possible_imports = imports_locator::find_similar_imports(
|
|
|
|
&ctx.sema,
|
|
|
|
ctx.krate?,
|
|
|
|
&potential_import_name,
|
|
|
|
50,
|
|
|
|
true,
|
|
|
|
)
|
|
|
|
.filter_map(|import_candidate| {
|
|
|
|
Some(match import_candidate {
|
|
|
|
Either::Left(module_def) => {
|
|
|
|
(current_module.find_use_path(ctx.db, module_def)?, ScopeDef::ModuleDef(module_def))
|
|
|
|
}
|
|
|
|
Either::Right(macro_def) => {
|
|
|
|
(current_module.find_use_path(ctx.db, macro_def)?, ScopeDef::MacroDef(macro_def))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.filter(|(mod_path, _)| mod_path.len() > 1)
|
|
|
|
.take(20)
|
|
|
|
.filter_map(|(import_path, definition)| {
|
|
|
|
render_resolution_with_import(
|
|
|
|
RenderContext::new(ctx),
|
2020-12-04 16:03:22 +02:00
|
|
|
ImportEdit {
|
|
|
|
import_path: import_path.clone(),
|
|
|
|
import_scope: import_scope.clone(),
|
|
|
|
merge_behaviour: ctx.config.merge,
|
|
|
|
},
|
2020-11-24 02:26:16 +02:00
|
|
|
&definition,
|
|
|
|
)
|
|
|
|
});
|
2020-11-14 01:26:31 +02:00
|
|
|
|
|
|
|
acc.add_all(possible_imports);
|
|
|
|
Some(())
|
2019-04-22 15:56:28 +03:00
|
|
|
}
|
|
|
|
|
2019-01-08 22:33:36 +03:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2020-08-21 13:19:31 +02:00
|
|
|
use expect_test::{expect, Expect};
|
2020-05-20 12:59:20 +02:00
|
|
|
use test_utils::mark;
|
2019-01-08 22:33:36 +03:00
|
|
|
|
2020-10-18 13:09:00 +03:00
|
|
|
use crate::{
|
2020-12-04 21:23:30 +02:00
|
|
|
test_utils::{check_edit, check_edit_with_config, completion_list},
|
|
|
|
CompletionConfig, CompletionKind,
|
2020-07-07 12:52:09 +02:00
|
|
|
};
|
2020-02-09 10:04:47 +01:00
|
|
|
|
2020-07-07 12:52:09 +02:00
|
|
|
fn check(ra_fixture: &str, expect: Expect) {
|
|
|
|
let actual = completion_list(ra_fixture, CompletionKind::Reference);
|
|
|
|
expect.assert_eq(&actual)
|
2019-01-08 22:33:36 +03:00
|
|
|
}
|
|
|
|
|
2020-04-17 14:28:20 +02:00
|
|
|
#[test]
|
|
|
|
fn self_fulfilling_completion() {
|
2020-05-20 12:59:20 +02:00
|
|
|
mark::check!(self_fulfilling_completion);
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
use foo<|>
|
|
|
|
use std::collections;
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
?? collections
|
|
|
|
"#]],
|
2020-04-17 14:28:20 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-03-19 00:11:25 -07:00
|
|
|
#[test]
|
|
|
|
fn bind_pat_and_path_ignore_at() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
enum Enum { A, B }
|
|
|
|
fn quux(x: Option<Enum>) {
|
|
|
|
match x {
|
|
|
|
None => (),
|
|
|
|
Some(en<|> @ Enum::A) => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[""]],
|
2020-03-19 00:11:25 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-03-09 18:10:25 -07:00
|
|
|
#[test]
|
2020-03-18 00:46:42 -07:00
|
|
|
fn bind_pat_and_path_ignore_ref() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
enum Enum { A, B }
|
|
|
|
fn quux(x: Option<Enum>) {
|
|
|
|
match x {
|
|
|
|
None => (),
|
|
|
|
Some(ref en<|>) => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[""]],
|
2020-03-09 18:10:25 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn bind_pat_and_path() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
enum Enum { A, B }
|
|
|
|
fn quux(x: Option<Enum>) {
|
|
|
|
match x {
|
|
|
|
None => (),
|
|
|
|
Some(En<|>) => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
en Enum
|
|
|
|
"#]],
|
2020-03-09 18:10:25 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-08 22:33:36 +03:00
|
|
|
#[test]
|
|
|
|
fn completes_bindings_from_let() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
fn quux(x: i32) {
|
|
|
|
let y = 92;
|
|
|
|
1 + <|>;
|
|
|
|
let z = ();
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fn quux(…) fn quux(x: i32)
|
|
|
|
bn x i32
|
|
|
|
bn y i32
|
|
|
|
"#]],
|
2019-07-28 12:28:14 +01:00
|
|
|
);
|
2019-01-08 22:33:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_bindings_from_if_let() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
fn quux() {
|
|
|
|
if let Some(x) = foo() {
|
|
|
|
let y = 92;
|
|
|
|
};
|
|
|
|
if let Some(a) = bar() {
|
|
|
|
let b = 62;
|
|
|
|
1 + <|>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
bn a
|
|
|
|
bn b i32
|
|
|
|
fn quux() fn quux()
|
|
|
|
"#]],
|
2019-07-28 12:28:14 +01:00
|
|
|
);
|
2019-01-08 22:33:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_bindings_from_for() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
fn quux() {
|
|
|
|
for x in &[1, 2, 3] { <|> }
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fn quux() fn quux()
|
|
|
|
bn x
|
|
|
|
"#]],
|
2019-07-28 12:28:14 +01:00
|
|
|
);
|
2019-01-08 22:33:36 +03:00
|
|
|
}
|
|
|
|
|
2020-05-24 16:47:35 +02:00
|
|
|
#[test]
|
2020-07-07 12:52:09 +02:00
|
|
|
fn completes_if_prefix_is_keyword() {
|
|
|
|
mark::check!(completes_if_prefix_is_keyword);
|
|
|
|
check_edit(
|
|
|
|
"wherewolf",
|
|
|
|
r#"
|
|
|
|
fn main() {
|
|
|
|
let wherewolf = 92;
|
|
|
|
drop(where<|>)
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
fn main() {
|
|
|
|
let wherewolf = 92;
|
|
|
|
drop(wherewolf)
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
)
|
2020-05-24 16:47:35 +02:00
|
|
|
}
|
|
|
|
|
2019-02-01 23:06:57 +01:00
|
|
|
#[test]
|
|
|
|
fn completes_generic_params() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"fn quux<T>() { <|> }"#,
|
|
|
|
expect![[r#"
|
|
|
|
tp T
|
|
|
|
fn quux() fn quux<T>()
|
|
|
|
"#]],
|
2019-07-28 12:28:14 +01:00
|
|
|
);
|
2019-02-01 23:06:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_generic_params_in_struct() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"struct S<T> { x: <|>}"#,
|
|
|
|
expect![[r#"
|
|
|
|
st S<…>
|
|
|
|
tp Self
|
|
|
|
tp T
|
|
|
|
"#]],
|
2019-07-28 12:28:14 +01:00
|
|
|
);
|
2019-02-01 23:06:57 +01:00
|
|
|
}
|
|
|
|
|
2019-01-08 22:33:36 +03:00
|
|
|
#[test]
|
2019-10-08 07:25:37 -04:00
|
|
|
fn completes_self_in_enum() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"enum X { Y(<|>) }"#,
|
|
|
|
expect![[r#"
|
|
|
|
tp Self
|
|
|
|
en X
|
|
|
|
"#]],
|
2019-10-08 07:25:37 -04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2019-01-08 22:33:36 +03:00
|
|
|
fn completes_module_items() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct S;
|
|
|
|
enum E {}
|
|
|
|
fn quux() { <|> }
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
en E
|
|
|
|
st S
|
|
|
|
fn quux() fn quux()
|
|
|
|
"#]],
|
|
|
|
);
|
2019-01-08 22:33:36 +03:00
|
|
|
}
|
|
|
|
|
2020-10-03 03:00:09 +02:00
|
|
|
/// Regression test for issue #6091.
|
|
|
|
#[test]
|
|
|
|
fn correctly_completes_module_items_prefixed_with_underscore() {
|
|
|
|
check_edit(
|
|
|
|
"_alpha",
|
|
|
|
r#"
|
|
|
|
fn main() {
|
|
|
|
_<|>
|
|
|
|
}
|
|
|
|
fn _alpha() {}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
fn main() {
|
|
|
|
_alpha()$0
|
|
|
|
}
|
|
|
|
fn _alpha() {}
|
|
|
|
"#,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-01-08 22:33:36 +03:00
|
|
|
#[test]
|
2019-02-04 22:09:56 +01:00
|
|
|
fn completes_extern_prelude() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
2020-10-02 16:13:48 +02:00
|
|
|
//- /lib.rs crate:main deps:other_crate
|
2020-07-07 12:52:09 +02:00
|
|
|
use <|>;
|
|
|
|
|
2020-10-02 16:13:48 +02:00
|
|
|
//- /other_crate/lib.rs crate:other_crate
|
2020-07-07 12:52:09 +02:00
|
|
|
// nothing here
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
md other_crate
|
|
|
|
"#]],
|
2019-07-28 12:28:14 +01:00
|
|
|
);
|
2019-02-04 22:09:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2019-01-08 22:33:36 +03:00
|
|
|
fn completes_module_items_in_nested_modules() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct Foo;
|
|
|
|
mod m {
|
|
|
|
struct Bar;
|
|
|
|
fn quux() { <|> }
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
st Bar
|
|
|
|
fn quux() fn quux()
|
|
|
|
"#]],
|
2019-07-28 12:28:14 +01:00
|
|
|
);
|
2019-01-08 22:33:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_return_type() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct Foo;
|
|
|
|
fn x() -> <|>
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
st Foo
|
|
|
|
fn x() fn x()
|
|
|
|
"#]],
|
2019-07-28 12:28:14 +01:00
|
|
|
);
|
2019-01-08 22:33:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn dont_show_both_completions_for_shadowing() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
fn foo() {
|
|
|
|
let bar = 92;
|
|
|
|
{
|
|
|
|
let bar = 62;
|
|
|
|
drop(<|>)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
// FIXME: should be only one bar here
|
|
|
|
expect![[r#"
|
|
|
|
bn bar i32
|
|
|
|
bn bar i32
|
|
|
|
fn foo() fn foo()
|
|
|
|
"#]],
|
2019-07-28 12:28:14 +01:00
|
|
|
);
|
2019-01-08 22:33:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_self_in_methods() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"impl S { fn foo(&self) { <|> } }"#,
|
|
|
|
expect![[r#"
|
|
|
|
tp Self
|
|
|
|
bn self &{unknown}
|
|
|
|
"#]],
|
2019-07-28 12:28:14 +01:00
|
|
|
);
|
2019-01-08 22:33:36 +03:00
|
|
|
}
|
2019-02-13 20:53:42 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_prelude() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
2020-10-02 16:13:48 +02:00
|
|
|
//- /main.rs crate:main deps:std
|
2020-07-07 12:52:09 +02:00
|
|
|
fn foo() { let x: <|> }
|
|
|
|
|
2020-10-02 16:13:48 +02:00
|
|
|
//- /std/lib.rs crate:std
|
2020-07-07 12:52:09 +02:00
|
|
|
#[prelude_import]
|
|
|
|
use prelude::*;
|
|
|
|
|
|
|
|
mod prelude { struct Option; }
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
st Option
|
|
|
|
fn foo() fn foo()
|
|
|
|
md std
|
|
|
|
"#]],
|
2019-07-28 12:28:14 +01:00
|
|
|
);
|
2019-02-13 20:53:42 +01:00
|
|
|
}
|
2019-09-10 13:32:47 +08:00
|
|
|
|
2019-11-09 17:38:08 -08:00
|
|
|
#[test]
|
|
|
|
fn completes_std_prelude_if_core_is_defined() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
2020-10-02 16:13:48 +02:00
|
|
|
//- /main.rs crate:main deps:core,std
|
2020-07-07 12:52:09 +02:00
|
|
|
fn foo() { let x: <|> }
|
|
|
|
|
2020-10-02 16:13:48 +02:00
|
|
|
//- /core/lib.rs crate:core
|
2020-07-07 12:52:09 +02:00
|
|
|
#[prelude_import]
|
|
|
|
use prelude::*;
|
|
|
|
|
|
|
|
mod prelude { struct Option; }
|
|
|
|
|
2020-10-02 16:13:48 +02:00
|
|
|
//- /std/lib.rs crate:std deps:core
|
2020-07-07 12:52:09 +02:00
|
|
|
#[prelude_import]
|
|
|
|
use prelude::*;
|
|
|
|
|
|
|
|
mod prelude { struct String; }
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
st String
|
|
|
|
md core
|
|
|
|
fn foo() fn foo()
|
|
|
|
md std
|
|
|
|
"#]],
|
2019-11-09 17:38:08 -08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-09-10 13:32:47 +08:00
|
|
|
#[test]
|
|
|
|
fn completes_macros_as_value() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
macro_rules! foo { () => {} }
|
2019-09-10 13:32:47 +08:00
|
|
|
|
2020-07-07 12:52:09 +02:00
|
|
|
#[macro_use]
|
|
|
|
mod m1 {
|
|
|
|
macro_rules! bar { () => {} }
|
|
|
|
}
|
2019-09-10 13:32:47 +08:00
|
|
|
|
2020-07-07 12:52:09 +02:00
|
|
|
mod m2 {
|
|
|
|
macro_rules! nope { () => {} }
|
2019-09-10 13:32:47 +08:00
|
|
|
|
2020-07-07 12:52:09 +02:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! baz { () => {} }
|
|
|
|
}
|
2019-09-10 13:32:47 +08:00
|
|
|
|
2020-07-07 12:52:09 +02:00
|
|
|
fn main() { let v = <|> }
|
|
|
|
"#,
|
|
|
|
expect![[r##"
|
|
|
|
ma bar!(…) macro_rules! bar
|
|
|
|
ma baz!(…) #[macro_export]
|
|
|
|
macro_rules! baz
|
|
|
|
ma foo!(…) macro_rules! foo
|
|
|
|
md m1
|
|
|
|
md m2
|
|
|
|
fn main() fn main()
|
|
|
|
"##]],
|
2019-09-10 13:32:47 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_both_macro_and_value() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
macro_rules! foo { () => {} }
|
|
|
|
fn foo() { <|> }
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
ma foo!(…) macro_rules! foo
|
|
|
|
fn foo() fn foo()
|
|
|
|
"#]],
|
2019-09-10 13:32:47 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_macros_as_type() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
macro_rules! foo { () => {} }
|
|
|
|
fn main() { let x: <|> }
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
ma foo!(…) macro_rules! foo
|
|
|
|
fn main() fn main()
|
|
|
|
"#]],
|
2019-09-10 13:32:47 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_macros_as_stmt() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
macro_rules! foo { () => {} }
|
|
|
|
fn main() { <|> }
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
ma foo!(…) macro_rules! foo
|
|
|
|
fn main() fn main()
|
|
|
|
"#]],
|
2019-09-10 13:32:47 +08:00
|
|
|
);
|
|
|
|
}
|
2019-12-22 20:12:23 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_local_item() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
fn main() {
|
|
|
|
return f<|>;
|
|
|
|
fn frobnicate() {}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fn frobnicate() fn frobnicate()
|
|
|
|
fn main() fn main()
|
|
|
|
"#]],
|
|
|
|
);
|
2019-12-22 20:12:23 +01:00
|
|
|
}
|
2020-03-07 15:27:03 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_in_simple_macro_1() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
macro_rules! m { ($e:expr) => { $e } }
|
|
|
|
fn quux(x: i32) {
|
|
|
|
let y = 92;
|
|
|
|
m!(<|>);
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
ma m!(…) macro_rules! m
|
|
|
|
fn quux(…) fn quux(x: i32)
|
|
|
|
bn x i32
|
|
|
|
bn y i32
|
|
|
|
"#]],
|
2020-03-07 15:27:03 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_in_simple_macro_2() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r"
|
|
|
|
macro_rules! m { ($e:expr) => { $e } }
|
|
|
|
fn quux(x: i32) {
|
|
|
|
let y = 92;
|
|
|
|
m!(x<|>);
|
|
|
|
}
|
|
|
|
",
|
|
|
|
expect![[r#"
|
|
|
|
ma m!(…) macro_rules! m
|
|
|
|
fn quux(…) fn quux(x: i32)
|
|
|
|
bn x i32
|
|
|
|
bn y i32
|
|
|
|
"#]],
|
2020-03-15 11:26:54 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_in_simple_macro_without_closing_parens() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
macro_rules! m { ($e:expr) => { $e } }
|
|
|
|
fn quux(x: i32) {
|
|
|
|
let y = 92;
|
|
|
|
m!(x<|>
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
ma m!(…) macro_rules! m
|
|
|
|
fn quux(…) fn quux(x: i32)
|
|
|
|
bn x i32
|
|
|
|
bn y i32
|
|
|
|
"#]],
|
2020-03-07 15:27:03 +01:00
|
|
|
);
|
|
|
|
}
|
2020-03-13 09:29:16 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_unresolved_uses() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
use spam::Quux;
|
|
|
|
|
|
|
|
fn main() { <|> }
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
?? Quux
|
|
|
|
fn main() fn main()
|
|
|
|
"#]],
|
2020-03-13 09:29:16 +01:00
|
|
|
);
|
|
|
|
}
|
2020-04-20 15:29:53 -04:00
|
|
|
#[test]
|
|
|
|
fn completes_enum_variant_matcharm() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
enum Foo { Bar, Baz, Quux }
|
2020-04-20 15:29:53 -04:00
|
|
|
|
2020-07-07 12:52:09 +02:00
|
|
|
fn main() {
|
|
|
|
let foo = Foo::Quux;
|
|
|
|
match foo { Qu<|> }
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
en Foo
|
|
|
|
ev Foo::Bar ()
|
|
|
|
ev Foo::Baz ()
|
|
|
|
ev Foo::Quux ()
|
|
|
|
"#]],
|
2020-04-20 15:29:53 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_enum_variant_iflet() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
enum Foo { Bar, Baz, Quux }
|
2020-04-20 15:29:53 -04:00
|
|
|
|
2020-07-07 12:52:09 +02:00
|
|
|
fn main() {
|
|
|
|
let foo = Foo::Quux;
|
|
|
|
if let Qu<|> = foo { }
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
en Foo
|
|
|
|
ev Foo::Bar ()
|
|
|
|
ev Foo::Baz ()
|
|
|
|
ev Foo::Quux ()
|
|
|
|
"#]],
|
2020-04-20 15:29:53 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_enum_variant_basic_expr() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
enum Foo { Bar, Baz, Quux }
|
|
|
|
fn main() { let foo: Foo = Q<|> }
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
en Foo
|
|
|
|
ev Foo::Bar ()
|
|
|
|
ev Foo::Baz ()
|
|
|
|
ev Foo::Quux ()
|
|
|
|
fn main() fn main()
|
|
|
|
"#]],
|
2020-04-20 15:29:53 -04:00
|
|
|
)
|
|
|
|
}
|
2020-04-24 22:18:59 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_enum_variant_from_module() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
mod m { pub enum E { V } }
|
|
|
|
fn f() -> m::E { V<|> }
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fn f() fn f() -> m::E
|
|
|
|
md m
|
|
|
|
ev m::E::V ()
|
|
|
|
"#]],
|
2020-04-24 22:18:59 +02:00
|
|
|
)
|
|
|
|
}
|
2020-05-04 16:48:50 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn dont_complete_attr() {
|
2020-07-07 12:52:09 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct Foo;
|
|
|
|
#[<|>]
|
|
|
|
fn f() {}
|
|
|
|
"#,
|
|
|
|
expect![[""]],
|
2020-05-04 16:48:50 +02:00
|
|
|
)
|
|
|
|
}
|
2020-07-09 12:14:26 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_type_or_trait_in_impl_block() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
trait MyTrait {}
|
|
|
|
struct MyStruct {}
|
|
|
|
|
|
|
|
impl My<|>
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
st MyStruct
|
|
|
|
tt MyTrait
|
|
|
|
tp Self
|
|
|
|
"#]],
|
|
|
|
)
|
|
|
|
}
|
2020-11-14 01:26:31 +02:00
|
|
|
|
|
|
|
#[test]
|
2020-11-14 14:59:03 +02:00
|
|
|
fn function_fuzzy_completion() {
|
2020-11-14 01:26:31 +02:00
|
|
|
check_edit(
|
|
|
|
"stdin",
|
|
|
|
r#"
|
|
|
|
//- /lib.rs crate:dep
|
|
|
|
pub mod io {
|
|
|
|
pub fn stdin() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
//- /main.rs crate:main deps:dep
|
|
|
|
fn main() {
|
|
|
|
stdi<|>
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
use dep::io::stdin;
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
stdin()$0
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2020-11-14 14:59:03 +02:00
|
|
|
fn macro_fuzzy_completion() {
|
2020-11-14 01:26:31 +02:00
|
|
|
check_edit(
|
|
|
|
"macro_with_curlies!",
|
|
|
|
r#"
|
|
|
|
//- /lib.rs crate:dep
|
|
|
|
/// Please call me as macro_with_curlies! {}
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! macro_with_curlies {
|
|
|
|
() => {}
|
|
|
|
}
|
|
|
|
|
|
|
|
//- /main.rs crate:main deps:dep
|
|
|
|
fn main() {
|
|
|
|
curli<|>
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
use dep::macro_with_curlies;
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
macro_with_curlies! {$0}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2020-11-14 14:59:03 +02:00
|
|
|
fn struct_fuzzy_completion() {
|
2020-11-14 01:26:31 +02:00
|
|
|
check_edit(
|
|
|
|
"ThirdStruct",
|
|
|
|
r#"
|
|
|
|
//- /lib.rs crate:dep
|
|
|
|
pub struct FirstStruct;
|
|
|
|
pub mod some_module {
|
|
|
|
pub struct SecondStruct;
|
|
|
|
pub struct ThirdStruct;
|
|
|
|
}
|
|
|
|
|
|
|
|
//- /main.rs crate:main deps:dep
|
|
|
|
use dep::{FirstStruct, some_module::SecondStruct};
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
this<|>
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
ThirdStruct
|
|
|
|
}
|
2020-12-04 21:23:30 +02:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// LSP protocol supports separate completion resolve requests to do the heavy computations there.
|
|
|
|
/// This test checks that for a certain resolve capatilities no such operations (autoimport) are done.
|
|
|
|
#[test]
|
|
|
|
fn no_fuzzy_completions_applied_for_certain_resolve_capability() {
|
|
|
|
let mut completion_config = CompletionConfig::default();
|
|
|
|
completion_config
|
|
|
|
.active_resolve_capabilities
|
|
|
|
.insert(crate::CompletionResolveCapability::AdditionalTextEdits);
|
|
|
|
|
|
|
|
check_edit_with_config(
|
|
|
|
completion_config,
|
|
|
|
"ThirdStruct",
|
|
|
|
r#"
|
|
|
|
//- /lib.rs crate:dep
|
|
|
|
pub struct FirstStruct;
|
|
|
|
pub mod some_module {
|
|
|
|
pub struct SecondStruct;
|
|
|
|
pub struct ThirdStruct;
|
|
|
|
}
|
|
|
|
|
|
|
|
//- /main.rs crate:main deps:dep
|
|
|
|
use dep::{FirstStruct, some_module::SecondStruct};
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
this<|>
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
use dep::{FirstStruct, some_module::SecondStruct};
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
ThirdStruct
|
|
|
|
}
|
2020-11-14 01:26:31 +02:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
2019-01-08 22:33:36 +03:00
|
|
|
}
|