Repository: rust-analyzer/rust-analyzer
Pull request #6760 (2020-12-08 13:29:20)

Open Cargo.toml opens more specific manifest
bors r+
🤖


Patch:
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index 4e4e2b36f0..81691cd7f2 100644
--- a/crates/completion/src/completions/unqualified_path.rs
+++ b/crates/completion/src/completions/unqualified_path.rs
@@ -9,7 +9,7 @@ use test_utils::mark;
 
 use crate::{
     render::{render_resolution_with_import, RenderContext},
-    CompletionContext, Completions, ImportEdit,
+    CompletionContext, Completions,
 };
 
 pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
@@ -44,7 +44,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
         acc.add_resolution(ctx, name.to_string(), &res)
     });
 
-    if ctx.config.enable_autoimport_completions && ctx.config.resolve_additional_edits_lazily() {
+    if ctx.config.enable_experimental_completions {
         fuzzy_completion(acc, ctx).unwrap_or_default()
     }
 }
@@ -73,64 +73,19 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
     }
 }
 
-// Feature: Fuzzy Completion and Autoimports
-//
-// When completing names in the current scope, proposes additional imports from other modules or crates,
-// if they can be qualified in the scope and their name contains all symbols from the completion input
-// (case-insensitive, in any order or places).
-//
-// ```
-// fn main() {
-//     pda<|>
-// }
-// # pub mod std { pub mod marker { pub struct PhantomData { } } }
-// ```
-// ->
-// ```
-// use std::marker::PhantomData;
-//
-// fn main() {
-//     PhantomData
-// }
-// # pub mod std { pub mod marker { pub struct PhantomData { } } }
-// ```
-//
-// .Fuzzy search details
-//
-// To avoid an excessive amount of the results returned, completion input is checked for inclusion in the identifiers only
-// (i.e. in `HashMap` in the `std::collections::HashMap` path), also not in the module indentifiers.
-//
-// .Merge Behaviour
-//
-// It is possible to configure how use-trees are merged with the `importMergeBehaviour` setting.
-// Mimics the corresponding behaviour of the `Auto Import` feature.
-//
-// .LSP and performance implications
-//
-// The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits`
-// (case sensitive) resolve client capability in its client capabilities.
-// This way the server is able to defer the costly computations, doing them for a selected completion item only.
-// For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones,
-// which might be slow ergo the feature is automatically disabled.
-//
-// .Feature toggle
-//
-// The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.enableAutoimportCompletions` flag.
-// Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding
-// capability enabled.
 fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
     let _p = profile::span("fuzzy_completion");
-    let potential_import_name = ctx.token.to_string();
-
     let current_module = ctx.scope.module()?;
     let anchor = ctx.name_ref_syntax.as_ref()?;
     let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
 
+    let potential_import_name = ctx.token.to_string();
+
     let possible_imports = imports_locator::find_similar_imports(
         &ctx.sema,
         ctx.krate?,
-        Some(100),
         &potential_import_name,
+        50,
         true,
     )
     .filter_map(|import_candidate| {
@@ -144,14 +99,13 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()
         })
     })
     .filter(|(mod_path, _)| mod_path.len() > 1)
+    .take(20)
     .filter_map(|(import_path, definition)| {
         render_resolution_with_import(
             RenderContext::new(ctx),
-            ImportEdit {
-                import_path: import_path.clone(),
-                import_scope: import_scope.clone(),
-                merge_behaviour: ctx.config.merge,
-            },
+            import_path.clone(),
+            import_scope.clone(),
+            ctx.config.merge,
             &definition,
         )
     });
