aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src/handlers/convert_integer_literal.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists/src/handlers/convert_integer_literal.rs')
-rw-r--r--crates/ide_assists/src/handlers/convert_integer_literal.rs268
1 files changed, 268 insertions, 0 deletions
diff --git a/crates/ide_assists/src/handlers/convert_integer_literal.rs b/crates/ide_assists/src/handlers/convert_integer_literal.rs
new file mode 100644
index 000000000..a8a819cfc
--- /dev/null
+++ b/crates/ide_assists/src/handlers/convert_integer_literal.rs
@@ -0,0 +1,268 @@
1use syntax::{ast, ast::Radix, AstToken};
2
3use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
4
5// Assist: convert_integer_literal
6//
7// Converts the base of integer literals to other bases.
8//
9// ```
10// const _: i32 = 10$0;
11// ```
12// ->
13// ```
14// const _: i32 = 0b1010;
15// ```
16pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
17 let literal = ctx.find_node_at_offset::<ast::Literal>()?;
18 let literal = match literal.kind() {
19 ast::LiteralKind::IntNumber(it) => it,
20 _ => return None,
21 };
22 let radix = literal.radix();
23 let value = literal.value()?;
24 let suffix = literal.suffix();
25
26 let range = literal.syntax().text_range();
27 let group_id = GroupLabel("Convert integer base".into());
28
29 for &target_radix in Radix::ALL {
30 if target_radix == radix {
31 continue;
32 }
33
34 let mut converted = match target_radix {
35 Radix::Binary => format!("0b{:b}", value),
36 Radix::Octal => format!("0o{:o}", value),
37 Radix::Decimal => value.to_string(),
38 Radix::Hexadecimal => format!("0x{:X}", value),
39 };
40
41 let label = format!("Convert {} to {}{}", literal, converted, suffix.unwrap_or_default());
42
43 // Appends the type suffix back into the new literal if it exists.
44 if let Some(suffix) = suffix {
45 converted.push_str(suffix);
46 }
47
48 acc.add_group(
49 &group_id,
50 AssistId("convert_integer_literal", AssistKind::RefactorInline),
51 label,
52 range,
53 |builder| builder.replace(range, converted),
54 );
55 }
56
57 Some(())
58}
59
60#[cfg(test)]
61mod tests {
62 use crate::tests::{check_assist_by_label, check_assist_not_applicable, check_assist_target};
63
64 use super::*;
65
66 #[test]
67 fn binary_target() {
68 check_assist_target(convert_integer_literal, "const _: i32 = 0b1010$0;", "0b1010");
69 }
70
71 #[test]
72 fn octal_target() {
73 check_assist_target(convert_integer_literal, "const _: i32 = 0o12$0;", "0o12");
74 }
75
76 #[test]
77 fn decimal_target() {
78 check_assist_target(convert_integer_literal, "const _: i32 = 10$0;", "10");
79 }
80
81 #[test]
82 fn hexadecimal_target() {
83 check_assist_target(convert_integer_literal, "const _: i32 = 0xA$0;", "0xA");
84 }
85
86 #[test]
87 fn binary_target_with_underscores() {
88 check_assist_target(convert_integer_literal, "const _: i32 = 0b10_10$0;", "0b10_10");
89 }
90
91 #[test]
92 fn octal_target_with_underscores() {
93 check_assist_target(convert_integer_literal, "const _: i32 = 0o1_2$0;", "0o1_2");
94 }
95
96 #[test]
97 fn decimal_target_with_underscores() {
98 check_assist_target(convert_integer_literal, "const _: i32 = 1_0$0;", "1_0");
99 }
100
101 #[test]
102 fn hexadecimal_target_with_underscores() {
103 check_assist_target(convert_integer_literal, "const _: i32 = 0x_A$0;", "0x_A");
104 }
105
106 #[test]
107 fn convert_decimal_integer() {
108 let before = "const _: i32 = 1000$0;";
109
110 check_assist_by_label(
111 convert_integer_literal,
112 before,
113 "const _: i32 = 0b1111101000;",
114 "Convert 1000 to 0b1111101000",
115 );
116
117 check_assist_by_label(
118 convert_integer_literal,
119 before,
120 "const _: i32 = 0o1750;",
121 "Convert 1000 to 0o1750",
122 );
123
124 check_assist_by_label(
125 convert_integer_literal,
126 before,
127 "const _: i32 = 0x3E8;",
128 "Convert 1000 to 0x3E8",
129 );
130 }
131
132 #[test]
133 fn convert_hexadecimal_integer() {
134 let before = "const _: i32 = 0xFF$0;";
135
136 check_assist_by_label(
137 convert_integer_literal,
138 before,
139 "const _: i32 = 0b11111111;",
140 "Convert 0xFF to 0b11111111",
141 );
142
143 check_assist_by_label(
144 convert_integer_literal,
145 before,
146 "const _: i32 = 0o377;",
147 "Convert 0xFF to 0o377",
148 );
149
150 check_assist_by_label(
151 convert_integer_literal,
152 before,
153 "const _: i32 = 255;",
154 "Convert 0xFF to 255",
155 );
156 }
157
158 #[test]
159 fn convert_binary_integer() {
160 let before = "const _: i32 = 0b11111111$0;";
161
162 check_assist_by_label(
163 convert_integer_literal,
164 before,
165 "const _: i32 = 0o377;",
166 "Convert 0b11111111 to 0o377",
167 );
168
169 check_assist_by_label(
170 convert_integer_literal,
171 before,
172 "const _: i32 = 255;",
173 "Convert 0b11111111 to 255",
174 );
175
176 check_assist_by_label(
177 convert_integer_literal,
178 before,
179 "const _: i32 = 0xFF;",
180 "Convert 0b11111111 to 0xFF",
181 );
182 }
183
184 #[test]
185 fn convert_octal_integer() {
186 let before = "const _: i32 = 0o377$0;";
187
188 check_assist_by_label(
189 convert_integer_literal,
190 before,
191 "const _: i32 = 0b11111111;",
192 "Convert 0o377 to 0b11111111",
193 );
194
195 check_assist_by_label(
196 convert_integer_literal,
197 before,
198 "const _: i32 = 255;",
199 "Convert 0o377 to 255",
200 );
201
202 check_assist_by_label(
203 convert_integer_literal,
204 before,
205 "const _: i32 = 0xFF;",
206 "Convert 0o377 to 0xFF",
207 );
208 }
209
210 #[test]
211 fn convert_integer_with_underscores() {
212 let before = "const _: i32 = 1_00_0$0;";
213
214 check_assist_by_label(
215 convert_integer_literal,
216 before,
217 "const _: i32 = 0b1111101000;",
218 "Convert 1_00_0 to 0b1111101000",
219 );
220
221 check_assist_by_label(
222 convert_integer_literal,
223 before,
224 "const _: i32 = 0o1750;",
225 "Convert 1_00_0 to 0o1750",
226 );
227
228 check_assist_by_label(
229 convert_integer_literal,
230 before,
231 "const _: i32 = 0x3E8;",
232 "Convert 1_00_0 to 0x3E8",
233 );
234 }
235
236 #[test]
237 fn convert_integer_with_suffix() {
238 let before = "const _: i32 = 1000i32$0;";
239
240 check_assist_by_label(
241 convert_integer_literal,
242 before,
243 "const _: i32 = 0b1111101000i32;",
244 "Convert 1000i32 to 0b1111101000i32",
245 );
246
247 check_assist_by_label(
248 convert_integer_literal,
249 before,
250 "const _: i32 = 0o1750i32;",
251 "Convert 1000i32 to 0o1750i32",
252 );
253
254 check_assist_by_label(
255 convert_integer_literal,
256 before,
257 "const _: i32 = 0x3E8i32;",
258 "Convert 1000i32 to 0x3E8i32",
259 );
260 }
261
262 #[test]
263 fn convert_overflowing_literal() {
264 let before = "const _: i32 =
265 111111111111111111111111111111111111111111111111111111111111111111111111$0;";
266 check_assist_not_applicable(convert_integer_literal, before);
267 }
268}