mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Move path completions for patterns into pattern module
This commit is contained in:
parent
33fd2d7aef
commit
9f5ee155c1
@ -27,6 +27,9 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
|
||||
cov_mark::hit!(no_keyword_completion_in_non_trivial_path);
|
||||
return;
|
||||
}
|
||||
if ctx.pattern_ctx.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut add_keyword = |kw, snippet| add_keyword(acc, ctx, kw, snippet);
|
||||
|
||||
@ -117,7 +120,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
|
||||
add_keyword("else if", "else if $1 {\n $0\n}");
|
||||
}
|
||||
|
||||
if ctx.expects_ident_pat_or_ref_expr() {
|
||||
if ctx.expects_ident_ref_expr() {
|
||||
add_keyword("mut", "mut ");
|
||||
}
|
||||
|
||||
|
@ -1,20 +1,52 @@
|
||||
//! Completes constants and paths in unqualified patterns.
|
||||
|
||||
use hir::db::DefDatabase;
|
||||
use hir::{db::DefDatabase, AssocItem, ScopeDef};
|
||||
use rustc_hash::FxHashSet;
|
||||
use syntax::ast::Pat;
|
||||
|
||||
use crate::{
|
||||
context::{PatternContext, PatternRefutability},
|
||||
context::{PathCompletionCtx, PathQualifierCtx, PatternRefutability},
|
||||
CompletionContext, Completions,
|
||||
};
|
||||
|
||||
/// Completes constants and paths in unqualified patterns.
|
||||
pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
let refutable = match ctx.pattern_ctx {
|
||||
Some(PatternContext { refutability, .. }) if ctx.path_context.is_none() => {
|
||||
refutability == PatternRefutability::Refutable
|
||||
}
|
||||
let patctx = match &ctx.pattern_ctx {
|
||||
Some(ctx) => ctx,
|
||||
_ => return,
|
||||
};
|
||||
let refutable = patctx.refutability == PatternRefutability::Refutable;
|
||||
|
||||
if let Some(path_ctx) = &ctx.path_context {
|
||||
pattern_path_completion(acc, ctx, path_ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
match patctx.parent_pat.as_ref() {
|
||||
Some(Pat::RangePat(_) | Pat::BoxPat(_)) => (),
|
||||
Some(Pat::RefPat(r)) => {
|
||||
if r.mut_token().is_none() {
|
||||
acc.add_keyword(ctx, "mut");
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let tok = ctx.token.text_range().start();
|
||||
match (patctx.ref_token.as_ref(), patctx.mut_token.as_ref()) {
|
||||
(None, None) => {
|
||||
acc.add_keyword(ctx, "ref");
|
||||
acc.add_keyword(ctx, "mut");
|
||||
}
|
||||
(None, Some(m)) if tok < m.text_range().start() => {
|
||||
acc.add_keyword(ctx, "ref");
|
||||
}
|
||||
(Some(r), None) if tok > r.text_range().end() => {
|
||||
acc.add_keyword(ctx, "mut");
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let single_variant_enum = |enum_: hir::Enum| ctx.db.enum_data(enum_.into()).variants.len() == 1;
|
||||
|
||||
if let Some(hir::Adt::Enum(e)) =
|
||||
@ -63,3 +95,104 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn pattern_path_completion(
|
||||
acc: &mut Completions,
|
||||
ctx: &CompletionContext,
|
||||
PathCompletionCtx { qualifier, is_absolute_path, .. }: &PathCompletionCtx,
|
||||
) {
|
||||
match qualifier {
|
||||
Some(PathQualifierCtx { resolution, is_super_chain, .. }) => {
|
||||
if *is_super_chain {
|
||||
acc.add_keyword(ctx, "super::");
|
||||
}
|
||||
|
||||
let resolution = match resolution {
|
||||
Some(it) => it,
|
||||
None => return,
|
||||
};
|
||||
|
||||
match resolution {
|
||||
hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
|
||||
let module_scope = module.scope(ctx.db, ctx.module);
|
||||
for (name, def) in module_scope {
|
||||
let add_resolution = match def {
|
||||
ScopeDef::MacroDef(m) if m.is_fn_like() => true,
|
||||
ScopeDef::ModuleDef(_) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if add_resolution {
|
||||
acc.add_resolution(ctx, name, def);
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
|
||||
cov_mark::hit!(enum_plain_qualified_use_tree);
|
||||
e.variants(ctx.db)
|
||||
.into_iter()
|
||||
.for_each(|variant| acc.add_enum_variant(ctx, variant, None));
|
||||
}
|
||||
res @ (hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_)) => {
|
||||
if let Some(krate) = ctx.krate {
|
||||
let ty = match res {
|
||||
hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
|
||||
hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// Note associated consts cannot be referenced in patterns
|
||||
if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
|
||||
e.variants(ctx.db)
|
||||
.into_iter()
|
||||
.for_each(|variant| acc.add_enum_variant(ctx, variant, None));
|
||||
}
|
||||
|
||||
let traits_in_scope = ctx.scope.visible_traits();
|
||||
let mut seen = FxHashSet::default();
|
||||
ty.iterate_path_candidates(
|
||||
ctx.db,
|
||||
krate,
|
||||
&traits_in_scope,
|
||||
ctx.module,
|
||||
None,
|
||||
|_ty, item| {
|
||||
// We might iterate candidates of a trait multiple times here, so deduplicate
|
||||
// them.
|
||||
if let AssocItem::TypeAlias(ta) = item {
|
||||
if seen.insert(item) {
|
||||
acc.add_type_alias(ctx, ta);
|
||||
}
|
||||
}
|
||||
None::<()>
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
// qualifier can only be none here if we are in a TuplePat or RecordPat in which case special characters have to follow the path
|
||||
// so executing the rest of this completion doesn't make sense
|
||||
// fresh use tree with leading colon2, only show crate roots
|
||||
None if *is_absolute_path => {
|
||||
cov_mark::hit!(use_tree_crate_roots_only);
|
||||
ctx.process_all_names(&mut |name, res| match res {
|
||||
ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => {
|
||||
acc.add_resolution(ctx, name, res);
|
||||
}
|
||||
_ => (),
|
||||
});
|
||||
}
|
||||
// only show modules in a fresh UseTree
|
||||
None => {
|
||||
cov_mark::hit!(unqualified_path_only_modules_in_import);
|
||||
ctx.process_all_names(&mut |name, res| {
|
||||
if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
|
||||
acc.add_resolution(ctx, name, res);
|
||||
}
|
||||
});
|
||||
["self::", "super::", "crate::"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,9 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||
if ctx.is_path_disallowed() || ctx.has_impl_or_trait_prev_sibling() {
|
||||
return;
|
||||
}
|
||||
if ctx.pattern_ctx.is_some() {
|
||||
return;
|
||||
}
|
||||
let (qualifier, kind) = match ctx.path_context {
|
||||
// let ... else, syntax would come in really handy here right now
|
||||
Some(PathCompletionCtx { qualifier: Some(ref qualifier), kind, .. }) => (qualifier, kind),
|
||||
@ -60,10 +63,9 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||
}
|
||||
|
||||
match kind {
|
||||
Some(PathKind::Attr { .. } | PathKind::Vis { .. } | PathKind::Use) => {
|
||||
Some(PathKind::Pat | PathKind::Attr { .. } | PathKind::Vis { .. } | PathKind::Use) => {
|
||||
return;
|
||||
}
|
||||
Some(PathKind::Pat) => (),
|
||||
_ => {
|
||||
// Add associated types on type parameters and `Self`.
|
||||
ctx.scope.assoc_type_shorthand_candidates(&resolution, |_, alias| {
|
||||
|
@ -17,7 +17,13 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
|
||||
}
|
||||
match ctx.path_context {
|
||||
Some(PathCompletionCtx {
|
||||
kind: Some(PathKind::Vis { .. } | PathKind::Attr { .. } | PathKind::Use { .. }),
|
||||
kind:
|
||||
Some(
|
||||
PathKind::Vis { .. }
|
||||
| PathKind::Attr { .. }
|
||||
| PathKind::Use { .. }
|
||||
| PathKind::Pat,
|
||||
),
|
||||
..
|
||||
}) => return,
|
||||
Some(PathCompletionCtx { is_absolute_path: false, qualifier: None, .. }) => (),
|
||||
|
@ -85,6 +85,9 @@ pub(super) struct PatternContext {
|
||||
pub(super) refutability: PatternRefutability,
|
||||
pub(super) param_ctx: Option<(ast::ParamList, ast::Param, ParamKind)>,
|
||||
pub(super) has_type_ascription: bool,
|
||||
pub(super) parent_pat: Option<ast::Pat>,
|
||||
pub(super) ref_token: Option<SyntaxToken>,
|
||||
pub(super) mut_token: Option<SyntaxToken>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -219,11 +222,8 @@ impl<'a> CompletionContext<'a> {
|
||||
matches!(self.completion_location, Some(ImmediateLocation::StmtList))
|
||||
}
|
||||
|
||||
pub(crate) fn expects_ident_pat_or_ref_expr(&self) -> bool {
|
||||
matches!(
|
||||
self.completion_location,
|
||||
Some(ImmediateLocation::IdentPat | ImmediateLocation::RefExpr)
|
||||
)
|
||||
pub(crate) fn expects_ident_ref_expr(&self) -> bool {
|
||||
matches!(self.completion_location, Some(ImmediateLocation::RefExpr))
|
||||
}
|
||||
|
||||
pub(crate) fn expect_field(&self) -> bool {
|
||||
@ -789,9 +789,6 @@ impl<'a> CompletionContext<'a> {
|
||||
if is_name_in_field_pat {
|
||||
return None;
|
||||
}
|
||||
if !bind_pat.is_simple_ident() {
|
||||
return None;
|
||||
}
|
||||
Some(pattern_context_for(original_file, bind_pat.into()))
|
||||
}
|
||||
|
||||
@ -949,7 +946,18 @@ fn pattern_context_for(original_file: &SyntaxNode, pat: ast::Pat) -> PatternCont
|
||||
};
|
||||
(refutability, false)
|
||||
});
|
||||
PatternContext { refutability, param_ctx: is_param, has_type_ascription }
|
||||
let (ref_token, mut_token) = match &pat {
|
||||
ast::Pat::IdentPat(it) => (it.ref_token(), it.mut_token()),
|
||||
_ => (None, None),
|
||||
};
|
||||
PatternContext {
|
||||
refutability,
|
||||
param_ctx: is_param,
|
||||
has_type_ascription,
|
||||
parent_pat: pat.syntax().parent().and_then(ast::Pat::cast),
|
||||
mut_token,
|
||||
ref_token,
|
||||
}
|
||||
}
|
||||
|
||||
fn find_node_in_file<N: AstNode>(syntax: &SyntaxNode, node: &N) -> Option<N> {
|
||||
|
@ -17,6 +17,7 @@ fn baz(file$0) {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
bn file_id: usize
|
||||
kw ref
|
||||
kw mut
|
||||
"#]],
|
||||
);
|
||||
@ -32,6 +33,7 @@ fn baz(foo: (), file$0) {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
bn file_id: usize
|
||||
kw ref
|
||||
kw mut
|
||||
"#]],
|
||||
);
|
||||
@ -47,6 +49,7 @@ fn baz(file$0 id: u32) {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
bn file_id: usize,
|
||||
kw ref
|
||||
kw mut
|
||||
"#]],
|
||||
);
|
||||
@ -60,6 +63,7 @@ fn foo(file_id: usize) {}
|
||||
fn bar(file_id: u32, $0) {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
kw ref
|
||||
kw mut
|
||||
"#]],
|
||||
);
|
||||
@ -76,6 +80,7 @@ pub(crate) trait SourceRoot {
|
||||
"#,
|
||||
expect![[r#"
|
||||
bn file_id: usize
|
||||
kw ref
|
||||
kw mut
|
||||
"#]],
|
||||
);
|
||||
@ -91,6 +96,7 @@ fn outer(text: &str) {
|
||||
"#,
|
||||
expect![[r#"
|
||||
bn text: &str
|
||||
kw ref
|
||||
kw mut
|
||||
"#]],
|
||||
)
|
||||
@ -106,6 +112,7 @@ fn foo2($0) {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
bn Bar { bar }: Bar
|
||||
kw ref
|
||||
kw mut
|
||||
bn Bar Bar { bar$1 }: Bar$0
|
||||
st Bar
|
||||
@ -130,6 +137,7 @@ impl A {
|
||||
bn mut self
|
||||
bn &mut self
|
||||
bn file_id: usize
|
||||
kw ref
|
||||
kw mut
|
||||
sp Self
|
||||
st A
|
||||
@ -150,6 +158,7 @@ impl A {
|
||||
"#,
|
||||
expect![[r#"
|
||||
bn file_id: usize
|
||||
kw ref
|
||||
kw mut
|
||||
sp Self
|
||||
st A
|
||||
@ -178,6 +187,7 @@ fn outer() {
|
||||
bn foo: i32
|
||||
bn baz: i32
|
||||
bn bar: i32
|
||||
kw ref
|
||||
kw mut
|
||||
"#]],
|
||||
)
|
||||
@ -202,6 +212,22 @@ fn outer() {
|
||||
bn baz: i32
|
||||
bn bar: i32
|
||||
bn foo: i32
|
||||
kw ref
|
||||
kw mut
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_fully_equal() {
|
||||
check(
|
||||
r#"
|
||||
fn foo(bar: u32) {}
|
||||
fn bar(bar$0) {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
bn bar: u32
|
||||
kw ref
|
||||
kw mut
|
||||
"#]],
|
||||
)
|
||||
|
@ -22,6 +22,7 @@ fn quux() {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
kw ref
|
||||
kw mut
|
||||
"#]],
|
||||
);
|
||||
@ -53,16 +54,13 @@ fn quux() {
|
||||
|
||||
#[test]
|
||||
fn ident_ref_mut_pat() {
|
||||
// FIXME mut is already here, don't complete it again
|
||||
check_empty(
|
||||
r#"
|
||||
fn quux() {
|
||||
let ref mut en$0
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
kw mut
|
||||
"#]],
|
||||
expect![[r#""#]],
|
||||
);
|
||||
check_empty(
|
||||
r#"
|
||||
@ -70,9 +68,7 @@ fn quux() {
|
||||
let ref mut en$0 @ x
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
kw mut
|
||||
"#]],
|
||||
expect![[r#""#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -88,16 +84,13 @@ fn quux() {
|
||||
kw mut
|
||||
"#]],
|
||||
);
|
||||
// FIXME mut is already here, don't complete it again
|
||||
check_empty(
|
||||
r#"
|
||||
fn quux() {
|
||||
let &mut en$0
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
kw mut
|
||||
"#]],
|
||||
expect![[r#""#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -110,6 +103,7 @@ fn foo() {
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
kw ref
|
||||
kw mut
|
||||
en Enum
|
||||
bn Record Record { field$1 }$0
|
||||
@ -139,6 +133,7 @@ fn foo() {
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
kw ref
|
||||
kw mut
|
||||
bn Record Record { field$1 }$0
|
||||
st Record
|
||||
@ -160,6 +155,7 @@ fn foo(a$0) {
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
kw ref
|
||||
kw mut
|
||||
bn Record Record { field$1 }: Record$0
|
||||
st Record
|
||||
@ -175,6 +171,7 @@ fn foo(a$0: Tuple) {
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
kw ref
|
||||
kw mut
|
||||
bn Record Record { field$1 }$0
|
||||
st Record
|
||||
@ -200,6 +197,7 @@ fn foo() {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
kw ref
|
||||
kw mut
|
||||
ma m!(…) macro_rules! m
|
||||
"#]],
|
||||
@ -218,6 +216,7 @@ fn foo() {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
kw ref
|
||||
kw mut
|
||||
ev E::X ()
|
||||
en E
|
||||
@ -242,6 +241,7 @@ fn outer() {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
kw ref
|
||||
kw mut
|
||||
bn Record Record { field$1, .. }$0
|
||||
st Record
|
||||
@ -267,6 +267,7 @@ impl Foo {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
kw ref
|
||||
kw mut
|
||||
bn Self Self($1)$0
|
||||
sp Self
|
||||
@ -278,7 +279,6 @@ impl Foo {
|
||||
|
||||
#[test]
|
||||
fn enum_qualified() {
|
||||
// FIXME: Don't show functions, they aren't patterns
|
||||
check(
|
||||
r#"
|
||||
impl Enum {
|
||||
@ -291,12 +291,9 @@ fn func() {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ev TupleV(…) (u32)
|
||||
ev RecordV {field: u32}
|
||||
ev UnitV ()
|
||||
ct ASSOC_CONST const ASSOC_CONST: ()
|
||||
fn assoc_fn() fn()
|
||||
ta AssocType type AssocType = ()
|
||||
ev TupleV(…) (u32)
|
||||
ev RecordV {field: u32}
|
||||
ev UnitV ()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -310,6 +307,7 @@ struct Bar(u32);
|
||||
fn outer(Foo { bar: $0 }: Foo) {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
kw ref
|
||||
kw mut
|
||||
bn Foo Foo { bar$1 }$0
|
||||
st Foo
|
||||
@ -340,6 +338,7 @@ struct Bar(u32);
|
||||
fn foo($0) {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
kw ref
|
||||
kw mut
|
||||
bn Foo Foo { bar$1 }: Foo$0
|
||||
st Foo
|
||||
@ -360,6 +359,7 @@ fn foo() {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
kw ref
|
||||
kw mut
|
||||
bn Foo Foo { bar$1 }$0
|
||||
st Foo
|
||||
@ -368,17 +368,3 @@ fn foo() {
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_fully_equal() {
|
||||
check_empty(
|
||||
r#"
|
||||
fn foo(bar: u32) {}
|
||||
fn bar(bar$0) {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
bn bar: u32
|
||||
kw mut
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user