aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_editor/src')
-rw-r--r--crates/ra_editor/src/diagnostics.rs134
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};
10use ra_syntax::SyntaxNodeRef;
10use ra_text_edit::{ 11use 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
45fn check_unnecessary_braces_in_use_statement(file: &SourceFileNode) -> Vec<Diagnostic> { 49fn 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
80fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement( 81fn 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
102fn check_struct_shorthand_initialization(file: &SourceFileNode) -> Vec<Diagnostic> { 103fn 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();