diff options
Diffstat (limited to 'crates/ra_editor/src')
-rw-r--r-- | crates/ra_editor/src/diagnostics.rs | 134 |
1 files changed, 72 insertions, 62 deletions
diff --git a/crates/ra_editor/src/diagnostics.rs b/crates/ra_editor/src/diagnostics.rs index d1667fd7c..1b336cfe2 100644 --- a/crates/ra_editor/src/diagnostics.rs +++ b/crates/ra_editor/src/diagnostics.rs | |||
@@ -7,6 +7,7 @@ use ra_syntax::{ | |||
7 | SyntaxKind, | 7 | SyntaxKind, |
8 | TextRange, | 8 | TextRange, |
9 | }; | 9 | }; |
10 | use ra_syntax::SyntaxNodeRef; | ||
10 | use ra_text_edit::{ | 11 | use ra_text_edit::{ |
11 | TextEdit, | 12 | TextEdit, |
12 | TextEditBuilder, | 13 | TextEditBuilder, |
@@ -37,44 +38,44 @@ pub fn diagnostics(file: &SourceFileNode) -> Vec<Diagnostic> { | |||
37 | }) | 38 | }) |
38 | .collect(); | 39 | .collect(); |
39 | 40 | ||
40 | errors.extend(check_unnecessary_braces_in_use_statement(file)); | 41 | for node in file.syntax().descendants() { |
41 | errors.extend(check_struct_shorthand_initialization(file)); | 42 | check_unnecessary_braces_in_use_statement(&mut errors, node); |
43 | check_struct_shorthand_initialization(&mut errors, node); | ||
44 | } | ||
45 | |||
42 | errors | 46 | errors |
43 | } | 47 | } |
44 | 48 | ||
45 | fn check_unnecessary_braces_in_use_statement(file: &SourceFileNode) -> Vec<Diagnostic> { | 49 | fn check_unnecessary_braces_in_use_statement( |
46 | let mut diagnostics = Vec::new(); | 50 | acc: &mut Vec<Diagnostic>, |
47 | for use_tree_list in file | 51 | node: SyntaxNodeRef, |
48 | .syntax() | 52 | ) -> Option<()> { |
49 | .descendants() | 53 | let use_tree_list = ast::UseTreeList::cast(node)?; |
50 | .filter_map(ast::UseTreeList::cast) | 54 | if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() { |
51 | { | 55 | let range = use_tree_list.syntax().range(); |
52 | if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() { | 56 | let edit = |
53 | let range = use_tree_list.syntax().range(); | 57 | text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(single_use_tree) |
54 | let edit = | 58 | .unwrap_or_else(|| { |
55 | text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(single_use_tree) | 59 | let to_replace = single_use_tree.syntax().text().to_string(); |
56 | .unwrap_or_else(|| { | 60 | let mut edit_builder = TextEditBuilder::new(); |
57 | let to_replace = single_use_tree.syntax().text().to_string(); | 61 | edit_builder.delete(range); |
58 | let mut edit_builder = TextEditBuilder::new(); | 62 | edit_builder.insert(range.start(), to_replace); |
59 | edit_builder.delete(range); | 63 | edit_builder.finish() |
60 | edit_builder.insert(range.start(), to_replace); | 64 | }); |
61 | edit_builder.finish() | ||
62 | }); | ||
63 | 65 | ||
64 | diagnostics.push(Diagnostic { | 66 | acc.push(Diagnostic { |
65 | range, | 67 | range, |
66 | msg: format!("Unnecessary braces in use statement"), | 68 | msg: format!("Unnecessary braces in use statement"), |
67 | severity: Severity::WeakWarning, | 69 | severity: Severity::WeakWarning, |
68 | fix: Some(LocalEdit { | 70 | fix: Some(LocalEdit { |
69 | label: "Remove unnecessary braces".to_string(), | 71 | label: "Remove unnecessary braces".to_string(), |
70 | edit, | 72 | edit, |
71 | cursor_position: None, | 73 | cursor_position: None, |
72 | }), | 74 | }), |
73 | }) | 75 | }); |
74 | } | ||
75 | } | 76 | } |
76 | 77 | ||
77 | diagnostics | 78 | Some(()) |
78 | } | 79 | } |
79 | 80 | ||
80 | fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement( | 81 | fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement( |
@@ -99,36 +100,36 @@ fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement( | |||
99 | None | 100 | None |
100 | } | 101 | } |
101 | 102 | ||
102 | fn check_struct_shorthand_initialization(file: &SourceFileNode) -> Vec<Diagnostic> { | 103 | fn check_struct_shorthand_initialization( |
103 | let mut diagnostics = Vec::new(); | 104 | acc: &mut Vec<Diagnostic>, |
104 | for struct_lit in file.syntax().descendants().filter_map(ast::StructLit::cast) { | 105 | node: SyntaxNodeRef, |
105 | if let Some(named_field_list) = struct_lit.named_field_list() { | 106 | ) -> Option<()> { |
106 | for named_field in named_field_list.fields() { | 107 | let struct_lit = ast::StructLit::cast(node)?; |
107 | if let (Some(name_ref), Some(expr)) = (named_field.name_ref(), named_field.expr()) { | 108 | let named_field_list = struct_lit.named_field_list()?; |
108 | let field_name = name_ref.syntax().text().to_string(); | 109 | for named_field in named_field_list.fields() { |
109 | let field_expr = expr.syntax().text().to_string(); | 110 | if let (Some(name_ref), Some(expr)) = (named_field.name_ref(), named_field.expr()) { |
110 | if field_name == field_expr { | 111 | let field_name = name_ref.syntax().text().to_string(); |
111 | let mut edit_builder = TextEditBuilder::new(); | 112 | let field_expr = expr.syntax().text().to_string(); |
112 | edit_builder.delete(named_field.syntax().range()); | 113 | if field_name == field_expr { |
113 | edit_builder.insert(named_field.syntax().range().start(), field_name); | 114 | let mut edit_builder = TextEditBuilder::new(); |
114 | let edit = edit_builder.finish(); | 115 | edit_builder.delete(named_field.syntax().range()); |
116 | edit_builder.insert(named_field.syntax().range().start(), field_name); | ||
117 | let edit = edit_builder.finish(); | ||
115 | 118 | ||
116 | diagnostics.push(Diagnostic { | 119 | acc.push(Diagnostic { |
117 | range: named_field.syntax().range(), | 120 | range: named_field.syntax().range(), |
118 | msg: format!("Shorthand struct initialization"), | 121 | msg: format!("Shorthand struct initialization"), |
119 | severity: Severity::WeakWarning, | 122 | severity: Severity::WeakWarning, |
120 | fix: Some(LocalEdit { | 123 | fix: Some(LocalEdit { |
121 | label: "use struct shorthand initialization".to_string(), | 124 | label: "use struct shorthand initialization".to_string(), |
122 | edit, | 125 | edit, |
123 | cursor_position: None, | 126 | cursor_position: None, |
124 | }), | 127 | }), |
125 | }); | 128 | }); |
126 | } | ||
127 | } | ||
128 | } | 129 | } |
129 | } | 130 | } |
130 | } | 131 | } |
131 | diagnostics | 132 | Some(()) |
132 | } | 133 | } |
133 | 134 | ||
134 | #[cfg(test)] | 135 | #[cfg(test)] |
@@ -137,15 +138,24 @@ mod tests { | |||
137 | 138 | ||
138 | use super::*; | 139 | use super::*; |
139 | 140 | ||
140 | fn check_not_applicable(code: &str, func: fn(file: &SourceFileNode) -> Vec<Diagnostic>) { | 141 | type DiagnosticChecker = fn(&mut Vec<Diagnostic>, SyntaxNodeRef) -> Option<()>; |
142 | |||
143 | fn check_not_applicable(code: &str, func: DiagnosticChecker) { | ||
141 | let file = SourceFileNode::parse(code); | 144 | let file = SourceFileNode::parse(code); |
142 | let diagnostics = func(&file); | 145 | let mut diagnostics = Vec::new(); |
146 | for node in file.syntax().descendants() { | ||
147 | func(&mut diagnostics, node); | ||
148 | } | ||
143 | assert!(diagnostics.is_empty()); | 149 | assert!(diagnostics.is_empty()); |
144 | } | 150 | } |
145 | 151 | ||
146 | fn check_apply(before: &str, after: &str, func: fn(file: &SourceFileNode) -> Vec<Diagnostic>) { | 152 | fn check_apply(before: &str, after: &str, func: DiagnosticChecker) { |
147 | let file = SourceFileNode::parse(before); | 153 | let file = SourceFileNode::parse(before); |
148 | let diagnostic = func(&file) | 154 | let mut diagnostics = Vec::new(); |
155 | for node in file.syntax().descendants() { | ||
156 | func(&mut diagnostics, node); | ||
157 | } | ||
158 | let diagnostic = diagnostics | ||
149 | .pop() | 159 | .pop() |
150 | .unwrap_or_else(|| panic!("no diagnostics for:\n{}\n", before)); | 160 | .unwrap_or_else(|| panic!("no diagnostics for:\n{}\n", before)); |
151 | let fix = diagnostic.fix.unwrap(); | 161 | let fix = diagnostic.fix.unwrap(); |