mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 21:13:37 +00:00
fix: Insert whitespace into trait-impl completions when coming from macros
This commit is contained in:
parent
6f006b7524
commit
86d1d9067e
6 changed files with 99 additions and 83 deletions
|
@ -939,7 +939,6 @@ struct Foo(usize);
|
|||
|
||||
impl FooB for Foo {
|
||||
$0fn foo< 'lt>(& 'lt self){}
|
||||
|
||||
}
|
||||
"#,
|
||||
)
|
||||
|
|
|
@ -32,10 +32,12 @@
|
|||
//! ```
|
||||
|
||||
use hir::{self, HasAttrs};
|
||||
use ide_db::{path_transform::PathTransform, traits::get_missing_assoc_items, SymbolKind};
|
||||
use ide_db::{
|
||||
path_transform::PathTransform, syntax_helpers::insert_whitespace_into_node,
|
||||
traits::get_missing_assoc_items, SymbolKind,
|
||||
};
|
||||
use syntax::{
|
||||
ast::{self, edit_in_place::AttrsOwnerEdit},
|
||||
display::function_declaration,
|
||||
AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, T,
|
||||
};
|
||||
use text_edit::TextEdit;
|
||||
|
@ -179,7 +181,7 @@ fn add_function_impl(
|
|||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let function_decl = function_declaration(&transformed_fn);
|
||||
let function_decl = function_declaration(&transformed_fn, source.file_id.is_macro());
|
||||
match ctx.config.snippet_cap {
|
||||
Some(cap) => {
|
||||
let snippet = format!("{} {{\n $0\n}}", function_decl);
|
||||
|
@ -260,7 +262,7 @@ fn add_const_impl(
|
|||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let label = make_const_compl_syntax(&transformed_const);
|
||||
let label = make_const_compl_syntax(&transformed_const, source.file_id.is_macro());
|
||||
let replacement = format!("{} ", label);
|
||||
|
||||
let mut item = CompletionItem::new(SymbolKind::Const, replacement_range, label);
|
||||
|
@ -283,17 +285,18 @@ fn add_const_impl(
|
|||
}
|
||||
}
|
||||
|
||||
fn make_const_compl_syntax(const_: &ast::Const) -> String {
|
||||
fn make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> String {
|
||||
const_.remove_attrs_and_docs();
|
||||
let const_ = if needs_whitespace {
|
||||
insert_whitespace_into_node::insert_ws_into(const_.syntax().clone())
|
||||
} else {
|
||||
const_.syntax().clone()
|
||||
};
|
||||
|
||||
let const_start = const_.syntax().text_range().start();
|
||||
let const_end = const_.syntax().text_range().end();
|
||||
|
||||
let start =
|
||||
const_.syntax().first_child_or_token().map_or(const_start, |f| f.text_range().start());
|
||||
let start = const_.text_range().start();
|
||||
let const_end = const_.text_range().end();
|
||||
|
||||
let end = const_
|
||||
.syntax()
|
||||
.children_with_tokens()
|
||||
.find(|s| s.kind() == T![;] || s.kind() == T![=])
|
||||
.map_or(const_end, |f| f.text_range().start());
|
||||
|
@ -301,11 +304,36 @@ fn make_const_compl_syntax(const_: &ast::Const) -> String {
|
|||
let len = end - start;
|
||||
let range = TextRange::new(0.into(), len);
|
||||
|
||||
let syntax = const_.syntax().text().slice(range).to_string();
|
||||
let syntax = const_.text().slice(range).to_string();
|
||||
|
||||
format!("{} =", syntax.trim_end())
|
||||
}
|
||||
|
||||
fn function_declaration(node: &ast::Fn, needs_whitespace: bool) -> String {
|
||||
node.remove_attrs_and_docs();
|
||||
|
||||
let node = if needs_whitespace {
|
||||
insert_whitespace_into_node::insert_ws_into(node.syntax().clone())
|
||||
} else {
|
||||
node.syntax().clone()
|
||||
};
|
||||
|
||||
let start = node.text_range().start();
|
||||
let end = node.text_range().end();
|
||||
|
||||
let end = node
|
||||
.last_child_or_token()
|
||||
.filter(|s| s.kind() == T![;] || s.kind() == SyntaxKind::BLOCK_EXPR)
|
||||
.map_or(end, |f| f.text_range().start());
|
||||
|
||||
let len = end - start;
|
||||
let range = TextRange::new(0.into(), len);
|
||||
|
||||
let syntax = node.text().slice(range).to_string();
|
||||
|
||||
syntax.trim_end().to_owned()
|
||||
}
|
||||
|
||||
fn replacement_range(ctx: &CompletionContext, item: &SyntaxNode) -> TextRange {
|
||||
let first_child = item
|
||||
.children_with_tokens()
|
||||
|
@ -655,8 +683,7 @@ trait Test {
|
|||
struct T;
|
||||
|
||||
impl Test for T {
|
||||
fn foo<T>()
|
||||
where T: Into<String> {
|
||||
fn foo<T>() where T: Into<String> {
|
||||
$0
|
||||
}
|
||||
}
|
||||
|
@ -992,7 +1019,7 @@ trait SomeTrait<T> {}
|
|||
|
||||
trait Foo<T> {
|
||||
fn function()
|
||||
where Self: SomeTrait<T>;
|
||||
where Self: SomeTrait<T>;
|
||||
}
|
||||
struct Bar;
|
||||
|
||||
|
@ -1005,13 +1032,13 @@ trait SomeTrait<T> {}
|
|||
|
||||
trait Foo<T> {
|
||||
fn function()
|
||||
where Self: SomeTrait<T>;
|
||||
where Self: SomeTrait<T>;
|
||||
}
|
||||
struct Bar;
|
||||
|
||||
impl Foo<u32> for Bar {
|
||||
fn function()
|
||||
where Self: SomeTrait<u32> {
|
||||
where Self: SomeTrait<u32> {
|
||||
$0
|
||||
}
|
||||
}
|
||||
|
@ -1052,4 +1079,51 @@ impl Tr for () {
|
|||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fixes_up_macro_generated() {
|
||||
check_edit(
|
||||
"fn foo",
|
||||
r#"
|
||||
macro_rules! noop {
|
||||
($($item: item)*) => {
|
||||
$($item)*
|
||||
}
|
||||
}
|
||||
|
||||
noop! {
|
||||
trait Foo {
|
||||
fn foo(&mut self, bar: i64, baz: &mut u32) -> Result<(), u32>;
|
||||
}
|
||||
}
|
||||
|
||||
struct Test;
|
||||
|
||||
impl Foo for Test {
|
||||
$0
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
macro_rules! noop {
|
||||
($($item: item)*) => {
|
||||
$($item)*
|
||||
}
|
||||
}
|
||||
|
||||
noop! {
|
||||
trait Foo {
|
||||
fn foo(&mut self, bar: i64, baz: &mut u32) -> Result<(), u32>;
|
||||
}
|
||||
}
|
||||
|
||||
struct Test;
|
||||
|
||||
impl Foo for Test {
|
||||
fn foo(&mut self,bar:i64,baz: &mut u32) -> Result<(),u32> {
|
||||
$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,6 +114,10 @@ pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode {
|
|||
ted::insert(pos, insert);
|
||||
}
|
||||
|
||||
if let Some(it) = syn.last_token().filter(|it| it.kind() == SyntaxKind::WHITESPACE) {
|
||||
ted::remove(it);
|
||||
}
|
||||
|
||||
syn
|
||||
}
|
||||
|
||||
|
|
|
@ -250,8 +250,7 @@ fn main() {
|
|||
"#,
|
||||
expect![[r#"
|
||||
bar
|
||||
for _ in 0..42{}
|
||||
"#]],
|
||||
for _ in 0..42{}"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -273,7 +272,6 @@ f$0oo!();
|
|||
expect![[r#"
|
||||
foo
|
||||
fn b(){}
|
||||
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -297,8 +295,7 @@ f$0oo!();
|
|||
fn some_thing() -> u32 {
|
||||
let a = 0;
|
||||
a+10
|
||||
}
|
||||
"#]],
|
||||
}"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -359,8 +356,7 @@ fn main() {
|
|||
"#,
|
||||
expect![[r#"
|
||||
match_ast
|
||||
{}
|
||||
"#]],
|
||||
{}"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -421,8 +417,7 @@ fn main() {
|
|||
"#,
|
||||
expect![[r#"
|
||||
foo
|
||||
fn f<T>(_: &dyn ::std::marker::Copy){}
|
||||
"#]],
|
||||
fn f<T>(_: &dyn ::std::marker::Copy){}"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -440,7 +435,6 @@ struct Foo {}
|
|||
expect![[r#"
|
||||
Clone
|
||||
impl < >core::clone::Clone for Foo< >{}
|
||||
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -458,7 +452,6 @@ struct Foo {}
|
|||
expect![[r#"
|
||||
Copy
|
||||
impl < >core::marker::Copy for Foo< >{}
|
||||
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -475,7 +468,6 @@ struct Foo {}
|
|||
expect![[r#"
|
||||
Copy
|
||||
impl < >core::marker::Copy for Foo< >{}
|
||||
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
|
@ -488,7 +480,6 @@ struct Foo {}
|
|||
expect![[r#"
|
||||
Clone
|
||||
impl < >core::clone::Clone for Foo< >{}
|
||||
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
//! This module contains utilities for rendering syntax nodes into a string representing their signature.
|
||||
|
||||
use crate::ast::{self, HasGenericParams, HasName};
|
||||
|
||||
use ast::HasVisibility;
|
||||
use stdx::format_to;
|
||||
|
||||
pub fn function_declaration(node: &ast::Fn) -> String {
|
||||
let mut buf = String::new();
|
||||
if let Some(vis) = node.visibility() {
|
||||
format_to!(buf, "{} ", vis);
|
||||
}
|
||||
if node.async_token().is_some() {
|
||||
format_to!(buf, "async ");
|
||||
}
|
||||
if node.const_token().is_some() {
|
||||
format_to!(buf, "const ");
|
||||
}
|
||||
if node.unsafe_token().is_some() {
|
||||
format_to!(buf, "unsafe ");
|
||||
}
|
||||
if let Some(abi) = node.abi() {
|
||||
// Keyword `extern` is included in the string.
|
||||
format_to!(buf, "{} ", abi);
|
||||
}
|
||||
if let Some(name) = node.name() {
|
||||
format_to!(buf, "fn {}", name);
|
||||
}
|
||||
if let Some(type_params) = node.generic_param_list() {
|
||||
format_to!(buf, "{}", type_params);
|
||||
}
|
||||
if let Some(param_list) = node.param_list() {
|
||||
let params: Vec<String> = param_list
|
||||
.self_param()
|
||||
.into_iter()
|
||||
.map(|self_param| self_param.to_string())
|
||||
.chain(param_list.params().map(|param| param.to_string()))
|
||||
.collect();
|
||||
// Useful to inline parameters
|
||||
format_to!(buf, "({})", params.join(", "));
|
||||
}
|
||||
if let Some(ret_type) = node.ret_type() {
|
||||
if ret_type.ty().is_some() {
|
||||
format_to!(buf, " {}", ret_type);
|
||||
}
|
||||
}
|
||||
if let Some(where_clause) = node.where_clause() {
|
||||
format_to!(buf, "\n{}", where_clause);
|
||||
}
|
||||
buf
|
||||
}
|
|
@ -33,7 +33,6 @@ mod token_text;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub mod display;
|
||||
pub mod algo;
|
||||
pub mod ast;
|
||||
#[doc(hidden)]
|
||||
|
|
Loading…
Reference in a new issue