]> git.lizzy.rs Git - rust.git/commitdiff
Merge #6577 #6579 #6581
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>
Tue, 17 Nov 2020 18:01:18 +0000 (18:01 +0000)
committerGitHub <noreply@github.com>
Tue, 17 Nov 2020 18:01:18 +0000 (18:01 +0000)
6577: fix typos in syntax.md r=matklad a=jakobhellermann

6579: cargo update and add new license r=matklad a=kjeremy

6581: Use vscode-languageclient 7.0.0-next.14 r=matklad a=kjeremy

Co-authored-by: Jakob Hellermann <jakob.hellermann@protonmail.com>
Co-authored-by: kjeremy <kjeremy@gmail.com>
32 files changed:
Cargo.lock
crates/assists/src/handlers/auto_import.rs
crates/assists/src/handlers/extract_struct_from_enum_variant.rs
crates/assists/src/handlers/replace_derive_with_manual_impl.rs
crates/assists/src/handlers/replace_qualified_name_with_use.rs
crates/assists/src/utils.rs
crates/assists/src/utils/import_assets.rs
crates/assists/src/utils/insert_use.rs
crates/cfg/src/lib.rs
crates/completion/Cargo.toml
crates/completion/src/completions.rs
crates/completion/src/completions/unqualified_path.rs
crates/completion/src/config.rs
crates/completion/src/item.rs
crates/completion/src/render.rs
crates/completion/src/render/enum_variant.rs
crates/completion/src/render/function.rs
crates/completion/src/render/macro_.rs
crates/hir/src/code_model.rs
crates/hir/src/diagnostics.rs
crates/hir/src/lib.rs
crates/hir_expand/src/diagnostics.rs
crates/ide/src/diagnostics.rs
crates/ide_db/src/imports_locator.rs
crates/project_model/src/workspace.rs
crates/rust-analyzer/src/config.rs
crates/rust-analyzer/src/handlers.rs
crates/rust-analyzer/src/reload.rs
editors/code/package-lock.json
editors/code/package.json
editors/code/src/client.ts
xtask/tests/tidy.rs

