mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 22:31:43 +00:00
internal: Lift out IdentContext from CompletionContext
This commit is contained in:
parent
bcf10cde13
commit
6e9c963348
21 changed files with 456 additions and 351 deletions
|
@ -8,8 +8,7 @@ use syntax::SmolStr;
|
|||
|
||||
use crate::{
|
||||
context::{
|
||||
CompletionContext, DotAccess, DotAccessKind, IdentContext, NameRefContext, NameRefKind,
|
||||
PathCompletionCtx, PathKind, Qualified,
|
||||
CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind, Qualified,
|
||||
},
|
||||
item::{Builder, CompletionItem, CompletionItemKind, CompletionRelevance},
|
||||
render::{compute_exact_name_match, compute_ref_match, compute_type_match, RenderContext},
|
||||
|
@ -23,21 +22,54 @@ enum FuncKind {
|
|||
|
||||
pub(crate) fn render_fn(
|
||||
ctx: RenderContext<'_>,
|
||||
path_ctx: &PathCompletionCtx,
|
||||
local_name: Option<hir::Name>,
|
||||
func: hir::Function,
|
||||
) -> Builder {
|
||||
let _p = profile::span("render_fn");
|
||||
render(ctx, local_name, func, FuncKind::Function)
|
||||
let func_kind = FuncKind::Function;
|
||||
let params = match ctx.completion.config.snippet_cap {
|
||||
Some(_) => {
|
||||
if !matches!(
|
||||
path_ctx,
|
||||
PathCompletionCtx { kind: PathKind::Expr { .. }, has_call_parens: true, .. }
|
||||
| PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. }
|
||||
) {
|
||||
params(ctx.completion, func, &func_kind, false)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
render(
|
||||
ctx,
|
||||
local_name,
|
||||
func,
|
||||
func_kind,
|
||||
params,
|
||||
matches!(path_ctx.qualified, Qualified::With { .. }),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn render_method(
|
||||
ctx: RenderContext<'_>,
|
||||
dot_access: &DotAccess,
|
||||
receiver: Option<hir::Name>,
|
||||
local_name: Option<hir::Name>,
|
||||
func: hir::Function,
|
||||
) -> Builder {
|
||||
let _p = profile::span("render_method");
|
||||
render(ctx, local_name, func, FuncKind::Method(receiver))
|
||||
let func_kind = FuncKind::Method(receiver);
|
||||
let params = match ctx.completion.config.snippet_cap {
|
||||
Some(_) => match dot_access {
|
||||
DotAccess { kind: DotAccessKind::Method { has_parens: true }, .. } => None,
|
||||
_ => params(ctx.completion, func, &func_kind, true),
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
|
||||
render(ctx, local_name, func, func_kind, params, false)
|
||||
}
|
||||
|
||||
fn render(
|
||||
|
@ -45,6 +77,8 @@ fn render(
|
|||
local_name: Option<hir::Name>,
|
||||
func: hir::Function,
|
||||
func_kind: FuncKind,
|
||||
params: Option<(Option<hir::SelfParam>, Vec<hir::Param>)>,
|
||||
qualified_path: bool,
|
||||
) -> Builder {
|
||||
let db = completion.db;
|
||||
|
||||
|
@ -80,16 +114,6 @@ fn render(
|
|||
// FIXME For now we don't properly calculate the edits for ref match
|
||||
// completions on methods or qualified paths, so we've disabled them.
|
||||
// See #8058.
|
||||
let qualified_path = matches!(
|
||||
ctx.completion.ident_ctx,
|
||||
IdentContext::NameRef(NameRefContext {
|
||||
kind: NameRefKind::Path(PathCompletionCtx {
|
||||
qualified: Qualified::With { .. },
|
||||
..
|
||||
}),
|
||||
..
|
||||
})
|
||||
);
|
||||
if matches!(func_kind, FuncKind::Function) && !qualified_path {
|
||||
item.ref_match(ref_match);
|
||||
}
|
||||
|
@ -100,11 +124,9 @@ fn render(
|
|||
.detail(detail(db, func))
|
||||
.lookup_by(name.to_smol_str());
|
||||
|
||||
match completion.config.snippet_cap {
|
||||
Some(cap) => {
|
||||
if let Some((self_param, params)) = params(completion, func, &func_kind) {
|
||||
add_call_parens(&mut item, completion, cap, call, self_param, params);
|
||||
}
|
||||
match completion.config.snippet_cap.zip(params) {
|
||||
Some((cap, (self_param, params))) => {
|
||||
add_call_parens(&mut item, completion, cap, call, self_param, params);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -254,37 +276,12 @@ fn params(
|
|||
ctx: &CompletionContext<'_>,
|
||||
func: hir::Function,
|
||||
func_kind: &FuncKind,
|
||||
has_dot_receiver: bool,
|
||||
) -> Option<(Option<hir::SelfParam>, Vec<hir::Param>)> {
|
||||
if ctx.config.callable.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let has_dot_receiver = match ctx.ident_ctx {
|
||||
IdentContext::NameRef(NameRefContext {
|
||||
kind:
|
||||
NameRefKind::DotAccess(DotAccess {
|
||||
kind: DotAccessKind::Method { has_parens: true },
|
||||
..
|
||||
}),
|
||||
..
|
||||
}) => return None,
|
||||
IdentContext::NameRef(NameRefContext {
|
||||
kind: NameRefKind::DotAccess(DotAccess { .. }),
|
||||
..
|
||||
}) => true,
|
||||
IdentContext::NameRef(NameRefContext {
|
||||
kind:
|
||||
NameRefKind::Path(
|
||||
PathCompletionCtx {
|
||||
kind: PathKind::Expr { .. }, has_call_parens: true, ..
|
||||
}
|
||||
| PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. },
|
||||
),
|
||||
..
|
||||
}) => return None,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
// Don't add parentheses if the expected type is some function reference.
|
||||
if let Some(ty) = &ctx.expected_type {
|
||||
// FIXME: check signature matches?
|
||||
|
|
|
@ -4,9 +4,7 @@ use hir::{db::HirDatabase, Documentation, HasAttrs, StructKind};
|
|||
use ide_db::SymbolKind;
|
||||
|
||||
use crate::{
|
||||
context::{
|
||||
CompletionContext, IdentContext, NameRefContext, NameRefKind, PathCompletionCtx, PathKind,
|
||||
},
|
||||
context::{CompletionContext, PathCompletionCtx, PathKind},
|
||||
item::{Builder, CompletionItem},
|
||||
render::{
|
||||
compute_ref_match, compute_type_match,
|
||||
|
@ -21,6 +19,7 @@ use crate::{
|
|||
|
||||
pub(crate) fn render_variant_lit(
|
||||
ctx: RenderContext<'_>,
|
||||
path_ctx: &PathCompletionCtx,
|
||||
local_name: Option<hir::Name>,
|
||||
variant: hir::Variant,
|
||||
path: Option<hir::ModPath>,
|
||||
|
@ -29,11 +28,12 @@ pub(crate) fn render_variant_lit(
|
|||
let db = ctx.db();
|
||||
|
||||
let name = local_name.unwrap_or_else(|| variant.name(db));
|
||||
render(ctx, Variant::EnumVariant(variant), name, path)
|
||||
render(ctx, path_ctx, Variant::EnumVariant(variant), name, path)
|
||||
}
|
||||
|
||||
pub(crate) fn render_struct_literal(
|
||||
ctx: RenderContext<'_>,
|
||||
path_ctx: &PathCompletionCtx,
|
||||
strukt: hir::Struct,
|
||||
path: Option<hir::ModPath>,
|
||||
local_name: Option<hir::Name>,
|
||||
|
@ -42,29 +42,21 @@ pub(crate) fn render_struct_literal(
|
|||
let db = ctx.db();
|
||||
|
||||
let name = local_name.unwrap_or_else(|| strukt.name(db));
|
||||
render(ctx, Variant::Struct(strukt), name, path)
|
||||
render(ctx, path_ctx, Variant::Struct(strukt), name, path)
|
||||
}
|
||||
|
||||
fn render(
|
||||
ctx @ RenderContext { completion, .. }: RenderContext<'_>,
|
||||
path_ctx: &PathCompletionCtx,
|
||||
thing: Variant,
|
||||
name: hir::Name,
|
||||
path: Option<hir::ModPath>,
|
||||
) -> Option<Builder> {
|
||||
let db = completion.db;
|
||||
let mut kind = thing.kind(db);
|
||||
let should_add_parens = match &completion.ident_ctx {
|
||||
IdentContext::NameRef(NameRefContext {
|
||||
kind: NameRefKind::Path(PathCompletionCtx { has_call_parens: true, .. }),
|
||||
..
|
||||
}) => false,
|
||||
IdentContext::NameRef(NameRefContext {
|
||||
kind:
|
||||
NameRefKind::Path(PathCompletionCtx {
|
||||
kind: PathKind::Use | PathKind::Type { .. }, ..
|
||||
}),
|
||||
..
|
||||
}) => false,
|
||||
let should_add_parens = match &path_ctx {
|
||||
PathCompletionCtx { has_call_parens: true, .. } => false,
|
||||
PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. } => false,
|
||||
_ => true,
|
||||
};
|
||||
|
||||
|
|
|
@ -5,18 +5,24 @@ use ide_db::SymbolKind;
|
|||
use syntax::SmolStr;
|
||||
|
||||
use crate::{
|
||||
context::{IdentContext, NameRefContext, NameRefKind, PathCompletionCtx, PathKind},
|
||||
context::{PathCompletionCtx, PathKind},
|
||||
item::{Builder, CompletionItem},
|
||||
render::RenderContext,
|
||||
};
|
||||
|
||||
pub(crate) fn render_macro(ctx: RenderContext<'_>, name: hir::Name, macro_: hir::Macro) -> Builder {
|
||||
pub(crate) fn render_macro(
|
||||
ctx: RenderContext<'_>,
|
||||
path_ctx: &PathCompletionCtx,
|
||||
name: hir::Name,
|
||||
macro_: hir::Macro,
|
||||
) -> Builder {
|
||||
let _p = profile::span("render_macro");
|
||||
render(ctx, name, macro_)
|
||||
render(ctx, path_ctx, name, macro_)
|
||||
}
|
||||
|
||||
fn render(
|
||||
ctx @ RenderContext { completion, .. }: RenderContext<'_>,
|
||||
PathCompletionCtx { kind, has_macro_bang, has_call_parens, .. }: &PathCompletionCtx,
|
||||
name: hir::Name,
|
||||
macro_: hir::Macro,
|
||||
) -> Builder {
|
||||
|
@ -33,13 +39,7 @@ fn render(
|
|||
let is_fn_like = macro_.is_fn_like(completion.db);
|
||||
let (bra, ket) = if is_fn_like { guess_macro_braces(&name, docs_str) } else { ("", "") };
|
||||
|
||||
let needs_bang = match &completion.ident_ctx {
|
||||
IdentContext::NameRef(NameRefContext {
|
||||
kind: NameRefKind::Path(PathCompletionCtx { kind, has_macro_bang, .. }),
|
||||
..
|
||||
}) => is_fn_like && *kind != PathKind::Use && !has_macro_bang,
|
||||
_ => is_fn_like,
|
||||
};
|
||||
let needs_bang = is_fn_like && *kind != PathKind::Use && !has_macro_bang;
|
||||
|
||||
let mut item = CompletionItem::new(
|
||||
SymbolKind::from(macro_.kind(completion.db)),
|
||||
|
@ -53,7 +53,7 @@ fn render(
|
|||
|
||||
let name = &*name;
|
||||
match ctx.snippet_cap() {
|
||||
Some(cap) if needs_bang && !ctx.path_is_call() => {
|
||||
Some(cap) if needs_bang && !has_call_parens => {
|
||||
let snippet = format!("{}!{}$0{}", name, bra, ket);
|
||||
let lookup = banged_name(name);
|
||||
item.insert_snippet(cap, snippet).lookup_by(lookup);
|
||||
|
|
|
@ -6,16 +6,14 @@ use itertools::Itertools;
|
|||
use syntax::SmolStr;
|
||||
|
||||
use crate::{
|
||||
context::{
|
||||
IdentContext, NameContext, NameKind, NameRefContext, NameRefKind, ParamKind,
|
||||
PathCompletionCtx, PathKind, PatternContext,
|
||||
},
|
||||
context::{ParamKind, PatternContext},
|
||||
render::{variant::visible_fields, RenderContext},
|
||||
CompletionItem, CompletionItemKind,
|
||||
};
|
||||
|
||||
pub(crate) fn render_struct_pat(
|
||||
ctx: RenderContext<'_>,
|
||||
pattern_ctx: &PatternContext,
|
||||
strukt: hir::Struct,
|
||||
local_name: Option<Name>,
|
||||
) -> Option<CompletionItem> {
|
||||
|
@ -30,13 +28,21 @@ pub(crate) fn render_struct_pat(
|
|||
}
|
||||
|
||||
let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_smol_str();
|
||||
let pat = render_pat(&ctx, &name, strukt.kind(ctx.db()), &visible_fields, fields_omitted)?;
|
||||
let pat = render_pat(
|
||||
&ctx,
|
||||
pattern_ctx,
|
||||
&name,
|
||||
strukt.kind(ctx.db()),
|
||||
&visible_fields,
|
||||
fields_omitted,
|
||||
)?;
|
||||
|
||||
Some(build_completion(ctx, name, pat, strukt))
|
||||
}
|
||||
|
||||
pub(crate) fn render_variant_pat(
|
||||
ctx: RenderContext<'_>,
|
||||
pattern_ctx: &PatternContext,
|
||||
variant: hir::Variant,
|
||||
local_name: Option<Name>,
|
||||
path: Option<&hir::ModPath>,
|
||||
|
@ -50,7 +56,14 @@ pub(crate) fn render_variant_pat(
|
|||
Some(path) => path.to_string().into(),
|
||||
None => local_name.unwrap_or_else(|| variant.name(ctx.db())).to_smol_str(),
|
||||
};
|
||||
let pat = render_pat(&ctx, &name, variant.kind(ctx.db()), &visible_fields, fields_omitted)?;
|
||||
let pat = render_pat(
|
||||
&ctx,
|
||||
pattern_ctx,
|
||||
&name,
|
||||
variant.kind(ctx.db()),
|
||||
&visible_fields,
|
||||
fields_omitted,
|
||||
)?;
|
||||
|
||||
Some(build_completion(ctx, name, pat, variant))
|
||||
}
|
||||
|
@ -75,49 +88,28 @@ fn build_completion(
|
|||
|
||||
fn render_pat(
|
||||
ctx: &RenderContext<'_>,
|
||||
pattern_ctx: &PatternContext,
|
||||
name: &str,
|
||||
kind: StructKind,
|
||||
fields: &[hir::Field],
|
||||
fields_omitted: bool,
|
||||
) -> Option<String> {
|
||||
let has_call_parens = matches!(
|
||||
ctx.completion.ident_ctx,
|
||||
IdentContext::NameRef(NameRefContext {
|
||||
kind: NameRefKind::Path(PathCompletionCtx { has_call_parens: true, .. }),
|
||||
..
|
||||
})
|
||||
);
|
||||
let mut pat = match kind {
|
||||
StructKind::Tuple if !has_call_parens => {
|
||||
render_tuple_as_pat(ctx.snippet_cap(), fields, name, fields_omitted)
|
||||
}
|
||||
StructKind::Record if !has_call_parens => {
|
||||
StructKind::Tuple => render_tuple_as_pat(ctx.snippet_cap(), fields, name, fields_omitted),
|
||||
StructKind::Record => {
|
||||
render_record_as_pat(ctx.db(), ctx.snippet_cap(), fields, name, fields_omitted)
|
||||
}
|
||||
StructKind::Unit => return None,
|
||||
_ => name.to_owned(),
|
||||
};
|
||||
|
||||
let needs_ascription = !has_call_parens
|
||||
&& matches!(
|
||||
&ctx.completion.ident_ctx,
|
||||
IdentContext::NameRef(NameRefContext {
|
||||
kind: NameRefKind::Path(PathCompletionCtx {
|
||||
kind: PathKind::Pat {
|
||||
pat_ctx
|
||||
},
|
||||
..
|
||||
}),
|
||||
..
|
||||
}) | IdentContext::Name(NameContext {
|
||||
kind: NameKind::IdentPat(pat_ctx), ..}
|
||||
)
|
||||
if matches!(pat_ctx, PatternContext {
|
||||
param_ctx: Some((.., ParamKind::Function(_))),
|
||||
has_type_ascription: false,
|
||||
..
|
||||
})
|
||||
);
|
||||
let needs_ascription = matches!(
|
||||
pattern_ctx,
|
||||
PatternContext {
|
||||
param_ctx: Some((.., ParamKind::Function(_))),
|
||||
has_type_ascription: false,
|
||||
..
|
||||
}
|
||||
);
|
||||
if needs_ascription {
|
||||
pat.push(':');
|
||||
pat.push(' ');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue