mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-26 14:43:24 +00:00
Add generate_constant assist
This commit is contained in:
parent
0618a6f184
commit
4d1a4dc0d6
130
crates/ide_assists/src/handlers/generate_constant.rs
Normal file
130
crates/ide_assists/src/handlers/generate_constant.rs
Normal file
@ -0,0 +1,130 @@
|
||||
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 statement = ctx.find_node_at_offset::<ast::Stmt>()?;
|
||||
let arg_list = ctx.find_node_at_offset::<ast::ArgList>()?;
|
||||
let expr = ctx.find_node_at_offset::<ast::Expr>()?;
|
||||
let constant_token = ctx.find_node_at_offset::<ast::NameRef>()?;
|
||||
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 !arg_list.syntax().text_range().contains_range(constant_token.syntax().text_range()) {
|
||||
return None;
|
||||
}
|
||||
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();
|
||||
let statement_syntax = statement.syntax().clone_for_update();
|
||||
acc.add(
|
||||
AssistId("generate_constant", AssistKind::QuickFix),
|
||||
"Generate constant",
|
||||
target,
|
||||
|builder| {
|
||||
builder.replace(
|
||||
statement.syntax().text_range(),
|
||||
format!(
|
||||
"const {}: {} = $0;\n{}{}",
|
||||
constant_token,
|
||||
type_name,
|
||||
indent,
|
||||
statement_syntax.text()
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[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