Don't use an untyped String for ActiveParam tracking

This commit is contained in:
Lukas Wirth 2021-03-20 23:22:09 +01:00
parent 5cc8ad0c4a
commit 38048c35d8
5 changed files with 44 additions and 24 deletions

View File

@ -23,7 +23,7 @@ pub(super) fn ra_fixture(
expanded: SyntaxToken, expanded: SyntaxToken,
) -> Option<()> { ) -> Option<()> {
let active_parameter = ActiveParameter::at_token(&sema, expanded)?; let active_parameter = ActiveParameter::at_token(&sema, expanded)?;
if !active_parameter.name.starts_with("ra_fixture") { if !active_parameter.ident().map_or(false, |name| name.text().starts_with("ra_fixture")) {
return None; return None;
} }
let value = literal.value()?; let value = literal.value()?;

View File

@ -4,8 +4,11 @@
use ide_db::base_db::{FilePosition, SourceDatabase}; use ide_db::base_db::{FilePosition, SourceDatabase};
use ide_db::{call_info::ActiveParameter, RootDatabase}; use ide_db::{call_info::ActiveParameter, RootDatabase};
use syntax::{ use syntax::{
algo::find_node_at_offset, ast, match_ast, AstNode, NodeOrToken, SyntaxKind::*, SyntaxNode, algo::find_node_at_offset,
SyntaxToken, TextRange, TextSize, ast::{self, NameOrNameRef, NameOwner},
match_ast, AstNode, NodeOrToken,
SyntaxKind::*,
SyntaxNode, SyntaxToken, TextRange, TextSize,
}; };
use text_edit::Indel; use text_edit::Indel;
@ -35,7 +38,7 @@ pub(crate) struct CompletionContext<'a> {
/// The token before the cursor, in the macro-expanded file. /// The token before the cursor, in the macro-expanded file.
pub(super) token: SyntaxToken, pub(super) token: SyntaxToken,
pub(super) krate: Option<hir::Crate>, pub(super) krate: Option<hir::Crate>,
pub(super) expected_name: Option<String>, pub(super) expected_name: Option<NameOrNameRef>,
pub(super) expected_type: Option<Type>, pub(super) expected_type: Option<Type>,
pub(super) name_ref_syntax: Option<ast::NameRef>, pub(super) name_ref_syntax: Option<ast::NameRef>,
pub(super) function_syntax: Option<ast::Fn>, pub(super) function_syntax: Option<ast::Fn>,
@ -292,13 +295,13 @@ fn fill(
file_with_fake_ident: SyntaxNode, file_with_fake_ident: SyntaxNode,
offset: TextSize, offset: TextSize,
) { ) {
let expected = { let (expected_type, expected_name) = {
let mut node = match self.token.parent() { let mut node = match self.token.parent() {
Some(it) => it, Some(it) => it,
None => return, None => return,
}; };
loop { loop {
let ret = match_ast! { break match_ast! {
match node { match node {
ast::LetStmt(it) => { ast::LetStmt(it) => {
cov_mark::hit!(expected_type_let_with_leading_char); cov_mark::hit!(expected_type_let_with_leading_char);
@ -306,7 +309,7 @@ fn fill(
let ty = it.pat() let ty = it.pat()
.and_then(|pat| self.sema.type_of_pat(&pat)); .and_then(|pat| self.sema.type_of_pat(&pat));
let name = if let Some(ast::Pat::IdentPat(ident)) = it.pat() { let name = if let Some(ast::Pat::IdentPat(ident)) = it.pat() {
Some(ident.syntax().text().to_string()) ident.name().map(NameOrNameRef::Name)
} else { } else {
None None
}; };
@ -319,7 +322,10 @@ fn fill(
ActiveParameter::at_token( ActiveParameter::at_token(
&self.sema, &self.sema,
self.token.clone(), self.token.clone(),
).map(|ap| (Some(ap.ty), Some(ap.name))) ).map(|ap| {
let name = ap.ident().map(NameOrNameRef::Name);
(Some(ap.ty), name)
})
.unwrap_or((None, None)) .unwrap_or((None, None))
}, },
ast::RecordExprFieldList(_it) => { ast::RecordExprFieldList(_it) => {
@ -327,10 +333,10 @@ fn fill(
self.token.prev_sibling_or_token() self.token.prev_sibling_or_token()
.and_then(|se| se.into_node()) .and_then(|se| se.into_node())
.and_then(|node| ast::RecordExprField::cast(node)) .and_then(|node| ast::RecordExprField::cast(node))
.and_then(|rf| self.sema.resolve_record_field(&rf)) .and_then(|rf| self.sema.resolve_record_field(&rf).zip(Some(rf)))
.map(|f|( .map(|(f, rf)|(
Some(f.0.signature_ty(self.db)), Some(f.0.signature_ty(self.db)),
Some(f.0.name(self.db).to_string()), rf.field_name().map(NameOrNameRef::NameRef),
)) ))
.unwrap_or((None, None)) .unwrap_or((None, None))
}, },
@ -340,7 +346,7 @@ fn fill(
.resolve_record_field(&it) .resolve_record_field(&it)
.map(|f|( .map(|f|(
Some(f.0.signature_ty(self.db)), Some(f.0.signature_ty(self.db)),
Some(f.0.name(self.db).to_string()), it.field_name().map(NameOrNameRef::NameRef),
)) ))
.unwrap_or((None, None)) .unwrap_or((None, None))
}, },
@ -378,12 +384,10 @@ fn fill(
}, },
} }
}; };
break ret;
} }
}; };
self.expected_type = expected.0; self.expected_type = expected_type;
self.expected_name = expected.1; self.expected_name = expected_name;
self.attribute_under_caret = find_node_at_offset(&file_with_fake_ident, offset); self.attribute_under_caret = find_node_at_offset(&file_with_fake_ident, offset);
// First, let's try to complete a reference to some declaration. // First, let's try to complete a reference to some declaration.
@ -631,7 +635,9 @@ fn check_expected_type_and_name(ra_fixture: &str, expect: Expect) {
.map(|t| t.display_test(&db).to_string()) .map(|t| t.display_test(&db).to_string())
.unwrap_or("?".to_owned()); .unwrap_or("?".to_owned());
let name = completion_context.expected_name.unwrap_or("?".to_owned()); let name = completion_context
.expected_name
.map_or_else(|| "?".to_owned(), |name| name.to_string());
expect.assert_eq(&format!("ty: {}, name: {}", ty, name)); expect.assert_eq(&format!("ty: {}, name: {}", ty, name));
} }

View File

@ -243,7 +243,7 @@ fn render_resolution(
item.set_relevance(CompletionRelevance { item.set_relevance(CompletionRelevance {
exact_type_match: compute_exact_type_match(self.ctx.completion, &ty), exact_type_match: compute_exact_type_match(self.ctx.completion, &ty),
exact_name_match: compute_exact_name_match(self.ctx.completion, local_name.clone()), exact_name_match: compute_exact_name_match(self.ctx.completion, &local_name),
is_local: true, is_local: true,
..CompletionRelevance::default() ..CompletionRelevance::default()
}); });
@ -319,8 +319,7 @@ fn compute_exact_type_match(ctx: &CompletionContext, completion_ty: &hir::Type)
fn compute_exact_name_match(ctx: &CompletionContext, completion_name: impl Into<String>) -> bool { fn compute_exact_name_match(ctx: &CompletionContext, completion_name: impl Into<String>) -> bool {
let completion_name = completion_name.into(); let completion_name = completion_name.into();
ctx.expected_name.as_ref().map_or(false, |name| name.text() == completion_name)
Some(&completion_name) == ctx.expected_name.as_ref()
} }
fn compute_ref_match(ctx: &CompletionContext, completion_ty: &hir::Type) -> Option<Mutability> { fn compute_ref_match(ctx: &CompletionContext, completion_ty: &hir::Type) -> Option<Mutability> {

View File

@ -4,7 +4,7 @@
use hir::{HasAttrs, HirDisplay, Semantics, Type}; use hir::{HasAttrs, HirDisplay, Semantics, Type};
use stdx::format_to; use stdx::format_to;
use syntax::{ use syntax::{
ast::{self, ArgListOwner}, ast::{self, ArgListOwner, NameOwner},
match_ast, AstNode, SyntaxNode, SyntaxToken, TextRange, TextSize, match_ast, AstNode, SyntaxNode, SyntaxToken, TextRange, TextSize,
}; };
@ -142,7 +142,7 @@ fn call_info_impl(
#[derive(Debug)] #[derive(Debug)]
pub struct ActiveParameter { pub struct ActiveParameter {
pub ty: Type, pub ty: Type,
pub name: String, pub pat: Either<ast::SelfParam, ast::Pat>,
} }
impl ActiveParameter { impl ActiveParameter {
@ -165,8 +165,14 @@ pub fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Se
return None; return None;
} }
let (pat, ty) = params.swap_remove(idx); let (pat, ty) = params.swap_remove(idx);
let name = pat?.to_string(); pat.map(|pat| ActiveParameter { ty, pat })
Some(ActiveParameter { ty, name }) }
pub fn ident(&self) -> Option<ast::Name> {
self.pat.as_ref().right().and_then(|param| match param {
ast::Pat::IdentPat(ident) => ident.name(),
_ => None,
})
} }
} }

View File

@ -380,6 +380,15 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
} }
} }
impl NameOrNameRef {
pub fn text(&self) -> &str {
match self {
NameOrNameRef::Name(name) => name.text(),
NameOrNameRef::NameRef(name_ref) => name_ref.text(),
}
}
}
impl ast::RecordPatField { impl ast::RecordPatField {
pub fn for_field_name_ref(field_name: &ast::NameRef) -> Option<ast::RecordPatField> { pub fn for_field_name_ref(field_name: &ast::NameRef) -> Option<ast::RecordPatField> {
let candidate = field_name.syntax().parent().and_then(ast::RecordPatField::cast)?; let candidate = field_name.syntax().parent().and_then(ast::RecordPatField::cast)?;