index 09215a37a2be110cfc2cb0ef610f446affb16e4f..6345ce9934343823187f626e70517410e708fc95 100644 (file)
@@ -242,9 +242,9 @@ dependencies = [
 
 [[package]]
 name = "cmake"
-version = "0.1.44"
+version = "0.1.45"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e56268c17a6248366d66d4a47a3381369d068cce8409bb1716ed77ea32163bb"
+checksum = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855"
 dependencies = [
  "cc",
 ]
@@ -255,6 +255,7 @@ version = "0.0.0"
 dependencies = [
  "assists",
  "base_db",
+ "either",
  "expect-test",
  "hir",
  "ide_db",
@@ -1065,9 +1066,9 @@ checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
 
 [[package]]
 name = "once_cell"
-version = "1.5.1"
+version = "1.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f53cef67919d7d247eb9a2f128ca9e522789967ef1eb4ccd8c71a95a8aedf596"
+checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
 
 [[package]]
 name = "oorandom"
@@ -1739,9 +1740,18 @@ dependencies = [
 
 [[package]]
 name = "tinyvec"
-version = "0.3.4"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "238ce071d267c5710f9d31451efec16c5ee22de34df17cc05e56cbc92e967117"
+checksum = "b78a366903f506d2ad52ca8dc552102ffdd3e937ba8a227f024dc1d1eae28575"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
 
 [[package]]
 name = "toolchain"
@@ -1879,18 +1889,18 @@ dependencies = [
 
 [[package]]
 name = "unicode-normalization"
-version = "0.1.13"
+version = "0.1.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977"
+checksum = "b7f98e67a4d84f730d343392f9bfff7d21e3fca562b9cb7a43b768350beeddc6"
 dependencies = [
  "tinyvec",
 ]
 
 [[package]]
 name = "unicode-segmentation"
-version = "1.6.0"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
+checksum = "db8716a166f290ff49dabc18b44aa407cb7c6dbe1aa0971b44b8a24b0ca35aae"
 
 [[package]]
 name = "unicode-xid"
index 37dd6126618efd813d9bd592246b795481618214..d665837a2f3bad0b4b8279ca1ca16f2cfdac8fda 100644 (file)
@@ -98,7 +98,8 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
 
     let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range;
     let group = import_group_message(import_assets.import_candidate());
-    let scope = ImportScope::find_insert_use_container(import_assets.syntax_under_caret(), ctx)?;
+    let scope =
+        ImportScope::find_insert_use_container(import_assets.syntax_under_caret(), &ctx.sema)?;
     for (import, _) in proposed_imports {
         acc.add_group(
             &group,
index 067afabf2edf7b45c765ac40c32d82e693ad10e0..cac77c49bbc46fdc601245e4881f945e1689e1ea 100644 (file)
@@ -143,8 +143,7 @@ fn insert_import(
     if let Some(mut mod_path) = mod_path {
         mod_path.segments.pop();
         mod_path.segments.push(variant_hir_name.clone());
-        let scope = ImportScope::find_insert_use_container(scope_node, ctx)?;
-
+        let scope = ImportScope::find_insert_use_container(scope_node, &ctx.sema)?;
         *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use.merge);
     }
     Some(())
index 82625516c211a2f05724867a7ab9dc67c98be44a..453a6cebfb8cbca4082fe0433f6084ee451840bf 100644 (file)
@@ -62,19 +62,21 @@ pub(crate) fn replace_derive_with_manual_impl(
     let current_module = ctx.sema.scope(annotated_name.syntax()).module()?;
     let current_crate = current_module.krate();
 
-    let found_traits = imports_locator::find_imports(&ctx.sema, current_crate, trait_token.text())
-        .into_iter()
-        .filter_map(|candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate {
-            either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_),
-            _ => None,
-        })
-        .flat_map(|trait_| {
-            current_module
-                .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
-                .as_ref()
-                .map(mod_path_to_ast)
-                .zip(Some(trait_))
-        });
+    let found_traits =
+        imports_locator::find_exact_imports(&ctx.sema, current_crate, trait_token.text())
+            .filter_map(
+                |candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate {
+                    either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_),
+                    _ => None,
+                },
+            )
+            .flat_map(|trait_| {
+                current_module
+                    .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
+                    .as_ref()
+                    .map(mod_path_to_ast)
+                    .zip(Some(trait_))
+            });
 
     let mut no_traits_found = true;
     for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
index d7e1d95805e67529b4f172bd19b0bec2c5c1a55e..a66db9ae3a15f271b78fc8a9a7e58edda1b1ae9e 100644 (file)
@@ -34,7 +34,7 @@ pub(crate) fn replace_qualified_name_with_use(
     }
 
     let target = path.syntax().text_range();
-    let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?;
+    let scope = ImportScope::find_insert_use_container(path.syntax(), &ctx.sema)?;
     let syntax = scope.as_syntax_node();
     acc.add(
         AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite),
index d1a0a99b1dd6e91872a7d9f1be21caa3b34e3eea..66c0cdd5faf37b7ea82d0898e6528044922a40cc 100644 (file)
@@ -22,8 +22,7 @@
     ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
 };
 
-pub use insert_use::MergeBehaviour;
-pub(crate) use insert_use::{insert_use, ImportScope};
+pub use insert_use::{insert_use, ImportScope, MergeBehaviour};
 
 pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
     let mut segments = Vec::new();
index f47edbb765851defcd73547e7de480f79b35dd01..ff5c0e78ee8c20f2d2ea70859f17b4a925bebc3d 100644 (file)
@@ -179,21 +179,25 @@ fn search_for(
             }
         };
 
-        let mut res = imports_locator::find_imports(sema, current_crate, &self.get_search_query())
-            .into_iter()
-            .filter_map(filter)
-            .filter_map(|candidate| {
-                let item: hir::ItemInNs = candidate.either(Into::into, Into::into);
-                if let Some(prefix_kind) = prefixed {
-                    self.module_with_name_to_import.find_use_path_prefixed(db, item, prefix_kind)
-                } else {
-                    self.module_with_name_to_import.find_use_path(db, item)
-                }
-                .map(|path| (path, item))
-            })
-            .filter(|(use_path, _)| !use_path.segments.is_empty())
-            .take(20)
-            .collect::<Vec<_>>();
+        let mut res =
+            imports_locator::find_exact_imports(sema, current_crate, &self.get_search_query())
+                .filter_map(filter)
+                .filter_map(|candidate| {
+                    let item: hir::ItemInNs = candidate.either(Into::into, Into::into);
+                    if let Some(prefix_kind) = prefixed {
+                        self.module_with_name_to_import.find_use_path_prefixed(
+                            db,
+                            item,
+                            prefix_kind,
+                        )
+                    } else {
+                        self.module_with_name_to_import.find_use_path(db, item)
+                    }
+                    .map(|path| (path, item))
+                })
+                .filter(|(use_path, _)| use_path.len() > 1)
+                .take(20)
+                .collect::<Vec<_>>();
         res.sort_by_key(|(path, _)| path.clone());
         res
     }
index af3fc96b6c2fce2b4e89bb624b9e85092256b17f..423782a0e0e728f426dd3bbe881fe00572ebbd07 100644 (file)
@@ -1,6 +1,8 @@
 //! Handle syntactic aspects of inserting a new `use`.
 use std::{cmp::Ordering, iter::successors};
 
+use hir::Semantics;
+use ide_db::RootDatabase;
 use itertools::{EitherOrBoth, Itertools};
 use syntax::{
     algo::SyntaxRewriter,
@@ -13,8 +15,8 @@
 };
 use test_utils::mark;
 
-#[derive(Debug)]
-pub(crate) enum ImportScope {
+#[derive(Debug, Clone)]
+pub enum ImportScope {
     File(ast::SourceFile),
     Module(ast::ItemList),
 }
@@ -31,14 +33,14 @@ pub(crate) fn from(syntax: SyntaxNode) -> Option<Self> {
     }
 
     /// Determines the containing syntax node in which to insert a `use` statement affecting `position`.
-    pub(crate) fn find_insert_use_container(
+    pub fn find_insert_use_container(
         position: &SyntaxNode,
-        ctx: &crate::assist_context::AssistContext,
+        sema: &Semantics<'_, RootDatabase>,
     ) -> Option<Self> {
-        ctx.sema.ancestors_with_macros(position.clone()).find_map(Self::from)
+        sema.ancestors_with_macros(position.clone()).find_map(Self::from)
     }
 
-    pub(crate) fn as_syntax_node(&self) -> &SyntaxNode {
+    pub fn as_syntax_node(&self) -> &SyntaxNode {
         match self {
             ImportScope::File(file) => file.syntax(),
             ImportScope::Module(item_list) => item_list.syntax(),
@@ -88,7 +90,7 @@ fn is_inner_comment(token: SyntaxToken) -> bool {
 }
 
 /// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur.
-pub(crate) fn insert_use<'a>(
+pub fn insert_use<'a>(
     scope: &ImportScope,
     path: ast::Path,
     merge: Option<MergeBehaviour>,
index d0e08cf5f7741ea63570d52cdd82915813b43826..d88ecf8b091796ee91bb31ef65127f89ffe8e3a8 100644 (file)
@@ -41,12 +41,6 @@ pub fn insert_key_value(&mut self, key: SmolStr, value: SmolStr) {
         self.enabled.insert(CfgAtom::KeyValue { key, value });
     }
 
-    pub fn append(&mut self, other: &CfgOptions) {
-        for atom in &other.enabled {
-            self.enabled.insert(atom.clone());
-        }
-    }
-
     pub fn apply_diff(&mut self, diff: CfgDiff) {
         for atom in diff.enable {
             self.enabled.insert(atom);
index 3015ec9e0ea4e49bf149c555cd55989fdb77a911..e7df9d955656bcf1b450ed2358b35a5254c42faa 100644 (file)
@@ -13,6 +13,7 @@ doctest = false
 itertools = "0.9.0"
 log = "0.4.8"
 rustc-hash = "1.1.0"
+either = "1.6.1"
 
 assists = { path = "../assists", version = "0.0.0" }
 stdx = { path = "../stdx", version = "0.0.0" }
index 75dbb1a23bb5c8c616d7c2b752994aa573e627e9..9b7d6c5809131b2819176037086402d516113267 100644 (file)
@@ -90,7 +90,7 @@ pub(crate) fn add_macro(
             Some(it) => it,
             None => return,
         };
-        if let Some(item) = render_macro(RenderContext::new(ctx), name, macro_) {
+        if let Some(item) = render_macro(RenderContext::new(ctx), None, name, macro_) {
             self.add(item);
         }
     }
@@ -101,7 +101,7 @@ pub(crate) fn add_function(
         func: hir::Function,
         local_name: Option<String>,
     ) {
-        let item = render_fn(RenderContext::new(ctx), local_name, func);
+        let item = render_fn(RenderContext::new(ctx), None, local_name, func);
         self.add(item)
     }
 
@@ -123,7 +123,7 @@ pub(crate) fn add_qualified_enum_variant(
         variant: hir::EnumVariant,
         path: ModPath,
     ) {
-        let item = render_enum_variant(RenderContext::new(ctx), None, variant, Some(path));
+        let item = render_enum_variant(RenderContext::new(ctx), None, None, variant, Some(path));
         self.add(item);
     }
 
@@ -133,7 +133,7 @@ pub(crate) fn add_enum_variant(
         variant: hir::EnumVariant,
         local_name: Option<String>,
     ) {
-        let item = render_enum_variant(RenderContext::new(ctx), local_name, variant, None);
+        let item = render_enum_variant(RenderContext::new(ctx), None, local_name, variant, None);
         self.add(item);
     }
 }
index 7df58e1da82932c62fe27532a7223275388bec26..86c143b637f713bfbee8e25c574b1108947a26db 100644 (file)
@@ -1,10 +1,16 @@
 //! Completion of names from the current scope, e.g. locals and imported items.
 
+use assists::utils::ImportScope;
+use either::Either;
 use hir::{Adt, ModuleDef, ScopeDef, Type};
+use ide_db::imports_locator;
 use syntax::AstNode;
 use test_utils::mark;
 
-use crate::{CompletionContext, Completions};
+use crate::{
+    render::{render_resolution_with_import, RenderContext},
+    CompletionContext, Completions,
+};
 
 pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
     if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) {
@@ -37,6 +43,8 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
         }
         acc.add_resolution(ctx, name.to_string(), &res)
     });
+
+    fuzzy_completion(acc, ctx).unwrap_or_default()
 }
 
 fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) {
@@ -63,6 +71,45 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
     }
 }
 
+fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
+    let _p = profile::span("fuzzy_completion");
+    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?, &potential_import_name, 400)
+            .filter_map(|import_candidate| match import_candidate {
+                // when completing outside the use declaration, modules are pretty useless
+                // and tend to bloat the completion suggestions a lot
+                Either::Left(ModuleDef::Module(_)) => None,
+                Either::Left(module_def) => Some((
+                    current_module.find_use_path(ctx.db, module_def)?,
+                    ScopeDef::ModuleDef(module_def),
+                )),
+                Either::Right(macro_def) => Some((
+                    current_module.find_use_path(ctx.db, macro_def)?,
+                    ScopeDef::MacroDef(macro_def),
+                )),
+            })
+            .filter(|(mod_path, _)| mod_path.len() > 1)
+            .filter_map(|(import_path, definition)| {
+                render_resolution_with_import(
+                    RenderContext::new(ctx),
+                    import_path.clone(),
+                    import_scope.clone(),
+                    ctx.config.merge,
+                    &definition,
+                )
+            })
+            .take(20);
+
+    acc.add_all(possible_imports);
+    Some(())
+}
+
 #[cfg(test)]
 mod tests {
     use expect_test::{expect, Expect};
@@ -676,4 +723,85 @@ impl My<|>
             "#]],
         )
     }
