Skip to content

Commit 4cfe237

Browse files
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 <[email protected]> Co-authored-by: 龙方淞 <[email protected]>
2 parents 5ff9924 + 3fde682 commit 4cfe237

File tree

3 files changed

+143
-0
lines changed

3 files changed

+143
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
use crate::assist_context::{AssistContext, Assists};
2+
use hir::HirDisplay;
3+
use ide_db::{
4+
assists::{AssistId, AssistKind},
5+
defs::NameRefClass,
6+
};
7+
use syntax::{
8+
ast::{self, edit::IndentLevel},
9+
AstNode,
10+
};
11+
12+
// Assist: generate_constant
13+
//
14+
// Generate a named constant.
15+
//
16+
// ```
17+
// struct S { i: usize }
18+
// impl S { pub fn new(n: usize) {} }
19+
// fn main() {
20+
// let v = S::new(CAPA$0CITY);
21+
// }
22+
// ```
23+
// ->
24+
// ```
25+
// struct S { i: usize }
26+
// impl S { pub fn new(n: usize) {} }
27+
// fn main() {
28+
// const CAPACITY: usize = $0;
29+
// let v = S::new(CAPACITY);
30+
// }
31+
// ```
32+
33+
pub(crate) fn generate_constant(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
34+
let constant_token = ctx.find_node_at_offset::<ast::NameRef>()?;
35+
let expr = constant_token.syntax().ancestors().find_map(ast::Expr::cast)?;
36+
let statement = expr.syntax().ancestors().find_map(ast::Stmt::cast)?;
37+
let ty = ctx.sema.type_of_expr(&expr)?;
38+
let scope = ctx.sema.scope(statement.syntax());
39+
let module = scope.module()?;
40+
let type_name = ty.original().display_source_code(ctx.db(), module.into()).ok()?;
41+
let indent = IndentLevel::from_node(statement.syntax());
42+
if constant_token.to_string().chars().any(|it| !(it.is_uppercase() || it == '_')) {
43+
cov_mark::hit!(not_constant_name);
44+
return None;
45+
}
46+
if NameRefClass::classify(&ctx.sema, &constant_token).is_some() {
47+
cov_mark::hit!(already_defined);
48+
return None;
49+
}
50+
let target = statement.syntax().parent()?.text_range();
51+
acc.add(
52+
AssistId("generate_constant", AssistKind::QuickFix),
53+
"Generate constant",
54+
target,
55+
|builder| {
56+
builder.insert(
57+
statement.syntax().text_range().start(),
58+
format!("const {}: {} = $0;\n{}", constant_token, type_name, indent),
59+
);
60+
},
61+
)
62+
}
63+
64+
#[cfg(test)]
65+
mod tests {
66+
use super::*;
67+
use crate::tests::{check_assist, check_assist_not_applicable};
68+
69+
#[test]
70+
fn test_trivial() {
71+
check_assist(
72+
generate_constant,
73+
r#"struct S { i: usize }
74+
impl S {
75+
pub fn new(n: usize) {}
76+
}
77+
fn main() {
78+
let v = S::new(CAPA$0CITY);
79+
}"#,
80+
r#"struct S { i: usize }
81+
impl S {
82+
pub fn new(n: usize) {}
83+
}
84+
fn main() {
85+
const CAPACITY: usize = $0;
86+
let v = S::new(CAPACITY);
87+
}"#,
88+
);
89+
}
90+
#[test]
91+
fn test_wont_apply_when_defined() {
92+
cov_mark::check!(already_defined);
93+
check_assist_not_applicable(
94+
generate_constant,
95+
r#"struct S { i: usize }
96+
impl S {
97+
pub fn new(n: usize) {}
98+
}
99+
fn main() {
100+
const CAPACITY: usize = 10;
101+
let v = S::new(CAPAC$0ITY);
102+
}"#,
103+
);
104+
}
105+
#[test]
106+
fn test_wont_apply_when_maybe_not_constant() {
107+
cov_mark::check!(not_constant_name);
108+
check_assist_not_applicable(
109+
generate_constant,
110+
r#"struct S { i: usize }
111+
impl S {
112+
pub fn new(n: usize) {}
113+
}
114+
fn main() {
115+
let v = S::new(capa$0city);
116+
}"#,
117+
);
118+
}
119+
}

crates/ide_assists/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ mod handlers {
130130
mod flip_binexpr;
131131
mod flip_comma;
132132
mod flip_trait_bound;
133+
mod generate_constant;
133134
mod generate_default_from_enum_variant;
134135
mod generate_default_from_new;
135136
mod generate_deref;
@@ -205,6 +206,7 @@ mod handlers {
205206
flip_binexpr::flip_binexpr,
206207
flip_comma::flip_comma,
207208
flip_trait_bound::flip_trait_bound,
209+
generate_constant::generate_constant,
208210
generate_default_from_enum_variant::generate_default_from_enum_variant,
209211
generate_default_from_new::generate_default_from_new,
210212
generate_deref::generate_deref,

crates/ide_assists/src/tests/generated.rs

+22
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,28 @@ fn foo<T: Copy + Clone>() { }
648648
)
649649
}
650650

651+
#[test]
652+
fn doctest_generate_constant() {
653+
check_doc_test(
654+
"generate_constant",
655+
r#####"
656+
struct S { i: usize }
657+
impl S { pub fn new(n: usize) {} }
658+
fn main() {
659+
let v = S::new(CAPA$0CITY);
660+
}
661+
"#####,
662+
r#####"
663+
struct S { i: usize }
664+
impl S { pub fn new(n: usize) {} }
665+
fn main() {
666+
const CAPACITY: usize = $0;
667+
let v = S::new(CAPACITY);
668+
}
669+
"#####,
670+
)
671+
}
672+
651673
#[test]
652674
fn doctest_generate_default_from_enum_variant() {
653675
check_doc_test(

0 commit comments

Comments
 (0)