Unnamed repository; edit this file 'description' to name the repository.
Fix flyimport not filtering via stability of import path
Lukas Wirth 2025-01-25
parent e22bcfb · commit b31f53e
-rw-r--r--crates/hir-def/src/find_path.rs25
-rw-r--r--crates/hir-def/src/lib.rs3
-rw-r--r--crates/hir-ty/src/display.rs1
-rw-r--r--crates/ide-assists/src/assist_config.rs1
-rw-r--r--crates/ide-completion/src/completions.rs2
-rw-r--r--crates/ide-completion/src/completions/expr.rs4
-rw-r--r--crates/ide-completion/src/completions/flyimport.rs6
-rw-r--r--crates/ide-completion/src/completions/postfix.rs2
-rw-r--r--crates/ide-completion/src/config.rs3
-rw-r--r--crates/ide-completion/src/context.rs4
-rw-r--r--crates/ide-completion/src/lib.rs2
-rw-r--r--crates/ide-completion/src/render.rs2
-rw-r--r--crates/ide-completion/src/snippet.rs2
-rw-r--r--crates/ide-completion/src/tests/flyimport.rs35
-rw-r--r--crates/ide-db/src/path_transform.rs3
-rw-r--r--crates/ide-diagnostics/src/handlers/json_is_not_rust.rs1
-rw-r--r--crates/ide-diagnostics/src/handlers/missing_fields.rs1
-rw-r--r--crates/ide-diagnostics/src/handlers/typed_hole.rs1
-rw-r--r--crates/ide-diagnostics/src/lib.rs9
-rw-r--r--crates/ide-ssr/src/matching.rs1
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs1
21 files changed, 89 insertions, 20 deletions
diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs
index 5d67902c8a..c30ad0163b 100644
--- a/crates/hir-def/src/find_path.rs
+++ b/crates/hir-def/src/find_path.rs
@@ -445,6 +445,10 @@ fn find_in_dep(
};
cov_mark::hit!(partially_imported);
if info.is_unstable {
+ if !ctx.cfg.allow_unstable {
+ // the item is unstable and we are not allowed to use unstable items
+ continue;
+ }
choice.stability = Unstable;
}
@@ -670,6 +674,7 @@ mod tests {
prefer_prelude: bool,
prefer_absolute: bool,
prefer_no_std: bool,
+ allow_unstable: bool,
expect: Expect,
) {
let (db, pos) = TestDB::with_position(ra_fixture);
@@ -711,7 +716,7 @@ mod tests {
module,
prefix,
ignore_local_imports,
- ImportPathConfig { prefer_no_std, prefer_prelude, prefer_absolute },
+ ImportPathConfig { prefer_no_std, prefer_prelude, prefer_absolute, allow_unstable },
);
format_to!(
res,
@@ -732,7 +737,7 @@ mod tests {
path: &str,
expect: Expect,
) {
- check_found_path_(ra_fixture, path, false, false, false, expect);
+ check_found_path_(ra_fixture, path, false, false, false, false, expect);
}
fn check_found_path_prelude(
@@ -740,7 +745,7 @@ mod tests {
path: &str,
expect: Expect,
) {
- check_found_path_(ra_fixture, path, true, false, false, expect);
+ check_found_path_(ra_fixture, path, true, false, false, false, expect);
}
fn check_found_path_absolute(
@@ -748,7 +753,7 @@ mod tests {
path: &str,
expect: Expect,
) {
- check_found_path_(ra_fixture, path, false, true, false, expect);
+ check_found_path_(ra_fixture, path, false, true, false, false, expect);
}
fn check_found_path_prefer_no_std(
@@ -756,7 +761,15 @@ mod tests {
path: &str,
expect: Expect,
) {
- check_found_path_(ra_fixture, path, false, false, true, expect);
+ check_found_path_(ra_fixture, path, false, false, true, false, expect);
+ }
+
+ fn check_found_path_prefer_no_std_allow_unstable(
+ #[rust_analyzer::rust_fixture] ra_fixture: &str,
+ path: &str,
+ expect: Expect,
+ ) {
+ check_found_path_(ra_fixture, path, false, false, true, true, expect);
}
#[test]
@@ -1951,7 +1964,7 @@ pub mod ops {
#[test]
fn respect_unstable_modules() {
- check_found_path_prefer_no_std(
+ check_found_path_prefer_no_std_allow_unstable(
r#"
//- /main.rs crate:main deps:std,core
extern crate std;
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index da9ffae8aa..c78818c642 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -114,6 +114,9 @@ pub struct ImportPathConfig {
pub prefer_prelude: bool,
/// If true, prefer abs path (starting with `::`) where it is available.
pub prefer_absolute: bool,
+ /// If true, paths containing `#[unstable]` segments may be returned, but only if if there is no
+ /// stable path. This does not check, whether the item itself that is being imported is `#[unstable]`.
+ pub allow_unstable: bool,
}
#[derive(Debug)]
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 3545bf7677..d960aaf99f 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -1159,6 +1159,7 @@ impl HirDisplay for Ty {
prefer_no_std: false,
prefer_prelude: true,
prefer_absolute: false,
+ allow_unstable: true,
},
) {
write!(f, "{}", path.display(f.db.upcast(), f.edition()))?;
diff --git a/crates/ide-assists/src/assist_config.rs b/crates/ide-assists/src/assist_config.rs
index 82d8db4258..fb533077d9 100644
--- a/crates/ide-assists/src/assist_config.rs
+++ b/crates/ide-assists/src/assist_config.rs
@@ -28,6 +28,7 @@ impl AssistConfig {
prefer_no_std: self.prefer_no_std,
prefer_prelude: self.prefer_prelude,
prefer_absolute: self.prefer_absolute,
+ allow_unstable: true,
}
}
}
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index 40669c65c5..88f893e42a 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -660,7 +660,7 @@ fn enum_variants_with_paths(
if let Some(path) = ctx.module.find_path(
ctx.db,
hir::ModuleDef::from(variant),
- ctx.config.import_path_config(),
+ ctx.config.import_path_config(ctx.is_nightly),
) {
// Variants with trivial paths are already added by the existing completion logic,
// so we should avoid adding these twice
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index db18b531d7..e710175170 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -247,7 +247,7 @@ pub(crate) fn complete_expr_path(
.find_path(
ctx.db,
hir::ModuleDef::from(strukt),
- ctx.config.import_path_config(),
+ ctx.config.import_path_config(ctx.is_nightly),
)
.filter(|it| it.len() > 1);
@@ -269,7 +269,7 @@ pub(crate) fn complete_expr_path(
.find_path(
ctx.db,
hir::ModuleDef::from(un),
- ctx.config.import_path_config(),
+ ctx.config.import_path_config(ctx.is_nightly),
)
.filter(|it| it.len() > 1);
diff --git a/crates/ide-completion/src/completions/flyimport.rs b/crates/ide-completion/src/completions/flyimport.rs
index 435b88de4a..24243f57b4 100644
--- a/crates/ide-completion/src/completions/flyimport.rs
+++ b/crates/ide-completion/src/completions/flyimport.rs
@@ -257,7 +257,7 @@ fn import_on_the_fly(
};
let user_input_lowercased = potential_import_name.to_lowercase();
- let import_cfg = ctx.config.import_path_config();
+ let import_cfg = ctx.config.import_path_config(ctx.is_nightly);
import_assets
.search_for_imports(&ctx.sema, import_cfg, ctx.config.insert_use.prefix_kind)
@@ -316,7 +316,7 @@ fn import_on_the_fly_pat_(
ItemInNs::Values(def) => matches!(def, hir::ModuleDef::Const(_)),
};
let user_input_lowercased = potential_import_name.to_lowercase();
- let cfg = ctx.config.import_path_config();
+ let cfg = ctx.config.import_path_config(ctx.is_nightly);
import_assets
.search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind)
@@ -358,7 +358,7 @@ fn import_on_the_fly_method(
let user_input_lowercased = potential_import_name.to_lowercase();
- let cfg = ctx.config.import_path_config();
+ let cfg = ctx.config.import_path_config(ctx.is_nightly);
import_assets
.search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind)
diff --git a/crates/ide-completion/src/completions/postfix.rs b/crates/ide-completion/src/completions/postfix.rs
index 67ea05e002..2c39a8fdfe 100644
--- a/crates/ide-completion/src/completions/postfix.rs
+++ b/crates/ide-completion/src/completions/postfix.rs
@@ -60,7 +60,7 @@ pub(crate) fn complete_postfix(
None => return,
};
- let cfg = ctx.config.import_path_config();
+ let cfg = ctx.config.import_path_config(ctx.is_nightly);
if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() {
if receiver_ty.impls_trait(ctx.db, drop_trait, &[]) {
diff --git a/crates/ide-completion/src/config.rs b/crates/ide-completion/src/config.rs
index c641df38ff..45aab38e8e 100644
--- a/crates/ide-completion/src/config.rs
+++ b/crates/ide-completion/src/config.rs
@@ -59,11 +59,12 @@ impl CompletionConfig<'_> {
.flat_map(|snip| snip.prefix_triggers.iter().map(move |trigger| (&**trigger, snip)))
}
- pub fn import_path_config(&self) -> ImportPathConfig {
+ pub fn import_path_config(&self, allow_unstable: bool) -> ImportPathConfig {
ImportPathConfig {
prefer_no_std: self.prefer_no_std,
prefer_prelude: self.prefer_prelude,
prefer_absolute: self.prefer_absolute,
+ allow_unstable,
}
}
}
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 3a2a4a23a1..366e79cddf 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -443,7 +443,9 @@ pub(crate) struct CompletionContext<'a> {
/// The module of the `scope`.
pub(crate) module: hir::Module,
/// Whether nightly toolchain is used. Cached since this is looked up a lot.
- is_nightly: bool,
+ pub(crate) is_nightly: bool,
+ /// The edition of the current crate
+ // FIXME: This should probably be the crate of the current token?
pub(crate) edition: Edition,
/// The expected name of what we are completing.
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index 56d7eeaf8e..ac6b1207f2 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -289,7 +289,7 @@ pub fn resolve_completion_edits(
let new_ast = scope.clone_for_update();
let mut import_insert = TextEdit::builder();
- let cfg = config.import_path_config();
+ let cfg = config.import_path_config(true);
imports.into_iter().for_each(|(full_import_path, imported_name)| {
let items_with_name = items_locator::items_with_name(
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs
index 1b7adf1adb..dc7eacbfba 100644
--- a/crates/ide-completion/src/render.rs
+++ b/crates/ide-completion/src/render.rs
@@ -301,7 +301,7 @@ pub(crate) fn render_expr(
.unwrap_or_else(|| String::from("..."))
};
- let cfg = ctx.config.import_path_config();
+ let cfg = ctx.config.import_path_config(ctx.is_nightly);
let label = expr.gen_source_code(&ctx.scope, &mut label_formatter, cfg, ctx.edition).ok()?;
diff --git a/crates/ide-completion/src/snippet.rs b/crates/ide-completion/src/snippet.rs
index 04bb178c65..866b83a614 100644
--- a/crates/ide-completion/src/snippet.rs
+++ b/crates/ide-completion/src/snippet.rs
@@ -164,7 +164,7 @@ impl Snippet {
}
fn import_edits(ctx: &CompletionContext<'_>, requires: &[ModPath]) -> Option<Vec<LocatedImport>> {
- let import_cfg = ctx.config.import_path_config();
+ let import_cfg = ctx.config.import_path_config(ctx.is_nightly);
let resolve = |import| {
let item = ctx.scope.resolve_mod_path(import).next()?;
diff --git a/crates/ide-completion/src/tests/flyimport.rs b/crates/ide-completion/src/tests/flyimport.rs
index d491e438fe..2e7c53def7 100644
--- a/crates/ide-completion/src/tests/flyimport.rs
+++ b/crates/ide-completion/src/tests/flyimport.rs
@@ -1391,6 +1391,41 @@ pub struct FooStruct {}
}
#[test]
+fn flyimport_pattern_unstable_path() {
+ check(
+ r#"
+//- /main.rs crate:main deps:std
+fn function() {
+ let foo$0
+}
+//- /std.rs crate:std
+#[unstable]
+pub mod unstable {
+ pub struct FooStruct {}
+}
+"#,
+ expect![""],
+ );
+ check(
+ r#"
+//- toolchain:nightly
+//- /main.rs crate:main deps:std
+fn function() {
+ let foo$0
+}
+//- /std.rs crate:std
+#[unstable]
+pub mod unstable {
+ pub struct FooStruct {}
+}
+"#,
+ expect![[r#"
+ st FooStruct (use std::unstable::FooStruct)
+ "#]],
+ );
+}
+
+#[test]
fn flyimport_pattern_unstable_item_on_nightly() {
check(
r#"
diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs
index a045c22c2d..f045e44dd3 100644
--- a/crates/ide-db/src/path_transform.rs
+++ b/crates/ide-db/src/path_transform.rs
@@ -319,6 +319,7 @@ impl Ctx<'_> {
prefer_no_std: false,
prefer_prelude: true,
prefer_absolute: false,
+ allow_unstable: true,
};
let found_path = self.target_module.find_path(
self.source_scope.db.upcast(),
@@ -378,6 +379,7 @@ impl Ctx<'_> {
prefer_no_std: false,
prefer_prelude: true,
prefer_absolute: false,
+ allow_unstable: true,
};
let found_path =
self.target_module.find_path(self.source_scope.db.upcast(), def, cfg)?;
@@ -417,6 +419,7 @@ impl Ctx<'_> {
prefer_no_std: false,
prefer_prelude: true,
prefer_absolute: false,
+ allow_unstable: true,
};
let found_path = self.target_module.find_path(
self.source_scope.db.upcast(),
diff --git a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
index dca889d1a8..f22041ebe2 100644
--- a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
+++ b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
@@ -147,6 +147,7 @@ pub(crate) fn json_in_items(
prefer_no_std: config.prefer_no_std,
prefer_prelude: config.prefer_prelude,
prefer_absolute: config.prefer_absolute,
+ allow_unstable: true,
};
if !scope_has("Serialize") {
diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs
index fd1044e51b..938b7182bc 100644
--- a/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -128,6 +128,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
+ allow_unstable: ctx.is_nightly,
},
)?;
diff --git a/crates/ide-diagnostics/src/handlers/typed_hole.rs b/crates/ide-diagnostics/src/handlers/typed_hole.rs
index 3ad84f7bda..b023a95fb3 100644
--- a/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -70,6 +70,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist>
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
+ allow_unstable: ctx.is_nightly,
},
ctx.edition,
)
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index 1e99d7ad6e..50c91a6960 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -83,7 +83,7 @@ use either::Either;
use hir::{db::ExpandDatabase, diagnostics::AnyDiagnostic, Crate, HirFileId, InFile, Semantics};
use ide_db::{
assists::{Assist, AssistId, AssistKind, AssistResolveStrategy},
- base_db::SourceDatabase,
+ base_db::{ReleaseChannel, SourceDatabase},
generated::lints::{Lint, LintGroup, CLIPPY_LINT_GROUPS, DEFAULT_LINTS, DEFAULT_LINT_GROUPS},
imports::insert_use::InsertUseConfig,
label::Label,
@@ -276,6 +276,7 @@ struct DiagnosticsContext<'a> {
sema: Semantics<'a, RootDatabase>,
resolve: &'a AssistResolveStrategy,
edition: Edition,
+ is_nightly: bool,
}
impl DiagnosticsContext<'_> {
@@ -368,7 +369,11 @@ pub fn semantic_diagnostics(
let module = sema.file_to_module_def(file_id);
- let ctx = DiagnosticsContext { config, sema, resolve, edition: file_id.edition() };
+ let is_nightly = matches!(
+ module.and_then(|m| db.toolchain_channel(m.krate().into())),
+ Some(ReleaseChannel::Nightly) | None
+ );
+ let ctx = DiagnosticsContext { config, sema, resolve, edition: file_id.edition(), is_nightly };
let mut diags = Vec::new();
match module {
diff --git a/crates/ide-ssr/src/matching.rs b/crates/ide-ssr/src/matching.rs
index 4edc3633fb..4bead14e31 100644
--- a/crates/ide-ssr/src/matching.rs
+++ b/crates/ide-ssr/src/matching.rs
@@ -673,6 +673,7 @@ impl Match {
prefer_no_std: false,
prefer_prelude: true,
prefer_absolute: false,
+ allow_unstable: true,
};
let mod_path = module.find_path(sema.db, module_def, cfg).ok_or_else(|| {
match_error!("Failed to render template path `{}` at match location")
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index bcaec52019..18c27c8449 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -465,6 +465,7 @@ impl flags::AnalysisStats {
prefer_no_std: false,
prefer_prelude: true,
prefer_absolute: false,
+ allow_unstable: true,
},
Edition::LATEST,
)