aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_analysis/src/imp.rs60
-rw-r--r--crates/ra_analysis/src/lib.rs5
-rw-r--r--crates/ra_editor/src/code_actions.rs7
-rw-r--r--crates/ra_editor/src/lib.rs26
-rw-r--r--crates/ra_editor/src/typing.rs31
5 files changed, 68 insertions, 61 deletions
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index a547c5a20..69c9b104e 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -3,31 +3,32 @@ use std::{
3 sync::Arc, 3 sync::Arc,
4}; 4};
5 5
6use ra_editor::{self, find_node_at_offset, FileSymbol, LineIndex, LocalEdit, Severity};
7use ra_syntax::{
8 ast::{self, ArgListOwner, Expr, NameOwner, FnDef},
9 algo::find_covering_node,
10 AstNode, SourceFileNode,
11 SyntaxKind::*,
12 SyntaxNodeRef, TextRange, TextUnit,
13};
14use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase};
15use rayon::prelude::*; 6use rayon::prelude::*;
16use salsa::{Database, ParallelDatabase}; 7use salsa::{Database, ParallelDatabase};
8
17use hir::{ 9use hir::{
18 self, 10 self,
19 source_binder,
20 FnSignatureInfo, 11 FnSignatureInfo,
21 Problem, 12 Problem,
13 source_binder,
14};
15use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase};
16use ra_editor::{self, FileSymbol, find_node_at_offset, LineIndex, LocalEdit, Severity};
17use ra_syntax::{
18 algo::find_covering_node,
19 ast::{self, ArgListOwner, Expr, FnDef, NameOwner},
20 AstNode, SourceFileNode,
21 SyntaxKind::*,
22 SyntaxNodeRef, TextRange, TextUnit,
22}; 23};
23 24
24use crate::{ 25use crate::{
25 completion::{completions, CompletionItem}, 26 AnalysisChange,
26 db, 27 Cancelable,
27 symbol_index::{SymbolIndex, SymbolsDatabase, LibrarySymbolsQuery}, 28 completion::{CompletionItem, completions},
28 AnalysisChange, RootChange, Cancelable, CrateId, Diagnostic, FileId, 29 CrateId, db, Diagnostic, FileId, FilePosition, FileSystemEdit,
29 FileSystemEdit, FilePosition, Query, SourceChange, SourceFileEdit, 30 Query, ReferenceResolution, RootChange, SourceChange, SourceFileEdit,
30 ReferenceResolution, 31 symbol_index::{LibrarySymbolsQuery, SymbolIndex, SymbolsDatabase},
31}; 32};
32 33
33#[derive(Debug, Default)] 34#[derive(Debug, Default)]
@@ -366,7 +367,7 @@ impl AnalysisImpl {
366 range: d.range, 367 range: d.range,
367 message: d.msg, 368 message: d.msg,
368 severity: d.severity, 369 severity: d.severity,
369 fix: None, 370 fix: d.fix.map(|fix| SourceChange::from_local_edit(file_id, fix)),
370 }) 371 })
371 .collect::<Vec<_>>(); 372 .collect::<Vec<_>>();
372 if let Some(m) = source_binder::module_from_file_id(&*self.db, file_id)? { 373 if let Some(m) = source_binder::module_from_file_id(&*self.db, file_id)? {
@@ -425,25 +426,14 @@ impl AnalysisImpl {
425 let file = self.file_syntax(file_id); 426 let file = self.file_syntax(file_id);
426 let offset = range.start(); 427 let offset = range.start();
427 let actions = vec![ 428 let actions = vec![
428 ( 429 ra_editor::flip_comma(&file, offset).map(|f| f()),
429 "flip comma", 430 ra_editor::add_derive(&file, offset).map(|f| f()),
430 ra_editor::flip_comma(&file, offset).map(|f| f()), 431 ra_editor::add_impl(&file, offset).map(|f| f()),
431 ), 432 ra_editor::introduce_variable(&file, range).map(|f| f()),
432 (
433 "add `#[derive]`",
434 ra_editor::add_derive(&file, offset).map(|f| f()),
435 ),
436 ("add impl", ra_editor::add_impl(&file, offset).map(|f| f())),
437 (
438 "introduce variable",
439 ra_editor::introduce_variable(&file, range).map(|f| f()),
440 ),
441 ]; 433 ];
442 actions 434 actions
443 .into_iter() 435 .into_iter()
444 .filter_map(|(name, local_edit)| { 436 .filter_map(|local_edit| Some(SourceChange::from_local_edit(file_id, local_edit?)))
445 Some(SourceChange::from_local_edit(file_id, name, local_edit?))
446 })
447 .collect() 437 .collect()
448 } 438 }
449 439
@@ -541,13 +531,13 @@ impl AnalysisImpl {
541} 531}
542 532
543impl SourceChange { 533impl SourceChange {
544 pub(crate) fn from_local_edit(file_id: FileId, label: &str, edit: LocalEdit) -> SourceChange { 534 pub(crate) fn from_local_edit(file_id: FileId, edit: LocalEdit) -> SourceChange {
545 let file_edit = SourceFileEdit { 535 let file_edit = SourceFileEdit {
546 file_id, 536 file_id,
547 edit: edit.edit, 537 edit: edit.edit,
548 }; 538 };
549 SourceChange { 539 SourceChange {
550 label: label.to_string(), 540 label: edit.label,
551 source_file_edits: vec![file_edit], 541 source_file_edits: vec![file_edit],
552 file_system_edits: vec![], 542 file_system_edits: vec![],
553 cursor_position: edit 543 cursor_position: edit
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index a029f66b4..476d1b438 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -288,19 +288,18 @@ impl Analysis {
288 } 288 }
289 pub fn join_lines(&self, file_id: FileId, range: TextRange) -> SourceChange { 289 pub fn join_lines(&self, file_id: FileId, range: TextRange) -> SourceChange {
290 let file = self.imp.file_syntax(file_id); 290 let file = self.imp.file_syntax(file_id);
291 SourceChange::from_local_edit(file_id, "join lines", ra_editor::join_lines(&file, range)) 291 SourceChange::from_local_edit(file_id, ra_editor::join_lines(&file, range))
292 } 292 }
293 pub fn on_enter(&self, position: FilePosition) -> Option<SourceChange> { 293 pub fn on_enter(&self, position: FilePosition) -> Option<SourceChange> {
294 let file = self.imp.file_syntax(position.file_id); 294 let file = self.imp.file_syntax(position.file_id);
295 let edit = ra_editor::on_enter(&file, position.offset)?; 295 let edit = ra_editor::on_enter(&file, position.offset)?;
296 let res = SourceChange::from_local_edit(position.file_id, "on enter", edit); 296 let res = SourceChange::from_local_edit(position.file_id, edit);
297 Some(res) 297 Some(res)
298 } 298 }
299 pub fn on_eq_typed(&self, position: FilePosition) -> Option<SourceChange> { 299 pub fn on_eq_typed(&self, position: FilePosition) -> Option<SourceChange> {
300 let file = self.imp.file_syntax(position.file_id); 300 let file = self.imp.file_syntax(position.file_id);
301 Some(SourceChange::from_local_edit( 301 Some(SourceChange::from_local_edit(
302 position.file_id, 302 position.file_id,
303 "add semicolon",
304 ra_editor::on_eq_typed(&file, position.offset)?, 303 ra_editor::on_eq_typed(&file, position.offset)?,
305 )) 304 ))
306 } 305 }
diff --git a/crates/ra_editor/src/code_actions.rs b/crates/ra_editor/src/code_actions.rs
index 1d78cb7e8..7615f37a6 100644
--- a/crates/ra_editor/src/code_actions.rs
+++ b/crates/ra_editor/src/code_actions.rs
@@ -12,6 +12,7 @@ use crate::{find_node_at_offset, TextEdit, TextEditBuilder};
12 12
13#[derive(Debug)] 13#[derive(Debug)]
14pub struct LocalEdit { 14pub struct LocalEdit {
15 pub label: String,
15 pub edit: TextEdit, 16 pub edit: TextEdit,
16 pub cursor_position: Option<TextUnit>, 17 pub cursor_position: Option<TextUnit>,
17} 18}
@@ -30,6 +31,7 @@ pub fn flip_comma<'a>(
30 edit.replace(prev.range(), next.text().to_string()); 31 edit.replace(prev.range(), next.text().to_string());
31 edit.replace(next.range(), prev.text().to_string()); 32 edit.replace(next.range(), prev.text().to_string());
32 LocalEdit { 33 LocalEdit {
34 label: "flip comma".to_string(),
33 edit: edit.finish(), 35 edit: edit.finish(),
34 cursor_position: None, 36 cursor_position: None,
35 } 37 }
@@ -58,6 +60,7 @@ pub fn add_derive<'a>(
58 Some(tt) => tt.syntax().range().end() - TextUnit::of_char(')'), 60 Some(tt) => tt.syntax().range().end() - TextUnit::of_char(')'),
59 }; 61 };
60 LocalEdit { 62 LocalEdit {
63 label: "add `#[derive]`".to_string(),
61 edit: edit.finish(), 64 edit: edit.finish(),
62 cursor_position: Some(offset), 65 cursor_position: Some(offset),
63 } 66 }
@@ -109,6 +112,7 @@ pub fn add_impl<'a>(
109 buf.push_str("\n}"); 112 buf.push_str("\n}");
110 edit.insert(start_offset, buf); 113 edit.insert(start_offset, buf);
111 LocalEdit { 114 LocalEdit {
115 label: "add impl".to_string(),
112 edit: edit.finish(), 116 edit: edit.finish(),
113 cursor_position: Some(offset), 117 cursor_position: Some(offset),
114 } 118 }
@@ -148,6 +152,7 @@ pub fn introduce_variable<'a>(
148 } 152 }
149 let cursor_position = anchor_stmt.range().start() + TextUnit::of_str("let "); 153 let cursor_position = anchor_stmt.range().start() + TextUnit::of_str("let ");
150 LocalEdit { 154 LocalEdit {
155 label: "introduce variable".to_string(),
151 edit: edit.finish(), 156 edit: edit.finish(),
152 cursor_position: Some(cursor_position), 157 cursor_position: Some(cursor_position),
153 } 158 }
@@ -194,6 +199,7 @@ pub fn make_pub_crate<'a>(
194 || parent.children().any(|child| child.kind() == VISIBILITY) 199 || parent.children().any(|child| child.kind() == VISIBILITY)
195 { 200 {
196 return LocalEdit { 201 return LocalEdit {
202 label: "make pub crate".to_string(),
197 edit: edit.finish(), 203 edit: edit.finish(),
198 cursor_position: Some(offset), 204 cursor_position: Some(offset),
199 }; 205 };
@@ -201,6 +207,7 @@ pub fn make_pub_crate<'a>(
201 207
202 edit.insert(node_start, "pub(crate) ".to_string()); 208 edit.insert(node_start, "pub(crate) ".to_string());
203 LocalEdit { 209 LocalEdit {
210 label: "make pub crate".to_string(),
204 edit: edit.finish(), 211 edit: edit.finish(),
205 cursor_position: Some(node_start), 212 cursor_position: Some(node_start),
206 } 213 }
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs
index 7a689b0f2..898d9b8c7 100644
--- a/crates/ra_editor/src/lib.rs
+++ b/crates/ra_editor/src/lib.rs
@@ -42,6 +42,7 @@ pub struct Diagnostic {
42 pub range: TextRange, 42 pub range: TextRange,
43 pub msg: String, 43 pub msg: String,
44 pub severity: Severity, 44 pub severity: Severity,
45 pub fix: Option<LocalEdit>,
45} 46}
46 47
47#[derive(Debug)] 48#[derive(Debug)]
@@ -111,6 +112,7 @@ pub fn diagnostics(file: &SourceFileNode) -> Vec<Diagnostic> {
111 range: location_to_range(err.location()), 112 range: location_to_range(err.location()),
112 msg: format!("Syntax Error: {}", err), 113 msg: format!("Syntax Error: {}", err),
113 severity: Severity::Error, 114 severity: Severity::Error,
115 fix: None,
114 }) 116 })
115 .collect(); 117 .collect();
116 118
@@ -124,11 +126,27 @@ fn check_unnecessary_braces_in_use_statement(file: &SourceFileNode) -> Vec<Diagn
124 let mut diagnostics = Vec::new(); 126 let mut diagnostics = Vec::new();
125 for node in file.syntax().descendants() { 127 for node in file.syntax().descendants() {
126 if let Some(use_tree_list) = ast::UseTreeList::cast(node) { 128 if let Some(use_tree_list) = ast::UseTreeList::cast(node) {
127 if use_tree_list.use_trees().count() <= 1 { 129 if use_tree_list.use_trees().count() == 1 {
130 let range = use_tree_list.syntax().range();
131 // use_tree_list always has one child, so we use unwrap directly here.
132 let to_replace = typing::single_use_tree(use_tree_list)
133 .unwrap()
134 .syntax()
135 .text()
136 .to_string();
137 let mut edit_builder = TextEditBuilder::new();
138 edit_builder.delete(range);
139 edit_builder.insert(range.start(), to_replace);
140
128 diagnostics.push(Diagnostic { 141 diagnostics.push(Diagnostic {
129 range: use_tree_list.syntax().range(), 142 range: range,
130 msg: format!("Unnecessary braces in use statement"), 143 msg: format!("Unnecessary braces in use statement"),
131 severity: Severity::WeakWarning, 144 severity: Severity::WeakWarning,
145 fix: Some(LocalEdit {
146 label: "Remove unnecessary braces".to_string(),
147 edit: edit_builder.finish(),
148 cursor_position: None,
149 }),
132 }) 150 })
133 } 151 }
134 } 152 }
@@ -250,9 +268,7 @@ fn main() {}
250 ); 268 );
251 let diagnostics = check_unnecessary_braces_in_use_statement(&file); 269 let diagnostics = check_unnecessary_braces_in_use_statement(&file);
252 assert_eq_dbg( 270 assert_eq_dbg(
253 r#"[Diagnostic { range: [12; 15), msg: "Unnecessary braces in use statement", severity: WeakWarning }, 271 "[Diagnostic { range: [12; 15), msg: \"Unnecessary braces in use statement\", severity: WeakWarning, fix: Some(LocalEdit { label: \"Remove unnecessary braces\", edit: TextEdit { atoms: [AtomTextEdit { delete: [12; 12), insert: \"b\" }, AtomTextEdit { delete: [12; 15), insert: \"\" }] }, cursor_position: Some(12) }) }, Diagnostic { range: [24; 27), msg: \"Unnecessary braces in use statement\", severity: WeakWarning, fix: Some(LocalEdit { label: \"Remove unnecessary braces\", edit: TextEdit { atoms: [AtomTextEdit { delete: [24; 24), insert: \"c\" }, AtomTextEdit { delete: [24; 27), insert: \"\" }] }, cursor_position: Some(24) }) }, Diagnostic { range: [61; 64), msg: \"Unnecessary braces in use statement\", severity: WeakWarning, fix: Some(LocalEdit { label: \"Remove unnecessary braces\", edit: TextEdit { atoms: [AtomTextEdit { delete: [61; 61), insert: \"e\" }, AtomTextEdit { delete: [61; 64), insert: \"\" }] }, cursor_position: Some(61) }) }]",
254 Diagnostic { range: [24; 27), msg: "Unnecessary braces in use statement", severity: WeakWarning },
255 Diagnostic { range: [61; 64), msg: "Unnecessary braces in use statement", severity: WeakWarning }]"#,
256 &diagnostics, 272 &diagnostics,
257 ) 273 )
258 } 274 }
diff --git a/crates/ra_editor/src/typing.rs b/crates/ra_editor/src/typing.rs
index 5e412bcfa..dcc8793af 100644
--- a/crates/ra_editor/src/typing.rs
+++ b/crates/ra_editor/src/typing.rs
@@ -8,7 +8,9 @@ use ra_syntax::{
8 SyntaxKind::*, 8 SyntaxKind::*,
9 SyntaxNodeRef, TextRange, TextUnit, 9 SyntaxNodeRef, TextRange, TextUnit,
10}; 10};
11use ra_text_edit::text_utils::contains_offset_nonstrict; 11use ra_text_edit::text_utils::{
12 contains_offset_nonstrict
13};
12 14
13use crate::{find_node_at_offset, TextEditBuilder, LocalEdit}; 15use crate::{find_node_at_offset, TextEditBuilder, LocalEdit};
14 16
@@ -19,6 +21,7 @@ pub fn join_lines(file: &SourceFileNode, range: TextRange) -> LocalEdit {
19 let pos = match text.find('\n') { 21 let pos = match text.find('\n') {
20 None => { 22 None => {
21 return LocalEdit { 23 return LocalEdit {
24 label: "join lines".to_string(),
22 edit: TextEditBuilder::new().finish(), 25 edit: TextEditBuilder::new().finish(),
23 cursor_position: None, 26 cursor_position: None,
24 }; 27 };
@@ -51,6 +54,7 @@ pub fn join_lines(file: &SourceFileNode, range: TextRange) -> LocalEdit {
51 } 54 }
52 55
53 LocalEdit { 56 LocalEdit {
57 label: "join lines".to_string(),
54 edit: edit.finish(), 58 edit: edit.finish(),
55 cursor_position: None, 59 cursor_position: None,
56 } 60 }
@@ -76,6 +80,7 @@ pub fn on_enter(file: &SourceFileNode, offset: TextUnit) -> Option<LocalEdit> {
76 let mut edit = TextEditBuilder::new(); 80 let mut edit = TextEditBuilder::new();
77 edit.insert(offset, inserted); 81 edit.insert(offset, inserted);
78 Some(LocalEdit { 82 Some(LocalEdit {
83 label: "on enter".to_string(),
79 edit: edit.finish(), 84 edit: edit.finish(),
80 cursor_position: Some(cursor_position), 85 cursor_position: Some(cursor_position),
81 }) 86 })
@@ -126,6 +131,7 @@ pub fn on_eq_typed(file: &SourceFileNode, offset: TextUnit) -> Option<LocalEdit>
126 let mut edit = TextEditBuilder::new(); 131 let mut edit = TextEditBuilder::new();
127 edit.insert(offset, ";".to_string()); 132 edit.insert(offset, ";".to_string());
128 Some(LocalEdit { 133 Some(LocalEdit {
134 label: "add semicolon".to_string(),
129 edit: edit.finish(), 135 edit: edit.finish(),
130 cursor_position: None, 136 cursor_position: None,
131 }) 137 })
@@ -248,24 +254,13 @@ fn join_single_use_tree(edit: &mut TextEditBuilder, node: SyntaxNodeRef) -> Opti
248 Some(()) 254 Some(())
249} 255}
250 256
251fn single_use_tree(tree_list: ast::UseTreeList) -> Option<ast::UseTree> { 257pub(crate) fn single_use_tree(tree_list: ast::UseTreeList) -> Option<ast::UseTree> {
252 let mut res = None; 258 let sub_use_trees = tree_list.use_trees().count();
253 for child in tree_list.syntax().children() { 259 if sub_use_trees != 1 {
254 if let Some(tree) = ast::UseTree::cast(child) { 260 return None;
255 if tree.syntax().text().contains('\n') {
256 return None;
257 }
258 if mem::replace(&mut res, Some(tree)).is_some() {
259 return None;
260 }
261 } else {
262 match child.kind() {
263 WHITESPACE | L_CURLY | R_CURLY | COMMA => (),
264 _ => return None,
265 }
266 }
267 } 261 }
268 res 262
263 tree_list.use_trees().next()
269} 264}
270 265
271fn compute_ws(left: SyntaxNodeRef, right: SyntaxNodeRef) -> &'static str { 266fn compute_ws(left: SyntaxNodeRef, right: SyntaxNodeRef) -> &'static str {