diff options
author | Zac Pullar-Strecker <[email protected]> | 2020-08-24 10:19:53 +0100 |
---|---|---|
committer | Zac Pullar-Strecker <[email protected]> | 2020-08-24 10:20:13 +0100 |
commit | 7bbca7a1b3f9293d2f5cc5745199bc5f8396f2f0 (patch) | |
tree | bdb47765991cb973b2cd5481a088fac636bd326c /crates/assists/src/handlers/remove_dbg.rs | |
parent | ca464650eeaca6195891199a93f4f76cf3e7e697 (diff) | |
parent | e65d48d1fb3d4d91d9dc1148a7a836ff5c9a3c87 (diff) |
Merge remote-tracking branch 'upstream/master' into 503-hover-doc-links
Diffstat (limited to 'crates/assists/src/handlers/remove_dbg.rs')
-rw-r--r-- | crates/assists/src/handlers/remove_dbg.rs | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/crates/assists/src/handlers/remove_dbg.rs b/crates/assists/src/handlers/remove_dbg.rs new file mode 100644 index 000000000..4e252edf0 --- /dev/null +++ b/crates/assists/src/handlers/remove_dbg.rs | |||
@@ -0,0 +1,206 @@ | |||
1 | use syntax::{ | ||
2 | ast::{self, AstNode}, | ||
3 | TextRange, TextSize, T, | ||
4 | }; | ||
5 | |||
6 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | ||
7 | |||
8 | // Assist: remove_dbg | ||
9 | // | ||
10 | // Removes `dbg!()` macro call. | ||
11 | // | ||
12 | // ``` | ||
13 | // fn main() { | ||
14 | // <|>dbg!(92); | ||
15 | // } | ||
16 | // ``` | ||
17 | // -> | ||
18 | // ``` | ||
19 | // fn main() { | ||
20 | // 92; | ||
21 | // } | ||
22 | // ``` | ||
23 | pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
24 | let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?; | ||
25 | |||
26 | if !is_valid_macrocall(¯o_call, "dbg")? { | ||
27 | return None; | ||
28 | } | ||
29 | |||
30 | let is_leaf = macro_call.syntax().next_sibling().is_none(); | ||
31 | |||
32 | let macro_end = if macro_call.semicolon_token().is_some() { | ||
33 | macro_call.syntax().text_range().end() - TextSize::of(';') | ||
34 | } else { | ||
35 | macro_call.syntax().text_range().end() | ||
36 | }; | ||
37 | |||
38 | // macro_range determines what will be deleted and replaced with macro_content | ||
39 | let macro_range = TextRange::new(macro_call.syntax().text_range().start(), macro_end); | ||
40 | let paste_instead_of_dbg = { | ||
41 | let text = macro_call.token_tree()?.syntax().text(); | ||
42 | |||
43 | // leafiness determines if we should include the parenthesis or not | ||
44 | let slice_index: TextRange = if is_leaf { | ||
45 | // leaf means - we can extract the contents of the dbg! in text | ||
46 | TextRange::new(TextSize::of('('), text.len() - TextSize::of(')')) | ||
47 | } else { | ||
48 | // not leaf - means we should keep the parens | ||
49 | TextRange::up_to(text.len()) | ||
50 | }; | ||
51 | text.slice(slice_index).to_string() | ||
52 | }; | ||
53 | |||
54 | let target = macro_call.syntax().text_range(); | ||
55 | acc.add(AssistId("remove_dbg", AssistKind::Refactor), "Remove dbg!()", target, |builder| { | ||
56 | builder.replace(macro_range, paste_instead_of_dbg); | ||
57 | }) | ||
58 | } | ||
59 | |||
60 | /// Verifies that the given macro_call actually matches the given name | ||
61 | /// and contains proper ending tokens | ||
62 | fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<bool> { | ||
63 | let path = macro_call.path()?; | ||
64 | let name_ref = path.segment()?.name_ref()?; | ||
65 | |||
66 | // Make sure it is actually a dbg-macro call, dbg followed by ! | ||
67 | let excl = path.syntax().next_sibling_or_token()?; | ||
68 | |||
69 | if name_ref.text() != macro_name || excl.kind() != T![!] { | ||
70 | return None; | ||
71 | } | ||
72 | |||
73 | let node = macro_call.token_tree()?.syntax().clone(); | ||
74 | let first_child = node.first_child_or_token()?; | ||
75 | let last_child = node.last_child_or_token()?; | ||
76 | |||
77 | match (first_child.kind(), last_child.kind()) { | ||
78 | (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => Some(true), | ||
79 | _ => Some(false), | ||
80 | } | ||
81 | } | ||
82 | |||
83 | #[cfg(test)] | ||
84 | mod tests { | ||
85 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; | ||
86 | |||
87 | use super::*; | ||
88 | |||
89 | #[test] | ||
90 | fn test_remove_dbg() { | ||
91 | check_assist(remove_dbg, "<|>dbg!(1 + 1)", "1 + 1"); | ||
92 | |||
93 | check_assist(remove_dbg, "dbg!<|>((1 + 1))", "(1 + 1)"); | ||
94 | |||
95 | check_assist(remove_dbg, "dbg!(1 <|>+ 1)", "1 + 1"); | ||
96 | |||
97 | check_assist(remove_dbg, "let _ = <|>dbg!(1 + 1)", "let _ = 1 + 1"); | ||
98 | |||
99 | check_assist( | ||
100 | remove_dbg, | ||
101 | " | ||
102 | fn foo(n: usize) { | ||
103 | if let Some(_) = dbg!(n.<|>checked_sub(4)) { | ||
104 | // ... | ||
105 | } | ||
106 | } | ||
107 | ", | ||
108 | " | ||
109 | fn foo(n: usize) { | ||
110 | if let Some(_) = n.checked_sub(4) { | ||
111 | // ... | ||
112 | } | ||
113 | } | ||
114 | ", | ||
115 | ); | ||
116 | } | ||
117 | |||
118 | #[test] | ||
119 | fn test_remove_dbg_with_brackets_and_braces() { | ||
120 | check_assist(remove_dbg, "dbg![<|>1 + 1]", "1 + 1"); | ||
121 | check_assist(remove_dbg, "dbg!{<|>1 + 1}", "1 + 1"); | ||
122 | } | ||
123 | |||
124 | #[test] | ||
125 | fn test_remove_dbg_not_applicable() { | ||
126 | check_assist_not_applicable(remove_dbg, "<|>vec![1, 2, 3]"); | ||
127 | check_assist_not_applicable(remove_dbg, "<|>dbg(5, 6, 7)"); | ||
128 | check_assist_not_applicable(remove_dbg, "<|>dbg!(5, 6, 7"); | ||
129 | } | ||
130 | |||
131 | #[test] | ||
132 | fn test_remove_dbg_target() { | ||
133 | check_assist_target( | ||
134 | remove_dbg, | ||
135 | " | ||
136 | fn foo(n: usize) { | ||
137 | if let Some(_) = dbg!(n.<|>checked_sub(4)) { | ||
138 | // ... | ||
139 | } | ||
140 | } | ||
141 | ", | ||
142 | "dbg!(n.checked_sub(4))", | ||
143 | ); | ||
144 | } | ||
145 | |||
146 | #[test] | ||
147 | fn test_remove_dbg_keep_semicolon() { | ||
148 | // https://github.com/rust-analyzer/rust-analyzer/issues/5129#issuecomment-651399779 | ||
149 | // not quite though | ||
150 | // adding a comment at the end of the line makes | ||
151 | // the ast::MacroCall to include the semicolon at the end | ||
152 | check_assist( | ||
153 | remove_dbg, | ||
154 | r#"let res = <|>dbg!(1 * 20); // needless comment"#, | ||
155 | r#"let res = 1 * 20; // needless comment"#, | ||
156 | ); | ||
157 | } | ||
158 | |||
159 | #[test] | ||
160 | fn test_remove_dbg_keep_expression() { | ||
161 | check_assist( | ||
162 | remove_dbg, | ||
163 | r#"let res = <|>dbg!(a + b).foo();"#, | ||
164 | r#"let res = (a + b).foo();"#, | ||
165 | ); | ||
166 | } | ||
167 | |||
168 | #[test] | ||
169 | fn test_remove_dbg_from_inside_fn() { | ||
170 | check_assist_target( | ||
171 | remove_dbg, | ||
172 | r#" | ||
173 | fn square(x: u32) -> u32 { | ||
174 | x * x | ||
175 | } | ||
176 | |||
177 | fn main() { | ||
178 | let x = square(dbg<|>!(5 + 10)); | ||
179 | println!("{}", x); | ||
180 | }"#, | ||
181 | "dbg!(5 + 10)", | ||
182 | ); | ||
183 | |||
184 | check_assist( | ||
185 | remove_dbg, | ||
186 | r#" | ||
187 | fn square(x: u32) -> u32 { | ||
188 | x * x | ||
189 | } | ||
190 | |||
191 | fn main() { | ||
192 | let x = square(dbg<|>!(5 + 10)); | ||
193 | println!("{}", x); | ||
194 | }"#, | ||
195 | r#" | ||
196 | fn square(x: u32) -> u32 { | ||
197 | x * x | ||
198 | } | ||
199 | |||
200 | fn main() { | ||
201 | let x = square(5 + 10); | ||
202 | println!("{}", x); | ||
203 | }"#, | ||
204 | ); | ||
205 | } | ||
206 | } | ||