aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_editor/src/lib.rs')
-rw-r--r--crates/ra_editor/src/lib.rs90
1 files changed, 71 insertions, 19 deletions
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs
index 619497f0b..d9b89155b 100644
--- a/crates/ra_editor/src/lib.rs
+++ b/crates/ra_editor/src/lib.rs
@@ -26,6 +26,7 @@ use ra_syntax::{
26 SyntaxKind::{self, *}, 26 SyntaxKind::{self, *},
27 SyntaxNodeRef, TextRange, TextUnit, 27 SyntaxNodeRef, TextRange, TextUnit,
28}; 28};
29use itertools::Itertools;
29 30
30#[derive(Debug)] 31#[derive(Debug)]
31pub struct HighlightedRange { 32pub struct HighlightedRange {
@@ -44,6 +45,7 @@ pub struct Diagnostic {
44 pub range: TextRange, 45 pub range: TextRange,
45 pub msg: String, 46 pub msg: String,
46 pub severity: Severity, 47 pub severity: Severity,
48 pub fix: Option<LocalEdit>,
47} 49}
48 50
49#[derive(Debug)] 51#[derive(Debug)]
@@ -113,6 +115,7 @@ pub fn diagnostics(file: &SourceFileNode) -> Vec<Diagnostic> {
113 range: location_to_range(err.location()), 115 range: location_to_range(err.location()),
114 msg: format!("Syntax Error: {}", err), 116 msg: format!("Syntax Error: {}", err),
115 severity: Severity::Error, 117 severity: Severity::Error,
118 fix: None,
116 }) 119 })
117 .collect(); 120 .collect();
118 121
@@ -126,11 +129,28 @@ fn check_unnecessary_braces_in_use_statement(file: &SourceFileNode) -> Vec<Diagn
126 let mut diagnostics = Vec::new(); 129 let mut diagnostics = Vec::new();
127 for node in file.syntax().descendants() { 130 for node in file.syntax().descendants() {
128 if let Some(use_tree_list) = ast::UseTreeList::cast(node) { 131 if let Some(use_tree_list) = ast::UseTreeList::cast(node) {
129 if use_tree_list.use_trees().count() <= 1 { 132 if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() {
133 let range = use_tree_list.syntax().range();
134 let edit = text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
135 single_use_tree,
136 )
137 .unwrap_or_else(|| {
138 let to_replace = single_use_tree.syntax().text().to_string();
139 let mut edit_builder = TextEditBuilder::new();
140 edit_builder.delete(range);
141 edit_builder.insert(range.start(), to_replace);
142 edit_builder.finish()
143 });
144
130 diagnostics.push(Diagnostic { 145 diagnostics.push(Diagnostic {
131 range: use_tree_list.syntax().range(), 146 range: range,
132 msg: format!("Unnecessary braces in use statement"), 147 msg: format!("Unnecessary braces in use statement"),
133 severity: Severity::WeakWarning, 148 severity: Severity::WeakWarning,
149 fix: Some(LocalEdit {
150 label: "Remove unnecessary braces".to_string(),
151 edit: edit,
152 cursor_position: None,
153 }),
134 }) 154 })
135 } 155 }
136 } 156 }
@@ -139,6 +159,28 @@ fn check_unnecessary_braces_in_use_statement(file: &SourceFileNode) -> Vec<Diagn
139 diagnostics 159 diagnostics
140} 160}
141 161
162fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
163 single_use_tree: ast::UseTree,
164) -> Option<TextEdit> {
165 let use_tree_list_node = single_use_tree.syntax().parent()?;
166 if single_use_tree
167 .path()?
168 .segment()?
169 .syntax()
170 .first_child()?
171 .kind()
172 == SyntaxKind::SELF_KW
173 {
174 let start = use_tree_list_node.prev_sibling()?.range().start();
175 let end = use_tree_list_node.range().end();
176 let range = TextRange::from_to(start, end);
177 let mut edit_builder = TextEditBuilder::new();
178 edit_builder.delete(range);
179 return Some(edit_builder.finish());
180 }
181 None
182}
183
142pub fn syntax_tree(file: &SourceFileNode) -> String { 184pub fn syntax_tree(file: &SourceFileNode) -> String {
143 ::ra_syntax::utils::dump_tree(file.syntax()) 185 ::ra_syntax::utils::dump_tree(file.syntax())
144} 186}
@@ -175,8 +217,9 @@ pub fn find_node_at_offset<'a, N: AstNode<'a>>(
175 217
176#[cfg(test)] 218#[cfg(test)]
177mod tests { 219mod tests {
220 use crate::test_utils::{add_cursor, assert_eq_dbg, assert_eq_text, extract_offset};
221
178 use super::*; 222 use super::*;
179 use crate::test_utils::{add_cursor, assert_eq_dbg, extract_offset, assert_eq_text};
180 223
181 #[test] 224 #[test]
182 fn test_highlighting() { 225 fn test_highlighting() {
@@ -240,22 +283,31 @@ fn test_foo() {}
240 283
241 #[test] 284 #[test]
242 fn test_check_unnecessary_braces_in_use_statement() { 285 fn test_check_unnecessary_braces_in_use_statement() {
243 let file = SourceFileNode::parse( 286 fn check_not_applicable(code: &str) {
244 r#" 287 let file = SourceFileNode::parse(code);
245use a; 288 let diagnostics = check_unnecessary_braces_in_use_statement(&file);
246use {b}; 289 assert!(diagnostics.is_empty());
247use a::{c}; 290 }
248use a::{c, d::e}; 291
249use a::{c, d::{e}}; 292 fn check_apply(before: &str, after: &str) {
250fn main() {} 293 let file = SourceFileNode::parse(before);
251"#, 294 let diagnostic = check_unnecessary_braces_in_use_statement(&file)
295 .pop()
296 .unwrap_or_else(|| panic!("no diagnostics for:\n{}\n", before));
297 let fix = diagnostic.fix.unwrap();
298 let actual = fix.edit.apply(&before);
299 assert_eq_text!(after, &actual);
300 }
301
302 check_not_applicable(
303 "
304 use a;
305 use a::{c, d::e};
306 ",
252 ); 307 );
253 let diagnostics = check_unnecessary_braces_in_use_statement(&file); 308 check_apply("use {b};", "use b;");
254 assert_eq_dbg( 309 check_apply("use a::{c};", "use a::c;");
255 r#"[Diagnostic { range: [12; 15), msg: "Unnecessary braces in use statement", severity: WeakWarning }, 310 check_apply("use a::{self};", "use a;");
256 Diagnostic { range: [24; 27), msg: "Unnecessary braces in use statement", severity: WeakWarning }, 311 check_apply("use a::{c, d::{e}};", "use a::{c, d::e};");
257 Diagnostic { range: [61; 64), msg: "Unnecessary braces in use statement", severity: WeakWarning }]"#,
258 &diagnostics,
259 )
260 } 312 }
261} 313}