From 58712088ac2114e41d754ec6bcb5cd6bc3625256 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 14 Jun 2021 21:23:59 +0300 Subject: minor: make diagnostics more similar --- crates/ide_diagnostics/src/field_shorthand.rs | 203 --------------------- .../src/handlers/field_shorthand.rs | 203 +++++++++++++++++++++ .../ide_diagnostics/src/handlers/missing_fields.rs | 29 +++ .../ide_diagnostics/src/handlers/unlinked_file.rs | 23 +-- .../ide_diagnostics/src/handlers/useless_braces.rs | 148 +++++++++++++++ crates/ide_diagnostics/src/lib.rs | 203 ++------------------- 6 files changed, 406 insertions(+), 403 deletions(-) delete mode 100644 crates/ide_diagnostics/src/field_shorthand.rs create mode 100644 crates/ide_diagnostics/src/handlers/field_shorthand.rs create mode 100644 crates/ide_diagnostics/src/handlers/useless_braces.rs diff --git a/crates/ide_diagnostics/src/field_shorthand.rs b/crates/ide_diagnostics/src/field_shorthand.rs deleted file mode 100644 index 0b6af9965..000000000 --- a/crates/ide_diagnostics/src/field_shorthand.rs +++ /dev/null @@ -1,203 +0,0 @@ -//! Suggests shortening `Foo { field: field }` to `Foo { field }` in both -//! expressions and patterns. - -use ide_db::{base_db::FileId, source_change::SourceChange}; -use syntax::{ast, match_ast, AstNode, SyntaxNode}; -use text_edit::TextEdit; - -use crate::{fix, Diagnostic, Severity}; - -pub(super) fn check(acc: &mut Vec, file_id: FileId, node: &SyntaxNode) { - match_ast! { - match node { - ast::RecordExpr(it) => check_expr_field_shorthand(acc, file_id, it), - ast::RecordPat(it) => check_pat_field_shorthand(acc, file_id, it), - _ => () - } - }; -} - -fn check_expr_field_shorthand( - acc: &mut Vec, - file_id: FileId, - record_expr: ast::RecordExpr, -) { - let record_field_list = match record_expr.record_expr_field_list() { - Some(it) => it, - None => return, - }; - for record_field in record_field_list.fields() { - let (name_ref, expr) = match record_field.name_ref().zip(record_field.expr()) { - Some(it) => it, - None => continue, - }; - - let field_name = name_ref.syntax().text().to_string(); - let field_expr = expr.syntax().text().to_string(); - let field_name_is_tup_index = name_ref.as_tuple_field().is_some(); - if field_name != field_expr || field_name_is_tup_index { - continue; - } - - let mut edit_builder = TextEdit::builder(); - edit_builder.delete(record_field.syntax().text_range()); - edit_builder.insert(record_field.syntax().text_range().start(), field_name); - let edit = edit_builder.finish(); - - let field_range = record_field.syntax().text_range(); - acc.push( - Diagnostic::new("use-field-shorthand", "Shorthand struct initialization", field_range) - .severity(Severity::WeakWarning) - .with_fixes(Some(vec![fix( - "use_expr_field_shorthand", - "Use struct shorthand initialization", - SourceChange::from_text_edit(file_id, edit), - field_range, - )])), - ); - } -} - -fn check_pat_field_shorthand( - acc: &mut Vec, - file_id: FileId, - record_pat: ast::RecordPat, -) { - let record_pat_field_list = match record_pat.record_pat_field_list() { - Some(it) => it, - None => return, - }; - for record_pat_field in record_pat_field_list.fields() { - let (name_ref, pat) = match record_pat_field.name_ref().zip(record_pat_field.pat()) { - Some(it) => it, - None => continue, - }; - - let field_name = name_ref.syntax().text().to_string(); - let field_pat = pat.syntax().text().to_string(); - let field_name_is_tup_index = name_ref.as_tuple_field().is_some(); - if field_name != field_pat || field_name_is_tup_index { - continue; - } - - let mut edit_builder = TextEdit::builder(); - edit_builder.delete(record_pat_field.syntax().text_range()); - edit_builder.insert(record_pat_field.syntax().text_range().start(), field_name); - let edit = edit_builder.finish(); - - let field_range = record_pat_field.syntax().text_range(); - acc.push( - Diagnostic::new("use-field-shorthand", "Shorthand struct pattern", field_range) - .severity(Severity::WeakWarning) - .with_fixes(Some(vec![fix( - "use_pat_field_shorthand", - "Use struct field shorthand", - SourceChange::from_text_edit(file_id, edit), - field_range, - )])), - ); - } -} - -#[cfg(test)] -mod tests { - use crate::tests::{check_diagnostics, check_fix}; - - #[test] - fn test_check_expr_field_shorthand() { - check_diagnostics( - r#" -struct A { a: &'static str } -fn main() { A { a: "hello" } } -"#, - ); - check_diagnostics( - r#" -struct A(usize); -fn main() { A { 0: 0 } } -"#, - ); - - check_fix( - r#" -struct A { a: &'static str } -fn main() { - let a = "haha"; - A { a$0: a } -} -"#, - r#" -struct A { a: &'static str } -fn main() { - let a = "haha"; - A { a } -} -"#, - ); - - check_fix( - r#" -struct A { a: &'static str, b: &'static str } -fn main() { - let a = "haha"; - let b = "bb"; - A { a$0: a, b } -} -"#, - r#" -struct A { a: &'static str, b: &'static str } -fn main() { - let a = "haha"; - let b = "bb"; - A { a, b } -} -"#, - ); - } - - #[test] - fn test_check_pat_field_shorthand() { - check_diagnostics( - r#" -struct A { a: &'static str } -fn f(a: A) { let A { a: hello } = a; } -"#, - ); - check_diagnostics( - r#" -struct A(usize); -fn f(a: A) { let A { 0: 0 } = a; } -"#, - ); - - check_fix( - r#" -struct A { a: &'static str } -fn f(a: A) { - let A { a$0: a } = a; -} -"#, - r#" -struct A { a: &'static str } -fn f(a: A) { - let A { a } = a; -} -"#, - ); - - check_fix( - r#" -struct A { a: &'static str, b: &'static str } -fn f(a: A) { - let A { a$0: a, b } = a; -} -"#, - r#" -struct A { a: &'static str, b: &'static str } -fn f(a: A) { - let A { a, b } = a; -} -"#, - ); - } -} diff --git a/crates/ide_diagnostics/src/handlers/field_shorthand.rs b/crates/ide_diagnostics/src/handlers/field_shorthand.rs new file mode 100644 index 000000000..33152e284 --- /dev/null +++ b/crates/ide_diagnostics/src/handlers/field_shorthand.rs @@ -0,0 +1,203 @@ +//! Suggests shortening `Foo { field: field }` to `Foo { field }` in both +//! expressions and patterns. + +use ide_db::{base_db::FileId, source_change::SourceChange}; +use syntax::{ast, match_ast, AstNode, SyntaxNode}; +use text_edit::TextEdit; + +use crate::{fix, Diagnostic, Severity}; + +pub(crate) fn field_shorthand(acc: &mut Vec, file_id: FileId, node: &SyntaxNode) { + match_ast! { + match node { + ast::RecordExpr(it) => check_expr_field_shorthand(acc, file_id, it), + ast::RecordPat(it) => check_pat_field_shorthand(acc, file_id, it), + _ => () + } + }; +} + +fn check_expr_field_shorthand( + acc: &mut Vec, + file_id: FileId, + record_expr: ast::RecordExpr, +) { + let record_field_list = match record_expr.record_expr_field_list() { + Some(it) => it, + None => return, + }; + for record_field in record_field_list.fields() { + let (name_ref, expr) = match record_field.name_ref().zip(record_field.expr()) { + Some(it) => it, + None => continue, + }; + + let field_name = name_ref.syntax().text().to_string(); + let field_expr = expr.syntax().text().to_string(); + let field_name_is_tup_index = name_ref.as_tuple_field().is_some(); + if field_name != field_expr || field_name_is_tup_index { + continue; + } + + let mut edit_builder = TextEdit::builder(); + edit_builder.delete(record_field.syntax().text_range()); + edit_builder.insert(record_field.syntax().text_range().start(), field_name); + let edit = edit_builder.finish(); + + let field_range = record_field.syntax().text_range(); + acc.push( + Diagnostic::new("use-field-shorthand", "Shorthand struct initialization", field_range) + .severity(Severity::WeakWarning) + .with_fixes(Some(vec![fix( + "use_expr_field_shorthand", + "Use struct shorthand initialization", + SourceChange::from_text_edit(file_id, edit), + field_range, + )])), + ); + } +} + +fn check_pat_field_shorthand( + acc: &mut Vec, + file_id: FileId, + record_pat: ast::RecordPat, +) { + let record_pat_field_list = match record_pat.record_pat_field_list() { + Some(it) => it, + None => return, + }; + for record_pat_field in record_pat_field_list.fields() { + let (name_ref, pat) = match record_pat_field.name_ref().zip(record_pat_field.pat()) { + Some(it) => it, + None => continue, + }; + + let field_name = name_ref.syntax().text().to_string(); + let field_pat = pat.syntax().text().to_string(); + let field_name_is_tup_index = name_ref.as_tuple_field().is_some(); + if field_name != field_pat || field_name_is_tup_index { + continue; + } + + let mut edit_builder = TextEdit::builder(); + edit_builder.delete(record_pat_field.syntax().text_range()); + edit_builder.insert(record_pat_field.syntax().text_range().start(), field_name); + let edit = edit_builder.finish(); + + let field_range = record_pat_field.syntax().text_range(); + acc.push( + Diagnostic::new("use-field-shorthand", "Shorthand struct pattern", field_range) + .severity(Severity::WeakWarning) + .with_fixes(Some(vec![fix( + "use_pat_field_shorthand", + "Use struct field shorthand", + SourceChange::from_text_edit(file_id, edit), + field_range, + )])), + ); + } +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_diagnostics, check_fix}; + + #[test] + fn test_check_expr_field_shorthand() { + check_diagnostics( + r#" +struct A { a: &'static str } +fn main() { A { a: "hello" } } +"#, + ); + check_diagnostics( + r#" +struct A(usize); +fn main() { A { 0: 0 } } +"#, + ); + + check_fix( + r#" +struct A { a: &'static str } +fn main() { + let a = "haha"; + A { a$0: a } +} +"#, + r#" +struct A { a: &'static str } +fn main() { + let a = "haha"; + A { a } +} +"#, + ); + + check_fix( + r#" +struct A { a: &'static str, b: &'static str } +fn main() { + let a = "haha"; + let b = "bb"; + A { a$0: a, b } +} +"#, + r#" +struct A { a: &'static str, b: &'static str } +fn main() { + let a = "haha"; + let b = "bb"; + A { a, b } +} +"#, + ); + } + + #[test] + fn test_check_pat_field_shorthand() { + check_diagnostics( + r#" +struct A { a: &'static str } +fn f(a: A) { let A { a: hello } = a; } +"#, + ); + check_diagnostics( + r#" +struct A(usize); +fn f(a: A) { let A { 0: 0 } = a; } +"#, + ); + + check_fix( + r#" +struct A { a: &'static str } +fn f(a: A) { + let A { a$0: a } = a; +} +"#, + r#" +struct A { a: &'static str } +fn f(a: A) { + let A { a } = a; +} +"#, + ); + + check_fix( + r#" +struct A { a: &'static str, b: &'static str } +fn f(a: A) { + let A { a$0: a, b } = a; +} +"#, + r#" +struct A { a: &'static str, b: &'static str } +fn f(a: A) { + let A { a, b } = a; +} +"#, + ); + } +} diff --git a/crates/ide_diagnostics/src/handlers/missing_fields.rs b/crates/ide_diagnostics/src/handlers/missing_fields.rs index bc82c0e4a..0dd36fb23 100644 --- a/crates/ide_diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide_diagnostics/src/handlers/missing_fields.rs @@ -323,4 +323,33 @@ fn f() { "#, ); } + + #[test] + fn import_extern_crate_clash_with_inner_item() { + // This is more of a resolver test, but doesn't really work with the hir_def testsuite. + + check_diagnostics( + r#" +//- /lib.rs crate:lib deps:jwt +mod permissions; + +use permissions::jwt; + +fn f() { + fn inner() {} + jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic +} + +//- /permissions.rs +pub mod jwt { + pub struct Claims {} +} + +//- /jwt/lib.rs crate:jwt +pub struct Claims { + field: u8, +} + "#, + ); + } } diff --git a/crates/ide_diagnostics/src/handlers/unlinked_file.rs b/crates/ide_diagnostics/src/handlers/unlinked_file.rs index 8921ddde2..8e601fa48 100644 --- a/crates/ide_diagnostics/src/handlers/unlinked_file.rs +++ b/crates/ide_diagnostics/src/handlers/unlinked_file.rs @@ -14,32 +14,29 @@ use text_edit::TextEdit; use crate::{fix, Assist, Diagnostic, DiagnosticsContext}; -#[derive(Debug)] -pub(crate) struct UnlinkedFile { - pub(crate) file: FileId, -} - // Diagnostic: unlinked-file // // This diagnostic is shown for files that are not included in any crate, or files that are part of // crates rust-analyzer failed to discover. The file will not have IDE features available. -pub(crate) fn unlinked_file(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Diagnostic { +pub(crate) fn unlinked_file(ctx: &DiagnosticsContext, acc: &mut Vec, file_id: FileId) { // Limit diagnostic to the first few characters in the file. This matches how VS Code // renders it with the full span, but on other editors, and is less invasive. - let range = ctx.sema.db.parse(d.file).syntax_node().text_range(); + let range = ctx.sema.db.parse(file_id).syntax_node().text_range(); // FIXME: This is wrong if one of the first three characters is not ascii: `//Ы`. let range = range.intersect(TextRange::up_to(TextSize::of("..."))).unwrap_or(range); - Diagnostic::new("unlinked-file", "file not included in module tree", range) - .with_fixes(fixes(ctx, d)) + acc.push( + Diagnostic::new("unlinked-file", "file not included in module tree", range) + .with_fixes(fixes(ctx, file_id)), + ); } -fn fixes(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Option> { +fn fixes(ctx: &DiagnosticsContext, file_id: FileId) -> Option> { // If there's an existing module that could add `mod` or `pub mod` items to include the unlinked file, // suggest that as a fix. - let source_root = ctx.sema.db.source_root(ctx.sema.db.file_source_root(d.file)); - let our_path = source_root.path_for_file(&d.file)?; + let source_root = ctx.sema.db.source_root(ctx.sema.db.file_source_root(file_id)); + let our_path = source_root.path_for_file(&file_id)?; let module_name = our_path.name_and_extension()?.0; // Candidates to look for: @@ -68,7 +65,7 @@ fn fixes(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Option> { } if module.origin.file_id() == Some(*parent_id) { - return make_fixes(ctx.sema.db, *parent_id, module_name, d.file); + return make_fixes(ctx.sema.db, *parent_id, module_name, file_id); } } } diff --git a/crates/ide_diagnostics/src/handlers/useless_braces.rs b/crates/ide_diagnostics/src/handlers/useless_braces.rs new file mode 100644 index 000000000..8b9330e04 --- /dev/null +++ b/crates/ide_diagnostics/src/handlers/useless_braces.rs @@ -0,0 +1,148 @@ +use ide_db::{base_db::FileId, source_change::SourceChange}; +use itertools::Itertools; +use syntax::{ast, AstNode, SyntaxNode, TextRange}; +use text_edit::TextEdit; + +use crate::{fix, Diagnostic, Severity}; + +// Diagnostic: unnecessary-braces +// +// Diagnostic for unnecessary braces in `use` items. +pub(crate) fn useless_braces( + acc: &mut Vec, + file_id: FileId, + node: &SyntaxNode, +) -> Option<()> { + let use_tree_list = ast::UseTreeList::cast(node.clone())?; + if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() { + // If there is a comment inside the bracketed `use`, + // assume it is a commented out module path and don't show diagnostic. + if use_tree_list.has_inner_comment() { + return Some(()); + } + + let use_range = use_tree_list.syntax().text_range(); + let edit = remove_braces(&single_use_tree).unwrap_or_else(|| { + let to_replace = single_use_tree.syntax().text().to_string(); + let mut edit_builder = TextEdit::builder(); + edit_builder.delete(use_range); + edit_builder.insert(use_range.start(), to_replace); + edit_builder.finish() + }); + + acc.push( + Diagnostic::new( + "unnecessary-braces", + "Unnecessary braces in use statement".to_string(), + use_range, + ) + .severity(Severity::WeakWarning) + .with_fixes(Some(vec![fix( + "remove_braces", + "Remove unnecessary braces", + SourceChange::from_text_edit(file_id, edit), + use_range, + )])), + ); + } + + Some(()) +} + +fn remove_braces(single_use_tree: &ast::UseTree) -> Option { + let use_tree_list_node = single_use_tree.syntax().parent()?; + if single_use_tree.path()?.segment()?.self_token().is_some() { + let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start(); + let end = use_tree_list_node.text_range().end(); + return Some(TextEdit::delete(TextRange::new(start, end))); + } + None +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_diagnostics, check_fix}; + + #[test] + fn test_check_unnecessary_braces_in_use_statement() { + check_diagnostics( + r#" +use a; +use a::{c, d::e}; + +mod a { + mod c {} + mod d { + mod e {} + } +} +"#, + ); + check_diagnostics( + r#" +use a; +use a::{ + c, + // d::e +}; + +mod a { + mod c {} + mod d { + mod e {} + } +} +"#, + ); + check_fix( + r#" +mod b {} +use {$0b}; +"#, + r#" +mod b {} +use b; +"#, + ); + check_fix( + r#" +mod b {} +use {b$0}; +"#, + r#" +mod b {} +use b; +"#, + ); + check_fix( + r#" +mod a { mod c {} } +use a::{c$0}; +"#, + r#" +mod a { mod c {} } +use a::c; +"#, + ); + check_fix( + r#" +mod a {} +use a::{self$0}; +"#, + r#" +mod a {} +use a; +"#, + ); + check_fix( + r#" +mod a { mod c {} mod d { mod e {} } } +use a::{c, d::{e$0}}; +"#, + r#" +mod a { mod c {} mod d { mod e {} } } +use a::{c, d::e}; +"#, + ); + } +} diff --git a/crates/ide_diagnostics/src/lib.rs b/crates/ide_diagnostics/src/lib.rs index 88037be5a..52474eeab 100644 --- a/crates/ide_diagnostics/src/lib.rs +++ b/crates/ide_diagnostics/src/lib.rs @@ -37,15 +37,17 @@ mod handlers { pub(crate) mod remove_this_semicolon; pub(crate) mod replace_filter_map_next_with_find_map; pub(crate) mod unimplemented_builtin_macro; - pub(crate) mod unlinked_file; pub(crate) mod unresolved_extern_crate; pub(crate) mod unresolved_import; pub(crate) mod unresolved_macro_call; pub(crate) mod unresolved_module; pub(crate) mod unresolved_proc_macro; -} -mod field_shorthand; + // The handlers bellow are unusual, the implement the diagnostics as well. + pub(crate) mod field_shorthand; + pub(crate) mod useless_braces; + pub(crate) mod unlinked_file; +} use hir::{diagnostics::AnyDiagnostic, Semantics}; use ide_db::{ @@ -55,15 +57,8 @@ use ide_db::{ source_change::SourceChange, RootDatabase, }; -use itertools::Itertools; use rustc_hash::FxHashSet; -use syntax::{ - ast::{self, AstNode}, - SyntaxNode, TextRange, -}; -use text_edit::TextEdit; - -use crate::handlers::unlinked_file::UnlinkedFile; +use syntax::{ast::AstNode, TextRange}; #[derive(Copy, Clone, Debug, PartialEq)] pub struct DiagnosticCode(pub &'static str); @@ -123,6 +118,8 @@ impl Diagnostic { #[derive(Debug, Copy, Clone)] pub enum Severity { Error, + // We don't actually emit this one yet, but we should at some point. + // Warning, WeakWarning, } @@ -157,21 +154,20 @@ pub fn diagnostics( ); for node in parse.tree().syntax().descendants() { - check_unnecessary_braces_in_use_statement(&mut res, file_id, &node); - field_shorthand::check(&mut res, file_id, &node); + handlers::useless_braces::useless_braces(&mut res, file_id, &node); + handlers::field_shorthand::field_shorthand(&mut res, file_id, &node); } - let mut diags = Vec::new(); let module = sema.to_module_def(file_id); - if let Some(m) = module { - m.diagnostics(db, &mut diags) - } let ctx = DiagnosticsContext { config, sema, resolve }; if module.is_none() { - let d = UnlinkedFile { file: file_id }; - let d = handlers::unlinked_file::unlinked_file(&ctx, &d); - res.push(d) + handlers::unlinked_file::unlinked_file(&ctx, &mut res, file_id); + } + + let mut diags = Vec::new(); + if let Some(m) = module { + m.diagnostics(db, &mut diags) } for diag in diags { @@ -211,61 +207,6 @@ pub fn diagnostics( res } -fn check_unnecessary_braces_in_use_statement( - acc: &mut Vec, - file_id: FileId, - node: &SyntaxNode, -) -> Option<()> { - let use_tree_list = ast::UseTreeList::cast(node.clone())?; - if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() { - // If there is a comment inside the bracketed `use`, - // assume it is a commented out module path and don't show diagnostic. - if use_tree_list.has_inner_comment() { - return Some(()); - } - - let use_range = use_tree_list.syntax().text_range(); - let edit = - text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(&single_use_tree) - .unwrap_or_else(|| { - let to_replace = single_use_tree.syntax().text().to_string(); - let mut edit_builder = TextEdit::builder(); - edit_builder.delete(use_range); - edit_builder.insert(use_range.start(), to_replace); - edit_builder.finish() - }); - - acc.push( - Diagnostic::new( - "unnecessary-braces", - "Unnecessary braces in use statement".to_string(), - use_range, - ) - .severity(Severity::WeakWarning) - .with_fixes(Some(vec![fix( - "remove_braces", - "Remove unnecessary braces", - SourceChange::from_text_edit(file_id, edit), - use_range, - )])), - ); - } - - Some(()) -} - -fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement( - single_use_tree: &ast::UseTree, -) -> Option { - let use_tree_list_node = single_use_tree.syntax().parent()?; - if single_use_tree.path()?.segment()?.self_token().is_some() { - let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start(); - let end = use_tree_list_node.text_range().end(); - return Some(TextEdit::delete(TextRange::new(start, end))); - } - None -} - fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist { let mut res = unresolved_fix(id, label, target); res.source_change = Some(source_change); @@ -397,89 +338,6 @@ mod tests { } } - #[test] - fn test_check_unnecessary_braces_in_use_statement() { - check_diagnostics( - r#" -use a; -use a::{c, d::e}; - -mod a { - mod c {} - mod d { - mod e {} - } -} -"#, - ); - check_diagnostics( - r#" -use a; -use a::{ - c, - // d::e -}; - -mod a { - mod c {} - mod d { - mod e {} - } -} -"#, - ); - check_fix( - r" - mod b {} - use {$0b}; - ", - r" - mod b {} - use b; - ", - ); - check_fix( - r" - mod b {} - use {b$0}; - ", - r" - mod b {} - use b; - ", - ); - check_fix( - r" - mod a { mod c {} } - use a::{c$0}; - ", - r" - mod a { mod c {} } - use a::c; - ", - ); - check_fix( - r" - mod a {} - use a::{self$0}; - ", - r" - mod a {} - use a; - ", - ); - check_fix( - r" - mod a { mod c {} mod d { mod e {} } } - use a::{c, d::{e$0}}; - ", - r" - mod a { mod c {} mod d { mod e {} } } - use a::{c, d::e}; - ", - ); - } - #[test] fn test_disabled_diagnostics() { let mut config = DiagnosticsConfig::default(); @@ -498,33 +356,4 @@ mod a { ); assert!(!diagnostics.is_empty()); } - - #[test] - fn import_extern_crate_clash_with_inner_item() { - // This is more of a resolver test, but doesn't really work with the hir_def testsuite. - - check_diagnostics( - r#" -//- /lib.rs crate:lib deps:jwt -mod permissions; - -use permissions::jwt; - -fn f() { - fn inner() {} - jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic -} - -//- /permissions.rs -pub mod jwt { - pub struct Claims {} -} - -//- /jwt/lib.rs crate:jwt -pub struct Claims { - field: u8, -} - "#, - ); - } } -- cgit v1.2.3 From 4cfc767d7fadeab025227d67f104065c9e8a55d3 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 14 Jun 2021 22:06:28 +0300 Subject: internal: test diagnostic severeties and presense of fixes --- .../src/handlers/break_outside_of_loop.rs | 2 +- .../ide_diagnostics/src/handlers/inactive_code.rs | 26 +++--- .../ide_diagnostics/src/handlers/incorrect_case.rs | 42 +++++----- crates/ide_diagnostics/src/handlers/macro_error.rs | 20 ++--- .../src/handlers/mismatched_arg_count.rs | 22 ++--- .../ide_diagnostics/src/handlers/missing_fields.rs | 4 +- .../src/handlers/missing_match_arms.rs | 96 +++++++++++----------- .../ide_diagnostics/src/handlers/missing_unsafe.rs | 10 +-- .../ide_diagnostics/src/handlers/no_such_field.rs | 4 +- .../src/handlers/remove_this_semicolon.rs | 2 +- .../replace_filter_map_next_with_find_map.rs | 14 ++-- .../src/handlers/unresolved_extern_crate.rs | 4 +- .../src/handlers/unresolved_import.rs | 18 ++-- .../src/handlers/unresolved_macro_call.rs | 8 +- .../src/handlers/unresolved_module.rs | 2 +- crates/ide_diagnostics/src/lib.rs | 21 ++++- 16 files changed, 155 insertions(+), 140 deletions(-) diff --git a/crates/ide_diagnostics/src/handlers/break_outside_of_loop.rs b/crates/ide_diagnostics/src/handlers/break_outside_of_loop.rs index 5ad0fbd1b..d12594a4c 100644 --- a/crates/ide_diagnostics/src/handlers/break_outside_of_loop.rs +++ b/crates/ide_diagnostics/src/handlers/break_outside_of_loop.rs @@ -23,7 +23,7 @@ mod tests { check_diagnostics( r#" fn foo() { break; } - //^^^^^ break outside of loop + //^^^^^ error: break outside of loop "#, ); } diff --git a/crates/ide_diagnostics/src/handlers/inactive_code.rs b/crates/ide_diagnostics/src/handlers/inactive_code.rs index 4b722fd64..dfd0e3351 100644 --- a/crates/ide_diagnostics/src/handlers/inactive_code.rs +++ b/crates/ide_diagnostics/src/handlers/inactive_code.rs @@ -49,26 +49,26 @@ fn f() { // The three g̶e̶n̶d̶e̶r̶s̶ statements: #[cfg(a)] fn f() {} // Item statement - //^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled + //^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled #[cfg(a)] {} // Expression statement - //^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled + //^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled #[cfg(a)] let x = 0; // let statement - //^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled + //^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled abc(#[cfg(a)] 0); - //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled + //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled let x = Struct { #[cfg(a)] f: 0, - //^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled + //^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled }; match () { () => (), #[cfg(a)] () => (), - //^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled + //^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled } #[cfg(a)] 0 // Trailing expression of block - //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled + //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled } "#, ); @@ -81,16 +81,16 @@ fn f() { check( r#" #[cfg(no)] pub fn f() {} - //^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled + //^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled #[cfg(no)] #[cfg(no2)] mod m; - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no and no2 are disabled + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no and no2 are disabled #[cfg(all(not(a), b))] enum E {} - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: b is disabled + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: b is disabled #[cfg(feature = "std")] use std; - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: feature = "std" is disabled + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: feature = "std" is disabled "#, ); } @@ -102,14 +102,14 @@ fn f() { check( r#" #[cfg_attr(not(never), cfg(no))] fn f() {} - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled #[cfg_attr(not(never), cfg(not(no)))] fn f() {} #[cfg_attr(never, cfg(no))] fn g() {} #[cfg_attr(not(never), inline, cfg(no))] fn h() {} - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled "#, ); } diff --git a/crates/ide_diagnostics/src/handlers/incorrect_case.rs b/crates/ide_diagnostics/src/handlers/incorrect_case.rs index 3a33029cf..72f251961 100644 --- a/crates/ide_diagnostics/src/handlers/incorrect_case.rs +++ b/crates/ide_diagnostics/src/handlers/incorrect_case.rs @@ -149,7 +149,7 @@ impl TestStruct { check_diagnostics( r#" fn FOO() {} -// ^^^ Function `FOO` should have snake_case name, e.g. `foo` +// ^^^ 💡 weak: Function `FOO` should have snake_case name, e.g. `foo` "#, ); check_fix(r#"fn FOO$0() {}"#, r#"fn foo() {}"#); @@ -160,7 +160,7 @@ fn FOO() {} check_diagnostics( r#" fn NonSnakeCaseName() {} -// ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` +// ^^^^^^^^^^^^^^^^ 💡 weak: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` "#, ); } @@ -170,10 +170,10 @@ fn NonSnakeCaseName() {} check_diagnostics( r#" fn foo(SomeParam: u8) {} - // ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param` + // ^^^^^^^^^ 💡 weak: Parameter `SomeParam` should have snake_case name, e.g. `some_param` fn foo2(ok_param: &str, CAPS_PARAM: u8) {} - // ^^^^^^^^^^ Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param` + // ^^^^^^^^^^ 💡 weak: Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param` "#, ); } @@ -184,9 +184,9 @@ fn foo2(ok_param: &str, CAPS_PARAM: u8) {} r#" fn foo() { let SOME_VALUE = 10; - // ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value` + // ^^^^^^^^^^ 💡 weak: Variable `SOME_VALUE` should have snake_case name, e.g. `some_value` let AnotherValue = 20; - // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value` + // ^^^^^^^^^^^^ 💡 weak: Variable `AnotherValue` should have snake_case name, e.g. `another_value` } "#, ); @@ -197,10 +197,10 @@ fn foo() { check_diagnostics( r#" struct non_camel_case_name {} - // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName` + // ^^^^^^^^^^^^^^^^^^^ 💡 weak: Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName` struct SCREAMING_CASE {} - // ^^^^^^^^^^^^^^ Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase` + // ^^^^^^^^^^^^^^ 💡 weak: Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase` "#, ); } @@ -219,7 +219,7 @@ struct AABB {} check_diagnostics( r#" struct SomeStruct { SomeField: u8 } - // ^^^^^^^^^ Field `SomeField` should have snake_case name, e.g. `some_field` + // ^^^^^^^^^ 💡 weak: Field `SomeField` should have snake_case name, e.g. `some_field` "#, ); } @@ -229,10 +229,10 @@ struct SomeStruct { SomeField: u8 } check_diagnostics( r#" enum some_enum { Val(u8) } - // ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum` + // ^^^^^^^^^ 💡 weak: Enum `some_enum` should have CamelCase name, e.g. `SomeEnum` enum SOME_ENUM {} - // ^^^^^^^^^ Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum` + // ^^^^^^^^^ 💡 weak: Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum` "#, ); } @@ -251,7 +251,7 @@ enum AABB {} check_diagnostics( r#" enum SomeEnum { SOME_VARIANT(u8) } - // ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant` + // ^^^^^^^^^^^^ 💡 weak: Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant` "#, ); } @@ -261,7 +261,7 @@ enum SomeEnum { SOME_VARIANT(u8) } check_diagnostics( r#" const some_weird_const: u8 = 10; - // ^^^^^^^^^^^^^^^^ Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` + // ^^^^^^^^^^^^^^^^ 💡 weak: Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` "#, ); } @@ -271,7 +271,7 @@ const some_weird_const: u8 = 10; check_diagnostics( r#" static some_weird_const: u8 = 10; - // ^^^^^^^^^^^^^^^^ Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` + // ^^^^^^^^^^^^^^^^ 💡 weak: Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` "#, ); } @@ -281,13 +281,13 @@ static some_weird_const: u8 = 10; check_diagnostics( r#" struct someStruct; - // ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct` + // ^^^^^^^^^^ 💡 weak: Structure `someStruct` should have CamelCase name, e.g. `SomeStruct` impl someStruct { fn SomeFunc(&self) { - // ^^^^^^^^ Function `SomeFunc` should have snake_case name, e.g. `some_func` + // ^^^^^^^^ 💡 weak: Function `SomeFunc` should have snake_case name, e.g. `some_func` let WHY_VAR_IS_CAPS = 10; - // ^^^^^^^^^^^^^^^ Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps` + // ^^^^^^^^^^^^^^^ 💡 weak: Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps` } } "#, @@ -319,7 +319,7 @@ enum Option { Some, None } fn main() { match Option::None { SOME_VAR @ None => (), - // ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var` + // ^^^^^^^^ 💡 weak: Variable `SOME_VAR` should have snake_case name, e.g. `some_var` Some => (), } } @@ -421,11 +421,11 @@ extern { check_diagnostics( r#" trait BAD_TRAIT { - // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait` + // ^^^^^^^^^ 💡 weak: Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait` fn BAD_FUNCTION(); - // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function` + // ^^^^^^^^^^^^ 💡 weak: Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function` fn BadFunction(); - // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function` + // ^^^^^^^^^^^^ 💡 weak: Function `BadFunction` should have snake_case name, e.g. `bad_function` } "#, ); diff --git a/crates/ide_diagnostics/src/handlers/macro_error.rs b/crates/ide_diagnostics/src/handlers/macro_error.rs index d4d928ad1..356f089b2 100644 --- a/crates/ide_diagnostics/src/handlers/macro_error.rs +++ b/crates/ide_diagnostics/src/handlers/macro_error.rs @@ -27,7 +27,7 @@ mod tests { macro_rules! include { () => {} } include!("doesntexist"); -//^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `doesntexist` +//^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `doesntexist` "#, ); } @@ -66,7 +66,7 @@ macro_rules! env { () => {} } macro_rules! concat { () => {} } include!(concat!(env!("OUT_DIR"), "/out.rs")); -//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, enable "run build scripts" to fix "#, ); } @@ -108,23 +108,23 @@ fn main() { // Test a handful of built-in (eager) macros: include!(invalid); - //^^^^^^^^^^^^^^^^^ could not convert tokens + //^^^^^^^^^^^^^^^^^ error: could not convert tokens include!("does not exist"); - //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `does not exist` + //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `does not exist` env!(invalid); - //^^^^^^^^^^^^^ could not convert tokens + //^^^^^^^^^^^^^ error: could not convert tokens env!("OUT_DIR"); - //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix + //^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, enable "run build scripts" to fix compile_error!("compile_error works"); - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: compile_error works // Lazy: format_args!(); - //^^^^^^^^^^^^^^ no rule matches input tokens + //^^^^^^^^^^^^^^ error: no rule matches input tokens } "#, ); @@ -141,7 +141,7 @@ fn f() { m!(); m!(hi); - //^^^^^^ leftover tokens + //^^^^^^ error: leftover tokens } "#, ); @@ -166,7 +166,7 @@ macro_rules! outer { fn f() { outer!(); -} //^^^^^^^^ leftover tokens +} //^^^^^^^^ error: leftover tokens "#, ) } diff --git a/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs b/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs index ce313b2cc..a9b6d3870 100644 --- a/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs +++ b/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs @@ -26,7 +26,7 @@ mod tests { r#" fn zero() {} fn f() { zero(1); } - //^^^^^^^ expected 0 arguments, found 1 + //^^^^^^^ error: expected 0 arguments, found 1 "#, ); @@ -44,7 +44,7 @@ fn f() { zero(); } r#" fn one(arg: u8) {} fn f() { one(); } - //^^^^^ expected 1 argument, found 0 + //^^^^^ error: expected 1 argument, found 0 "#, ); @@ -65,7 +65,7 @@ impl S { fn method(&self) {} } fn f() { S::method(); -} //^^^^^^^^^^^ expected 1 argument, found 0 +} //^^^^^^^^^^^ error: expected 1 argument, found 0 "#, ); @@ -91,7 +91,7 @@ impl S { fn method(&self, arg: u8) {} } fn f() { S.method(); - } //^^^^^^^^^^ expected 1 argument, found 0 + } //^^^^^^^^^^ error: expected 1 argument, found 0 "#, ); @@ -131,7 +131,7 @@ fn f() { struct Tup(u8, u16); fn f() { Tup(0); -} //^^^^^^ expected 2 arguments, found 1 +} //^^^^^^ error: expected 2 arguments, found 1 "#, ) } @@ -143,7 +143,7 @@ fn f() { enum En { Variant(u8, u16), } fn f() { En::Variant(0); -} //^^^^^^^^^^^^^^ expected 2 arguments, found 1 +} //^^^^^^^^^^^^^^ error: expected 2 arguments, found 1 "#, ) } @@ -162,9 +162,9 @@ impl Foo { fn new() { Foo::Bar(0); Foo::Bar(0, 1); - //^^^^^^^^^^^^^^ expected 1 argument, found 2 + //^^^^^^^^^^^^^^ error: expected 1 argument, found 2 Foo::Bar(); - //^^^^^^^^^^ expected 1 argument, found 0 + //^^^^^^^^^^ error: expected 1 argument, found 0 } } "#, @@ -185,7 +185,7 @@ fn f() { unsafe { fixed(0); fixed(0, 1); - //^^^^^^^^^^^ expected 1 argument, found 2 + //^^^^^^^^^^^ error: expected 1 argument, found 2 varargs(0); varargs(0, 1); varargs2(); @@ -204,10 +204,10 @@ fn f() { fn main() { let f = |()| (); f(); - //^^^ expected 1 argument, found 0 + //^^^ error: expected 1 argument, found 0 f(()); f((), ()); - //^^^^^^^^^ expected 1 argument, found 2 + //^^^^^^^^^ error: expected 1 argument, found 2 } "#, ) diff --git a/crates/ide_diagnostics/src/handlers/missing_fields.rs b/crates/ide_diagnostics/src/handlers/missing_fields.rs index 0dd36fb23..bc56e0342 100644 --- a/crates/ide_diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide_diagnostics/src/handlers/missing_fields.rs @@ -19,7 +19,7 @@ use crate::{fix, Diagnostic, DiagnosticsContext}; // let a = A { a: 10 }; // ``` pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic { - let mut message = String::from("Missing structure fields:\n"); + let mut message = String::from("missing structure fields:\n"); for field in &d.missed_fields { format_to!(message, "- {}\n", field); } @@ -85,7 +85,7 @@ mod tests { struct S { foo: i32, bar: () } fn baz(s: S) { let S { foo: _ } = s; - //^ Missing structure fields: + //^ error: missing structure fields: //| - bar } "#, diff --git a/crates/ide_diagnostics/src/handlers/missing_match_arms.rs b/crates/ide_diagnostics/src/handlers/missing_match_arms.rs index 9ea533d74..947b0f2e2 100644 --- a/crates/ide_diagnostics/src/handlers/missing_match_arms.rs +++ b/crates/ide_diagnostics/src/handlers/missing_match_arms.rs @@ -31,9 +31,9 @@ mod tests { r#" fn main() { match () { } - //^^ missing match arm + //^^ error: missing match arm match (()) { } - //^^^^ missing match arm + //^^^^ error: missing match arm match () { _ => (), } match () { () => (), } @@ -49,7 +49,7 @@ fn main() { r#" fn main() { match ((), ()) { } - //^^^^^^^^ missing match arm + //^^^^^^^^ error: missing match arm match ((), ()) { ((), ()) => (), } } @@ -63,21 +63,21 @@ fn main() { r#" fn test_main() { match false { } - //^^^^^ missing match arm + //^^^^^ error: missing match arm match false { true => (), } - //^^^^^ missing match arm + //^^^^^ error: missing match arm match (false, true) {} - //^^^^^^^^^^^^^ missing match arm + //^^^^^^^^^^^^^ error: missing match arm match (false, true) { (true, true) => (), } - //^^^^^^^^^^^^^ missing match arm + //^^^^^^^^^^^^^ error: missing match arm match (false, true) { - //^^^^^^^^^^^^^ missing match arm + //^^^^^^^^^^^^^ error: missing match arm (false, true) => (), (false, false) => (), (true, false) => (), } match (false, true) { (true, _x) => (), } - //^^^^^^^^^^^^^ missing match arm + //^^^^^^^^^^^^^ error: missing match arm match false { true => (), false => (), } match (false, true) { @@ -116,11 +116,11 @@ fn test_main() { r#" fn main() { match (false, ((), false)) {} - //^^^^^^^^^^^^^^^^^^^^ missing match arm + //^^^^^^^^^^^^^^^^^^^^ error: missing match arm match (false, ((), false)) { (true, ((), true)) => (), } - //^^^^^^^^^^^^^^^^^^^^ missing match arm + //^^^^^^^^^^^^^^^^^^^^ error: missing match arm match (false, ((), false)) { (true, _) => (), } - //^^^^^^^^^^^^^^^^^^^^ missing match arm + //^^^^^^^^^^^^^^^^^^^^ error: missing match arm match (false, ((), false)) { (true, ((), true)) => (), @@ -146,12 +146,12 @@ enum Either { A, B, } fn main() { match Either::A { } - //^^^^^^^^^ missing match arm + //^^^^^^^^^ error: missing match arm match Either::B { Either::A => (), } - //^^^^^^^^^ missing match arm + //^^^^^^^^^ error: missing match arm match &Either::B { - //^^^^^^^^^^ missing match arm + //^^^^^^^^^^ error: missing match arm Either::A => (), } @@ -174,9 +174,9 @@ enum Either { A(bool), B } fn main() { match Either::B { } - //^^^^^^^^^ missing match arm + //^^^^^^^^^ error: missing match arm match Either::B { - //^^^^^^^^^ missing match arm + //^^^^^^^^^ error: missing match arm Either::A(true) => (), Either::B => () } @@ -207,7 +207,7 @@ enum Either { A(bool), B(bool, bool) } fn main() { match Either::A(false) { - //^^^^^^^^^^^^^^^^ missing match arm + //^^^^^^^^^^^^^^^^ error: missing match arm Either::A(_) => (), Either::B(false, _) => (), } @@ -352,7 +352,7 @@ fn main() { Either::A => (), } match loop { break Foo::A } { - //^^^^^^^^^^^^^^^^^^^^^ missing match arm + //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm Either::A => (), } match loop { break Foo::A } { @@ -390,19 +390,19 @@ enum Either { A { foo: bool }, B } fn main() { let a = Either::A { foo: true }; match a { } - //^ missing match arm + //^ error: missing match arm match a { Either::A { foo: true } => () } - //^ missing match arm + //^ error: missing match arm match a { Either::A { } => (), - //^^^^^^^^^ Missing structure fields: + //^^^^^^^^^ error: missing structure fields: // | - foo Either::B => (), } match a { - //^ missing match arm + //^ error: missing match arm Either::A { } => (), - } //^^^^^^^^^ Missing structure fields: + } //^^^^^^^^^ error: missing structure fields: // | - foo match a { @@ -431,7 +431,7 @@ enum Either { fn main() { let a = Either::A { foo: true, bar: () }; match a { - //^ missing match arm + //^ error: missing match arm Either::A { bar: (), foo: false } => (), Either::A { foo: true, bar: () } => (), } @@ -458,12 +458,12 @@ enum Either { fn main() { let a = Either::B; match a { - //^ missing match arm + //^ error: missing match arm Either::A { foo: true, .. } => (), Either::B => (), } match a { - //^ missing match arm + //^ error: missing match arm Either::A { .. } => (), } @@ -493,14 +493,14 @@ enum Either { fn main() { match Either::B { - //^^^^^^^^^ missing match arm + //^^^^^^^^^ error: missing match arm Either::A(true, .., true) => (), Either::A(true, .., false) => (), Either::A(false, .., false) => (), Either::B => (), } match Either::B { - //^^^^^^^^^ missing match arm + //^^^^^^^^^ error: missing match arm Either::A(true, .., true) => (), Either::A(true, .., false) => (), Either::A(.., true) => (), @@ -537,7 +537,7 @@ fn enum_(never: Never) { } fn enum_ref(never: &Never) { match never {} - //^^^^^ missing match arm + //^^^^^ error: missing match arm } fn bang(never: !) { match never {} @@ -561,7 +561,7 @@ fn main() { Some(never) => match never {}, } match Option::::None { - //^^^^^^^^^^^^^^^^^^^^^ missing match arm + //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm Option::Some(_never) => {}, } } @@ -575,7 +575,7 @@ fn main() { r#" fn main() { match (false, true, false) { - //^^^^^^^^^^^^^^^^^^^^ missing match arm + //^^^^^^^^^^^^^^^^^^^^ error: missing match arm (false, ..) => (), } }"#, @@ -588,7 +588,7 @@ fn main() { r#" fn main() { match (false, true, false) { - //^^^^^^^^^^^^^^^^^^^^ missing match arm + //^^^^^^^^^^^^^^^^^^^^ error: missing match arm (.., false) => (), } }"#, @@ -601,7 +601,7 @@ fn main() { r#" fn main() { match (false, true, false) { - //^^^^^^^^^^^^^^^^^^^^ missing match arm + //^^^^^^^^^^^^^^^^^^^^ error: missing match arm (true, .., false) => (), } }"#, @@ -614,11 +614,11 @@ fn main() { r#"struct Foo { a: bool } fn main(f: Foo) { match f {} - //^ missing match arm + //^ error: missing match arm match f { Foo { a: true } => () } - //^ missing match arm + //^ error: missing match arm match &f { Foo { a: true } => () } - //^^ missing match arm + //^^ error: missing match arm match f { Foo { a: _ } => () } match f { Foo { a: true } => (), @@ -639,9 +639,9 @@ fn main(f: Foo) { r#"struct Foo(bool); fn main(f: Foo) { match f {} - //^ missing match arm + //^ error: missing match arm match f { Foo(true) => () } - //^ missing match arm + //^ error: missing match arm match f { Foo(true) => (), Foo(false) => (), @@ -657,7 +657,7 @@ fn main(f: Foo) { r#"struct Foo; fn main(f: Foo) { match f {} - //^ missing match arm + //^ error: missing match arm match f { Foo => () } } "#, @@ -670,9 +670,9 @@ fn main(f: Foo) { r#"struct Foo { foo: bool, bar: bool } fn main(f: Foo) { match f { Foo { foo: true, .. } => () } - //^ missing match arm + //^ error: missing match arm match f { - //^ missing match arm + //^ error: missing match arm Foo { foo: true, .. } => (), Foo { bar: false, .. } => () } @@ -693,7 +693,7 @@ fn main(f: Foo) { fn main() { enum Either { A(bool), B } match Either::B { - //^^^^^^^^^ missing match arm + //^^^^^^^^^ error: missing match arm Either::A(true | false) => (), } } @@ -715,7 +715,7 @@ fn main(v: S) { match v { S{..} => {} } match v { _ => {} } match v { } - //^ missing match arm + //^ error: missing match arm } "#, ); @@ -731,7 +731,7 @@ fn main() { false => {} } match true { _x @ true => {} } - //^^^^ missing match arm + //^^^^ error: missing match arm } "#, ); @@ -786,12 +786,12 @@ use lib::E; fn main() { match E::A { _ => {} } match E::A { - //^^^^ missing match arm + //^^^^ error: missing match arm E::A => {} E::B => {} } match E::A { - //^^^^ missing match arm + //^^^^ error: missing match arm E::A | E::B => {} } } @@ -810,7 +810,7 @@ fn main() { false => {} } match true { - //^^^^ missing match arm + //^^^^ error: missing match arm true if false => {} false => {} } diff --git a/crates/ide_diagnostics/src/handlers/missing_unsafe.rs b/crates/ide_diagnostics/src/handlers/missing_unsafe.rs index 62d8687ba..7acd9228a 100644 --- a/crates/ide_diagnostics/src/handlers/missing_unsafe.rs +++ b/crates/ide_diagnostics/src/handlers/missing_unsafe.rs @@ -23,7 +23,7 @@ fn main() { let x = &5 as *const usize; unsafe { let y = *x; } let z = *x; -} //^^ this operation is unsafe and requires an unsafe function or block +} //^^ error: this operation is unsafe and requires an unsafe function or block "#, ) } @@ -48,9 +48,9 @@ unsafe fn unsafe_fn() { fn main() { unsafe_fn(); - //^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block HasUnsafe.unsafe_fn(); - //^^^^^^^^^^^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block unsafe { unsafe_fn(); HasUnsafe.unsafe_fn(); @@ -72,7 +72,7 @@ static mut STATIC_MUT: Ty = Ty { a: 0 }; fn main() { let x = STATIC_MUT.a; - //^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block unsafe { let x = STATIC_MUT.a; } @@ -93,7 +93,7 @@ extern "rust-intrinsic" { fn main() { let _ = bitreverse(12); let _ = floorf32(12.0); - //^^^^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block } "#, ); diff --git a/crates/ide_diagnostics/src/handlers/no_such_field.rs b/crates/ide_diagnostics/src/handlers/no_such_field.rs index e4cc8a840..92e8867f4 100644 --- a/crates/ide_diagnostics/src/handlers/no_such_field.rs +++ b/crates/ide_diagnostics/src/handlers/no_such_field.rs @@ -119,11 +119,11 @@ struct S { foo: i32, bar: () } impl S { fn new() -> S { S { - //^ Missing structure fields: + //^ 💡 error: missing structure fields: //| - bar foo: 92, baz: 62, - //^^^^^^^ no such field + //^^^^^^^ 💡 error: no such field } } } diff --git a/crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs b/crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs index b52e4dc84..4e639f214 100644 --- a/crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs +++ b/crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs @@ -49,7 +49,7 @@ mod tests { check_diagnostics( r#" fn test() -> i32 { 123; } - //^^^ remove this semicolon + //^^^ 💡 error: remove this semicolon "#, ); } diff --git a/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs index 10d5da15d..cd87a10bb 100644 --- a/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs +++ b/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs @@ -91,8 +91,8 @@ pub mod iter { check_diagnostics( r#" fn foo() { - let m = [1, 2, 3].iter().filter_map(|x| if *x == 2 { Some (4) } else { None }).next(); - } //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace filter_map(..).next() with find_map(..) + let m = [1, 2, 3].iter().filter_map(|x| Some(92)).next(); + } //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: replace filter_map(..).next() with find_map(..) "#, ); } @@ -104,7 +104,7 @@ pub mod iter { fn foo() { let m = [1, 2, 3] .iter() - .filter_map(|x| if *x == 2 { Some (4) } else { None }) + .filter_map(|x| Some(92)) .len(); } "#, @@ -118,7 +118,7 @@ fn foo() { fn foo() { let m = [1, 2, 3] .iter() - .filter_map(|x| if *x == 2 { Some (4) } else { None }) + .filter_map(|x| Some(92)) .map(|x| x + 2) .len(); } @@ -133,7 +133,7 @@ fn foo() { fn foo() { let m = [1, 2, 3] .iter() - .filter_map(|x| if *x == 2 { Some (4) } else { None }); + .filter_map(|x| Some(92)); let n = m.next(); } "#, @@ -148,7 +148,7 @@ fn foo() { use core::iter::Iterator; use core::option::Option::{self, Some, None}; fn foo() { - let m = [1, 2, 3].iter().$0filter_map(|x| if *x == 2 { Some (4) } else { None }).next(); + let m = [1, 2, 3].iter().$0filter_map(|x| Some(92)).next(); } //- /core/lib.rs crate:core pub mod option { @@ -171,7 +171,7 @@ pub mod iter { use core::iter::Iterator; use core::option::Option::{self, Some, None}; fn foo() { - let m = [1, 2, 3].iter().find_map(|x| if *x == 2 { Some (4) } else { None }); + let m = [1, 2, 3].iter().find_map(|x| Some(92)); } "#, ) diff --git a/crates/ide_diagnostics/src/handlers/unresolved_extern_crate.rs b/crates/ide_diagnostics/src/handlers/unresolved_extern_crate.rs index f5313cc0c..74e4a69c6 100644 --- a/crates/ide_diagnostics/src/handlers/unresolved_extern_crate.rs +++ b/crates/ide_diagnostics/src/handlers/unresolved_extern_crate.rs @@ -25,7 +25,7 @@ mod tests { //- /main.rs crate:main deps:core extern crate core; extern crate doesnotexist; -//^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate +//^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate //- /lib.rs crate:core "#, ); @@ -38,7 +38,7 @@ extern crate core; r#" //- /lib.rs extern crate doesnotexist; -//^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate +//^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate // Should not error. extern crate self as foo; struct Foo; diff --git a/crates/ide_diagnostics/src/handlers/unresolved_import.rs b/crates/ide_diagnostics/src/handlers/unresolved_import.rs index f30051c12..e52a88459 100644 --- a/crates/ide_diagnostics/src/handlers/unresolved_import.rs +++ b/crates/ide_diagnostics/src/handlers/unresolved_import.rs @@ -30,7 +30,7 @@ mod tests { r#" use does_exist; use does_not_exist; - //^^^^^^^^^^^^^^ unresolved import + //^^^^^^^^^^^^^^ error: unresolved import mod does_exist {} "#, @@ -43,18 +43,18 @@ mod does_exist {} check_diagnostics( r#" use does_exist::{Exists, DoesntExist}; - //^^^^^^^^^^^ unresolved import + //^^^^^^^^^^^ error: unresolved import use {does_not_exist::*, does_exist}; - //^^^^^^^^^^^^^^^^^ unresolved import + //^^^^^^^^^^^^^^^^^ error: unresolved import use does_not_exist::{ a, - //^ unresolved import + //^ error: unresolved import b, - //^ unresolved import + //^ error: unresolved import c, - //^ unresolved import + //^ error: unresolved import }; mod does_exist { @@ -71,18 +71,18 @@ mod does_exist { //- /main.rs crate:main mod a { extern crate doesnotexist; - //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate + //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate // Should not error, since we already errored for the missing crate. use doesnotexist::{self, bla, *}; use crate::doesnotexist; - //^^^^^^^^^^^^^^^^^^^ unresolved import + //^^^^^^^^^^^^^^^^^^^ error: unresolved import } mod m { use super::doesnotexist; - //^^^^^^^^^^^^^^^^^^^ unresolved import + //^^^^^^^^^^^^^^^^^^^ error: unresolved import } "#, ); diff --git a/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs b/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs index 4c3c1c19a..f0f7725db 100644 --- a/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs +++ b/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs @@ -40,7 +40,7 @@ mod tests { r#" fn f() { m!(); -} //^ unresolved macro `m!` +} //^ error: unresolved macro `m!` "#, ); @@ -51,7 +51,7 @@ fn f() { check_diagnostics( r#" foo::bar!(92); - //^^^ unresolved macro `foo::bar!` + //^^^ error: unresolved macro `foo::bar!` "#, ); } @@ -63,7 +63,7 @@ foo::bar!(92); macro_rules! m { () => {} } m!(); m2!(); - //^^ unresolved macro `self::m2!` + //^^ error: unresolved macro `self::m2!` "#, ); } @@ -77,7 +77,7 @@ mod mac { macro_rules! m { () => {} } } self::m!(); self::m2!(); - //^^ unresolved macro `self::m2!` + //^^ error: unresolved macro `self::m2!` "#, ); } diff --git a/crates/ide_diagnostics/src/handlers/unresolved_module.rs b/crates/ide_diagnostics/src/handlers/unresolved_module.rs index 17166a0c6..61fc43604 100644 --- a/crates/ide_diagnostics/src/handlers/unresolved_module.rs +++ b/crates/ide_diagnostics/src/handlers/unresolved_module.rs @@ -50,7 +50,7 @@ mod tests { //- /lib.rs mod foo; mod bar; -//^^^^^^^^ unresolved module +//^^^^^^^^ 💡 error: unresolved module mod baz {} //- /foo.rs "#, diff --git a/crates/ide_diagnostics/src/lib.rs b/crates/ide_diagnostics/src/lib.rs index 52474eeab..6ad1b4373 100644 --- a/crates/ide_diagnostics/src/lib.rs +++ b/crates/ide_diagnostics/src/lib.rs @@ -235,7 +235,7 @@ mod tests { use stdx::trim_indent; use test_utils::{assert_eq_text, extract_annotations}; - use crate::DiagnosticsConfig; + use crate::{DiagnosticsConfig, Severity}; /// Takes a multi-file input fixture with annotated cursor positions, /// and checks that: @@ -331,8 +331,23 @@ mod tests { super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id); let expected = extract_annotations(&*db.file_text(file_id)); - let mut actual = - diagnostics.into_iter().map(|d| (d.range, d.message)).collect::>(); + let mut actual = diagnostics + .into_iter() + .map(|d| { + let mut annotation = String::new(); + if let Some(fixes) = &d.fixes { + assert!(!fixes.is_empty()); + annotation.push_str("💡 ") + } + annotation.push_str(match d.severity { + Severity::Error => "error", + Severity::WeakWarning => "weak", + }); + annotation.push_str(": "); + annotation.push_str(&d.message); + (d.range, annotation) + }) + .collect::>(); actual.sort_by_key(|(range, _)| range.start()); assert_eq!(expected, actual); } -- cgit v1.2.3