mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-03 18:43:38 +00:00
Merge #10459
10459: feat: Add generate constant assist r=Veykril a=longfangsong Close #10330. ![demo(1)](https://user-images.githubusercontent.com/13777628/135885262-c80de86f-5555-4f84-9508-822243f8a876.gif) Co-authored-by: longfangsong <longfangsong@icloud.com> Co-authored-by: 龙方淞 <longfangsong@icloud.com>
This commit is contained in:
commit
4cfe237a56
119
crates/ide_assists/src/handlers/generate_constant.rs
Normal file
119
crates/ide_assists/src/handlers/generate_constant.rs
Normal file
@ -0,0 +1,119 @@
|
||||
use crate::assist_context::{AssistContext, Assists};
|
||||
use hir::HirDisplay;
|
||||
use ide_db::{
|
||||
assists::{AssistId, AssistKind},
|
||||
defs::NameRefClass,
|
||||
};
|
||||
use syntax::{
|
||||
ast::{self, edit::IndentLevel},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
// Assist: generate_constant
|
||||
//
|
||||
// Generate a named constant.
|
||||
//
|
||||
// ```
|
||||
// struct S { i: usize }
|
||||
// impl S { pub fn new(n: usize) {} }
|
||||
// fn main() {
|
||||
// let v = S::new(CAPA$0CITY);
|
||||
// }
|
||||
// ```
|
||||
// ->
|
||||
// ```
|
||||
// struct S { i: usize }
|
||||
// impl S { pub fn new(n: usize) {} }
|
||||
// fn main() {
|
||||
// const CAPACITY: usize = $0;
|
||||
// let v = S::new(CAPACITY);
|
||||
// }
|
||||
// ```
|
||||
|
||||
pub(crate) fn generate_constant(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||
let constant_token = ctx.find_node_at_offset::<ast::NameRef>()?;
|
||||
let expr = constant_token.syntax().ancestors().find_map(ast::Expr::cast)?;
|
||||
let statement = expr.syntax().ancestors().find_map(ast::Stmt::cast)?;
|
||||
let ty = ctx.sema.type_of_expr(&expr)?;
|
||||
let scope = ctx.sema.scope(statement.syntax());
|
||||
let module = scope.module()?;
|
||||
let type_name = ty.original().display_source_code(ctx.db(), module.into()).ok()?;
|
||||
let indent = IndentLevel::from_node(statement.syntax());
|
||||
if constant_token.to_string().chars().any(|it| !(it.is_uppercase() || it == '_')) {
|
||||
cov_mark::hit!(not_constant_name);
|
||||
return None;
|
||||
}
|
||||
if NameRefClass::classify(&ctx.sema, &constant_token).is_some() {
|
||||
cov_mark::hit!(already_defined);
|
||||
return None;
|
||||
}
|
||||
let target = statement.syntax().parent()?.text_range();
|
||||
acc.add(
|
||||
AssistId("generate_constant", AssistKind::QuickFix),
|
||||
"Generate constant",
|
||||
target,
|
||||
|builder| {
|
||||
builder.insert(
|
||||
statement.syntax().text_range().start(),
|
||||
format!("const {}: {} = $0;\n{}", constant_token, type_name, indent),
|
||||
);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::tests::{check_assist, check_assist_not_applicable};
|
||||
|
||||
#[test]
|
||||
fn test_trivial() {
|
||||
check_assist(
|
||||
generate_constant,
|
||||
r#"struct S { i: usize }
|
||||
impl S {
|
||||
pub fn new(n: usize) {}
|
||||
}
|
||||
fn main() {
|
||||
let v = S::new(CAPA$0CITY);
|
||||
}"#,
|
||||
r#"struct S { i: usize }
|
||||
impl S {
|
||||
pub fn new(n: usize) {}
|
||||
}
|
||||
fn main() {
|
||||
const CAPACITY: usize = $0;
|
||||
let v = S::new(CAPACITY);
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_wont_apply_when_defined() {
|
||||
cov_mark::check!(already_defined);
|
||||
check_assist_not_applicable(
|
||||
generate_constant,
|
||||
r#"struct S { i: usize }
|
||||
impl S {
|
||||
pub fn new(n: usize) {}
|
||||
}
|
||||
fn main() {
|
||||
const CAPACITY: usize = 10;
|
||||
let v = S::new(CAPAC$0ITY);
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_wont_apply_when_maybe_not_constant() {
|
||||
cov_mark::check!(not_constant_name);
|
||||
check_assist_not_applicable(
|
||||
generate_constant,
|
||||
r#"struct S { i: usize }
|
||||
impl S {
|
||||
pub fn new(n: usize) {}
|
||||
}
|
||||
fn main() {
|
||||
let v = S::new(capa$0city);
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
}
|
@ -130,6 +130,7 @@ mod handlers {
|
||||
mod flip_binexpr;
|
||||
mod flip_comma;
|
||||
mod flip_trait_bound;
|
||||
mod generate_constant;
|
||||
mod generate_default_from_enum_variant;
|
||||
mod generate_default_from_new;
|
||||
mod generate_deref;
|
||||
@ -205,6 +206,7 @@ mod handlers {
|
||||
flip_binexpr::flip_binexpr,
|
||||
flip_comma::flip_comma,
|
||||
flip_trait_bound::flip_trait_bound,
|
||||
generate_constant::generate_constant,
|
||||
generate_default_from_enum_variant::generate_default_from_enum_variant,
|
||||
generate_default_from_new::generate_default_from_new,
|
||||
generate_deref::generate_deref,
|
||||
|
@ -648,6 +648,28 @@ fn foo<T: Copy + Clone>() { }
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_generate_constant() {
|
||||
check_doc_test(
|
||||
"generate_constant",
|
||||
r#####"
|
||||
struct S { i: usize }
|
||||
impl S { pub fn new(n: usize) {} }
|
||||
fn main() {
|
||||
let v = S::new(CAPA$0CITY);
|
||||
}
|
||||
"#####,
|
||||
r#####"
|
||||
struct S { i: usize }
|
||||
impl S { pub fn new(n: usize) {} }
|
||||
fn main() {
|
||||
const CAPACITY: usize = $0;
|
||||
let v = S::new(CAPACITY);
|
||||
}
|
||||
"#####,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_generate_default_from_enum_variant() {
|
||||
check_doc_test(
|
||||
|
Loading…
Reference in New Issue
Block a user