add fix for removing unnecessary braces in use statements
This commit is contained in:
parent
5fb426cb9e
commit
72eb9de747
@ -3,31 +3,32 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use ra_editor::{self, find_node_at_offset, FileSymbol, LineIndex, LocalEdit, Severity};
|
||||
use rayon::prelude::*;
|
||||
use salsa::{Database, ParallelDatabase};
|
||||
|
||||
use hir::{
|
||||
self,
|
||||
FnSignatureInfo,
|
||||
Problem,
|
||||
source_binder,
|
||||
};
|
||||
use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase};
|
||||
use ra_editor::{self, FileSymbol, find_node_at_offset, LineIndex, LocalEdit, Severity};
|
||||
use ra_syntax::{
|
||||
ast::{self, ArgListOwner, Expr, NameOwner, FnDef},
|
||||
algo::find_covering_node,
|
||||
ast::{self, ArgListOwner, Expr, FnDef, NameOwner},
|
||||
AstNode, SourceFileNode,
|
||||
SyntaxKind::*,
|
||||
SyntaxNodeRef, TextRange, TextUnit,
|
||||
};
|
||||
use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase};
|
||||
use rayon::prelude::*;
|
||||
use salsa::{Database, ParallelDatabase};
|
||||
use hir::{
|
||||
self,
|
||||
source_binder,
|
||||
FnSignatureInfo,
|
||||
Problem,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
completion::{completions, CompletionItem},
|
||||
db,
|
||||
symbol_index::{SymbolIndex, SymbolsDatabase, LibrarySymbolsQuery},
|
||||
AnalysisChange, RootChange, Cancelable, CrateId, Diagnostic, FileId,
|
||||
FileSystemEdit, FilePosition, Query, SourceChange, SourceFileEdit,
|
||||
ReferenceResolution,
|
||||
AnalysisChange,
|
||||
Cancelable,
|
||||
completion::{CompletionItem, completions},
|
||||
CrateId, db, Diagnostic, FileId, FilePosition, FileSystemEdit,
|
||||
Query, ReferenceResolution, RootChange, SourceChange, SourceFileEdit,
|
||||
symbol_index::{LibrarySymbolsQuery, SymbolIndex, SymbolsDatabase},
|
||||
};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
@ -366,7 +367,7 @@ impl AnalysisImpl {
|
||||
range: d.range,
|
||||
message: d.msg,
|
||||
severity: d.severity,
|
||||
fix: None,
|
||||
fix: d.fix.map(|fix| SourceChange::from_local_edit(file_id, fix)),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if let Some(m) = source_binder::module_from_file_id(&*self.db, file_id)? {
|
||||
@ -425,25 +426,14 @@ impl AnalysisImpl {
|
||||
let file = self.file_syntax(file_id);
|
||||
let offset = range.start();
|
||||
let actions = vec![
|
||||
(
|
||||
"flip comma",
|
||||
ra_editor::flip_comma(&file, offset).map(|f| f()),
|
||||
),
|
||||
(
|
||||
"add `#[derive]`",
|
||||
ra_editor::add_derive(&file, offset).map(|f| f()),
|
||||
),
|
||||
("add impl", ra_editor::add_impl(&file, offset).map(|f| f())),
|
||||
(
|
||||
"introduce variable",
|
||||
ra_editor::introduce_variable(&file, range).map(|f| f()),
|
||||
),
|
||||
ra_editor::flip_comma(&file, offset).map(|f| f()),
|
||||
ra_editor::add_derive(&file, offset).map(|f| f()),
|
||||
ra_editor::add_impl(&file, offset).map(|f| f()),
|
||||
ra_editor::introduce_variable(&file, range).map(|f| f()),
|
||||
];
|
||||
actions
|
||||
.into_iter()
|
||||
.filter_map(|(name, local_edit)| {
|
||||
Some(SourceChange::from_local_edit(file_id, name, local_edit?))
|
||||
})
|
||||
.filter_map(|local_edit| Some(SourceChange::from_local_edit(file_id, local_edit?)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
@ -541,13 +531,13 @@ impl AnalysisImpl {
|
||||
}
|
||||
|
||||
impl SourceChange {
|
||||
pub(crate) fn from_local_edit(file_id: FileId, label: &str, edit: LocalEdit) -> SourceChange {
|
||||
pub(crate) fn from_local_edit(file_id: FileId, edit: LocalEdit) -> SourceChange {
|
||||
let file_edit = SourceFileEdit {
|
||||
file_id,
|
||||
edit: edit.edit,
|
||||
};
|
||||
SourceChange {
|
||||
label: label.to_string(),
|
||||
label: edit.label,
|
||||
source_file_edits: vec![file_edit],
|
||||
file_system_edits: vec![],
|
||||
cursor_position: edit
|
||||
|
@ -288,19 +288,18 @@ impl Analysis {
|
||||
}
|
||||
pub fn join_lines(&self, file_id: FileId, range: TextRange) -> SourceChange {
|
||||
let file = self.imp.file_syntax(file_id);
|
||||
SourceChange::from_local_edit(file_id, "join lines", ra_editor::join_lines(&file, range))
|
||||
SourceChange::from_local_edit(file_id, ra_editor::join_lines(&file, range))
|
||||
}
|
||||
pub fn on_enter(&self, position: FilePosition) -> Option<SourceChange> {
|
||||
let file = self.imp.file_syntax(position.file_id);
|
||||
let edit = ra_editor::on_enter(&file, position.offset)?;
|
||||
let res = SourceChange::from_local_edit(position.file_id, "on enter", edit);
|
||||
let res = SourceChange::from_local_edit(position.file_id, edit);
|
||||
Some(res)
|
||||
}
|
||||
pub fn on_eq_typed(&self, position: FilePosition) -> Option<SourceChange> {
|
||||
let file = self.imp.file_syntax(position.file_id);
|
||||
Some(SourceChange::from_local_edit(
|
||||
position.file_id,
|
||||
"add semicolon",
|
||||
ra_editor::on_eq_typed(&file, position.offset)?,
|
||||
))
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ use crate::{find_node_at_offset, TextEdit, TextEditBuilder};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LocalEdit {
|
||||
pub label: String,
|
||||
pub edit: TextEdit,
|
||||
pub cursor_position: Option<TextUnit>,
|
||||
}
|
||||
@ -30,6 +31,7 @@ pub fn flip_comma<'a>(
|
||||
edit.replace(prev.range(), next.text().to_string());
|
||||
edit.replace(next.range(), prev.text().to_string());
|
||||
LocalEdit {
|
||||
label: "flip comma".to_string(),
|
||||
edit: edit.finish(),
|
||||
cursor_position: None,
|
||||
}
|
||||
@ -58,6 +60,7 @@ pub fn add_derive<'a>(
|
||||
Some(tt) => tt.syntax().range().end() - TextUnit::of_char(')'),
|
||||
};
|
||||
LocalEdit {
|
||||
label: "add `#[derive]`".to_string(),
|
||||
edit: edit.finish(),
|
||||
cursor_position: Some(offset),
|
||||
}
|
||||
@ -109,6 +112,7 @@ pub fn add_impl<'a>(
|
||||
buf.push_str("\n}");
|
||||
edit.insert(start_offset, buf);
|
||||
LocalEdit {
|
||||
label: "add impl".to_string(),
|
||||
edit: edit.finish(),
|
||||
cursor_position: Some(offset),
|
||||
}
|
||||
@ -148,6 +152,7 @@ pub fn introduce_variable<'a>(
|
||||
}
|
||||
let cursor_position = anchor_stmt.range().start() + TextUnit::of_str("let ");
|
||||
LocalEdit {
|
||||
label: "introduce variable".to_string(),
|
||||
edit: edit.finish(),
|
||||
cursor_position: Some(cursor_position),
|
||||
}
|
||||
@ -194,6 +199,7 @@ pub fn make_pub_crate<'a>(
|
||||
|| parent.children().any(|child| child.kind() == VISIBILITY)
|
||||
{
|
||||
return LocalEdit {
|
||||
label: "make pub crate".to_string(),
|
||||
edit: edit.finish(),
|
||||
cursor_position: Some(offset),
|
||||
};
|
||||
@ -201,6 +207,7 @@ pub fn make_pub_crate<'a>(
|
||||
|
||||
edit.insert(node_start, "pub(crate) ".to_string());
|
||||
LocalEdit {
|
||||
label: "make pub crate".to_string(),
|
||||
edit: edit.finish(),
|
||||
cursor_position: Some(node_start),
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ pub struct Diagnostic {
|
||||
pub range: TextRange,
|
||||
pub msg: String,
|
||||
pub severity: Severity,
|
||||
pub fix: Option<LocalEdit>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -111,6 +112,7 @@ pub fn diagnostics(file: &SourceFileNode) -> Vec<Diagnostic> {
|
||||
range: location_to_range(err.location()),
|
||||
msg: format!("Syntax Error: {}", err),
|
||||
severity: Severity::Error,
|
||||
fix: None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -124,11 +126,27 @@ fn check_unnecessary_braces_in_use_statement(file: &SourceFileNode) -> Vec<Diagn
|
||||
let mut diagnostics = Vec::new();
|
||||
for node in file.syntax().descendants() {
|
||||
if let Some(use_tree_list) = ast::UseTreeList::cast(node) {
|
||||
if use_tree_list.use_trees().count() <= 1 {
|
||||
if use_tree_list.use_trees().count() == 1 {
|
||||
let range = use_tree_list.syntax().range();
|
||||
// use_tree_list always has one child, so we use unwrap directly here.
|
||||
let to_replace = typing::single_use_tree(use_tree_list)
|
||||
.unwrap()
|
||||
.syntax()
|
||||
.text()
|
||||
.to_string();
|
||||
let mut edit_builder = TextEditBuilder::new();
|
||||
edit_builder.delete(range);
|
||||
edit_builder.insert(range.start(), to_replace);
|
||||
|
||||
diagnostics.push(Diagnostic {
|
||||
range: use_tree_list.syntax().range(),
|
||||
range: range,
|
||||
msg: format!("Unnecessary braces in use statement"),
|
||||
severity: Severity::WeakWarning,
|
||||
fix: Some(LocalEdit {
|
||||
label: "Remove unnecessary braces".to_string(),
|
||||
edit: edit_builder.finish(),
|
||||
cursor_position: None,
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -250,9 +268,7 @@ fn main() {}
|
||||
);
|
||||
let diagnostics = check_unnecessary_braces_in_use_statement(&file);
|
||||
assert_eq_dbg(
|
||||
r#"[Diagnostic { range: [12; 15), msg: "Unnecessary braces in use statement", severity: WeakWarning },
|
||||
Diagnostic { range: [24; 27), msg: "Unnecessary braces in use statement", severity: WeakWarning },
|
||||
Diagnostic { range: [61; 64), msg: "Unnecessary braces in use statement", severity: WeakWarning }]"#,
|
||||
"[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) }) }]",
|
||||
&diagnostics,
|
||||
)
|
||||
}
|
||||
|
@ -8,7 +8,9 @@ use ra_syntax::{
|
||||
SyntaxKind::*,
|
||||
SyntaxNodeRef, TextRange, TextUnit,
|
||||
};
|
||||
use ra_text_edit::text_utils::contains_offset_nonstrict;
|
||||
use ra_text_edit::text_utils::{
|
||||
contains_offset_nonstrict
|
||||
};
|
||||
|
||||
use crate::{find_node_at_offset, TextEditBuilder, LocalEdit};
|
||||
|
||||
@ -19,6 +21,7 @@ pub fn join_lines(file: &SourceFileNode, range: TextRange) -> LocalEdit {
|
||||
let pos = match text.find('\n') {
|
||||
None => {
|
||||
return LocalEdit {
|
||||
label: "join lines".to_string(),
|
||||
edit: TextEditBuilder::new().finish(),
|
||||
cursor_position: None,
|
||||
};
|
||||
@ -51,6 +54,7 @@ pub fn join_lines(file: &SourceFileNode, range: TextRange) -> LocalEdit {
|
||||
}
|
||||
|
||||
LocalEdit {
|
||||
label: "join lines".to_string(),
|
||||
edit: edit.finish(),
|
||||
cursor_position: None,
|
||||
}
|
||||
@ -76,6 +80,7 @@ pub fn on_enter(file: &SourceFileNode, offset: TextUnit) -> Option<LocalEdit> {
|
||||
let mut edit = TextEditBuilder::new();
|
||||
edit.insert(offset, inserted);
|
||||
Some(LocalEdit {
|
||||
label: "on enter".to_string(),
|
||||
edit: edit.finish(),
|
||||
cursor_position: Some(cursor_position),
|
||||
})
|
||||
@ -126,6 +131,7 @@ pub fn on_eq_typed(file: &SourceFileNode, offset: TextUnit) -> Option<LocalEdit>
|
||||
let mut edit = TextEditBuilder::new();
|
||||
edit.insert(offset, ";".to_string());
|
||||
Some(LocalEdit {
|
||||
label: "add semicolon".to_string(),
|
||||
edit: edit.finish(),
|
||||
cursor_position: None,
|
||||
})
|
||||
@ -248,24 +254,13 @@ fn join_single_use_tree(edit: &mut TextEditBuilder, node: SyntaxNodeRef) -> Opti
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn single_use_tree(tree_list: ast::UseTreeList) -> Option<ast::UseTree> {
|
||||
let mut res = None;
|
||||
for child in tree_list.syntax().children() {
|
||||
if let Some(tree) = ast::UseTree::cast(child) {
|
||||
if tree.syntax().text().contains('\n') {
|
||||
return None;
|
||||
}
|
||||
if mem::replace(&mut res, Some(tree)).is_some() {
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
match child.kind() {
|
||||
WHITESPACE | L_CURLY | R_CURLY | COMMA => (),
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
pub(crate) fn single_use_tree(tree_list: ast::UseTreeList) -> Option<ast::UseTree> {
|
||||
let sub_use_trees = tree_list.use_trees().count();
|
||||
if sub_use_trees != 1 {
|
||||
return None;
|
||||
}
|
||||
res
|
||||
|
||||
tree_list.use_trees().next()
|
||||
}
|
||||
|
||||
fn compute_ws(left: SyntaxNodeRef, right: SyntaxNodeRef) -> &'static str {
|
||||
|
Loading…
x
Reference in New Issue
Block a user