mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Merge pull request #18690 from Giga-Bowser/extract-variable-string
feat: Use string literal contents as a name when extracting into variable
This commit is contained in:
commit
61c222e1af
1 changed files with 168 additions and 15 deletions
|
@ -1,5 +1,8 @@
|
|||
use hir::{HirDisplay, TypeInfo};
|
||||
use ide_db::{assists::GroupLabel, syntax_helpers::suggest_name};
|
||||
use ide_db::{
|
||||
assists::GroupLabel,
|
||||
syntax_helpers::{suggest_name, LexedStr},
|
||||
};
|
||||
use syntax::{
|
||||
ast::{
|
||||
self, edit::IndentLevel, edit_in_place::Indent, make, syntax_factory::SyntaxFactory,
|
||||
|
@ -320,24 +323,58 @@ impl ExtractionKind {
|
|||
ctx: &AssistContext<'_>,
|
||||
to_extract: &ast::Expr,
|
||||
) -> (String, SyntaxNode) {
|
||||
let field_shorthand = to_extract
|
||||
.syntax()
|
||||
.parent()
|
||||
.and_then(ast::RecordExprField::cast)
|
||||
.filter(|field| field.name_ref().is_some());
|
||||
let (var_name, expr_replace) = match field_shorthand {
|
||||
Some(field) => (field.to_string(), field.syntax().clone()),
|
||||
None => {
|
||||
(suggest_name::for_variable(to_extract, &ctx.sema), to_extract.syntax().clone())
|
||||
// We only do this sort of extraction for fields because they should have lowercase names
|
||||
if let ExtractionKind::Variable = self {
|
||||
let field_shorthand = to_extract
|
||||
.syntax()
|
||||
.parent()
|
||||
.and_then(ast::RecordExprField::cast)
|
||||
.filter(|field| field.name_ref().is_some());
|
||||
|
||||
if let Some(field) = field_shorthand {
|
||||
return (field.to_string(), field.syntax().clone());
|
||||
}
|
||||
}
|
||||
|
||||
let var_name = if let Some(literal_name) = get_literal_name(ctx, to_extract) {
|
||||
literal_name
|
||||
} else {
|
||||
suggest_name::for_variable(to_extract, &ctx.sema)
|
||||
};
|
||||
|
||||
let var_name = match self {
|
||||
ExtractionKind::Variable => var_name,
|
||||
ExtractionKind::Variable => var_name.to_lowercase(),
|
||||
ExtractionKind::Constant | ExtractionKind::Static => var_name.to_uppercase(),
|
||||
};
|
||||
|
||||
(var_name, expr_replace)
|
||||
(var_name, to_extract.syntax().clone())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_literal_name(ctx: &AssistContext<'_>, expr: &ast::Expr) -> Option<String> {
|
||||
let literal = match expr {
|
||||
ast::Expr::Literal(literal) => literal,
|
||||
_ => return None,
|
||||
};
|
||||
let inner = match literal.kind() {
|
||||
ast::LiteralKind::String(string) => string.value().ok()?.into_owned(),
|
||||
ast::LiteralKind::ByteString(byte_string) => {
|
||||
String::from_utf8(byte_string.value().ok()?.into_owned()).ok()?
|
||||
}
|
||||
ast::LiteralKind::CString(cstring) => {
|
||||
String::from_utf8(cstring.value().ok()?.into_owned()).ok()?
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
// Entirely arbitrary
|
||||
if inner.len() > 32 {
|
||||
return None;
|
||||
}
|
||||
|
||||
match LexedStr::single_token(ctx.file_id().edition(), &inner) {
|
||||
Some((SyntaxKind::IDENT, None)) => Some(inner),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -493,7 +530,7 @@ fn main() {
|
|||
"#,
|
||||
r#"
|
||||
fn main() {
|
||||
let $0var_name = "hello";
|
||||
let $0hello = "hello";
|
||||
}
|
||||
"#,
|
||||
"Extract into variable",
|
||||
|
@ -588,7 +625,7 @@ fn main() {
|
|||
"#,
|
||||
r#"
|
||||
fn main() {
|
||||
const $0VAR_NAME: &str = "hello";
|
||||
const $0HELLO: &str = "hello";
|
||||
}
|
||||
"#,
|
||||
"Extract into constant",
|
||||
|
@ -683,7 +720,7 @@ fn main() {
|
|||
"#,
|
||||
r#"
|
||||
fn main() {
|
||||
static $0VAR_NAME: &str = "hello";
|
||||
static $0HELLO: &str = "hello";
|
||||
}
|
||||
"#,
|
||||
"Extract into static",
|
||||
|
@ -2479,4 +2516,120 @@ fn foo() {
|
|||
"Extract into variable",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extract_string_literal() {
|
||||
check_assist_by_label(
|
||||
extract_variable,
|
||||
r#"
|
||||
struct Entry(&str);
|
||||
fn foo() {
|
||||
let entry = Entry($0"Hello"$0);
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct Entry(&str);
|
||||
fn foo() {
|
||||
let $0hello = "Hello";
|
||||
let entry = Entry(hello);
|
||||
}
|
||||
"#,
|
||||
"Extract into variable",
|
||||
);
|
||||
|
||||
check_assist_by_label(
|
||||
extract_variable,
|
||||
r#"
|
||||
struct Entry(&str);
|
||||
fn foo() {
|
||||
let entry = Entry($0"Hello"$0);
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct Entry(&str);
|
||||
fn foo() {
|
||||
const $0HELLO: &str = "Hello";
|
||||
let entry = Entry(HELLO);
|
||||
}
|
||||
"#,
|
||||
"Extract into constant",
|
||||
);
|
||||
|
||||
check_assist_by_label(
|
||||
extract_variable,
|
||||
r#"
|
||||
struct Entry(&str);
|
||||
fn foo() {
|
||||
let entry = Entry($0"Hello"$0);
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct Entry(&str);
|
||||
fn foo() {
|
||||
static $0HELLO: &str = "Hello";
|
||||
let entry = Entry(HELLO);
|
||||
}
|
||||
"#,
|
||||
"Extract into static",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extract_variable_string_literal_use_field_shorthand() {
|
||||
// When field shorthand is available, it should
|
||||
// only be used when extracting into a variable
|
||||
check_assist_by_label(
|
||||
extract_variable,
|
||||
r#"
|
||||
struct Entry { message: &str }
|
||||
fn foo() {
|
||||
let entry = Entry { message: $0"Hello"$0 };
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct Entry { message: &str }
|
||||
fn foo() {
|
||||
let $0message = "Hello";
|
||||
let entry = Entry { message };
|
||||
}
|
||||
"#,
|
||||
"Extract into variable",
|
||||
);
|
||||
|
||||
check_assist_by_label(
|
||||
extract_variable,
|
||||
r#"
|
||||
struct Entry { message: &str }
|
||||
fn foo() {
|
||||
let entry = Entry { message: $0"Hello"$0 };
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct Entry { message: &str }
|
||||
fn foo() {
|
||||
const $0HELLO: &str = "Hello";
|
||||
let entry = Entry { message: HELLO };
|
||||
}
|
||||
"#,
|
||||
"Extract into constant",
|
||||
);
|
||||
|
||||
check_assist_by_label(
|
||||
extract_variable,
|
||||
r#"
|
||||
struct Entry { message: &str }
|
||||
fn foo() {
|
||||
let entry = Entry { message: $0"Hello"$0 };
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct Entry { message: &str }
|
||||
fn foo() {
|
||||
static $0HELLO: &str = "Hello";
|
||||
let entry = Entry { message: HELLO };
|
||||
}
|
||||
"#,
|
||||
"Extract into static",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue