From 6d104de15aee6a24a442871c59528c39d410c161 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 13 Jun 2021 16:42:34 +0300 Subject: internal: refactor unresolved import diagnostic --- crates/ide/src/diagnostics.rs | 59 ++++++++-------- crates/ide/src/diagnostics/unresolved_import.rs | 90 +++++++++++++++++++++++++ crates/ide/src/diagnostics/unresolved_module.rs | 1 + 3 files changed, 121 insertions(+), 29 deletions(-) create mode 100644 crates/ide/src/diagnostics/unresolved_import.rs (limited to 'crates/ide/src') diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 1fbb7131d..3d05dd093 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs @@ -6,6 +6,7 @@ mod unresolved_module; mod unresolved_extern_crate; +mod unresolved_import; mod missing_fields; mod fixes; @@ -43,17 +44,39 @@ pub struct Diagnostic { pub fixes: Option>, pub unused: bool, pub code: Option, + pub experimental: bool, } impl Diagnostic { fn new(code: &'static str, message: impl Into, range: TextRange) -> Diagnostic { let message = message.into(); let code = Some(DiagnosticCode(code)); - Self { message, range, severity: Severity::Error, fixes: None, unused: false, code } + Self { + message, + range, + severity: Severity::Error, + fixes: None, + unused: false, + code, + experimental: false, + } + } + + fn experimental(mut self) -> Diagnostic { + self.experimental = true; + self } fn error(range: TextRange, message: String) -> Self { - Self { message, range, severity: Severity::Error, fixes: None, unused: false, code: None } + Self { + message, + range, + severity: Severity::Error, + fixes: None, + unused: false, + code: None, + experimental: false, + } } fn hint(range: TextRange, message: String) -> Self { @@ -64,6 +87,7 @@ impl Diagnostic { fixes: None, unused: false, code: None, + experimental: false, } } @@ -234,6 +258,7 @@ pub(crate) fn diagnostics( let d = match diag { AnyDiagnostic::UnresolvedModule(d) => unresolved_module::unresolved_module(&ctx, &d), AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), + AnyDiagnostic::UnresolvedImport(d) => unresolved_import::unresolved_import(&ctx, &d), AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), }; if let Some(code) = d.code { @@ -241,6 +266,9 @@ pub(crate) fn diagnostics( continue; } } + if ctx.config.disable_experimental && d.experimental { + continue; + } res.push(d) } @@ -462,33 +490,6 @@ foo::bar!(92); ); } - #[test] - fn unresolved_import_in_use_tree() { - // Only the relevant part of a nested `use` item should be highlighted. - check_diagnostics( - r#" -use does_exist::{Exists, DoesntExist}; - //^^^^^^^^^^^ unresolved import - -use {does_not_exist::*, does_exist}; - //^^^^^^^^^^^^^^^^^ unresolved import - -use does_not_exist::{ - a, - //^ unresolved import - b, - //^ unresolved import - c, - //^ unresolved import -}; - -mod does_exist { - pub struct Exists; -} -"#, - ); - } - #[test] fn range_mapping_out_of_macros() { // FIXME: this is very wrong, but somewhat tricky to fix. diff --git a/crates/ide/src/diagnostics/unresolved_import.rs b/crates/ide/src/diagnostics/unresolved_import.rs new file mode 100644 index 000000000..1cbf96ba1 --- /dev/null +++ b/crates/ide/src/diagnostics/unresolved_import.rs @@ -0,0 +1,90 @@ +use crate::diagnostics::{Diagnostic, DiagnosticsContext}; + +// Diagnostic: unresolved-import +// +// This diagnostic is triggered if rust-analyzer is unable to resolve a path in +// a `use` declaration. +pub(super) fn unresolved_import( + ctx: &DiagnosticsContext<'_>, + d: &hir::UnresolvedImport, +) -> Diagnostic { + Diagnostic::new( + "unresolved-import", + "unresolved import", + ctx.sema.diagnostics_display_range(d.decl.clone().map(|it| it.into())).range, + ) + // This currently results in false positives in the following cases: + // - `cfg_if!`-generated code in libstd (we don't load the sysroot correctly) + // - `core::arch` (we don't handle `#[path = "../"]` correctly) + // - proc macros and/or proc macro generated code + .experimental() +} + +#[cfg(test)] +mod tests { + use crate::diagnostics::tests::check_diagnostics; + + #[test] + fn unresolved_import() { + check_diagnostics( + r#" +use does_exist; +use does_not_exist; + //^^^^^^^^^^^^^^ unresolved import + +mod does_exist {} +"#, + ); + } + + #[test] + fn unresolved_import_in_use_tree() { + // Only the relevant part of a nested `use` item should be highlighted. + check_diagnostics( + r#" +use does_exist::{Exists, DoesntExist}; + //^^^^^^^^^^^ unresolved import + +use {does_not_exist::*, does_exist}; + //^^^^^^^^^^^^^^^^^ unresolved import + +use does_not_exist::{ + a, + //^ unresolved import + b, + //^ unresolved import + c, + //^ unresolved import +}; + +mod does_exist { + pub struct Exists; +} +"#, + ); + } + + #[test] + fn dedup_unresolved_import_from_unresolved_crate() { + check_diagnostics( + r#" +//- /main.rs crate:main +mod a { + extern crate doesnotexist; + //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate + + // Should not error, since we already errored for the missing crate. + use doesnotexist::{self, bla, *}; + + use crate::doesnotexist; + //^^^^^^^^^^^^^^^^^^^ unresolved import +} + +mod m { + use super::doesnotexist; + //^^^^^^^^^^^^^^^^^^^ unresolved import +} +"#, + ); + } +} diff --git a/crates/ide/src/diagnostics/unresolved_module.rs b/crates/ide/src/diagnostics/unresolved_module.rs index 4c8c74ff7..b1da8f0e1 100644 --- a/crates/ide/src/diagnostics/unresolved_module.rs +++ b/crates/ide/src/diagnostics/unresolved_module.rs @@ -104,6 +104,7 @@ mod baz {} "unresolved-module", ), ), + experimental: false, }, ] "#]], -- cgit v1.2.3