ide_diagnostics/handlers/
useless_braces.rs

1use 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
10// Diagnostic: unnecessary-braces
11//
12// Diagnostic for unnecessary braces in `use` items.
13pub(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 there is a `self` inside the bracketed `use`, don't show diagnostic.
22        if single_use_tree.path()?.segment()?.self_token().is_some() {
23            return Some(());
24        }
25
26        // If there is a comment inside the bracketed `use`,
27        // assume it is a commented out module path and don't show diagnostic.
28        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}