+
+    #[test]
+    fn function_fuzzy_completion() {
+        check_edit(
+            "stdin",
+            r#"
+//- /lib.rs crate:dep
+pub mod io {
+    pub fn stdin() {}
+};
+
+//- /main.rs crate:main deps:dep
+fn main() {
+    stdi<|>
+}
+"#,
+            r#"
+use dep::io::stdin;
+
+fn main() {
+    stdin()$0
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn macro_fuzzy_completion() {
+        check_edit(
+            "macro_with_curlies!",
+            r#"
+//- /lib.rs crate:dep
+/// Please call me as macro_with_curlies! {}
+#[macro_export]
+macro_rules! macro_with_curlies {
+    () => {}
+}
+
+//- /main.rs crate:main deps:dep
+fn main() {
+    curli<|>
+}
+"#,
+            r#"
+use dep::macro_with_curlies;
+
+fn main() {
+    macro_with_curlies! {$0}
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn struct_fuzzy_completion() {
+        check_edit(
+            "ThirdStruct",
+            r#"
+//- /lib.rs crate:dep
+pub struct FirstStruct;
+pub mod some_module {
+    pub struct SecondStruct;
+    pub struct ThirdStruct;
+}
+
+//- /main.rs crate:main deps:dep
+use dep::{FirstStruct, some_module::SecondStruct};
+
+fn main() {
+    this<|>
+}
+"#,
+            r#"
+use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
+
+fn main() {
+    ThirdStruct
+}
+"#,
+        );
+    }
 }
index 71b49ace8bfb0e38a746ff34866d9f3a3cfb46dc..82874ff256a610cb37a4388bc69ea9a40fea70e7 100644 (file)
@@ -4,12 +4,15 @@
 //! module, and we use to statically check that we only produce snippet
 //! completions if we are allowed to.
 
+use assists::utils::MergeBehaviour;
+
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct CompletionConfig {
     pub enable_postfix_completions: bool,
     pub add_call_parenthesis: bool,
     pub add_call_argument_snippets: bool,
     pub snippet_cap: Option<SnippetCap>,
+    pub merge: Option<MergeBehaviour>,
 }
 
 impl CompletionConfig {
@@ -30,6 +33,7 @@ fn default() -> Self {
             add_call_parenthesis: true,
             add_call_argument_snippets: true,
             snippet_cap: Some(SnippetCap { _private: () }),
+            merge: Some(MergeBehaviour::Full),
         }
     }
 }
index 6d1d085f4bc779e63ebfe1750b11577ac18494c3..b13c3f37628a608a5875b6520e8aecbb69034353 100644 (file)
@@ -2,8 +2,9 @@
 
 use std::fmt;
 
-use hir::{Documentation, Mutability};
-use syntax::TextRange;
+use assists::utils::{insert_use, mod_path_to_ast, ImportScope, MergeBehaviour};
+use hir::{Documentation, ModPath, Mutability};
+use syntax::{algo, TextRange};
 use text_edit::TextEdit;
 
 use crate::config::SnippetCap;
@@ -31,6 +32,7 @@ pub struct CompletionItem {
     ///
     /// Typically, replaces `source_range` with new identifier.
     text_edit: TextEdit,
+
     insert_text_format: InsertTextFormat,
 
     /// What item (struct, function, etc) are we completing.
@@ -199,8 +201,10 @@ pub(crate) fn new(
             trigger_call_info: None,
             score: None,
             ref_match: None,
+            import_data: None,
         }
     }
+
     /// What user sees in pop-up in the UI.
     pub fn label(&self) -> &str {
         &self.label
@@ -257,6 +261,7 @@ pub fn ref_match(&self) -> Option<(Mutability, CompletionScore)> {
 pub(crate) struct Builder {
     source_range: TextRange,
     completion_kind: CompletionKind,
+    import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
     label: String,
     insert_text: Option<String>,
     insert_text_format: InsertTextFormat,
@@ -273,23 +278,50 @@ pub(crate) struct Builder {
 
 impl Builder {
     pub(crate) fn build(self) -> CompletionItem {
-        let label = self.label;
-        let text_edit = match self.text_edit {
+        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_path, import_scope, merge_behaviour)) = self.import_data {
+            let import = mod_path_to_ast(&import_path);
+            let mut import_path_without_last_segment = import_path;
+            let _ = import_path_without_last_segment.segments.pop();
+
+            if !import_path_without_last_segment.segments.is_empty() {
+                if lookup.is_none() {
+                    lookup = Some(label.clone());
+                }
+                if insert_text.is_none() {
+                    insert_text = Some(label.clone());
+                }
+                label = format!("{}::{}", import_path_without_last_segment, label);
+            }
+
+            let rewriter = insert_use(&import_scope, import, 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 original_edit = match self.text_edit {
             Some(it) => it,
-            None => TextEdit::replace(
-                self.source_range,
-                self.insert_text.unwrap_or_else(|| label.clone()),
-            ),
+            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: self.lookup,
+            lookup,
             kind: self.kind,
             completion_kind: self.completion_kind,
             deprecated: self.deprecated.unwrap_or(false),
@@ -358,6 +390,13 @@ pub(crate) fn trigger_call_info(mut self) -> Builder {
         self.trigger_call_info = Some(true);
         self
     }
+    pub(crate) fn import_data(
+        mut self,
+        import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
+    ) -> Builder {
+        self.import_data = import_data;
+        self
+    }
     pub(crate) fn set_ref_match(
         mut self,
         ref_match: Option<(Mutability, CompletionScore)>,
index 1fa02c37522f0333e5c82c832bcc189a39e53b7a..e892d4de8590a6c76d00f452a4ff5baa11e3b737 100644 (file)
@@ -9,7 +9,8 @@
 
 mod builder_ext;
 
-use hir::{Documentation, HasAttrs, HirDisplay, Mutability, ScopeDef, Type};
+use assists::utils::{ImportScope, MergeBehaviour};
+use hir::{Documentation, HasAttrs, HirDisplay, ModPath, Mutability, ScopeDef, Type};
 use ide_db::RootDatabase;
 use syntax::TextRange;
 use test_utils::mark;
@@ -42,7 +43,22 @@ pub(crate) fn render_resolution<'a>(
     local_name: String,
     resolution: &ScopeDef,
 ) -> Option<CompletionItem> {
-    Render::new(ctx).render_resolution(local_name, resolution)
+    Render::new(ctx).render_resolution(local_name, None, resolution)
+}
+
+pub(crate) fn render_resolution_with_import<'a>(
+    ctx: RenderContext<'a>,
+    import: ModPath,
+    import_scope: ImportScope,
+    merge_behaviour: Option<MergeBehaviour>,
+    resolution: &ScopeDef,
+) -> Option<CompletionItem> {
+    let local_name = import.segments.last()?.to_string();
+    Render::new(ctx).render_resolution(
+        local_name,
+        Some((import, import_scope, merge_behaviour)),
+        resolution,
+    )
 }
 
 /// Interface for data and methods required for items rendering.
@@ -131,6 +147,7 @@ fn add_tuple_field(&mut self, field: usize, ty: &Type) -> CompletionItem {
     fn render_resolution(
         self,
         local_name: String,
+        import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
         resolution: &ScopeDef,
     ) -> Option<CompletionItem> {
         use hir::ModuleDef::*;
@@ -142,15 +159,15 @@ fn render_resolution(
 
         let kind = match resolution {
             ScopeDef::ModuleDef(Function(func)) => {
-                let item = render_fn(self.ctx, Some(local_name), *func);
+                let item = render_fn(self.ctx, import_data, Some(local_name), *func);
                 return Some(item);
             }
             ScopeDef::ModuleDef(EnumVariant(var)) => {
-                let item = render_enum_variant(self.ctx, Some(local_name), *var, None);
+                let item = render_enum_variant(self.ctx, import_data, Some(local_name), *var, None);
                 return Some(item);
             }
             ScopeDef::MacroDef(mac) => {
-                let item = render_macro(self.ctx, local_name, *mac);
+                let item = render_macro(self.ctx, import_data, local_name, *mac);
                 return item;
             }
 
@@ -175,6 +192,7 @@ fn render_resolution(
                     local_name,
                 )
                 .kind(CompletionItemKind::UnresolvedReference)
+                .import_data(import_data)
                 .build();
                 return Some(item);
             }
@@ -227,7 +245,12 @@ fn render_resolution(
             }
         }
 
-        let item = item.kind(kind).set_documentation(docs).set_ref_match(ref_match).build();
+        let item = item
+            .kind(kind)
+            .import_data(import_data)
+            .set_documentation(docs)
+            .set_ref_match(ref_match)
+            .build();
         Some(item)
     }
 
@@ -425,6 +448,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,
index fd412ed0eef881f348f4d3b36a0a5016767eb834..6070e9b1d7935033dfa8cfcb7a8070db8b1b2287 100644 (file)
@@ -1,5 +1,6 @@
 //! Renderer for `enum` variants.
 
+use assists::utils::{ImportScope, MergeBehaviour};
 use hir::{HasAttrs, HirDisplay, ModPath, StructKind};
 use itertools::Itertools;
 use test_utils::mark;
 
 pub(crate) fn render_enum_variant<'a>(
     ctx: RenderContext<'a>,
+    import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
     local_name: Option<String>,
     variant: hir::EnumVariant,
     path: Option<ModPath>,
 ) -> CompletionItem {
-    EnumVariantRender::new(ctx, local_name, variant, path).render()
+    EnumVariantRender::new(ctx, local_name, variant, path).render(import_data)
 }
 
 #[derive(Debug)]
@@ -60,7 +62,10 @@ fn new(
         }
     }
 
-    fn render(self) -> CompletionItem {
+    fn render(
+        self,
+        import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
+    ) -> CompletionItem {
         let mut builder = CompletionItem::new(
             CompletionKind::Reference,
             self.ctx.source_range(),
@@ -69,6 +74,7 @@ fn render(self) -> CompletionItem {
         .kind(CompletionItemKind::EnumVariant)
         .set_documentation(self.variant.docs(self.ctx.db()))
         .set_deprecated(self.ctx.is_deprecated(self.variant))
+        .import_data(import_data)
         .detail(self.detail());
 
         if self.variant_kind == StructKind::Tuple {
index 4fa6eafd72f6f8d83ac64e9bc580df1471385d4e..9dd5cd18c569031b9ffee4abd0aa327e0768feac 100644 (file)
@@ -1,6 +1,7 @@
 //! Renderer for function calls.
 
-use hir::{HasSource, Type};
+use assists::utils::{ImportScope, MergeBehaviour};
+use hir::{HasSource, ModPath, Type};
 use syntax::{ast::Fn, display::function_declaration};
 
 use crate::{
 
 pub(crate) fn render_fn<'a>(
     ctx: RenderContext<'a>,
+    import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
     local_name: Option<String>,
     fn_: hir::Function,
 ) -> CompletionItem {
-    FunctionRender::new(ctx, local_name, fn_).render()
+    FunctionRender::new(ctx, local_name, fn_).render(import_data)
 }
 
 #[derive(Debug)]
@@ -36,7 +38,10 @@ fn new(
         FunctionRender { ctx, name, fn_, ast_node }
     }
 
-    fn render(self) -> CompletionItem {
+    fn render(
+        self,
+        import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
+    ) -> CompletionItem {
         let params = self.params();
         CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone())
             .kind(self.kind())
@@ -44,6 +49,7 @@ fn render(self) -> CompletionItem {
             .set_deprecated(self.ctx.is_deprecated(self.fn_))
             .detail(self.detail())
             .add_call_parens(self.ctx.completion, self.name, params)
+            .import_data(import_data)
             .build()
     }
 
index 96be59cc336aeda40e1b3865b6ce8a0c60c691a9..fead59e41c09bafed1495af05a3efdd751741892 100644 (file)
@@ -1,6 +1,7 @@
 //! Renderer for macro invocations.
 
-use hir::{Documentation, HasSource};
+use assists::utils::{ImportScope, MergeBehaviour};
+use hir::{Documentation, HasSource, ModPath};
 use syntax::display::macro_label;
 use test_utils::mark;
 
 
 pub(crate) fn render_macro<'a>(
     ctx: RenderContext<'a>,
+    import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
     name: String,
     macro_: hir::MacroDef,
 ) -> Option<CompletionItem> {
-    MacroRender::new(ctx, name, macro_).render()
+    MacroRender::new(ctx, name, macro_).render(import_data)
 }
 
 #[derive(Debug)]
@@ -36,7 +38,10 @@ fn new(ctx: RenderContext<'a>, name: String, macro_: hir::MacroDef) -> MacroRend
         MacroRender { ctx, name, macro_, docs, bra, ket }
     }
 
-    fn render(&self) -> Option<CompletionItem> {
+    fn render(
+        &self,
+        import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
+    ) -> Option<CompletionItem> {
         // FIXME: Currently proc-macro do not have ast-node,
         // such that it does not have source
         if self.macro_.is_proc_macro() {
@@ -48,6 +53,7 @@ fn render(&self) -> Option<CompletionItem> {
                 .kind(CompletionItemKind::Macro)
                 .set_documentation(self.docs.clone())
                 .set_deprecated(self.ctx.is_deprecated(self.macro_))
+                .import_data(import_data)
                 .detail(self.detail());
 
         let needs_bang = self.needs_bang();
index 30a5e45809b9a2bbfa5b315e482fb3a0433aa196..37ed092ad0ad43ed6c70acfc914be095a91fb89d 100644 (file)
@@ -110,15 +110,9 @@ pub fn display_name(self, db: &dyn HirDatabase) -> Option<CrateDisplayName> {
     pub fn query_external_importables(
         self,
         db: &dyn DefDatabase,
-        query: &str,
+        query: import_map::Query,
     ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
-        import_map::search_dependencies(
-            db,
-            self.into(),
-            import_map::Query::new(query).anchor_end().case_sensitive().limit(40),
-        )
-        .into_iter()
-        .map(|item| match item {
+        import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| match item {
             ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()),
             ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()),
         })
index c18c1c5873992c5ef8ec37ff6f9a5337b86d91f2..d9ad8db6f76999def37cbbf11d770ffa0d8c0b4c 100644 (file)
@@ -1,6 +1,8 @@
 //! FIXME: write short doc here
 pub use hir_def::diagnostics::{InactiveCode, UnresolvedModule};
-pub use hir_expand::diagnostics::{Diagnostic, DiagnosticSink, DiagnosticSinkBuilder};
+pub use hir_expand::diagnostics::{
+    Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder,
+};
 pub use hir_ty::diagnostics::{
     IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr,
     NoSuchField,
index 0d184379f10242ded3695acebcf1f8dc52d39119..5fea25ef1b710b7e732e0a0c99196757fbc29e92 100644 (file)
@@ -49,6 +49,7 @@
     builtin_type::BuiltinType,
     docs::Documentation,
     find_path::PrefixKind,
+    import_map,
     item_scope::ItemInNs,
     nameres::ModuleSource,
     path::{ModPath, PathKind},
index 78ccc212c84c4214feb2a8747371b14b25389e48..1043c6aeb5becc71a32202b086a16574bafae0af 100644 (file)
@@ -20,7 +20,7 @@
 
 use crate::InFile;
 
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone, Debug, PartialEq)]
 pub struct DiagnosticCode(pub &'static str);
 
 impl DiagnosticCode {
index 1c7f0276321fdc338f100ebe9f1b2639d48e27a7..3df73ed4fa3450a5c21a4ad78a5ac34516ef558d 100644 (file)
@@ -10,7 +10,7 @@
 use std::cell::RefCell;
 
 use hir::{
-    diagnostics::{Diagnostic as _, DiagnosticSinkBuilder},
+    diagnostics::{Diagnostic as _, DiagnosticCode, DiagnosticSinkBuilder},
     Semantics,
 };
 use ide_db::base_db::SourceDatabase;
@@ -35,15 +35,23 @@ pub struct Diagnostic {
     pub severity: Severity,
     pub fix: Option<Fix>,
     pub unused: bool,
+    pub code: Option<DiagnosticCode>,
 }
 
 impl Diagnostic {
     fn error(range: TextRange, message: String) -> Self {
-        Self { message, range, severity: Severity::Error, fix: None, unused: false }
+        Self { message, range, severity: Severity::Error, fix: None, unused: false, code: None }
     }
 
     fn hint(range: TextRange, message: String) -> Self {
-        Self { message, range, severity: Severity::WeakWarning, fix: None, unused: false }
+        Self {
+            message,
+            range,
+            severity: Severity::WeakWarning,
+            fix: None,
+            unused: false,
+            code: None,
+        }
     }
 
     fn with_fix(self, fix: Option<Fix>) -> Self {
@@ -53,6 +61,10 @@ fn with_fix(self, fix: Option<Fix>) -> Self {
     fn with_unused(self, unused: bool) -> Self {
         Self { unused, ..self }
     }
+
+    fn with_code(self, code: Option<DiagnosticCode>) -> Self {
+        Self { code, ..self }
+    }
 }
 
 #[derive(Debug)]
@@ -126,7 +138,8 @@ pub(crate) fn diagnostics(
             // Override severity and mark as unused.
             res.borrow_mut().push(
                 Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message())
-                    .with_unused(true),
+                    .with_unused(true)
+                    .with_code(Some(d.code())),
             );
         })
         // Only collect experimental diagnostics when they're enabled.
@@ -137,8 +150,10 @@ pub(crate) fn diagnostics(
     let mut sink = sink_builder
         // Diagnostics not handled above get no fix and default treatment.
         .build(|d| {
-            res.borrow_mut()
-                .push(Diagnostic::error(sema.diagnostics_display_range(d).range, d.message()));
+            res.borrow_mut().push(
+                Diagnostic::error(sema.diagnostics_display_range(d).range, d.message())
+                    .with_code(Some(d.code())),
+            );
         });
 
     if let Some(m) = sema.to_module_def(file_id) {
@@ -149,11 +164,15 @@ pub(crate) fn diagnostics(
 }
 
 fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic {
-    Diagnostic::error(sema.diagnostics_display_range(d).range, d.message()).with_fix(d.fix(&sema))
+    Diagnostic::error(sema.diagnostics_display_range(d).range, d.message())
+        .with_fix(d.fix(&sema))
+        .with_code(Some(d.code()))
 }
 
 fn warning_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic {
-    Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message()).with_fix(d.fix(&sema))
+    Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message())
+        .with_fix(d.fix(&sema))
+        .with_code(Some(d.code()))
 }
 
 fn check_unnecessary_braces_in_use_statement(
@@ -589,6 +608,11 @@ fn test_unresolved_module_diagnostic() {
                             },
                         ),
                         unused: false,
+                        code: Some(
+                            DiagnosticCode(
+                                "unresolved-module",
+                            ),
+                        ),
                     },
                 ]
             "#]],
index df74be00bb20861a4e7039825cf240c3071cacbd..9d8ea7368d3a5141ae14dff7d03f18b45917e3a7 100644 (file)
@@ -1,36 +1,70 @@
 //! This module contains an import search funcionality that is provided to the assists module.
 //! Later, this should be moved away to a separate crate that is accessible from the assists module.
 
-use hir::{Crate, MacroDef, ModuleDef, Semantics};
+use hir::{import_map, Crate, MacroDef, ModuleDef, Semantics};
 use syntax::{ast, AstNode, SyntaxKind::NAME};
 
 use crate::{
     defs::{Definition, NameClass},
-    symbol_index::{self, FileSymbol, Query},
+    symbol_index::{self, FileSymbol},
     RootDatabase,
 };
 use either::Either;
 use rustc_hash::FxHashSet;
 
-pub fn find_imports<'a>(
+pub fn find_exact_imports<'a>(
     sema: &Semantics<'a, RootDatabase>,
     krate: Crate,
     name_to_import: &str,
-) -> Vec<Either<ModuleDef, MacroDef>> {
-    let _p = profile::span("search_for_imports");
+) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
+    let _p = profile::span("find_exact_imports");
+    find_imports(
+        sema,
+        krate,
+        {
+            let mut local_query = symbol_index::Query::new(name_to_import.to_string());
+            local_query.exact();
+            local_query.limit(40);
+            local_query
+        },
+        import_map::Query::new(name_to_import).anchor_end().case_sensitive().limit(40),
+    )
+}
+
+pub fn find_similar_imports<'a>(
+    sema: &Semantics<'a, RootDatabase>,
+    krate: Crate,
+    name_to_import: &str,
+    limit: usize,
+) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
+    let _p = profile::span("find_similar_imports");
+    find_imports(
+        sema,
+        krate,
+        {
+            let mut local_query = symbol_index::Query::new(name_to_import.to_string());
+            local_query.limit(limit);
+            local_query
+        },
+        import_map::Query::new(name_to_import).limit(limit),
+    )
+}
+
+fn find_imports<'a>(
+    sema: &Semantics<'a, RootDatabase>,
+    krate: Crate,
+    local_query: symbol_index::Query,
+    external_query: import_map::Query,
+) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
+    let _p = profile::span("find_similar_imports");
     let db = sema.db;
 
     // Query dependencies first.
     let mut candidates: FxHashSet<_> =
-        krate.query_external_importables(db, name_to_import).collect();
+        krate.query_external_importables(db, external_query).collect();
 
     // Query the local crate using the symbol index.
-    let local_results = {
-        let mut query = Query::new(name_to_import.to_string());
-        query.exact();
-        query.limit(40);
-        symbol_index::crate_symbols(db, krate.into(), query)
-    };
+    let local_results = symbol_index::crate_symbols(db, krate.into(), local_query);
 
     candidates.extend(
         local_results
@@ -43,7 +77,7 @@ pub fn find_imports<'a>(
             }),
     );
 
-    candidates.into_iter().collect()
+    candidates.into_iter()
 }
 
 fn get_name_definition<'a>(
index dbf1dc5bfac12425ac3193a70e36eae1bfdbed96..a71f96164d6287aac7a3bc567c3f64e14bb3f38d 100644 (file)
@@ -197,269 +197,280 @@ pub fn to_crate_graph(
         proc_macro_client: &ProcMacroClient,
         load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
     ) -> CrateGraph {
-        let mut crate_graph = CrateGraph::default();
-        match self {
+        let mut crate_graph = match self {
             ProjectWorkspace::Json { project, sysroot } => {
-                let sysroot_dps = sysroot
-                    .as_ref()
-                    .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load));
-
-                let mut cfg_cache: FxHashMap<Option<&str>, Vec<CfgFlag>> = FxHashMap::default();
-                let crates: FxHashMap<_, _> = project
-                    .crates()
-                    .filter_map(|(crate_id, krate)| {
-                        let file_path = &krate.root_module;
-                        let file_id = match load(&file_path) {
-                            Some(id) => id,
-                            None => {
-                                log::error!("failed to load crate root {}", file_path.display());
-                                return None;
-                            }
-                        };
-
-                        let env = krate.env.clone().into_iter().collect();
-                        let proc_macro = krate
-                            .proc_macro_dylib_path
-                            .clone()
-                            .map(|it| proc_macro_client.by_dylib_path(&it));
-
-                        let target = krate.target.as_deref().or(target);
-                        let target_cfgs = cfg_cache
-                            .entry(target)
-                            .or_insert_with(|| get_rustc_cfg_options(target));
-
-                        let mut cfg_options = CfgOptions::default();
-                        cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned());
-
-                        Some((
-                            crate_id,
-                            crate_graph.add_crate_root(
-                                file_id,
-                                krate.edition,
-                                krate.display_name.clone(),
-                                cfg_options,
-                                env,
-                                proc_macro.unwrap_or_default(),
-                            ),
-                        ))
-                    })
-                    .collect();
-
-                for (from, krate) in project.crates() {
-                    if let Some(&from) = crates.get(&from) {
-                        if let Some((public_deps, _proc_macro)) = &sysroot_dps {
-                            for (name, to) in public_deps.iter() {
-                                add_dep(&mut crate_graph, from, name.clone(), *to)
-                            }
-                        }
-
-                        for dep in &krate.deps {
-                            let to_crate_id = dep.crate_id;
-                            if let Some(&to) = crates.get(&to_crate_id) {
-                                add_dep(&mut crate_graph, from, dep.name.clone(), to)
-                            }
-                        }
-                    }
-                }
+                project_json_to_crate_graph(target, proc_macro_client, load, project, sysroot)
             }
             ProjectWorkspace::Cargo { cargo, sysroot, rustc } => {
-                let (public_deps, libproc_macro) =
-                    sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load);
+                cargo_to_crate_graph(target, proc_macro_client, load, cargo, sysroot, rustc)
+            }
+        };
+        if crate_graph.patch_cfg_if() {
+            log::debug!("Patched std to depend on cfg-if")
+        } else {
+            log::debug!("Did not patch std to depend on cfg-if")
+        }
+        crate_graph
+    }
+}
 
-                let mut cfg_options = CfgOptions::default();
-                cfg_options.extend(get_rustc_cfg_options(target));
+fn project_json_to_crate_graph(
+    target: Option<&str>,
+    proc_macro_client: &ProcMacroClient,
+    load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
+    project: &ProjectJson,
+    sysroot: &Option<Sysroot>,
+) -> CrateGraph {
+    let mut crate_graph = CrateGraph::default();
+    let sysroot_deps = sysroot
+        .as_ref()
+        .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load));
+
+    let mut cfg_cache: FxHashMap<Option<&str>, Vec<CfgFlag>> = FxHashMap::default();
+    let crates: FxHashMap<CrateId, CrateId> = project
+        .crates()
+        .filter_map(|(crate_id, krate)| {
+            let file_path = &krate.root_module;
+            let file_id = load(&file_path)?;
+            Some((crate_id, krate, file_id))
+        })
+        .map(|(crate_id, krate, file_id)| {
+            let env = krate.env.clone().into_iter().collect();
+            let proc_macro =
+                krate.proc_macro_dylib_path.clone().map(|it| proc_macro_client.by_dylib_path(&it));
+
+            let target = krate.target.as_deref().or(target);
+            let target_cfgs =
+                cfg_cache.entry(target).or_insert_with(|| get_rustc_cfg_options(target));
+
+            let mut cfg_options = CfgOptions::default();
+            cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned());
+            (
+                crate_id,
+                crate_graph.add_crate_root(
+                    file_id,
+                    krate.edition,
+                    krate.display_name.clone(),
+                    cfg_options,
+                    env,
+                    proc_macro.unwrap_or_default(),
+                ),
+            )
+        })
+        .collect();
 
-                let mut pkg_to_lib_crate = FxHashMap::default();
+    for (from, krate) in project.crates() {
+        if let Some(&from) = crates.get(&from) {
+            if let Some((public_deps, _proc_macro)) = &sysroot_deps {
+                for (name, to) in public_deps.iter() {
+                    add_dep(&mut crate_graph, from, name.clone(), *to)
+                }
+            }
+
+            for dep in &krate.deps {
+                if let Some(&to) = crates.get(&dep.crate_id) {
+                    add_dep(&mut crate_graph, from, dep.name.clone(), to)
+                }
+            }
+        }
+    }
+    crate_graph
+}
 
-                // Add test cfg for non-sysroot crates
-                cfg_options.insert_atom("test".into());
-                cfg_options.insert_atom("debug_assertions".into());
+fn cargo_to_crate_graph(
+    target: Option<&str>,
+    proc_macro_client: &ProcMacroClient,
+    load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
+    cargo: &CargoWorkspace,
+    sysroot: &Sysroot,
+    rustc: &Option<CargoWorkspace>,
+) -> CrateGraph {
+    let mut crate_graph = CrateGraph::default();
+    let (public_deps, libproc_macro) =
+        sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load);
 
-                let mut pkg_crates = FxHashMap::default();
+    let mut cfg_options = CfgOptions::default();
+    cfg_options.extend(get_rustc_cfg_options(target));
 
-                // Next, create crates for each package, target pair
-                for pkg in cargo.packages() {
-                    let mut lib_tgt = None;
-                    for &tgt in cargo[pkg].targets.iter() {
-                        if let Some(crate_id) = add_target_crate_root(
+    let mut pkg_to_lib_crate = FxHashMap::default();
+
+    // Add test cfg for non-sysroot crates
+    cfg_options.insert_atom("test".into());
+    cfg_options.insert_atom("debug_assertions".into());
+
+    let mut pkg_crates = FxHashMap::default();
+
+    // Next, create crates for each package, target pair
+    for pkg in cargo.packages() {
+        let mut lib_tgt = None;
+        for &tgt in cargo[pkg].targets.iter() {
+            if let Some(file_id) = load(&cargo[tgt].root) {
+                let crate_id = add_target_crate_root(
+                    &mut crate_graph,
+                    &cargo[pkg],
+                    &cfg_options,
+                    proc_macro_client,
+                    file_id,
+                );
+                if cargo[tgt].kind == TargetKind::Lib {
+                    lib_tgt = Some((crate_id, cargo[tgt].name.clone()));
+                    pkg_to_lib_crate.insert(pkg, crate_id);
+                }
+                if cargo[tgt].is_proc_macro {
+                    if let Some(proc_macro) = libproc_macro {
+                        add_dep(
                             &mut crate_graph,
-                            &cargo[pkg],
-                            &cargo[tgt],
-                            &cfg_options,
-                            proc_macro_client,
-                            load,
-                        ) {
-                            if cargo[tgt].kind == TargetKind::Lib {
-                                lib_tgt = Some((crate_id, cargo[tgt].name.clone()));
-                                pkg_to_lib_crate.insert(pkg, crate_id);
-                            }
-                            if cargo[tgt].is_proc_macro {
-                                if let Some(proc_macro) = libproc_macro {
-                                    add_dep(
-                                        &mut crate_graph,
-                                        crate_id,
-                                        CrateName::new("proc_macro").unwrap(),
-                                        proc_macro,
-                                    );
-                                }
-                            }
-
-                            pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
-                        }
+                            crate_id,
+                            CrateName::new("proc_macro").unwrap(),
+                            proc_macro,
+                        );
                     }
+                }
 
-                    // Set deps to the core, std and to the lib target of the current package
-                    for &from in pkg_crates.get(&pkg).into_iter().flatten() {
-                        if let Some((to, name)) = lib_tgt.clone() {
-                            // For root projects with dashes in their name,
-                            // cargo metadata does not do any normalization,
-                            // so we do it ourselves currently
-                            let name = CrateName::normalize_dashes(&name);
-                            if to != from {
-                                add_dep(&mut crate_graph, from, name, to);
-                            }
-                        }
-                        for (name, krate) in public_deps.iter() {
-                            add_dep(&mut crate_graph, from, name.clone(), *krate);
-                        }
-                    }
+                pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
+            }
+        }
+
+        // Set deps to the core, std and to the lib target of the current package
+        for &from in pkg_crates.get(&pkg).into_iter().flatten() {
+            if let Some((to, name)) = lib_tgt.clone() {
+                if to != from {
+                    // For root projects with dashes in their name,
+                    // cargo metadata does not do any normalization,
+                    // so we do it ourselves currently
+                    let name = CrateName::normalize_dashes(&name);
+                    add_dep(&mut crate_graph, from, name, to);
                 }
+            }
+            for (name, krate) in public_deps.iter() {
+                add_dep(&mut crate_graph, from, name.clone(), *krate);
+            }
+        }
+    }
 
-                // Now add a dep edge from all targets of upstream to the lib
-                // target of downstream.
-                for pkg in cargo.packages() {
-                    for dep in cargo[pkg].dependencies.iter() {
-                        let name = CrateName::new(&dep.name).unwrap();
-                        if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
-                            for &from in pkg_crates.get(&pkg).into_iter().flatten() {
-                                add_dep(&mut crate_graph, from, name.clone(), to)
-                            }
-                        }
-                    }
+    // Now add a dep edge from all targets of upstream to the lib
+    // target of downstream.
+    for pkg in cargo.packages() {
+        for dep in cargo[pkg].dependencies.iter() {
+            let name = CrateName::new(&dep.name).unwrap();
+            if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
+                for &from in pkg_crates.get(&pkg).into_iter().flatten() {
+                    add_dep(&mut crate_graph, from, name.clone(), to)
+                }
+            }
+        }
+    }
+
+    let mut rustc_pkg_crates = FxHashMap::default();
+
+    // If the user provided a path to rustc sources, we add all the rustc_private crates
+    // and create dependencies on them for the crates in the current workspace
+    if let Some(rustc_workspace) = rustc {
+        for pkg in rustc_workspace.packages() {
+            for &tgt in rustc_workspace[pkg].targets.iter() {
+                if rustc_workspace[tgt].kind != TargetKind::Lib {
+                    continue;
+                }
+                // Exclude alloc / core / std
+                if rustc_workspace[tgt]
+                    .root
+                    .components()
+                    .any(|c| c == Component::Normal("library".as_ref()))
+                {
+                    continue;
                 }
 
-                let mut rustc_pkg_crates = FxHashMap::default();
-
-                // If the user provided a path to rustc sources, we add all the rustc_private crates
-                // and create dependencies on them for the crates in the current workspace
-                if let Some(rustc_workspace) = rustc {
-                    for pkg in rustc_workspace.packages() {
-                        for &tgt in rustc_workspace[pkg].targets.iter() {
-                            if rustc_workspace[tgt].kind != TargetKind::Lib {
-                                continue;
-                            }
-                            // Exclude alloc / core / std
-                            if rustc_workspace[tgt]
-                                .root
-                                .components()
-                                .any(|c| c == Component::Normal("library".as_ref()))
-                            {
-                                continue;
-                            }
-
-                            if let Some(crate_id) = add_target_crate_root(
-                                &mut crate_graph,
-                                &rustc_workspace[pkg],
-                                &rustc_workspace[tgt],
-                                &cfg_options,
-                                proc_macro_client,
-                                load,
-                            ) {
-                                pkg_to_lib_crate.insert(pkg, crate_id);
-                                // Add dependencies on the core / std / alloc for rustc
-                                for (name, krate) in public_deps.iter() {
-                                    add_dep(&mut crate_graph, crate_id, name.clone(), *krate);
-                                }
-                                rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
-                            }
-                        }
+                if let Some(file_id) = load(&rustc_workspace[tgt].root) {
+                    let crate_id = add_target_crate_root(
+                        &mut crate_graph,
+                        &rustc_workspace[pkg],
+                        &cfg_options,
+                        proc_macro_client,
+                        file_id,
+                    );
+                    pkg_to_lib_crate.insert(pkg, crate_id);
+                    // Add dependencies on the core / std / alloc for rustc
+                    for (name, krate) in public_deps.iter() {
+                        add_dep(&mut crate_graph, crate_id, name.clone(), *krate);
                     }
-                    // Now add a dep edge from all targets of upstream to the lib
-                    // target of downstream.
-                    for pkg in rustc_workspace.packages() {
-                        for dep in rustc_workspace[pkg].dependencies.iter() {
-                            let name = CrateName::new(&dep.name).unwrap();
-                            if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
-                                for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() {
-                                    add_dep(&mut crate_graph, from, name.clone(), to);
-                                }
-                            }
-                        }
+                    rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
+                }
+            }
+        }
+        // Now add a dep edge from all targets of upstream to the lib
+        // target of downstream.
+        for pkg in rustc_workspace.packages() {
+            for dep in rustc_workspace[pkg].dependencies.iter() {
+                let name = CrateName::new(&dep.name).unwrap();
+                if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
+                    for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() {
+                        add_dep(&mut crate_graph, from, name.clone(), to);
                     }
+                }
+            }
+        }
 
-                    // Add dependencies for all the crates of the current workspace to rustc_private libraries
-                    for dep in rustc_workspace.packages() {
-                        let name = CrateName::normalize_dashes(&rustc_workspace[dep].name);
-
-                        if let Some(&to) = pkg_to_lib_crate.get(&dep) {
-                            for pkg in cargo.packages() {
-                                if !cargo[pkg].is_member {
-                                    continue;
-                                }
-                                for &from in pkg_crates.get(&pkg).into_iter().flatten() {
-                                    add_dep(&mut crate_graph, from, name.clone(), to);
-                                }
-                            }
-                        }
+        // Add dependencies for all the crates of the current workspace to rustc_private libraries
+        for dep in rustc_workspace.packages() {
+            let name = CrateName::normalize_dashes(&rustc_workspace[dep].name);
+
+            if let Some(&to) = pkg_to_lib_crate.get(&dep) {
+                for pkg in cargo.packages() {
+                    if !cargo[pkg].is_member {
+                        continue;
+                    }
+                    for &from in pkg_crates.get(&pkg).into_iter().flatten() {
+                        add_dep(&mut crate_graph, from, name.clone(), to);
                     }
                 }
             }
         }
-        if crate_graph.patch_cfg_if() {
-            log::debug!("Patched std to depend on cfg-if")
-        } else {
-            log::debug!("Did not patch std to depend on cfg-if")
-        }
-        crate_graph
     }
+    crate_graph
 }
 
 fn add_target_crate_root(
     crate_graph: &mut CrateGraph,
     pkg: &cargo_workspace::PackageData,
-    tgt: &cargo_workspace::TargetData,
     cfg_options: &CfgOptions,
     proc_macro_client: &ProcMacroClient,
-    load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
-) -> Option<CrateId> {
-    let root = tgt.root.as_path();
-    if let Some(file_id) = load(root) {
-        let edition = pkg.edition;
-        let cfg_options = {
-            let mut opts = cfg_options.clone();
-            for feature in pkg.features.iter() {
-                opts.insert_key_value("feature".into(), feature.into());
-            }
-            opts.extend(pkg.cfgs.iter().cloned());
-            opts
-        };
-        let mut env = Env::default();
-        if let Some(out_dir) = &pkg.out_dir {
-            // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
-            if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) {
-                env.set("OUT_DIR", out_dir);
-            }
+    file_id: FileId,
+) -> CrateId {
+    let edition = pkg.edition;
+    let cfg_options = {
+        let mut opts = cfg_options.clone();
+        for feature in pkg.features.iter() {
+            opts.insert_key_value("feature".into(), feature.into());
+        }
+        opts.extend(pkg.cfgs.iter().cloned());
+        opts
+    };
+    let mut env = Env::default();
+    if let Some(out_dir) = &pkg.out_dir {
+        // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
+        if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) {
+            env.set("OUT_DIR", out_dir);
         }
-        let proc_macro = pkg
-            .proc_macro_dylib_path
-            .as_ref()
-            .map(|it| proc_macro_client.by_dylib_path(&it))
-            .unwrap_or_default();
-
-        let display_name = CrateDisplayName::from_canonical_name(pkg.name.clone());
-        let crate_id = crate_graph.add_crate_root(
-            file_id,
-            edition,
-            Some(display_name),
-            cfg_options,
-            env,
-            proc_macro.clone(),
-        );
-
-        return Some(crate_id);
     }
-    None
+    let proc_macro = pkg
+        .proc_macro_dylib_path
+        .as_ref()
+        .map(|it| proc_macro_client.by_dylib_path(&it))
+        .unwrap_or_default();
+
+    let display_name = CrateDisplayName::from_canonical_name(pkg.name.clone());
+    let crate_id = crate_graph.add_crate_root(
+        file_id,
+        edition,
+        Some(display_name),
+        cfg_options,
+        env,
+        proc_macro.clone(),
+    );
+
+    crate_id
 }
+
 fn sysroot_to_crate_graph(
     crate_graph: &mut CrateGraph,
     sysroot: &Sysroot,
index d16796590087947737db0eb0e231d1b4dba43d07..5fc6800cf2fd9a6e934f73ed325ac8018470c1b8 100644 (file)
@@ -294,10 +294,6 @@ pub fn update(&mut self, json: serde_json::Value) {
             max_length: data.inlayHints_maxLength,
         };
 
-        self.completion.enable_postfix_completions = data.completion_postfix_enable;
-        self.completion.add_call_parenthesis = data.completion_addCallParenthesis;
-        self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets;
-
         self.assist.insert_use.merge = match data.assist_importMergeBehaviour {
             MergeBehaviourDef::None => None,
             MergeBehaviourDef::Full => Some(MergeBehaviour::Full),
@@ -309,6 +305,11 @@ pub fn update(&mut self, json: serde_json::Value) {
             ImportPrefixDef::BySelf => PrefixKind::BySelf,
         };
 
+        self.completion.enable_postfix_completions = data.completion_postfix_enable;
+        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;
+
         self.call_info_full = data.callInfo_full;
 
         self.lens = LensConfig {
index 4d1ebf6bf9890004dddb4c094a0f96acb830f293..118e7276f2b2e700ceba5a2b3c60ffdd69a97e79 100644 (file)
@@ -18,7 +18,7 @@
     CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams,
     CodeActionKind, CodeLens, Command, CompletionItem, Diagnostic, DiagnosticTag,
     DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeParams,
-    HoverContents, Location, Position, PrepareRenameResponse, Range, RenameParams,
+    HoverContents, Location, NumberOrString, Position, PrepareRenameResponse, Range, RenameParams,
     SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams,
     SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation,
     SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
@@ -573,7 +573,7 @@ pub(crate) fn handle_completion(
         .flat_map(|item| to_proto::completion_item(&line_index, line_endings, item))
         .collect();
 
-    let completion_list = lsp_types::CompletionList { is_incomplete: false, items };
+    let completion_list = lsp_types::CompletionList { is_incomplete: true, items };
     Ok(Some(completion_list.into()))
 }
 
@@ -1128,7 +1128,7 @@ pub(crate) fn publish_diagnostics(
         .map(|d| Diagnostic {
             range: to_proto::range(&line_index, d.range),
             severity: Some(to_proto::diagnostic_severity(d.severity)),
-            code: None,
+            code: d.code.map(|d| d.as_str().to_owned()).map(NumberOrString::String),
             code_description: None,
             source: Some("rust-analyzer".to_string()),
             message: d.message,
index fa6e09f42bda25b4d89999dae8888b004e225fc1..001bf59498fb453535bba7cdc130f91f28dc5b99 100644 (file)
@@ -203,7 +203,11 @@ pub(crate) fn switch_workspaces(&mut self, workspaces: Vec<anyhow::Result<Projec
                     let contents = loader.handle.load_sync(path);
                     vfs.set_file_contents(vfs_path.clone(), contents);
                 }
-                vfs.file_id(&vfs_path)
+                let res = vfs.file_id(&vfs_path);
+                if res.is_none() {
+                    log::error!("failed to load {}", path.display())
+                }
+                res
             };
             for ws in workspaces.iter() {
                 crate_graph.extend(ws.to_crate_graph(
index 83ef00058e4516029b387b8f8459dcef6fc53a8c..a60d3668be716da3e372969aff22ca7d97ffabda 100644 (file)
             "integrity": "sha512-1nG+6cuTtpzmXe7yYfO9GCkYlyV6Ai+jDnwidHiT2T7zhc+bJM+VTtc0T/CdTlDyTNTqIcCj0V1nD4TcVjJ7Ug=="
         },
         "vscode-languageclient": {
-            "version": "7.0.0-next.12",
-            "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-7.0.0-next.12.tgz",
-            "integrity": "sha512-OrzvOvhS5o26C0KctTJC7hkwh3avCwkVhllzy42AqwpIUZ3p2aVqkSG2uVxaeodq8ThBb3TLgtg50vxyWs6FEg==",
+            "version": "7.0.0-next.14",
+            "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-7.0.0-next.14.tgz",
+            "integrity": "sha512-QUccfXK2F6AXXRFR8QJCaIz7N2BhJK6ok8E1aO8LHq2IBU33+5hTSJBXs7nEqrqZ/cY2VlDDbMWtMvCxz+/y1w==",
             "requires": {
                 "semver": "^6.3.0",
-                "vscode-languageserver-protocol": "3.16.0-next.10"
+                "vscode-languageserver-protocol": "3.16.0-next.11"
             }
         },
         "vscode-languageserver-protocol": {
-            "version": "3.16.0-next.10",
-            "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0-next.10.tgz",
-            "integrity": "sha512-YRTctHUZvts0Z1xXKNYU0ha0o+Tlgtwr+6O8OmDquM086N8exiSKBMwMC+Ra1QtIE+1mfW43Wxsme2FnMkAS9A==",
+            "version": "3.16.0-next.11",
+            "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0-next.11.tgz",
+            "integrity": "sha512-31FmupmSmfznuMuGp7qN6h3d/hKUbexbvcwTvrUE/igqRlzFU542s8MtGICx1ERbVuDOLGp96W2Z92qbUbmBPA==",
             "requires": {
                 "vscode-jsonrpc": "6.0.0-next.7",
-                "vscode-languageserver-types": "3.16.0-next.4"
+                "vscode-languageserver-types": "3.16.0-next.5"
             }
         },
         "vscode-languageserver-types": {
-            "version": "3.16.0-next.4",
-            "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0-next.4.tgz",
-            "integrity": "sha512-NlKJyGcET/ZBCCLBYIPaGo2c37R03bPYeWXozUtnjyye7+9dhlbMSODyoG2INcQf8zFmB4qhm2UOJjgYEgPCNA=="
+            "version": "3.16.0-next.5",
+            "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0-next.5.tgz",
+            "integrity": "sha512-lf8Y1XXMtF1r2oDDAmJe+drizNXkybSRXAQQk5dPy2rYJsY9SPXYNO074L3THu9zNYepzV5fRJZUPo/V/TLBRQ=="
         },
         "vscode-test": {
             "version": "1.4.0",
index 220d44abc8f6e77d386d0da71b8420b71a9ef347..a2d6b1148fa18d80c7e82409ce2e5fa6fb857a78 100644 (file)
@@ -21,7 +21,7 @@
         "Programming Languages"
     ],
     "engines": {
-        "vscode": "^1.47.1"
+        "vscode": "^1.51.0"
     },
     "enableProposedApi": true,
     "scripts": {
@@ -36,7 +36,7 @@
     },
     "dependencies": {
         "node-fetch": "^2.6.1",
-        "vscode-languageclient": "7.0.0-next.12"
+        "vscode-languageclient": "7.0.0-next.14"
     },
     "devDependencies": {
         "@rollup/plugin-commonjs": "^13.0.2",
index c9d032ead38645ea414d5b99a6d653ffd4f47989..63ab82dde7b0835fcff69621ef2ee1e7854f6594 100644 (file)
@@ -174,6 +174,8 @@ class ExperimentalFeatures implements lc.StaticFeature {
     }
     initialize(_capabilities: lc.ServerCapabilities<any>, _documentSelector: lc.DocumentSelector | undefined): void {
     }
+    dispose(): void {
+    }
 }
 
 function isCodeActionWithoutEditsAndCommands(value: any): boolean {
index 99652e76b64658577d25a8677f3041a41ce19c05..4c58aed599acb482383eb8e41898b0332837512b 100644 (file)
@@ -168,6 +168,7 @@ fn check_licenses() {
 MIT
 MIT / Apache-2.0
 MIT OR Apache-2.0
+MIT OR Apache-2.0 OR Zlib
 MIT OR Zlib OR Apache-2.0
 MIT/Apache-2.0
 Unlicense OR MIT