Consider references when applying postfix completions
This commit is contained in:
parent
f9494f1147
commit
4e43df26b2
1 changed files with 123 additions and 17 deletions
|
@ -1,6 +1,9 @@
|
|||
//! FIXME: write short doc here
|
||||
|
||||
use ra_syntax::{ast::AstNode, TextRange, TextUnit};
|
||||
use ra_syntax::{
|
||||
ast::{self, AstNode},
|
||||
TextRange, TextUnit,
|
||||
};
|
||||
use ra_text_edit::TextEdit;
|
||||
|
||||
use crate::{
|
||||
|
@ -21,13 +24,8 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
|
|||
None => return,
|
||||
};
|
||||
|
||||
let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal {
|
||||
let text = dot_receiver.syntax().text();
|
||||
let without_dot = ..text.len() - TextUnit::of_char('.');
|
||||
text.slice(without_dot).to_string()
|
||||
} else {
|
||||
dot_receiver.syntax().text().to_string()
|
||||
};
|
||||
let receiver_text =
|
||||
get_receiver_text(dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal);
|
||||
|
||||
let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) {
|
||||
Some(it) => it,
|
||||
|
@ -35,10 +33,17 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
|
|||
};
|
||||
|
||||
if receiver_ty.is_bool() || receiver_ty.is_unknown() {
|
||||
postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text))
|
||||
.add_to(acc);
|
||||
postfix_snippet(
|
||||
ctx,
|
||||
&dot_receiver,
|
||||
"if",
|
||||
"if expr {}",
|
||||
&format!("if {} {{$0}}", receiver_text),
|
||||
)
|
||||
.add_to(acc);
|
||||
postfix_snippet(
|
||||
ctx,
|
||||
&dot_receiver,
|
||||
"while",
|
||||
"while expr {}",
|
||||
&format!("while {} {{\n$0\n}}", receiver_text),
|
||||
|
@ -46,28 +51,70 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
|
|||
.add_to(acc);
|
||||
}
|
||||
|
||||
postfix_snippet(ctx, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc);
|
||||
// !&&&42 is a compiler error, ergo process it before considering the references
|
||||
postfix_snippet(ctx, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc);
|
||||
|
||||
postfix_snippet(ctx, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc);
|
||||
postfix_snippet(ctx, "refm", "&mut expr", &format!("&mut {}", receiver_text)).add_to(acc);
|
||||
postfix_snippet(ctx, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc);
|
||||
postfix_snippet(ctx, &dot_receiver, "refm", "&mut expr", &format!("&mut {}", receiver_text))
|
||||
.add_to(acc);
|
||||
|
||||
// The rest of the postfix completions create an expression that moves an argument,
|
||||
// so it's better to consider references now to avoid breaking the compilation
|
||||
let dot_receiver = include_references(dot_receiver);
|
||||
let receiver_text =
|
||||
get_receiver_text(&dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal);
|
||||
|
||||
postfix_snippet(
|
||||
ctx,
|
||||
&dot_receiver,
|
||||
"match",
|
||||
"match expr {}",
|
||||
&format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text),
|
||||
)
|
||||
.add_to(acc);
|
||||
|
||||
postfix_snippet(ctx, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)).add_to(acc);
|
||||
postfix_snippet(
|
||||
ctx,
|
||||
&dot_receiver,
|
||||
"box",
|
||||
"Box::new(expr)",
|
||||
&format!("Box::new({})", receiver_text),
|
||||
)
|
||||
.add_to(acc);
|
||||
|
||||
postfix_snippet(ctx, "box", "Box::new(expr)", &format!("Box::new({})", receiver_text))
|
||||
postfix_snippet(ctx, &dot_receiver, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text))
|
||||
.add_to(acc);
|
||||
}
|
||||
|
||||
fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder {
|
||||
fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String {
|
||||
if receiver_is_ambiguous_float_literal {
|
||||
let text = receiver.syntax().text();
|
||||
let without_dot = ..text.len() - TextUnit::of_char('.');
|
||||
text.slice(without_dot).to_string()
|
||||
} else {
|
||||
receiver.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
fn include_references(initial_element: &ast::Expr) -> ast::Expr {
|
||||
let mut resulting_element = initial_element.clone();
|
||||
while let Some(parent_ref_element) =
|
||||
resulting_element.syntax().parent().and_then(ast::RefExpr::cast)
|
||||
{
|
||||
resulting_element = ast::Expr::from(parent_ref_element);
|
||||
}
|
||||
resulting_element
|
||||
}
|
||||
|
||||
fn postfix_snippet(
|
||||
ctx: &CompletionContext,
|
||||
receiver: &ast::Expr,
|
||||
label: &str,
|
||||
detail: &str,
|
||||
snippet: &str,
|
||||
) -> Builder {
|
||||
let edit = {
|
||||
let receiver_syntax = ctx.dot_receiver.as_ref().expect("no receiver available").syntax();
|
||||
let receiver_syntax = receiver.syntax();
|
||||
let receiver_range = ctx.sema.original_range(receiver_syntax).range;
|
||||
let delete_range = TextRange::from_to(receiver_range.start(), ctx.source_range().end());
|
||||
TextEdit::replace(delete_range, snippet.to_string())
|
||||
|
@ -340,4 +387,63 @@ mod tests {
|
|||
"###
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn postfix_completion_for_references() {
|
||||
assert_debug_snapshot!(
|
||||
do_postfix_completion(
|
||||
r#"
|
||||
fn main() {
|
||||
&&&&42.<|>
|
||||
}
|
||||
"#,
|
||||
),
|
||||
@r###"
|
||||
[
|
||||
CompletionItem {
|
||||
label: "box",
|
||||
source_range: [56; 56),
|
||||
delete: [49; 56),
|
||||
insert: "Box::new(&&&&42)",
|
||||
detail: "Box::new(expr)",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "dbg",
|
||||
source_range: [56; 56),
|
||||
delete: [49; 56),
|
||||
insert: "dbg!(&&&&42)",
|
||||
detail: "dbg!(expr)",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "match",
|
||||
source_range: [56; 56),
|
||||
delete: [49; 56),
|
||||
insert: "match &&&&42 {\n ${1:_} => {$0\\},\n}",
|
||||
detail: "match expr {}",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "not",
|
||||
source_range: [56; 56),
|
||||
delete: [53; 56),
|
||||
insert: "!42",
|
||||
detail: "!expr",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "ref",
|
||||
source_range: [56; 56),
|
||||
delete: [53; 56),
|
||||
insert: "&42",
|
||||
detail: "&expr",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "refm",
|
||||
source_range: [56; 56),
|
||||
delete: [53; 56),
|
||||
insert: "&mut 42",
|
||||
detail: "&mut expr",
|
||||
},
|
||||
]
|
||||
"###
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue