diff options
author | Aleksey Kladov <[email protected]> | 2019-03-21 16:05:15 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-03-21 16:08:54 +0000 |
commit | 7cae9ddeeb14aa81a911a0e69d9eec265cc364d3 (patch) | |
tree | dbdc74944dfc953c573863e8f0f4b5bcb8a6a40d /crates/ra_ide_api_light/src/diagnostics.rs | |
parent | 48472f55c3eba0746c088613888a163b48d07398 (diff) |
move diagnostics to ide_api
Diffstat (limited to 'crates/ra_ide_api_light/src/diagnostics.rs')
-rw-r--r-- | crates/ra_ide_api_light/src/diagnostics.rs | 246 |
1 files changed, 0 insertions, 246 deletions
diff --git a/crates/ra_ide_api_light/src/diagnostics.rs b/crates/ra_ide_api_light/src/diagnostics.rs deleted file mode 100644 index 7c383ca2a..000000000 --- a/crates/ra_ide_api_light/src/diagnostics.rs +++ /dev/null | |||
@@ -1,246 +0,0 @@ | |||
1 | use itertools::Itertools; | ||
2 | |||
3 | use ra_syntax::{ | ||
4 | Location, SourceFile, SyntaxKind, TextRange, SyntaxNode, | ||
5 | ast::{self, AstNode}, | ||
6 | |||
7 | }; | ||
8 | use ra_text_edit::{TextEdit, TextEditBuilder}; | ||
9 | |||
10 | use crate::{Diagnostic, LocalEdit, Severity}; | ||
11 | |||
12 | pub fn diagnostics(file: &SourceFile) -> Vec<Diagnostic> { | ||
13 | fn location_to_range(location: Location) -> TextRange { | ||
14 | match location { | ||
15 | Location::Offset(offset) => TextRange::offset_len(offset, 1.into()), | ||
16 | Location::Range(range) => range, | ||
17 | } | ||
18 | } | ||
19 | |||
20 | let mut errors: Vec<Diagnostic> = file | ||
21 | .errors() | ||
22 | .into_iter() | ||
23 | .map(|err| Diagnostic { | ||
24 | range: location_to_range(err.location()), | ||
25 | msg: format!("Syntax Error: {}", err), | ||
26 | severity: Severity::Error, | ||
27 | fix: None, | ||
28 | }) | ||
29 | .collect(); | ||
30 | |||
31 | for node in file.syntax().descendants() { | ||
32 | check_unnecessary_braces_in_use_statement(&mut errors, node); | ||
33 | check_struct_shorthand_initialization(&mut errors, node); | ||
34 | } | ||
35 | |||
36 | errors | ||
37 | } | ||
38 | |||
39 | fn check_unnecessary_braces_in_use_statement( | ||
40 | acc: &mut Vec<Diagnostic>, | ||
41 | node: &SyntaxNode, | ||
42 | ) -> Option<()> { | ||
43 | let use_tree_list = ast::UseTreeList::cast(node)?; | ||
44 | if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() { | ||
45 | let range = use_tree_list.syntax().range(); | ||
46 | let edit = | ||
47 | text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(single_use_tree) | ||
48 | .unwrap_or_else(|| { | ||
49 | let to_replace = single_use_tree.syntax().text().to_string(); | ||
50 | let mut edit_builder = TextEditBuilder::default(); | ||
51 | edit_builder.delete(range); | ||
52 | edit_builder.insert(range.start(), to_replace); | ||
53 | edit_builder.finish() | ||
54 | }); | ||
55 | |||
56 | acc.push(Diagnostic { | ||
57 | range, | ||
58 | msg: format!("Unnecessary braces in use statement"), | ||
59 | severity: Severity::WeakWarning, | ||
60 | fix: Some(LocalEdit { | ||
61 | label: "Remove unnecessary braces".to_string(), | ||
62 | edit, | ||
63 | cursor_position: None, | ||
64 | }), | ||
65 | }); | ||
66 | } | ||
67 | |||
68 | Some(()) | ||
69 | } | ||
70 | |||
71 | fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement( | ||
72 | single_use_tree: &ast::UseTree, | ||
73 | ) -> Option<TextEdit> { | ||
74 | let use_tree_list_node = single_use_tree.syntax().parent()?; | ||
75 | if single_use_tree.path()?.segment()?.syntax().first_child()?.kind() == SyntaxKind::SELF_KW { | ||
76 | let start = use_tree_list_node.prev_sibling()?.range().start(); | ||
77 | let end = use_tree_list_node.range().end(); | ||
78 | let range = TextRange::from_to(start, end); | ||
79 | let mut edit_builder = TextEditBuilder::default(); | ||
80 | edit_builder.delete(range); | ||
81 | return Some(edit_builder.finish()); | ||
82 | } | ||
83 | None | ||
84 | } | ||
85 | |||
86 | fn check_struct_shorthand_initialization( | ||
87 | acc: &mut Vec<Diagnostic>, | ||
88 | node: &SyntaxNode, | ||
89 | ) -> Option<()> { | ||
90 | let struct_lit = ast::StructLit::cast(node)?; | ||
91 | let named_field_list = struct_lit.named_field_list()?; | ||
92 | for named_field in named_field_list.fields() { | ||
93 | if let (Some(name_ref), Some(expr)) = (named_field.name_ref(), named_field.expr()) { | ||
94 | let field_name = name_ref.syntax().text().to_string(); | ||
95 | let field_expr = expr.syntax().text().to_string(); | ||
96 | if field_name == field_expr { | ||
97 | let mut edit_builder = TextEditBuilder::default(); | ||
98 | edit_builder.delete(named_field.syntax().range()); | ||
99 | edit_builder.insert(named_field.syntax().range().start(), field_name); | ||
100 | let edit = edit_builder.finish(); | ||
101 | |||
102 | acc.push(Diagnostic { | ||
103 | range: named_field.syntax().range(), | ||
104 | msg: format!("Shorthand struct initialization"), | ||
105 | severity: Severity::WeakWarning, | ||
106 | fix: Some(LocalEdit { | ||
107 | label: "use struct shorthand initialization".to_string(), | ||
108 | edit, | ||
109 | cursor_position: None, | ||
110 | }), | ||
111 | }); | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | Some(()) | ||
116 | } | ||
117 | |||
118 | #[cfg(test)] | ||
119 | mod tests { | ||
120 | use crate::test_utils::assert_eq_text; | ||
121 | |||
122 | use super::*; | ||
123 | |||
124 | type DiagnosticChecker = fn(&mut Vec<Diagnostic>, &SyntaxNode) -> Option<()>; | ||
125 | |||
126 | fn check_not_applicable(code: &str, func: DiagnosticChecker) { | ||
127 | let file = SourceFile::parse(code); | ||
128 | let mut diagnostics = Vec::new(); | ||
129 | for node in file.syntax().descendants() { | ||
130 | func(&mut diagnostics, node); | ||
131 | } | ||
132 | assert!(diagnostics.is_empty()); | ||
133 | } | ||
134 | |||
135 | fn check_apply(before: &str, after: &str, func: DiagnosticChecker) { | ||
136 | let file = SourceFile::parse(before); | ||
137 | let mut diagnostics = Vec::new(); | ||
138 | for node in file.syntax().descendants() { | ||
139 | func(&mut diagnostics, node); | ||
140 | } | ||
141 | let diagnostic = | ||
142 | diagnostics.pop().unwrap_or_else(|| panic!("no diagnostics for:\n{}\n", before)); | ||
143 | let fix = diagnostic.fix.unwrap(); | ||
144 | let actual = fix.edit.apply(&before); | ||
145 | assert_eq_text!(after, &actual); | ||
146 | } | ||
147 | |||
148 | #[test] | ||
149 | fn test_check_unnecessary_braces_in_use_statement() { | ||
150 | check_not_applicable( | ||
151 | " | ||
152 | use a; | ||
153 | use a::{c, d::e}; | ||
154 | ", | ||
155 | check_unnecessary_braces_in_use_statement, | ||
156 | ); | ||
157 | check_apply("use {b};", "use b;", check_unnecessary_braces_in_use_statement); | ||
158 | check_apply("use a::{c};", "use a::c;", check_unnecessary_braces_in_use_statement); | ||
159 | check_apply("use a::{self};", "use a;", check_unnecessary_braces_in_use_statement); | ||
160 | check_apply( | ||
161 | "use a::{c, d::{e}};", | ||
162 | "use a::{c, d::e};", | ||
163 | check_unnecessary_braces_in_use_statement, | ||
164 | ); | ||
165 | } | ||
166 | |||
167 | #[test] | ||
168 | fn test_check_struct_shorthand_initialization() { | ||
169 | check_not_applicable( | ||
170 | r#" | ||
171 | struct A { | ||
172 | a: &'static str | ||
173 | } | ||
174 | |||
175 | fn main() { | ||
176 | A { | ||
177 | a: "hello" | ||
178 | } | ||
179 | } | ||
180 | "#, | ||
181 | check_struct_shorthand_initialization, | ||
182 | ); | ||
183 | |||
184 | check_apply( | ||
185 | r#" | ||
186 | struct A { | ||
187 | a: &'static str | ||
188 | } | ||
189 | |||
190 | fn main() { | ||
191 | let a = "haha"; | ||
192 | A { | ||
193 | a: a | ||
194 | } | ||
195 | } | ||
196 | "#, | ||
197 | r#" | ||
198 | struct A { | ||
199 | a: &'static str | ||
200 | } | ||
201 | |||
202 | fn main() { | ||
203 | let a = "haha"; | ||
204 | A { | ||
205 | a | ||
206 | } | ||
207 | } | ||
208 | "#, | ||
209 | check_struct_shorthand_initialization, | ||
210 | ); | ||
211 | |||
212 | check_apply( | ||
213 | r#" | ||
214 | struct A { | ||
215 | a: &'static str, | ||
216 | b: &'static str | ||
217 | } | ||
218 | |||
219 | fn main() { | ||
220 | let a = "haha"; | ||
221 | let b = "bb"; | ||
222 | A { | ||
223 | a: a, | ||
224 | b | ||
225 | } | ||
226 | } | ||
227 | "#, | ||
228 | r#" | ||
229 | struct A { | ||
230 | a: &'static str, | ||
231 | b: &'static str | ||
232 | } | ||
233 | |||
234 | fn main() { | ||
235 | let a = "haha"; | ||
236 | let b = "bb"; | ||
237 | A { | ||
238 | a, | ||
239 | b | ||
240 | } | ||
241 | } | ||
242 | "#, | ||
243 | check_struct_shorthand_initialization, | ||
244 | ); | ||
245 | } | ||
246 | } | ||