@@ -166,8 +120,8 @@ mod tests {
     use test_utils::mark;
 
     use crate::{
-        test_utils::{check_edit, check_edit_with_config, completion_list},
-        CompletionConfig, CompletionKind,
+        test_utils::{check_edit, completion_list},
+        CompletionKind,
     };
 
     fn check(ra_fixture: &str, expect: Expect) {
@@ -776,13 +730,7 @@ impl My<|>
 
     #[test]
     fn function_fuzzy_completion() {
-        let mut completion_config = CompletionConfig::default();
-        completion_config
-            .active_resolve_capabilities
-            .insert(crate::CompletionResolveCapability::AdditionalTextEdits);
-
-        check_edit_with_config(
-            completion_config,
+        check_edit(
             "stdin",
             r#"
 //- /lib.rs crate:dep
@@ -807,13 +755,7 @@ fn main() {
 
     #[test]
     fn macro_fuzzy_completion() {
-        let mut completion_config = CompletionConfig::default();
-        completion_config
-            .active_resolve_capabilities
-            .insert(crate::CompletionResolveCapability::AdditionalTextEdits);
-
-        check_edit_with_config(
-            completion_config,
+        check_edit(
             "macro_with_curlies!",
             r#"
 //- /lib.rs crate:dep
@@ -840,13 +782,7 @@ fn main() {
 
     #[test]
     fn struct_fuzzy_completion() {
-        let mut completion_config = CompletionConfig::default();
-        completion_config
-            .active_resolve_capabilities
-            .insert(crate::CompletionResolveCapability::AdditionalTextEdits);
-
-        check_edit_with_config(
-            completion_config,
+        check_edit(
             "ThirdStruct",
             r#"
 //- /lib.rs crate:dep
diff --git a/crates/completion/src/config.rs b/crates/completion/src/config.rs
index 5175b9d69d..654a76f7b3 100644
--- a/crates/completion/src/config.rs
+++ b/crates/completion/src/config.rs
@@ -5,42 +5,21 @@
 //! completions if we are allowed to.
 
 use ide_db::helpers::insert_use::MergeBehaviour;
-use rustc_hash::FxHashSet;
 
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct CompletionConfig {
     pub enable_postfix_completions: bool,
-    pub enable_autoimport_completions: bool,
+    pub enable_experimental_completions: bool,
     pub add_call_parenthesis: bool,
     pub add_call_argument_snippets: bool,
     pub snippet_cap: Option<SnippetCap>,
     pub merge: Option<MergeBehaviour>,
-    /// A set of capabilities, enabled on the client and supported on the server.
-    pub active_resolve_capabilities: FxHashSet<CompletionResolveCapability>,
-}
-
-/// A resolve capability, supported on the server.
-/// If the client registers any completion resolve capabilities,
-/// the server is able to render completion items' corresponding fields later,
-/// not during an initial completion item request.
-/// See https://github.com/rust-analyzer/rust-analyzer/issues/6366 for more details.
-#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
-pub enum CompletionResolveCapability {
-    Documentation,
-    Detail,
-    AdditionalTextEdits,
 }
 
 impl CompletionConfig {
     pub fn allow_snippets(&mut self, yes: bool) {
         self.snippet_cap = if yes { Some(SnippetCap { _private: () }) } else { None }
     }
-
-    /// Whether the completions' additional edits are calculated when sending an initional completions list
-    /// or later, in a separate resolve request.
-    pub fn resolve_additional_edits_lazily(&self) -> bool {
-        self.active_resolve_capabilities.contains(&CompletionResolveCapability::AdditionalTextEdits)
-    }
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -52,12 +31,11 @@ impl Default for CompletionConfig {
     fn default() -> Self {
         CompletionConfig {
             enable_postfix_completions: true,
-            enable_autoimport_completions: true,
+            enable_experimental_completions: true,
             add_call_parenthesis: true,
             add_call_argument_snippets: true,
             snippet_cap: Some(SnippetCap { _private: () }),
             merge: Some(MergeBehaviour::Full),
-            active_resolve_capabilities: FxHashSet::default(),
         }
     }
 }
diff --git a/crates/completion/src/item.rs b/crates/completion/src/item.rs
index bd94402d75..e85549fef4 100644
--- a/crates/completion/src/item.rs
+++ b/crates/completion/src/item.rs
@@ -15,7 +15,6 @@ use crate::config::SnippetCap;
 /// `CompletionItem` describes a single completion variant in the editor pop-up.
 /// It is basically a POD with various properties. To construct a
 /// `CompletionItem`, use `new` method and the `Builder` struct.
-#[derive(Clone)]
 pub struct CompletionItem {
     /// Used only internally in tests, to check only specific kind of
     /// completion (postfix, keyword, reference, etc).
@@ -66,9 +65,6 @@ pub struct CompletionItem {
     /// Indicates that a reference or mutable reference to this variable is a
     /// possible match.
     ref_match: Option<(Mutability, CompletionScore)>,
-
-    /// The import data to add to completion's edits.
-    import_to_add: Option<ImportEdit>,
 }
 
 // We use custom debug for CompletionItem to make snapshot tests more readable.
@@ -260,37 +256,14 @@ impl CompletionItem {
     pub fn ref_match(&self) -> Option<(Mutability, CompletionScore)> {
         self.ref_match
     }
-
-    pub fn import_to_add(&self) -> Option<&ImportEdit> {
-        self.import_to_add.as_ref()
-    }
 }
 
 /// An extra import to add after the completion is applied.
-#[derive(Debug, Clone)]
-pub struct ImportEdit {
-    pub import_path: ModPath,
-    pub import_scope: ImportScope,
-    pub merge_behaviour: Option<MergeBehaviour>,
-}
-
-impl ImportEdit {
-    /// Attempts to insert the import to the given scope, producing a text edit.
-    /// May return no edit in edge cases, such as scope already containing the import.
-    pub fn to_text_edit(&self) -> Option<TextEdit> {
-        let _p = profile::span("ImportEdit::to_text_edit");
-
-        let rewriter = insert_use::insert_use(
-            &self.import_scope,
-            mod_path_to_ast(&self.import_path),
-            self.merge_behaviour,
-        );
-        let old_ast = rewriter.rewrite_root()?;
-        let mut import_insert = TextEdit::builder();
-        algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert);
-
-        Some(import_insert.finish())
-    }
+#[derive(Clone)]
+pub(crate) struct ImportToAdd {
+    pub(crate) import_path: ModPath,
+    pub(crate) import_scope: ImportScope,
+    pub(crate) merge_behaviour: Option<MergeBehaviour>,
 }
 
 /// A helper to make `CompletionItem`s.
@@ -299,7 +272,7 @@ impl ImportEdit {
 pub(crate) struct Builder {
     source_range: TextRange,
     completion_kind: CompletionKind,
-    import_to_add: Option<ImportEdit>,
+    import_to_add: Option<ImportToAdd>,
     label: String,
     insert_text: Option<String>,
     insert_text_format: InsertTextFormat,
@@ -321,9 +294,11 @@ impl Builder {
         let mut label = self.label;
         let mut lookup = self.lookup;
         let mut insert_text = self.insert_text;
+        let mut text_edits = TextEdit::builder();
 
-        if let Some(import_to_add) = self.import_to_add.as_ref() {
-            let mut import_path_without_last_segment = import_to_add.import_path.to_owned();
+        if let Some(import_data) = self.import_to_add {
+            let import = mod_path_to_ast(&import_data.import_path);
+            let mut import_path_without_last_segment = import_data.import_path;
             let _ = import_path_without_last_segment.segments.pop();
 
             if !import_path_without_last_segment.segments.is_empty() {
@@ -335,20 +310,32 @@ impl Builder {
                 }
                 label = format!("{}::{}", import_path_without_last_segment, label);
             }
+
+            let rewriter = insert_use::insert_use(
+                &import_data.import_scope,
+                import,
+                import_data.merge_behaviour,
+            );
+            if let Some(old_ast) = rewriter.rewrite_root() {
+                algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut text_edits);
+            }
         }
 
-        let text_edit = match self.text_edit {
+        let original_edit = match self.text_edit {
             Some(it) => it,
             None => {
                 TextEdit::replace(self.source_range, insert_text.unwrap_or_else(|| label.clone()))
             }
         };
 
+        let mut resulting_edit = text_edits.finish();
+        resulting_edit.union(original_edit).expect("Failed to unite text edits");
+
         CompletionItem {
             source_range: self.source_range,
             label,
             insert_text_format: self.insert_text_format,
-            text_edit,
+            text_edit: resulting_edit,
             detail: self.detail,
             documentation: self.documentation,
             lookup,
@@ -358,7 +345,6 @@ impl Builder {
             trigger_call_info: self.trigger_call_info.unwrap_or(false),
             score: self.score,
             ref_match: self.ref_match,
-            import_to_add: self.import_to_add,
         }
     }
     pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder {
@@ -421,7 +407,7 @@ impl Builder {
         self.trigger_call_info = Some(true);
         self
     }
-    pub(crate) fn add_import(mut self, import_to_add: Option<ImportEdit>) -> Builder {
+    pub(crate) fn add_import(mut self, import_to_add: Option<ImportToAdd>) -> Builder {
         self.import_to_add = import_to_add;
         self
     }
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs
index f60f87243f..1ec2e9be72 100644
--- a/crates/completion/src/lib.rs
+++ b/crates/completion/src/lib.rs
@@ -11,17 +11,14 @@ mod render;
 
 mod completions;
 
-use ide_db::{
-    base_db::FilePosition, helpers::insert_use::ImportScope, imports_locator, RootDatabase,
-};
-use syntax::AstNode;
-use text_edit::TextEdit;
+use ide_db::base_db::FilePosition;
+use ide_db::RootDatabase;
 
 use crate::{completions::Completions, context::CompletionContext, item::CompletionKind};
 
 pub use crate::{
-    config::{CompletionConfig, CompletionResolveCapability},
-    item::{CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, InsertTextFormat},
+    config::CompletionConfig,
+    item::{CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat},
 };
 
 //FIXME: split the following feature into fine-grained features.
@@ -73,9 +70,12 @@ pub use crate::{
 // }
 // ```
 //
-// And the auto import completions, enabled with the `rust-analyzer.completion.autoimport.enable` setting and the corresponding LSP client capabilities.
-// Those are the additional completion options with automatic `use` import and options from all project importable items,
-// fuzzy matched agains the completion imput.
+// And experimental completions, enabled with the `rust-analyzer.completion.enableExperimental` setting.
+// This flag enables or disables:
+//
+// - Auto import: additional completion options with automatic `use` import and options from all project importable items, matched for the input
+//
+// Experimental completions might cause issues with performance and completion list look.
 
 /// Main entry point for completion. We run completion as a two-phase process.
 ///
@@ -131,33 +131,6 @@ pub fn completions(
     Some(acc)
 }
 
-/// Resolves additional completion data at the position given.
-pub fn resolve_completion_edits(
-    db: &RootDatabase,
-    config: &CompletionConfig,
-    position: FilePosition,
-    full_import_path: &str,
-    imported_name: &str,
-) -> Option<Vec<TextEdit>> {
-    let ctx = CompletionContext::new(db, position, config)?;
-    let anchor = ctx.name_ref_syntax.as_ref()?;
-    let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
-
-    let current_module = ctx.sema.scope(anchor.syntax()).module()?;
-    let current_crate = current_module.krate();
-
-    let import_path = imports_locator::find_exact_imports(&ctx.sema, current_crate, imported_name)
-        .filter_map(|candidate| {
-            let item: hir::ItemInNs = candidate.either(Into::into, Into::into);
-            current_module.find_use_path(db, item)
-        })
-        .find(|mod_path| mod_path.to_string() == full_import_path)?;
-
-    ImportEdit { import_path, import_scope, merge_behaviour: config.merge }
-        .to_text_edit()
-        .map(|edit| vec![edit])
-}
-
 #[cfg(test)]
 mod tests {
     use crate::config::CompletionConfig;
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs
index b940388df2..504757a6ae 100644
--- a/crates/completion/src/render.rs
+++ b/crates/completion/src/render.rs
@@ -9,13 +9,14 @@ pub(crate) mod type_alias;
 
 mod builder_ext;
 
-use hir::{Documentation, HasAttrs, HirDisplay, Mutability, ScopeDef, Type};
+use hir::{Documentation, HasAttrs, HirDisplay, ModPath, Mutability, ScopeDef, Type};
+use ide_db::helpers::insert_use::{ImportScope, MergeBehaviour};
 use ide_db::RootDatabase;
 use syntax::TextRange;
 use test_utils::mark;
 
 use crate::{
-    config::SnippetCap, item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind,
+    config::SnippetCap, item::ImportToAdd, CompletionContext, CompletionItem, CompletionItemKind,
     CompletionKind, CompletionScore,
 };
 
@@ -47,12 +48,15 @@ pub(crate) fn render_resolution<'a>(
 
 pub(crate) fn render_resolution_with_import<'a>(
     ctx: RenderContext<'a>,
-    import_edit: ImportEdit,
+    import_path: ModPath,
+    import_scope: ImportScope,
+    merge_behaviour: Option<MergeBehaviour>,
     resolution: &ScopeDef,
 ) -> Option<CompletionItem> {
+    let local_name = import_path.segments.last()?.to_string();
     Render::new(ctx).render_resolution(
-        import_edit.import_path.segments.last()?.to_string(),
-        Some(import_edit),
+        local_name,
+        Some(ImportToAdd { import_path, import_scope, merge_behaviour }),
         resolution,
     )
 }
@@ -143,7 +147,7 @@ impl<'a> Render<'a> {
     fn render_resolution(
         self,
         local_name: String,
-        import_to_add: Option<ImportEdit>,
+        import_to_add: Option<ImportToAdd>,
         resolution: &ScopeDef,
     ) -> Option<CompletionItem> {
         let _p = profile::span("render_resolution");
@@ -446,6 +450,28 @@ fn main() { let _: m::Spam = S<|> }
                         insert: "m",
                         kind: Module,
                     },
+                    CompletionItem {
+                        label: "m::Spam",
+                        source_range: 75..76,
+                        text_edit: TextEdit {
+                            indels: [
+                                Indel {
+                                    insert: "use m::Spam;",
+                                    delete: 0..0,
+                                },
+                                Indel {
+                                    insert: "\n\n",
+                                    delete: 0..0,
+                                },
+                                Indel {
+                                    insert: "Spam",
+                                    delete: 75..76,
+                                },
+                            ],
+                        },
+                        kind: Enum,
+                        lookup: "Spam",
+                    },
                     CompletionItem {
                         label: "m::Spam::Foo",
                         source_range: 75..76,
diff --git a/crates/completion/src/render/enum_variant.rs b/crates/completion/src/render/enum_variant.rs
index 8e0fea6c0f..f4bd02f258 100644
--- a/crates/completion/src/render/enum_variant.rs
+++ b/crates/completion/src/render/enum_variant.rs
@@ -5,13 +5,13 @@ use itertools::Itertools;
 use test_utils::mark;
 
 use crate::{
-    item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit},
+    item::{CompletionItem, CompletionItemKind, CompletionKind, ImportToAdd},
     render::{builder_ext::Params, RenderContext},
 };
 
 pub(crate) fn render_enum_variant<'a>(
     ctx: RenderContext<'a>,
-    import_to_add: Option<ImportEdit>,
+    import_to_add: Option<ImportToAdd>,
     local_name: Option<String>,
     variant: hir::EnumVariant,
     path: Option<ModPath>,
@@ -62,7 +62,7 @@ impl<'a> EnumVariantRender<'a> {
         }
     }
 
-    fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
+    fn render(self, import_to_add: Option<ImportToAdd>) -> CompletionItem {
         let mut builder = CompletionItem::new(
             CompletionKind::Reference,
             self.ctx.source_range(),
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs
index d16005249c..00e3eb203e 100644
--- a/crates/completion/src/render/function.rs
+++ b/crates/completion/src/render/function.rs
@@ -5,13 +5,13 @@ use syntax::{ast::Fn, display::function_declaration};
 use test_utils::mark;
 
 use crate::{
-    item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit},
+    item::{CompletionItem, CompletionItemKind, CompletionKind, ImportToAdd},
     render::{builder_ext::Params, RenderContext},
 };
 
 pub(crate) fn render_fn<'a>(
     ctx: RenderContext<'a>,
-    import_to_add: Option<ImportEdit>,
+    import_to_add: Option<ImportToAdd>,
     local_name: Option<String>,
     fn_: hir::Function,
 ) -> CompletionItem {
@@ -39,7 +39,7 @@ impl<'a> FunctionRender<'a> {
         FunctionRender { ctx, name, func: fn_, ast_node }
     }
 
-    fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
+    fn render(self, import_to_add: Option<ImportToAdd>) -> CompletionItem {
         let params = self.params();
         CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone())
             .kind(self.kind())
diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs
index eb3209bee3..b4ab32c6e4 100644
--- a/crates/completion/src/render/macro_.rs
+++ b/crates/completion/src/render/macro_.rs
@@ -5,13 +5,13 @@ use syntax::display::macro_label;
 use test_utils::mark;
 
 use crate::{
-    item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit},
+    item::{CompletionItem, CompletionItemKind, CompletionKind, ImportToAdd},
     render::RenderContext,
 };
 
 pub(crate) fn render_macro<'a>(
     ctx: RenderContext<'a>,
-    import_to_add: Option<ImportEdit>,
+    import_to_add: Option<ImportToAdd>,
     name: String,
     macro_: hir::MacroDef,
 ) -> Option<CompletionItem> {
@@ -38,7 +38,7 @@ impl<'a> MacroRender<'a> {
         MacroRender { ctx, name, macro_, docs, bra, ket }
     }
 
-    fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> {
+    fn render(&self, import_to_add: Option<ImportToAdd>) -> Option<CompletionItem> {
         // FIXME: Currently proc-macro do not have ast-node,
         // such that it does not have source
         if self.macro_.is_proc_macro() {
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 71068cac28..5244bdd610 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -80,8 +80,7 @@ pub use crate::{
     },
 };
 pub use completion::{
-    CompletionConfig, CompletionItem, CompletionItemKind, CompletionResolveCapability,
-    CompletionScore, ImportEdit, InsertTextFormat,
+    CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat,
 };
 pub use ide_db::{
     call_info::CallInfo,
@@ -469,27 +468,6 @@ impl Analysis {
         self.with_db(|db| completion::completions(db, config, position).map(Into::into))
     }
 
-    /// Resolves additional completion data at the position given.
-    pub fn resolve_completion_edits(
-        &self,
-        config: &CompletionConfig,
-        position: FilePosition,
-        full_import_path: &str,
-        imported_name: &str,
-    ) -> Cancelable<Vec<TextEdit>> {
-        Ok(self
-            .with_db(|db| {
-                completion::resolve_completion_edits(
-                    db,
-                    config,
-                    position,
-                    full_import_path,
-                    imported_name,
-                )
-            })?
-            .unwrap_or_default())
-    }
-
     /// Computes resolved assists with source changes for the given position.
     pub fn resolved_assists(
         &self,
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs
index b2980a5d69..09046d3c36 100644
--- a/crates/ide_db/src/imports_locator.rs
+++ b/crates/ide_db/src/imports_locator.rs
@@ -34,25 +34,27 @@ pub fn find_exact_imports<'a>(
 pub fn find_similar_imports<'a>(
     sema: &Semantics<'a, RootDatabase>,
     krate: Crate,
-    limit: Option<usize>,
     name_to_import: &str,
+    limit: usize,
     ignore_modules: bool,
 ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
     let _p = profile::span("find_similar_imports");
 
-    let mut external_query = import_map::Query::new(name_to_import);
+    let mut external_query = import_map::Query::new(name_to_import).limit(limit);
     if ignore_modules {
         external_query = external_query.exclude_import_kind(import_map::ImportKind::Module);
     }
 
-    let mut local_query = symbol_index::Query::new(name_to_import.to_string());
-
-    if let Some(limit) = limit {
-        local_query.limit(limit);
-        external_query = external_query.limit(limit);
-    }
-
-    find_imports(sema, krate, local_query, external_query)
+    find_imports(
+        sema,
+        krate,
+        {
+            let mut local_query = symbol_index::Query::new(name_to_import.to_string());
+            local_query.limit(limit);
+            local_query
+        },
+        external_query,
+    )
 }
 
 fn find_imports<'a>(
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs
index 5e4c22bc5c..c7203451ca 100644
--- a/crates/rust-analyzer/src/caps.rs
+++ b/crates/rust-analyzer/src/caps.rs
@@ -1,7 +1,6 @@
 //! Advertizes the capabilities of the LSP Server.
 use std::env;
 
-use ide::CompletionResolveCapability;
 use lsp_types::{
     CallHierarchyServerCapability, ClientCapabilities, CodeActionKind, CodeActionOptions,
     CodeActionProviderCapability, CodeLensOptions, CompletionOptions,
@@ -12,7 +11,6 @@ use lsp_types::{
     TextDocumentSyncKind, TextDocumentSyncOptions, TypeDefinitionProviderCapability,
     WorkDoneProgressOptions,
 };
-use rustc_hash::FxHashSet;
 use serde_json::json;
 
 use crate::semantic_tokens;
@@ -32,7 +30,7 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti
         })),
         hover_provider: Some(HoverProviderCapability::Simple(true)),
         completion_provider: Some(CompletionOptions {
-            resolve_provider: completions_resolve_provider(client_caps),
+            resolve_provider: None,
             trigger_characters: Some(vec![":".to_string(), ".".to_string()]),
             work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
         }),
@@ -95,40 +93,6 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti
     }
 }
 
-fn completions_resolve_provider(client_caps: &ClientCapabilities) -> Option<bool> {
-    if enabled_completions_resolve_capabilities(client_caps)?.is_empty() {
-        log::info!("No `additionalTextEdits` completion resolve capability was found in the client capabilities, autoimport completion is disabled");
-        None
-    } else {
-        Some(true)
-    }
-}
-
-/// Parses client capabilities and returns all completion resolve capabilities rust-analyzer supports.
-pub(crate) fn enabled_completions_resolve_capabilities(
-    caps: &ClientCapabilities,
-) -> Option<FxHashSet<CompletionResolveCapability>> {
-    Some(
-        caps.text_document
-            .as_ref()?
-            .completion
-            .as_ref()?
-            .completion_item
-            .as_ref()?
-            .resolve_support
-            .as_ref()?
-            .properties
-            .iter()
-            .filter_map(|cap_string| match cap_string.as_str() {
-                "additionalTextEdits" => Some(CompletionResolveCapability::AdditionalTextEdits),
-                "detail" => Some(CompletionResolveCapability::Detail),
-                "documentation" => Some(CompletionResolveCapability::Documentation),
-                _unsupported => None,
-            })
-            .collect(),
-    )
-}
-
 fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProviderCapability {
     client_caps
         .text_document
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs
index 1ab72bd915..8a8b4a32cb 100644
--- a/crates/rust-analyzer/src/cargo_target_spec.rs
+++ b/crates/rust-analyzer/src/cargo_target_spec.rs
@@ -14,6 +14,7 @@ use crate::{global_state::GlobalStateSnapshot, Result};
 #[derive(Clone)]
 pub(crate) struct CargoTargetSpec {
     pub(crate) workspace_root: AbsPathBuf,
+    pub(crate) cargo_toml: AbsPathBuf,
     pub(crate) package: String,
     pub(crate) target: String,
     pub(crate) target_kind: TargetKind,
@@ -115,12 +116,17 @@ impl CargoTargetSpec {
             Some(it) => it,
             None => return Ok(None),
         };
+
+        let target_data = &cargo_ws[target];
+        let package_data = &cargo_ws[target_data.package];
         let res = CargoTargetSpec {
             workspace_root: cargo_ws.workspace_root().to_path_buf(),
-            package: cargo_ws.package_flag(&cargo_ws[cargo_ws[target].package]),
-            target: cargo_ws[target].name.clone(),
-            target_kind: cargo_ws[target].kind,
+            cargo_toml: package_data.manifest.clone(),
+            package: cargo_ws.package_flag(&package_data),
+            target: target_data.name.clone(),
+            target_kind: target_data.kind,
         };
+
         Ok(Some(res))
     }
 
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 5243b50c80..59269a74b9 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -19,7 +19,7 @@ use rustc_hash::FxHashSet;
 use serde::Deserialize;
 use vfs::AbsPathBuf;
 
-use crate::{caps::enabled_completions_resolve_capabilities, diagnostics::DiagnosticsMapConfig};
+use crate::diagnostics::DiagnosticsMapConfig;
 
 #[derive(Debug, Clone)]
 pub struct Config {
@@ -182,7 +182,7 @@ impl Config {
             },
             completion: CompletionConfig {
                 enable_postfix_completions: true,
-                enable_autoimport_completions: true,
+                enable_experimental_completions: true,
                 add_call_parenthesis: true,
                 add_call_argument_snippets: true,
                 ..CompletionConfig::default()
@@ -305,7 +305,7 @@ impl Config {
         };
 
         self.completion.enable_postfix_completions = data.completion_postfix_enable;
-        self.completion.enable_autoimport_completions = data.completion_autoimport_enable;
+        self.completion.enable_experimental_completions = data.completion_enableExperimental;
         self.completion.add_call_parenthesis = data.completion_addCallParenthesis;
         self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets;
         self.completion.merge = self.assist.insert_use.merge;
@@ -388,8 +388,6 @@ impl Config {
             }
 
             self.completion.allow_snippets(false);
-            self.completion.active_resolve_capabilities =
-                enabled_completions_resolve_capabilities(caps).unwrap_or_default();
             if let Some(completion) = &doc_caps.completion {
                 if let Some(completion_item) = &completion.completion_item {
                     if let Some(value) = completion_item.snippet_support {
@@ -508,7 +506,7 @@ config_data! {
         completion_addCallArgumentSnippets: bool = true,
         completion_addCallParenthesis: bool      = true,
         completion_postfix_enable: bool          = true,
-        completion_autoimport_enable: bool       = true,
+        completion_enableExperimental: bool      = true,
 
         diagnostics_enable: bool                = true,
         diagnostics_enableExperimental: bool    = true,
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 89c7fd2c7b..6250171bab 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -8,8 +8,8 @@ use std::{
 };
 
 use ide::{
-    CompletionResolveCapability, FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData,
-    NavigationTarget, Query, RangeInfo, Runnable, RunnableKind, SearchScope, TextEdit,
+    FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, NavigationTarget, Query,
+    RangeInfo, Runnable, RunnableKind, SearchScope, TextEdit,
 };
 use itertools::Itertools;
 use lsp_server::ErrorCode;
@@ -21,7 +21,7 @@ use lsp_types::{
     HoverContents, Location, NumberOrString, Position, PrepareRenameResponse, Range, RenameParams,
     SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams,
     SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation,
-    SymbolTag, TextDocumentIdentifier, TextDocumentPositionParams, Url, WorkspaceEdit,
+    SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
 };
 use project_model::TargetKind;
 use serde::{Deserialize, Serialize};
@@ -35,7 +35,6 @@ use crate::{
     from_json, from_proto,
     global_state::{GlobalState, GlobalStateSnapshot},
     lsp_ext::{self, InlayHint, InlayHintsParams},
-    lsp_utils::all_edits_are_disjoint,
     to_proto, LspError, Result,
 };
 
@@ -540,7 +539,6 @@ pub(crate) fn handle_completion(
     params: lsp_types::CompletionParams,
 ) -> Result<Option<lsp_types::CompletionResponse>> {
     let _p = profile::span("handle_completion");
-    let text_document_position = params.text_document_position.clone();
     let position = from_proto::file_position(&snap, params.text_document_position)?;
     let completion_triggered_after_single_colon = {
         let mut res = false;
@@ -570,99 +568,15 @@ pub(crate) fn handle_completion(
     };
     let line_index = snap.analysis.file_line_index(position.file_id)?;
     let line_endings = snap.file_line_endings(position.file_id);
-
     let items: Vec<CompletionItem> = items
         .into_iter()
-        .flat_map(|item| {
-            let mut new_completion_items =
-                to_proto::completion_item(&line_index, line_endings, item.clone());
-
-            if snap.config.completion.resolve_additional_edits_lazily() {
-                for new_item in &mut new_completion_items {
-                    let _ = fill_resolve_data(&mut new_item.data, &item, &text_document_position)
-                        .take();
-                }
-            }
-
-            new_completion_items
-        })
+        .flat_map(|item| to_proto::completion_item(&line_index, line_endings, item))
         .collect();
 
     let completion_list = lsp_types::CompletionList { is_incomplete: true, items };
     Ok(Some(completion_list.into()))
 }
 
-pub(crate) fn handle_completion_resolve(
-    snap: GlobalStateSnapshot,
-    mut original_completion: CompletionItem,
-) -> Result<CompletionItem> {
-    let _p = profile::span("handle_completion_resolve");
-
-    if !all_edits_are_disjoint(&original_completion, &[]) {
-        return Err(LspError::new(
-            ErrorCode::InvalidParams as i32,
-            "Received a completion with overlapping edits, this is not LSP-compliant".into(),
-        )
-        .into());
-    }
-
-    // FIXME resolve the other capabilities also?
-    if !snap
-        .config
-        .completion
-        .active_resolve_capabilities
-        .contains(&CompletionResolveCapability::AdditionalTextEdits)
-    {
-        return Ok(original_completion);
-    }
-
-    let resolve_data = match original_completion
-        .data
-        .take()
-        .map(|data| serde_json::from_value::<CompletionResolveData>(data))
-        .transpose()?
-    {
-        Some(data) => data,
-        None => return Ok(original_completion),
-    };
-
-    let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?;
-    let line_index = snap.analysis.file_line_index(file_id)?;
-    let line_endings = snap.file_line_endings(file_id);
-    let offset = from_proto::offset(&line_index, resolve_data.position.position);
-
-    let additional_edits = snap
-        .analysis
-        .resolve_completion_edits(
-            &snap.config.completion,
-            FilePosition { file_id, offset },
-            &resolve_data.full_import_path,
-            &resolve_data.imported_name,
-        )?
-        .into_iter()
-        .flat_map(|edit| {
-            edit.into_iter().map(|indel| to_proto::text_edit(&line_index, line_endings, indel))
-        })
-        .collect_vec();
-
-    if !all_edits_are_disjoint(&original_completion, &additional_edits) {
-        return Err(LspError::new(
-            ErrorCode::InternalError as i32,
-            "Import edit overlaps with the original completion edits, this is not LSP-compliant"
-                .into(),
-        )
-        .into());
-    }
-
-    if let Some(original_additional_edits) = original_completion.additional_text_edits.as_mut() {
-        original_additional_edits.extend(additional_edits.into_iter())
-    } else {
-        original_completion.additional_text_edits = Some(additional_edits);
-    }
-
-    Ok(original_completion)
-}
-
 pub(crate) fn handle_folding_range(
     snap: GlobalStateSnapshot,
     params: FoldingRangeParams,
@@ -1422,19 +1336,15 @@ pub(crate) fn handle_open_cargo_toml(
 ) -> Result<Option<lsp_types::GotoDefinitionResponse>> {
     let _p = profile::span("handle_open_cargo_toml");
     let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
-    let maybe_cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?;
-    if maybe_cargo_spec.is_none() {
-        return Ok(None);
-    }
 
-    let cargo_spec = maybe_cargo_spec.unwrap();
-    let cargo_toml_path = cargo_spec.workspace_root.join("Cargo.toml");
-    if !cargo_toml_path.exists() {
-        return Ok(None);
-    }
-    let cargo_toml_url = to_proto::url_from_abs_path(&cargo_toml_path);
-    let cargo_toml_location = Location::new(cargo_toml_url, Range::default());
-    let res = lsp_types::GotoDefinitionResponse::from(cargo_toml_location);
+    let cargo_spec = match CargoTargetSpec::for_file(&snap, file_id)? {
+        Some(it) => it,
+        None => return Ok(None),
+    };
+
+    let cargo_toml_url = to_proto::url_from_abs_path(&cargo_spec.cargo_toml);
+    let res: lsp_types::GotoDefinitionResponse =
+        Location::new(cargo_toml_url, Range::default()).into();
     Ok(Some(res))
 }
 
@@ -1620,30 +1530,3 @@ fn should_skip_target(runnable: &Runnable, cargo_spec: Option<&CargoTargetSpec>)
         _ => false,
     }
 }
-
-#[derive(Debug, Serialize, Deserialize)]
-struct CompletionResolveData {
-    position: lsp_types::TextDocumentPositionParams,
-    full_import_path: String,
-    imported_name: String,
-}
-
-fn fill_resolve_data(
-    resolve_data: &mut Option<serde_json::Value>,
-    item: &ide::CompletionItem,
-    position: &TextDocumentPositionParams,
-) -> Option<()> {
-    let import_edit = item.import_to_add()?;
-    let full_import_path = import_edit.import_path.to_string();
-    let imported_name = import_edit.import_path.segments.clone().pop()?.to_string();
-
-    *resolve_data = Some(
-        to_value(CompletionResolveData {
-            position: position.to_owned(),
-            full_import_path,
-            imported_name,
-        })
-        .unwrap(),
-    );
-    Some(())
-}
diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs
index 60c12e4e2e..6427c73672 100644
--- a/crates/rust-analyzer/src/lsp_utils.rs
+++ b/crates/rust-analyzer/src/lsp_utils.rs
@@ -129,40 +129,9 @@ pub(crate) fn apply_document_changes(
     }
 }
 
-/// Checks that the edits inside the completion and the additional edits do not overlap.
-/// LSP explicitly forbits the additional edits to overlap both with the main edit and themselves.
-pub(crate) fn all_edits_are_disjoint(
-    completion: &lsp_types::CompletionItem,
-    additional_edits: &[lsp_types::TextEdit],
-) -> bool {
-    let mut edit_ranges = Vec::new();
-    match completion.text_edit.as_ref() {
-        Some(lsp_types::CompletionTextEdit::Edit(edit)) => {
-            edit_ranges.push(edit.range);
-        }
-        Some(lsp_types::CompletionTextEdit::InsertAndReplace(edit)) => {
-            edit_ranges.push(edit.insert);
-            edit_ranges.push(edit.replace);
-        }
-        None => {}
-    }
-    if let Some(additional_changes) = completion.additional_text_edits.as_ref() {
-        edit_ranges.extend(additional_changes.iter().map(|edit| edit.range));
-    };
-    edit_ranges.extend(additional_edits.iter().map(|edit| edit.range));
-    edit_ranges.sort_by_key(|range| (range.start, range.end));
-    edit_ranges
-        .iter()
-        .zip(edit_ranges.iter().skip(1))
-        .all(|(previous, next)| previous.end <= next.start)
-}
-
 #[cfg(test)]
 mod tests {
-    use lsp_types::{
-        CompletionItem, CompletionTextEdit, InsertReplaceEdit, Position, Range,
-        TextDocumentContentChangeEvent,
-    };
+    use lsp_types::{Position, Range, TextDocumentContentChangeEvent};
 
     use super::*;
 
@@ -228,135 +197,4 @@ mod tests {
         apply_document_changes(&mut text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]);
         assert_eq!(text, "ațc\ncb");
     }
-
-    #[test]
-    fn empty_completion_disjoint_tests() {
-        let empty_completion =
-            CompletionItem::new_simple("label".to_string(), "detail".to_string());
-
-        let disjoint_edit_1 = lsp_types::TextEdit::new(
-            Range::new(Position::new(2, 2), Position::new(3, 3)),
-            "new_text".to_string(),
-        );
-        let disjoint_edit_2 = lsp_types::TextEdit::new(
-            Range::new(Position::new(3, 3), Position::new(4, 4)),
-            "new_text".to_string(),
-        );
-
-        let joint_edit = lsp_types::TextEdit::new(
-            Range::new(Position::new(1, 1), Position::new(5, 5)),
-            "new_text".to_string(),
-        );
-
-        assert!(
-            all_edits_are_disjoint(&empty_completion, &[]),
-            "Empty completion has all its edits disjoint"
-        );
-        assert!(
-            all_edits_are_disjoint(
-                &empty_completion,
-                &[disjoint_edit_1.clone(), disjoint_edit_2.clone()]
-            ),
-            "Empty completion is disjoint to whatever disjoint extra edits added"
-        );
-
-        assert!(
-            !all_edits_are_disjoint(
-                &empty_completion,
-                &[disjoint_edit_1, disjoint_edit_2, joint_edit]
-            ),
-            "Empty completion does not prevent joint extra edits from failing the validation"
-        );
-    }
-
-    #[test]
-    fn completion_with_joint_edits_disjoint_tests() {
-        let disjoint_edit = lsp_types::TextEdit::new(
-            Range::new(Position::new(1, 1), Position::new(2, 2)),
-            "new_text".to_string(),
-        );
-        let disjoint_edit_2 = lsp_types::TextEdit::new(
-            Range::new(Position::new(2, 2), Position::new(3, 3)),
-            "new_text".to_string(),
-        );
-        let joint_edit = lsp_types::TextEdit::new(
-            Range::new(Position::new(1, 1), Position::new(5, 5)),
-            "new_text".to_string(),
-        );
-
-        let mut completion_with_joint_edits =
-            CompletionItem::new_simple("label".to_string(), "detail".to_string());
-        completion_with_joint_edits.additional_text_edits =
-            Some(vec![disjoint_edit.clone(), joint_edit.clone()]);
-        assert!(
-            !all_edits_are_disjoint(&completion_with_joint_edits, &[]),
-            "Completion with disjoint edits fails the validaton even with empty extra edits"
-        );
-
-        completion_with_joint_edits.text_edit =
-            Some(CompletionTextEdit::Edit(disjoint_edit.clone()));
-        completion_with_joint_edits.additional_text_edits = Some(vec![joint_edit.clone()]);
-        assert!(
-            !all_edits_are_disjoint(&completion_with_joint_edits, &[]),
-            "Completion with disjoint edits fails the validaton even with empty extra edits"
-        );
-
-        completion_with_joint_edits.text_edit =
-            Some(CompletionTextEdit::InsertAndReplace(InsertReplaceEdit {
-                new_text: "new_text".to_string(),
-                insert: disjoint_edit.range,
-                replace: joint_edit.range,
-            }));
-        completion_with_joint_edits.additional_text_edits = None;
-        assert!(
-            !all_edits_are_disjoint(&completion_with_joint_edits, &[]),
-            "Completion with disjoint edits fails the validaton even with empty extra edits"
-        );
-
-        completion_with_joint_edits.text_edit =
-            Some(CompletionTextEdit::InsertAndReplace(InsertReplaceEdit {
-                new_text: "new_text".to_string(),
-                insert: disjoint_edit.range,
-                replace: disjoint_edit_2.range,
-            }));
-        completion_with_joint_edits.additional_text_edits = Some(vec![joint_edit]);
-        assert!(
-            !all_edits_are_disjoint(&completion_with_joint_edits, &[]),
-            "Completion with disjoint edits fails the validaton even with empty extra edits"
-        );
-    }
-
-    #[test]
-    fn completion_with_disjoint_edits_disjoint_tests() {
-        let disjoint_edit = lsp_types::TextEdit::new(
-            Range::new(Position::new(1, 1), Position::new(2, 2)),
-            "new_text".to_string(),
-        );
-        let disjoint_edit_2 = lsp_types::TextEdit::new(
-            Range::new(Position::new(2, 2), Position::new(3, 3)),
-            "new_text".to_string(),
-        );
-        let joint_edit = lsp_types::TextEdit::new(
-            Range::new(Position::new(1, 1), Position::new(5, 5)),
-            "new_text".to_string(),
-        );
-
-        let mut completion_with_disjoint_edits =
-            CompletionItem::new_simple("label".to_string(), "detail".to_string());
-        completion_with_disjoint_edits.text_edit = Some(CompletionTextEdit::Edit(disjoint_edit));
-        let completion_with_disjoint_edits = completion_with_disjoint_edits;
-
-        assert!(
-            all_edits_are_disjoint(&completion_with_disjoint_edits, &[]),
-            "Completion with disjoint edits is valid"
-        );
-        assert!(
-            !all_edits_are_disjoint(&completion_with_disjoint_edits, &[joint_edit.clone()]),
-            "Completion with disjoint edits and joint extra edit is invalid"
-        );
-        assert!(
-            all_edits_are_disjoint(&completion_with_disjoint_edits, &[disjoint_edit_2.clone()]),
-            "Completion with disjoint edits and joint extra edit is valid"
-        );
-    }
 }
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 95be2ebd39..55d46b09e7 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -454,7 +454,6 @@ impl GlobalState {
             .on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation)
             .on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
             .on::<lsp_types::request::Completion>(handlers::handle_completion)
-            .on::<lsp_types::request::ResolveCompletionItem>(handlers::handle_completion_resolve)
             .on::<lsp_types::request::CodeLensRequest>(handlers::handle_code_lens)
             .on::<lsp_types::request::CodeLensResolve>(handlers::handle_code_lens_resolve)
             .on::<lsp_types::request::FoldingRangeRequest>(handlers::handle_folding_range)
diff --git a/editors/code/package.json b/editors/code/package.json
index dbde37005c..af228f9837 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -460,13 +460,10 @@
                     "default": true,
                     "markdownDescription": "Whether to show postfix snippets like `dbg`, `if`, `not`, etc."
                 },
-                "rust-analyzer.completion.autoimport.enable": {
+                "rust-analyzer.completion.enableExperimental": {
                     "type": "boolean",
                     "default": true,
-                    "markdownDescription": [
-                        "Toggles the additional completions that automatically add imports when completed.",
-                        "Note that your client have to specify the `additionalTextEdits` LSP client capability to truly have this feature enabled"
-                    ]
+                    "markdownDescription": "Display additional completions with potential false positives and performance issues"
                 },
                 "rust-analyzer.callInfo.full": {
                     "type": "boolean",


Test patch:
diff --git a/crates/completion/src/test_utils.rs b/crates/completion/src/test_utils.rs
index 25f5f4924c..4c1b1a8392 100644
--- a/crates/completion/src/test_utils.rs
+++ b/crates/completion/src/test_utils.rs
@@ -96,16 +96,7 @@ pub(crate) fn check_edit_with_config(
         .collect_tuple()
         .unwrap_or_else(|| panic!("can't find {:?} completion in {:#?}", what, completions));
     let mut actual = db.file_text(position.file_id).to_string();
-
-    let mut combined_edit = completion.text_edit().to_owned();
-    if let Some(import_text_edit) = completion.import_to_add().and_then(|edit| edit.to_text_edit())
-    {
-        combined_edit.union(import_text_edit).expect(
-            "Failed to apply completion resolve changes: change ranges overlap, but should not",
-        )
-    }
-
-    combined_edit.apply(&mut actual);
+    completion.text_edit().apply(&mut actual);
     assert_eq_text!(&ra_fixture_after, &actual)
 }