From efa069d28818dd074afd2c7cee776907b63ca012 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 13 Jun 2021 14:41:19 +0300 Subject: internal: start new diagnostics API At the moment, this moves only a single diagnostic, but the idea is reafactor the rest to use the same pattern. We are going to have a single file per diagnostic. This file will define diagnostics code, rendering range and fixes, if any. It'll also have all of the tests. This is similar to how we deal with assists. After we refactor all diagnostics to follow this pattern, we'll probably move them to a new `ide_diagnostics` crate. Not that we intentionally want to test all diagnostics on this layer, despite the fact that they are generally emitted in the guts on the compiler. Diagnostics care to much about the end presentation details/fixes to be worth-while "unit" testing. So, we'll unit-test only the primary output of compilation process (types and name res tables), and will use integrated UI tests for diagnostics. --- crates/ide/src/diagnostics/unresolved_module.rs | 109 ++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 crates/ide/src/diagnostics/unresolved_module.rs (limited to 'crates/ide/src/diagnostics/unresolved_module.rs') diff --git a/crates/ide/src/diagnostics/unresolved_module.rs b/crates/ide/src/diagnostics/unresolved_module.rs new file mode 100644 index 000000000..abf53a57c --- /dev/null +++ b/crates/ide/src/diagnostics/unresolved_module.rs @@ -0,0 +1,109 @@ +use hir::db::AstDatabase; +use ide_assists::Assist; +use ide_db::{base_db::AnchoredPathBuf, source_change::FileSystemEdit}; +use syntax::AstNode; + +use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext}; + +// Diagnostic: unresolved-module +// +// This diagnostic is triggered if rust-analyzer is unable to discover referred module. +pub(super) fn render(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedModule) -> Diagnostic { + Diagnostic::new( + "unresolved-module", + "unresolved module", + ctx.sema.diagnostics_display_range(d.decl.clone().map(|it| it.into())).range, + ) + .with_fixes(fixes(ctx, d)) +} + +fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedModule) -> Option> { + let root = ctx.sema.db.parse_or_expand(d.decl.file_id)?; + let unresolved_module = d.decl.value.to_node(&root); + Some(vec![fix( + "create_module", + "Create module", + FileSystemEdit::CreateFile { + dst: AnchoredPathBuf { + anchor: d.decl.file_id.original_file(ctx.sema.db), + path: d.candidate.clone(), + }, + initial_contents: "".to_string(), + } + .into(), + unresolved_module.syntax().text_range(), + )]) +} + +#[cfg(test)] +mod tests { + use expect_test::expect; + + use crate::diagnostics::tests::{check_diagnostics, check_expect}; + + #[test] + fn unresolved_module() { + check_diagnostics( + r#" +//- /lib.rs +mod foo; + mod bar; +//^^^^^^^^ unresolved module +mod baz {} +//- /foo.rs +"#, + ); + } + + #[test] + fn test_unresolved_module_diagnostic() { + check_expect( + r#"mod foo;"#, + expect![[r#" + [ + Diagnostic { + message: "unresolved module", + range: 0..8, + severity: Error, + fixes: Some( + [ + Assist { + id: AssistId( + "create_module", + QuickFix, + ), + label: "Create module", + group: None, + target: 0..8, + source_change: Some( + SourceChange { + source_file_edits: {}, + file_system_edits: [ + CreateFile { + dst: AnchoredPathBuf { + anchor: FileId( + 0, + ), + path: "foo.rs", + }, + initial_contents: "", + }, + ], + is_snippet: false, + }, + ), + }, + ], + ), + unused: false, + code: Some( + DiagnosticCode( + "unresolved-module", + ), + ), + }, + ] + "#]], + ); + } +} -- cgit v1.2.3