ide_diagnostics/handlers/
useless_braces.rs1use hir::InFile;
2use ide_db::RootDatabase;
3use ide_db::text_edit::TextEdit;
4use ide_db::{EditionedFileId, FileRange, source_change::SourceChange};
5use itertools::Itertools;
6use syntax::{AstNode, SyntaxNode, SyntaxNodePtr, ast};
7
8use crate::{Diagnostic, DiagnosticCode, fix};
9
10pub(crate) fn useless_braces(
14 db: &RootDatabase,
15 acc: &mut Vec<Diagnostic>,
16 file_id: EditionedFileId,
17 node: &SyntaxNode,
18) -> Option<()> {
19 let use_tree_list = ast::UseTreeList::cast(node.clone())?;
20 if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() {
21 if single_use_tree.path()?.segment()?.self_token().is_some() {
23 return Some(());
24 }
25
26 if use_tree_list.has_inner_comment() {
29 return Some(());
30 }
31
32 let use_range = use_tree_list.syntax().text_range();
33 let to_replace = single_use_tree.syntax().text().to_string();
34 let mut edit_builder = TextEdit::builder();
35 edit_builder.delete(use_range);
36 edit_builder.insert(use_range.start(), to_replace);
37 let edit = edit_builder.finish();
38
39 acc.push(
40 Diagnostic::new(
41 DiagnosticCode::RustcLint("unused_braces"),
42 "Unnecessary braces in use statement".to_owned(),
43 FileRange { file_id: file_id.file_id(db), range: use_range },
44 )
45 .with_main_node(InFile::new(file_id.into(), SyntaxNodePtr::new(node)))
46 .with_fixes(Some(vec![fix(
47 "remove_braces",
48 "Remove unnecessary braces",
49 SourceChange::from_text_edit(file_id.file_id(db), edit),
50 use_range,
51 )])),
52 );
53 }
54
55 Some(())
56}
57
58#[cfg(test)]
59mod tests {
60 use crate::{
61 DiagnosticsConfig,
62 tests::{check_diagnostics, check_diagnostics_with_config, check_fix},
63 };
64
65 #[test]
66 fn test_check_unnecessary_braces_in_use_statement() {
67 check_diagnostics(
68 r#"
69use a;
70use a::{c, d::e};
71
72mod a {
73 pub mod c {}
74 pub mod d {
75 pub mod e {}
76 }
77}
78"#,
79 );
80 check_diagnostics(
81 r#"
82use a;
83use a::{
84 c,
85 // d::e
86};
87
88mod a {
89 pub mod c {}
90 pub mod d {
91 pub mod e {}
92 }
93}
94"#,
95 );
96 check_diagnostics(
97 r#"
98use a::{self};
99
100mod a {
101}
102"#,
103 );
104 check_diagnostics(
105 r#"
106use a::{self as cool_name};
107
108mod a {
109}
110"#,
111 );
112
113 let mut config = DiagnosticsConfig::test_sample();
114 config.disabled.insert("syntax-error".to_owned());
115 check_diagnostics_with_config(
116 config,
117 r#"
118mod a { pub mod b {} }
119use a::{b::self};
120"#,
121 );
122 check_fix(
123 r#"
124mod b {}
125use {$0b};
126"#,
127 r#"
128mod b {}
129use b;
130"#,
131 );
132 check_fix(
133 r#"
134mod b {}
135use {b$0};
136"#,
137 r#"
138mod b {}
139use b;
140"#,
141 );
142 check_fix(
143 r#"
144mod a { pub mod c {} }
145use a::{c$0};
146"#,
147 r#"
148mod a { pub mod c {} }
149use a::c;
150"#,
151 );
152 check_fix(
153 r#"
154mod a { pub mod c {} pub mod d { pub mod e {} } }
155use a::{c, d::{e$0}};
156"#,
157 r#"
158mod a { pub mod c {} pub mod d { pub mod e {} } }
159use a::{c, d::e};
160"#,
161 );
162 }
163
164 #[test]
165 fn respect_lint_attributes_for_unused_braces() {
166 check_diagnostics(
167 r#"
168mod b {}
169#[allow(unused_braces)]
170use {b};
171"#,
172 );
173 check_diagnostics(
174 r#"
175mod b {}
176#[deny(unused_braces)]
177use {b};
178 //^^^ 💡 error: Unnecessary braces in use statement
179"#,
180 );
181 }
182}