1 use ide_db::{
2 base_db::{FileLoader, FileRange},
3 source_change::SourceChange,
4 };
5 use syntax::{TextRange, TextSize};
6 use text_edit::TextEdit;
7
8 use crate::{fix, Assist, Diagnostic, DiagnosticsContext};
9
10 // Diagnostic: remove-this-semicolon
11 //
12 // This diagnostic is triggered when there's an erroneous `;` at the end of the block.
remove_this_semicolon( ctx: &DiagnosticsContext<'_>, d: &hir::RemoveThisSemicolon, ) -> Diagnostic13 pub(crate) fn remove_this_semicolon(
14 ctx: &DiagnosticsContext<'_>,
15 d: &hir::RemoveThisSemicolon,
16 ) -> Diagnostic {
17 Diagnostic::new(
18 "remove-this-semicolon",
19 "remove this semicolon",
20 semicolon_range(ctx, d).unwrap_or_else(|it| it).range,
21 )
22 .with_fixes(fixes(ctx, d))
23 }
24
semicolon_range( ctx: &DiagnosticsContext<'_>, d: &hir::RemoveThisSemicolon, ) -> Result<FileRange, FileRange>25 fn semicolon_range(
26 ctx: &DiagnosticsContext<'_>,
27 d: &hir::RemoveThisSemicolon,
28 ) -> Result<FileRange, FileRange> {
29 let expr_range = ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into()));
30 let file_text = ctx.sema.db.file_text(expr_range.file_id);
31 let range_end: usize = expr_range.range.end().into();
32 // FIXME: This doesn't handle whitespace and comments, but handling those in
33 // the presence of macros might prove tricky...
34 if file_text[range_end..].starts_with(';') {
35 Ok(FileRange {
36 file_id: expr_range.file_id,
37 range: TextRange::at(expr_range.range.end(), TextSize::of(';')),
38 })
39 } else {
40 Err(expr_range)
41 }
42 }
43
fixes(ctx: &DiagnosticsContext<'_>, d: &hir::RemoveThisSemicolon) -> Option<Vec<Assist>>44 fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::RemoveThisSemicolon) -> Option<Vec<Assist>> {
45 let semicolon_range = semicolon_range(ctx, d).ok()?;
46
47 let edit = TextEdit::delete(semicolon_range.range);
48 let source_change = SourceChange::from_text_edit(semicolon_range.file_id, edit);
49
50 Some(vec![fix(
51 "remove_semicolon",
52 "Remove this semicolon",
53 source_change,
54 semicolon_range.range,
55 )])
56 }
57
58 #[cfg(test)]
59 mod tests {
60 use crate::tests::{check_diagnostics, check_fix};
61
62 #[test]
missing_semicolon()63 fn missing_semicolon() {
64 check_diagnostics(
65 r#"
66 fn test() -> i32 { 123; }
67 //^ error: remove this semicolon
68 "#,
69 );
70 }
71
72 #[test]
remove_semicolon()73 fn remove_semicolon() {
74 check_fix(r#"fn f() -> i32 { 92$0; }"#, r#"fn f() -> i32 { 92 }"#);
75 }
76 }
77