diff options
Diffstat (limited to 'crates')
27 files changed, 652 insertions, 345 deletions
diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs index 37dd61266..d665837a2 100644 --- a/crates/assists/src/handlers/auto_import.rs +++ b/crates/assists/src/handlers/auto_import.rs | |||
@@ -98,7 +98,8 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
98 | 98 | ||
99 | let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range; | 99 | let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range; |
100 | let group = import_group_message(import_assets.import_candidate()); | 100 | let group = import_group_message(import_assets.import_candidate()); |
101 | let scope = ImportScope::find_insert_use_container(import_assets.syntax_under_caret(), ctx)?; | 101 | let scope = |
102 | ImportScope::find_insert_use_container(import_assets.syntax_under_caret(), &ctx.sema)?; | ||
102 | for (import, _) in proposed_imports { | 103 | for (import, _) in proposed_imports { |
103 | acc.add_group( | 104 | acc.add_group( |
104 | &group, | 105 | &group, |
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs index 067afabf2..cac77c49b 100644 --- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -143,8 +143,7 @@ fn insert_import( | |||
143 | if let Some(mut mod_path) = mod_path { | 143 | if let Some(mut mod_path) = mod_path { |
144 | mod_path.segments.pop(); | 144 | mod_path.segments.pop(); |
145 | mod_path.segments.push(variant_hir_name.clone()); | 145 | mod_path.segments.push(variant_hir_name.clone()); |
146 | let scope = ImportScope::find_insert_use_container(scope_node, ctx)?; | 146 | let scope = ImportScope::find_insert_use_container(scope_node, &ctx.sema)?; |
147 | |||
148 | *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use.merge); | 147 | *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use.merge); |
149 | } | 148 | } |
150 | Some(()) | 149 | Some(()) |
diff --git a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs index 82625516c..453a6cebf 100644 --- a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs | |||
@@ -62,19 +62,21 @@ pub(crate) fn replace_derive_with_manual_impl( | |||
62 | let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; | 62 | let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; |
63 | let current_crate = current_module.krate(); | 63 | let current_crate = current_module.krate(); |
64 | 64 | ||
65 | let found_traits = imports_locator::find_imports(&ctx.sema, current_crate, trait_token.text()) | 65 | let found_traits = |
66 | .into_iter() | 66 | imports_locator::find_exact_imports(&ctx.sema, current_crate, trait_token.text()) |
67 | .filter_map(|candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate { | 67 | .filter_map( |
68 | either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_), | 68 | |candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate { |
69 | _ => None, | 69 | either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_), |
70 | }) | 70 | _ => None, |
71 | .flat_map(|trait_| { | 71 | }, |
72 | current_module | 72 | ) |
73 | .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_)) | 73 | .flat_map(|trait_| { |
74 | .as_ref() | 74 | current_module |
75 | .map(mod_path_to_ast) | 75 | .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_)) |
76 | .zip(Some(trait_)) | 76 | .as_ref() |
77 | }); | 77 | .map(mod_path_to_ast) |
78 | .zip(Some(trait_)) | ||
79 | }); | ||
78 | 80 | ||
79 | let mut no_traits_found = true; | 81 | let mut no_traits_found = true; |
80 | for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { | 82 | for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { |
diff --git a/crates/assists/src/handlers/replace_qualified_name_with_use.rs b/crates/assists/src/handlers/replace_qualified_name_with_use.rs index d7e1d9580..a66db9ae3 100644 --- a/crates/assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -34,7 +34,7 @@ pub(crate) fn replace_qualified_name_with_use( | |||
34 | } | 34 | } |
35 | 35 | ||
36 | let target = path.syntax().text_range(); | 36 | let target = path.syntax().text_range(); |
37 | let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?; | 37 | let scope = ImportScope::find_insert_use_container(path.syntax(), &ctx.sema)?; |
38 | let syntax = scope.as_syntax_node(); | 38 | let syntax = scope.as_syntax_node(); |
39 | acc.add( | 39 | acc.add( |
40 | AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite), | 40 | AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite), |
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index d1a0a99b1..66c0cdd5f 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -22,8 +22,7 @@ use crate::{ | |||
22 | ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, | 22 | ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | pub use insert_use::MergeBehaviour; | 25 | pub use insert_use::{insert_use, ImportScope, MergeBehaviour}; |
26 | pub(crate) use insert_use::{insert_use, ImportScope}; | ||
27 | 26 | ||
28 | pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path { | 27 | pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path { |
29 | let mut segments = Vec::new(); | 28 | let mut segments = Vec::new(); |
diff --git a/crates/assists/src/utils/import_assets.rs b/crates/assists/src/utils/import_assets.rs index f47edbb76..ff5c0e78e 100644 --- a/crates/assists/src/utils/import_assets.rs +++ b/crates/assists/src/utils/import_assets.rs | |||
@@ -179,21 +179,25 @@ impl ImportAssets { | |||
179 | } | 179 | } |
180 | }; | 180 | }; |
181 | 181 | ||
182 | let mut res = imports_locator::find_imports(sema, current_crate, &self.get_search_query()) | 182 | let mut res = |
183 | .into_iter() | 183 | imports_locator::find_exact_imports(sema, current_crate, &self.get_search_query()) |
184 | .filter_map(filter) | 184 | .filter_map(filter) |
185 | .filter_map(|candidate| { | 185 | .filter_map(|candidate| { |
186 | let item: hir::ItemInNs = candidate.either(Into::into, Into::into); | 186 | let item: hir::ItemInNs = candidate.either(Into::into, Into::into); |
187 | if let Some(prefix_kind) = prefixed { | 187 | if let Some(prefix_kind) = prefixed { |
188 | self.module_with_name_to_import.find_use_path_prefixed(db, item, prefix_kind) | 188 | self.module_with_name_to_import.find_use_path_prefixed( |
189 | } else { | 189 | db, |
190 | self.module_with_name_to_import.find_use_path(db, item) | 190 | item, |
191 | } | 191 | prefix_kind, |
192 | .map(|path| (path, item)) | 192 | ) |
193 | }) | 193 | } else { |
194 | .filter(|(use_path, _)| !use_path.segments.is_empty()) | 194 | self.module_with_name_to_import.find_use_path(db, item) |
195 | .take(20) | 195 | } |
196 | .collect::<Vec<_>>(); | 196 | .map(|path| (path, item)) |
197 | }) | ||
198 | .filter(|(use_path, _)| use_path.len() > 1) | ||
199 | .take(20) | ||
200 | .collect::<Vec<_>>(); | ||
197 | res.sort_by_key(|(path, _)| path.clone()); | 201 | res.sort_by_key(|(path, _)| path.clone()); |
198 | res | 202 | res |
199 | } | 203 | } |
diff --git a/crates/assists/src/utils/insert_use.rs b/crates/assists/src/utils/insert_use.rs index af3fc96b6..423782a0e 100644 --- a/crates/assists/src/utils/insert_use.rs +++ b/crates/assists/src/utils/insert_use.rs | |||
@@ -1,6 +1,8 @@ | |||
1 | //! Handle syntactic aspects of inserting a new `use`. | 1 | //! Handle syntactic aspects of inserting a new `use`. |
2 | use std::{cmp::Ordering, iter::successors}; | 2 | use std::{cmp::Ordering, iter::successors}; |
3 | 3 | ||
4 | use hir::Semantics; | ||
5 | use ide_db::RootDatabase; | ||
4 | use itertools::{EitherOrBoth, Itertools}; | 6 | use itertools::{EitherOrBoth, Itertools}; |
5 | use syntax::{ | 7 | use syntax::{ |
6 | algo::SyntaxRewriter, | 8 | algo::SyntaxRewriter, |
@@ -13,8 +15,8 @@ use syntax::{ | |||
13 | }; | 15 | }; |
14 | use test_utils::mark; | 16 | use test_utils::mark; |
15 | 17 | ||
16 | #[derive(Debug)] | 18 | #[derive(Debug, Clone)] |
17 | pub(crate) enum ImportScope { | 19 | pub enum ImportScope { |
18 | File(ast::SourceFile), | 20 | File(ast::SourceFile), |
19 | Module(ast::ItemList), | 21 | Module(ast::ItemList), |
20 | } | 22 | } |
@@ -31,14 +33,14 @@ impl ImportScope { | |||
31 | } | 33 | } |
32 | 34 | ||
33 | /// Determines the containing syntax node in which to insert a `use` statement affecting `position`. | 35 | /// Determines the containing syntax node in which to insert a `use` statement affecting `position`. |
34 | pub(crate) fn find_insert_use_container( | 36 | pub fn find_insert_use_container( |
35 | position: &SyntaxNode, | 37 | position: &SyntaxNode, |
36 | ctx: &crate::assist_context::AssistContext, | 38 | sema: &Semantics<'_, RootDatabase>, |
37 | ) -> Option<Self> { | 39 | ) -> Option<Self> { |
38 | ctx.sema.ancestors_with_macros(position.clone()).find_map(Self::from) | 40 | sema.ancestors_with_macros(position.clone()).find_map(Self::from) |
39 | } | 41 | } |
40 | 42 | ||
41 | pub(crate) fn as_syntax_node(&self) -> &SyntaxNode { | 43 | pub fn as_syntax_node(&self) -> &SyntaxNode { |
42 | match self { | 44 | match self { |
43 | ImportScope::File(file) => file.syntax(), | 45 | ImportScope::File(file) => file.syntax(), |
44 | ImportScope::Module(item_list) => item_list.syntax(), | 46 | ImportScope::Module(item_list) => item_list.syntax(), |
@@ -88,7 +90,7 @@ fn is_inner_comment(token: SyntaxToken) -> bool { | |||
88 | } | 90 | } |
89 | 91 | ||
90 | /// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. | 92 | /// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. |
91 | pub(crate) fn insert_use<'a>( | 93 | pub fn insert_use<'a>( |
92 | scope: &ImportScope, | 94 | scope: &ImportScope, |
93 | path: ast::Path, | 95 | path: ast::Path, |
94 | merge: Option<MergeBehaviour>, | 96 | merge: Option<MergeBehaviour>, |
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs index d0e08cf5f..d88ecf8b0 100644 --- a/crates/cfg/src/lib.rs +++ b/crates/cfg/src/lib.rs | |||
@@ -41,12 +41,6 @@ impl CfgOptions { | |||
41 | self.enabled.insert(CfgAtom::KeyValue { key, value }); | 41 | self.enabled.insert(CfgAtom::KeyValue { key, value }); |
42 | } | 42 | } |
43 | 43 | ||
44 | pub fn append(&mut self, other: &CfgOptions) { | ||
45 | for atom in &other.enabled { | ||
46 | self.enabled.insert(atom.clone()); | ||
47 | } | ||
48 | } | ||
49 | |||
50 | pub fn apply_diff(&mut self, diff: CfgDiff) { | 44 | pub fn apply_diff(&mut self, diff: CfgDiff) { |
51 | for atom in diff.enable { | 45 | for atom in diff.enable { |
52 | self.enabled.insert(atom); | 46 | self.enabled.insert(atom); |
diff --git a/crates/completion/Cargo.toml b/crates/completion/Cargo.toml index 3015ec9e0..e7df9d955 100644 --- a/crates/completion/Cargo.toml +++ b/crates/completion/Cargo.toml | |||
@@ -13,6 +13,7 @@ doctest = false | |||
13 | itertools = "0.9.0" | 13 | itertools = "0.9.0" |
14 | log = "0.4.8" | 14 | log = "0.4.8" |
15 | rustc-hash = "1.1.0" | 15 | rustc-hash = "1.1.0" |
16 | either = "1.6.1" | ||
16 | 17 | ||
17 | assists = { path = "../assists", version = "0.0.0" } | 18 | assists = { path = "../assists", version = "0.0.0" } |
18 | stdx = { path = "../stdx", version = "0.0.0" } | 19 | stdx = { path = "../stdx", version = "0.0.0" } |
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index 75dbb1a23..9b7d6c580 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs | |||
@@ -90,7 +90,7 @@ impl Completions { | |||
90 | Some(it) => it, | 90 | Some(it) => it, |
91 | None => return, | 91 | None => return, |
92 | }; | 92 | }; |
93 | if let Some(item) = render_macro(RenderContext::new(ctx), name, macro_) { | 93 | if let Some(item) = render_macro(RenderContext::new(ctx), None, name, macro_) { |
94 | self.add(item); | 94 | self.add(item); |
95 | } | 95 | } |
96 | } | 96 | } |
@@ -101,7 +101,7 @@ impl Completions { | |||
101 | func: hir::Function, | 101 | func: hir::Function, |
102 | local_name: Option<String>, | 102 | local_name: Option<String>, |
103 | ) { | 103 | ) { |
104 | let item = render_fn(RenderContext::new(ctx), local_name, func); | 104 | let item = render_fn(RenderContext::new(ctx), None, local_name, func); |
105 | self.add(item) | 105 | self.add(item) |
106 | } | 106 | } |
107 | 107 | ||
@@ -123,7 +123,7 @@ impl Completions { | |||
123 | variant: hir::EnumVariant, | 123 | variant: hir::EnumVariant, |
124 | path: ModPath, | 124 | path: ModPath, |
125 | ) { | 125 | ) { |
126 | let item = render_enum_variant(RenderContext::new(ctx), None, variant, Some(path)); | 126 | let item = render_enum_variant(RenderContext::new(ctx), None, None, variant, Some(path)); |
127 | self.add(item); | 127 | self.add(item); |
128 | } | 128 | } |
129 | 129 | ||
@@ -133,7 +133,7 @@ impl Completions { | |||
133 | variant: hir::EnumVariant, | 133 | variant: hir::EnumVariant, |
134 | local_name: Option<String>, | 134 | local_name: Option<String>, |
135 | ) { | 135 | ) { |
136 | let item = render_enum_variant(RenderContext::new(ctx), local_name, variant, None); | 136 | let item = render_enum_variant(RenderContext::new(ctx), None, local_name, variant, None); |
137 | self.add(item); | 137 | self.add(item); |
138 | } | 138 | } |
139 | } | 139 | } |
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs index 7df58e1da..86c143b63 100644 --- a/crates/completion/src/completions/unqualified_path.rs +++ b/crates/completion/src/completions/unqualified_path.rs | |||
@@ -1,10 +1,16 @@ | |||
1 | //! Completion of names from the current scope, e.g. locals and imported items. | 1 | //! Completion of names from the current scope, e.g. locals and imported items. |
2 | 2 | ||
3 | use assists::utils::ImportScope; | ||
4 | use either::Either; | ||
3 | use hir::{Adt, ModuleDef, ScopeDef, Type}; | 5 | use hir::{Adt, ModuleDef, ScopeDef, Type}; |
6 | use ide_db::imports_locator; | ||
4 | use syntax::AstNode; | 7 | use syntax::AstNode; |
5 | use test_utils::mark; | 8 | use test_utils::mark; |
6 | 9 | ||
7 | use crate::{CompletionContext, Completions}; | 10 | use crate::{ |
11 | render::{render_resolution_with_import, RenderContext}, | ||
12 | CompletionContext, Completions, | ||
13 | }; | ||
8 | 14 | ||
9 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 15 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
10 | if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { | 16 | 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 | |||
37 | } | 43 | } |
38 | acc.add_resolution(ctx, name.to_string(), &res) | 44 | acc.add_resolution(ctx, name.to_string(), &res) |
39 | }); | 45 | }); |
46 | |||
47 | fuzzy_completion(acc, ctx).unwrap_or_default() | ||
40 | } | 48 | } |
41 | 49 | ||
42 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { | 50 | 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 | |||
63 | } | 71 | } |
64 | } | 72 | } |
65 | 73 | ||
74 | fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | ||
75 | let _p = profile::span("fuzzy_completion"); | ||
76 | let current_module = ctx.scope.module()?; | ||
77 | let anchor = ctx.name_ref_syntax.as_ref()?; | ||
78 | let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; | ||
79 | |||
80 | let potential_import_name = ctx.token.to_string(); | ||
81 | |||
82 | let possible_imports = | ||
83 | imports_locator::find_similar_imports(&ctx.sema, ctx.krate?, &potential_import_name, 400) | ||
84 | .filter_map(|import_candidate| match import_candidate { | ||
85 | // when completing outside the use declaration, modules are pretty useless | ||
86 | // and tend to bloat the completion suggestions a lot | ||
87 | Either::Left(ModuleDef::Module(_)) => None, | ||
88 | Either::Left(module_def) => Some(( | ||
89 | current_module.find_use_path(ctx.db, module_def)?, | ||
90 | ScopeDef::ModuleDef(module_def), | ||
91 | )), | ||
92 | Either::Right(macro_def) => Some(( | ||
93 | current_module.find_use_path(ctx.db, macro_def)?, | ||
94 | ScopeDef::MacroDef(macro_def), | ||
95 | )), | ||
96 | }) | ||
97 | .filter(|(mod_path, _)| mod_path.len() > 1) | ||
98 | .filter_map(|(import_path, definition)| { | ||
99 | render_resolution_with_import( | ||
100 | RenderContext::new(ctx), | ||
101 | import_path.clone(), | ||
102 | import_scope.clone(), | ||
103 | ctx.config.merge, | ||
104 | &definition, | ||
105 | ) | ||
106 | }) | ||
107 | .take(20); | ||
108 | |||
109 | acc.add_all(possible_imports); | ||
110 | Some(()) | ||
111 | } | ||
112 | |||
66 | #[cfg(test)] | 113 | #[cfg(test)] |
67 | mod tests { | 114 | mod tests { |
68 | use expect_test::{expect, Expect}; | 115 | use expect_test::{expect, Expect}; |
@@ -676,4 +723,85 @@ impl My<|> | |||
676 | "#]], | 723 | "#]], |
677 | ) | 724 | ) |
678 | } | 725 | } |
726 | |||
727 | #[test] | ||
728 | fn function_fuzzy_completion() { | ||
729 | check_edit( | ||
730 | "stdin", | ||
731 | r#" | ||
732 | //- /lib.rs crate:dep | ||
733 | pub mod io { | ||
734 | pub fn stdin() {} | ||
735 | }; | ||
736 | |||
737 | //- /main.rs crate:main deps:dep | ||
738 | fn main() { | ||
739 | stdi<|> | ||
740 | } | ||
741 | "#, | ||
742 | r#" | ||
743 | use dep::io::stdin; | ||
744 | |||
745 | fn main() { | ||
746 | stdin()$0 | ||
747 | } | ||
748 | "#, | ||
749 | ); | ||
750 | } | ||
751 | |||
752 | #[test] | ||
753 | fn macro_fuzzy_completion() { | ||
754 | check_edit( | ||
755 | "macro_with_curlies!", | ||
756 | r#" | ||
757 | //- /lib.rs crate:dep | ||
758 | /// Please call me as macro_with_curlies! {} | ||
759 | #[macro_export] | ||
760 | macro_rules! macro_with_curlies { | ||
761 | () => {} | ||
762 | } | ||
763 | |||
764 | //- /main.rs crate:main deps:dep | ||
765 | fn main() { | ||
766 | curli<|> | ||
767 | } | ||
768 | "#, | ||
769 | r#" | ||
770 | use dep::macro_with_curlies; | ||
771 | |||
772 | fn main() { | ||
773 | macro_with_curlies! {$0} | ||
774 | } | ||
775 | "#, | ||
776 | ); | ||
777 | } | ||
778 | |||
779 | #[test] | ||
780 | fn struct_fuzzy_completion() { | ||
781 | check_edit( | ||
782 | "ThirdStruct", | ||
783 | r#" | ||
784 | //- /lib.rs crate:dep | ||
785 | pub struct FirstStruct; | ||
786 | pub mod some_module { | ||
787 | pub struct SecondStruct; | ||
788 | pub struct ThirdStruct; | ||
789 | } | ||
790 | |||
791 | //- /main.rs crate:main deps:dep | ||
792 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
793 | |||
794 | fn main() { | ||
795 | this<|> | ||
796 | } | ||
797 | "#, | ||
798 | r#" | ||
799 | use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}}; | ||
800 | |||
801 | fn main() { | ||
802 | ThirdStruct | ||
803 | } | ||
804 | "#, | ||
805 | ); | ||
806 | } | ||
679 | } | 807 | } |
diff --git a/crates/completion/src/config.rs b/crates/completion/src/config.rs index 71b49ace8..82874ff25 100644 --- a/crates/completion/src/config.rs +++ b/crates/completion/src/config.rs | |||
@@ -4,12 +4,15 @@ | |||
4 | //! module, and we use to statically check that we only produce snippet | 4 | //! module, and we use to statically check that we only produce snippet |
5 | //! completions if we are allowed to. | 5 | //! completions if we are allowed to. |
6 | 6 | ||
7 | use assists::utils::MergeBehaviour; | ||
8 | |||
7 | #[derive(Clone, Debug, PartialEq, Eq)] | 9 | #[derive(Clone, Debug, PartialEq, Eq)] |
8 | pub struct CompletionConfig { | 10 | pub struct CompletionConfig { |
9 | pub enable_postfix_completions: bool, | 11 | pub enable_postfix_completions: bool, |
10 | pub add_call_parenthesis: bool, | 12 | pub add_call_parenthesis: bool, |
11 | pub add_call_argument_snippets: bool, | 13 | pub add_call_argument_snippets: bool, |
12 | pub snippet_cap: Option<SnippetCap>, | 14 | pub snippet_cap: Option<SnippetCap>, |
15 | pub merge: Option<MergeBehaviour>, | ||
13 | } | 16 | } |
14 | 17 | ||
15 | impl CompletionConfig { | 18 | impl CompletionConfig { |
@@ -30,6 +33,7 @@ impl Default for CompletionConfig { | |||
30 | add_call_parenthesis: true, | 33 | add_call_parenthesis: true, |
31 | add_call_argument_snippets: true, | 34 | add_call_argument_snippets: true, |
32 | snippet_cap: Some(SnippetCap { _private: () }), | 35 | snippet_cap: Some(SnippetCap { _private: () }), |
36 | merge: Some(MergeBehaviour::Full), | ||
33 | } | 37 | } |
34 | } | 38 | } |
35 | } | 39 | } |
diff --git a/crates/completion/src/item.rs b/crates/completion/src/item.rs index 6d1d085f4..b13c3f376 100644 --- a/crates/completion/src/item.rs +++ b/crates/completion/src/item.rs | |||
@@ -2,8 +2,9 @@ | |||
2 | 2 | ||
3 | use std::fmt; | 3 | use std::fmt; |
4 | 4 | ||
5 | use hir::{Documentation, Mutability}; | 5 | use assists::utils::{insert_use, mod_path_to_ast, ImportScope, MergeBehaviour}; |
6 | use syntax::TextRange; | 6 | use hir::{Documentation, ModPath, Mutability}; |
7 | use syntax::{algo, TextRange}; | ||
7 | use text_edit::TextEdit; | 8 | use text_edit::TextEdit; |
8 | 9 | ||
9 | use crate::config::SnippetCap; | 10 | use crate::config::SnippetCap; |
@@ -31,6 +32,7 @@ pub struct CompletionItem { | |||
31 | /// | 32 | /// |
32 | /// Typically, replaces `source_range` with new identifier. | 33 | /// Typically, replaces `source_range` with new identifier. |
33 | text_edit: TextEdit, | 34 | text_edit: TextEdit, |
35 | |||
34 | insert_text_format: InsertTextFormat, | 36 | insert_text_format: InsertTextFormat, |
35 | 37 | ||
36 | /// What item (struct, function, etc) are we completing. | 38 | /// What item (struct, function, etc) are we completing. |
@@ -199,8 +201,10 @@ impl CompletionItem { | |||
199 | trigger_call_info: None, | 201 | trigger_call_info: None, |
200 | score: None, | 202 | score: None, |
201 | ref_match: None, | 203 | ref_match: None, |
204 | import_data: None, | ||
202 | } | 205 | } |
203 | } | 206 | } |
207 | |||
204 | /// What user sees in pop-up in the UI. | 208 | /// What user sees in pop-up in the UI. |
205 | pub fn label(&self) -> &str { | 209 | pub fn label(&self) -> &str { |
206 | &self.label | 210 | &self.label |
@@ -257,6 +261,7 @@ impl CompletionItem { | |||
257 | pub(crate) struct Builder { | 261 | pub(crate) struct Builder { |
258 | source_range: TextRange, | 262 | source_range: TextRange, |
259 | completion_kind: CompletionKind, | 263 | completion_kind: CompletionKind, |
264 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
260 | label: String, | 265 | label: String, |
261 | insert_text: Option<String>, | 266 | insert_text: Option<String>, |
262 | insert_text_format: InsertTextFormat, | 267 | insert_text_format: InsertTextFormat, |
@@ -273,23 +278,50 @@ pub(crate) struct Builder { | |||
273 | 278 | ||
274 | impl Builder { | 279 | impl Builder { |
275 | pub(crate) fn build(self) -> CompletionItem { | 280 | pub(crate) fn build(self) -> CompletionItem { |
276 | let label = self.label; | 281 | let mut label = self.label; |
277 | let text_edit = match self.text_edit { | 282 | let mut lookup = self.lookup; |
283 | let mut insert_text = self.insert_text; | ||
284 | let mut text_edits = TextEdit::builder(); | ||
285 | |||
286 | if let Some((import_path, import_scope, merge_behaviour)) = self.import_data { | ||
287 | let import = mod_path_to_ast(&import_path); | ||
288 | let mut import_path_without_last_segment = import_path; | ||
289 | let _ = import_path_without_last_segment.segments.pop(); | ||
290 | |||
291 | if !import_path_without_last_segment.segments.is_empty() { | ||
292 | if lookup.is_none() { | ||
293 | lookup = Some(label.clone()); | ||
294 | } | ||
295 | if insert_text.is_none() { | ||
296 | insert_text = Some(label.clone()); | ||
297 | } | ||
298 | label = format!("{}::{}", import_path_without_last_segment, label); | ||
299 | } | ||
300 | |||
301 | let rewriter = insert_use(&import_scope, import, merge_behaviour); | ||
302 | if let Some(old_ast) = rewriter.rewrite_root() { | ||
303 | algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut text_edits); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | let original_edit = match self.text_edit { | ||
278 | Some(it) => it, | 308 | Some(it) => it, |
279 | None => TextEdit::replace( | 309 | None => { |
280 | self.source_range, | 310 | TextEdit::replace(self.source_range, insert_text.unwrap_or_else(|| label.clone())) |
281 | self.insert_text.unwrap_or_else(|| label.clone()), | 311 | } |
282 | ), | ||
283 | }; | 312 | }; |
284 | 313 | ||
314 | let mut resulting_edit = text_edits.finish(); | ||
315 | resulting_edit.union(original_edit).expect("Failed to unite text edits"); | ||
316 | |||
285 | CompletionItem { | 317 | CompletionItem { |
286 | source_range: self.source_range, | 318 | source_range: self.source_range, |
287 | label, | 319 | label, |
288 | insert_text_format: self.insert_text_format, | 320 | insert_text_format: self.insert_text_format, |
289 | text_edit, | 321 | text_edit: resulting_edit, |
290 | detail: self.detail, | 322 | detail: self.detail, |
291 | documentation: self.documentation, | 323 | documentation: self.documentation, |
292 | lookup: self.lookup, | 324 | lookup, |
293 | kind: self.kind, | 325 | kind: self.kind, |
294 | completion_kind: self.completion_kind, | 326 | completion_kind: self.completion_kind, |
295 | deprecated: self.deprecated.unwrap_or(false), | 327 | deprecated: self.deprecated.unwrap_or(false), |
@@ -358,6 +390,13 @@ impl Builder { | |||
358 | self.trigger_call_info = Some(true); | 390 | self.trigger_call_info = Some(true); |
359 | self | 391 | self |
360 | } | 392 | } |
393 | pub(crate) fn import_data( | ||
394 | mut self, | ||
395 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
396 | ) -> Builder { | ||
397 | self.import_data = import_data; | ||
398 | self | ||
399 | } | ||
361 | pub(crate) fn set_ref_match( | 400 | pub(crate) fn set_ref_match( |
362 | mut self, | 401 | mut self, |
363 | ref_match: Option<(Mutability, CompletionScore)>, | 402 | ref_match: Option<(Mutability, CompletionScore)>, |
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs index 1fa02c375..e892d4de8 100644 --- a/crates/completion/src/render.rs +++ b/crates/completion/src/render.rs | |||
@@ -9,7 +9,8 @@ pub(crate) mod type_alias; | |||
9 | 9 | ||
10 | mod builder_ext; | 10 | mod builder_ext; |
11 | 11 | ||
12 | use hir::{Documentation, HasAttrs, HirDisplay, Mutability, ScopeDef, Type}; | 12 | use assists::utils::{ImportScope, MergeBehaviour}; |
13 | use hir::{Documentation, HasAttrs, HirDisplay, ModPath, Mutability, ScopeDef, Type}; | ||
13 | use ide_db::RootDatabase; | 14 | use ide_db::RootDatabase; |
14 | use syntax::TextRange; | 15 | use syntax::TextRange; |
15 | use test_utils::mark; | 16 | use test_utils::mark; |
@@ -42,7 +43,22 @@ pub(crate) fn render_resolution<'a>( | |||
42 | local_name: String, | 43 | local_name: String, |
43 | resolution: &ScopeDef, | 44 | resolution: &ScopeDef, |
44 | ) -> Option<CompletionItem> { | 45 | ) -> Option<CompletionItem> { |
45 | Render::new(ctx).render_resolution(local_name, resolution) | 46 | Render::new(ctx).render_resolution(local_name, None, resolution) |
47 | } | ||
48 | |||
49 | pub(crate) fn render_resolution_with_import<'a>( | ||
50 | ctx: RenderContext<'a>, | ||
51 | import: ModPath, | ||
52 | import_scope: ImportScope, | ||
53 | merge_behaviour: Option<MergeBehaviour>, | ||
54 | resolution: &ScopeDef, | ||
55 | ) -> Option<CompletionItem> { | ||
56 | let local_name = import.segments.last()?.to_string(); | ||
57 | Render::new(ctx).render_resolution( | ||
58 | local_name, | ||
59 | Some((import, import_scope, merge_behaviour)), | ||
60 | resolution, | ||
61 | ) | ||
46 | } | 62 | } |
47 | 63 | ||
48 | /// Interface for data and methods required for items rendering. | 64 | /// Interface for data and methods required for items rendering. |
@@ -131,6 +147,7 @@ impl<'a> Render<'a> { | |||
131 | fn render_resolution( | 147 | fn render_resolution( |
132 | self, | 148 | self, |
133 | local_name: String, | 149 | local_name: String, |
150 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
134 | resolution: &ScopeDef, | 151 | resolution: &ScopeDef, |
135 | ) -> Option<CompletionItem> { | 152 | ) -> Option<CompletionItem> { |
136 | use hir::ModuleDef::*; | 153 | use hir::ModuleDef::*; |
@@ -142,15 +159,15 @@ impl<'a> Render<'a> { | |||
142 | 159 | ||
143 | let kind = match resolution { | 160 | let kind = match resolution { |
144 | ScopeDef::ModuleDef(Function(func)) => { | 161 | ScopeDef::ModuleDef(Function(func)) => { |
145 | let item = render_fn(self.ctx, Some(local_name), *func); | 162 | let item = render_fn(self.ctx, import_data, Some(local_name), *func); |
146 | return Some(item); | 163 | return Some(item); |
147 | } | 164 | } |
148 | ScopeDef::ModuleDef(EnumVariant(var)) => { | 165 | ScopeDef::ModuleDef(EnumVariant(var)) => { |
149 | let item = render_enum_variant(self.ctx, Some(local_name), *var, None); | 166 | let item = render_enum_variant(self.ctx, import_data, Some(local_name), *var, None); |
150 | return Some(item); | 167 | return Some(item); |
151 | } | 168 | } |
152 | ScopeDef::MacroDef(mac) => { | 169 | ScopeDef::MacroDef(mac) => { |
153 | let item = render_macro(self.ctx, local_name, *mac); | 170 | let item = render_macro(self.ctx, import_data, local_name, *mac); |
154 | return item; | 171 | return item; |
155 | } | 172 | } |
156 | 173 | ||
@@ -175,6 +192,7 @@ impl<'a> Render<'a> { | |||
175 | local_name, | 192 | local_name, |
176 | ) | 193 | ) |
177 | .kind(CompletionItemKind::UnresolvedReference) | 194 | .kind(CompletionItemKind::UnresolvedReference) |
195 | .import_data(import_data) | ||
178 | .build(); | 196 | .build(); |
179 | return Some(item); | 197 | return Some(item); |
180 | } | 198 | } |
@@ -227,7 +245,12 @@ impl<'a> Render<'a> { | |||
227 | } | 245 | } |
228 | } | 246 | } |
229 | 247 | ||
230 | let item = item.kind(kind).set_documentation(docs).set_ref_match(ref_match).build(); | 248 | let item = item |
249 | .kind(kind) | ||
250 | .import_data(import_data) | ||
251 | .set_documentation(docs) | ||
252 | .set_ref_match(ref_match) | ||
253 | .build(); | ||
231 | Some(item) | 254 | Some(item) |
232 | } | 255 | } |
233 | 256 | ||
@@ -426,6 +449,28 @@ fn main() { let _: m::Spam = S<|> } | |||
426 | kind: Module, | 449 | kind: Module, |
427 | }, | 450 | }, |
428 | CompletionItem { | 451 | CompletionItem { |
452 | label: "m::Spam", | ||
453 | source_range: 75..76, | ||
454 | text_edit: TextEdit { | ||
455 | indels: [ | ||
456 | Indel { | ||
457 | insert: "use m::Spam;", | ||
458 | delete: 0..0, | ||
459 | }, | ||
460 | Indel { | ||
461 | insert: "\n\n", | ||
462 | delete: 0..0, | ||
463 | }, | ||
464 | Indel { | ||
465 | insert: "Spam", | ||
466 | delete: 75..76, | ||
467 | }, | ||
468 | ], | ||
469 | }, | ||
470 | kind: Enum, | ||
471 | lookup: "Spam", | ||
472 | }, | ||
473 | CompletionItem { | ||
429 | label: "m::Spam::Foo", | 474 | label: "m::Spam::Foo", |
430 | source_range: 75..76, | 475 | source_range: 75..76, |
431 | delete: 75..76, | 476 | delete: 75..76, |
diff --git a/crates/completion/src/render/enum_variant.rs b/crates/completion/src/render/enum_variant.rs index fd412ed0e..6070e9b1d 100644 --- a/crates/completion/src/render/enum_variant.rs +++ b/crates/completion/src/render/enum_variant.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | //! Renderer for `enum` variants. | 1 | //! Renderer for `enum` variants. |
2 | 2 | ||
3 | use assists::utils::{ImportScope, MergeBehaviour}; | ||
3 | use hir::{HasAttrs, HirDisplay, ModPath, StructKind}; | 4 | use hir::{HasAttrs, HirDisplay, ModPath, StructKind}; |
4 | use itertools::Itertools; | 5 | use itertools::Itertools; |
5 | use test_utils::mark; | 6 | use test_utils::mark; |
@@ -11,11 +12,12 @@ use crate::{ | |||
11 | 12 | ||
12 | pub(crate) fn render_enum_variant<'a>( | 13 | pub(crate) fn render_enum_variant<'a>( |
13 | ctx: RenderContext<'a>, | 14 | ctx: RenderContext<'a>, |
15 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
14 | local_name: Option<String>, | 16 | local_name: Option<String>, |
15 | variant: hir::EnumVariant, | 17 | variant: hir::EnumVariant, |
16 | path: Option<ModPath>, | 18 | path: Option<ModPath>, |
17 | ) -> CompletionItem { | 19 | ) -> CompletionItem { |
18 | EnumVariantRender::new(ctx, local_name, variant, path).render() | 20 | EnumVariantRender::new(ctx, local_name, variant, path).render(import_data) |
19 | } | 21 | } |
20 | 22 | ||
21 | #[derive(Debug)] | 23 | #[derive(Debug)] |
@@ -60,7 +62,10 @@ impl<'a> EnumVariantRender<'a> { | |||
60 | } | 62 | } |
61 | } | 63 | } |
62 | 64 | ||
63 | fn render(self) -> CompletionItem { | 65 | fn render( |
66 | self, | ||
67 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
68 | ) -> CompletionItem { | ||
64 | let mut builder = CompletionItem::new( | 69 | let mut builder = CompletionItem::new( |
65 | CompletionKind::Reference, | 70 | CompletionKind::Reference, |
66 | self.ctx.source_range(), | 71 | self.ctx.source_range(), |
@@ -69,6 +74,7 @@ impl<'a> EnumVariantRender<'a> { | |||
69 | .kind(CompletionItemKind::EnumVariant) | 74 | .kind(CompletionItemKind::EnumVariant) |
70 | .set_documentation(self.variant.docs(self.ctx.db())) | 75 | .set_documentation(self.variant.docs(self.ctx.db())) |
71 | .set_deprecated(self.ctx.is_deprecated(self.variant)) | 76 | .set_deprecated(self.ctx.is_deprecated(self.variant)) |
77 | .import_data(import_data) | ||
72 | .detail(self.detail()); | 78 | .detail(self.detail()); |
73 | 79 | ||
74 | if self.variant_kind == StructKind::Tuple { | 80 | if self.variant_kind == StructKind::Tuple { |
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs index 4fa6eafd7..9dd5cd18c 100644 --- a/crates/completion/src/render/function.rs +++ b/crates/completion/src/render/function.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! Renderer for function calls. | 1 | //! Renderer for function calls. |
2 | 2 | ||
3 | use hir::{HasSource, Type}; | 3 | use assists::utils::{ImportScope, MergeBehaviour}; |
4 | use hir::{HasSource, ModPath, Type}; | ||
4 | use syntax::{ast::Fn, display::function_declaration}; | 5 | use syntax::{ast::Fn, display::function_declaration}; |
5 | 6 | ||
6 | use crate::{ | 7 | use crate::{ |
@@ -10,10 +11,11 @@ use crate::{ | |||
10 | 11 | ||
11 | pub(crate) fn render_fn<'a>( | 12 | pub(crate) fn render_fn<'a>( |
12 | ctx: RenderContext<'a>, | 13 | ctx: RenderContext<'a>, |
14 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
13 | local_name: Option<String>, | 15 | local_name: Option<String>, |
14 | fn_: hir::Function, | 16 | fn_: hir::Function, |
15 | ) -> CompletionItem { | 17 | ) -> CompletionItem { |
16 | FunctionRender::new(ctx, local_name, fn_).render() | 18 | FunctionRender::new(ctx, local_name, fn_).render(import_data) |
17 | } | 19 | } |
18 | 20 | ||
19 | #[derive(Debug)] | 21 | #[derive(Debug)] |
@@ -36,7 +38,10 @@ impl<'a> FunctionRender<'a> { | |||
36 | FunctionRender { ctx, name, fn_, ast_node } | 38 | FunctionRender { ctx, name, fn_, ast_node } |
37 | } | 39 | } |
38 | 40 | ||
39 | fn render(self) -> CompletionItem { | 41 | fn render( |
42 | self, | ||
43 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
44 | ) -> CompletionItem { | ||
40 | let params = self.params(); | 45 | let params = self.params(); |
41 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) | 46 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) |
42 | .kind(self.kind()) | 47 | .kind(self.kind()) |
@@ -44,6 +49,7 @@ impl<'a> FunctionRender<'a> { | |||
44 | .set_deprecated(self.ctx.is_deprecated(self.fn_)) | 49 | .set_deprecated(self.ctx.is_deprecated(self.fn_)) |
45 | .detail(self.detail()) | 50 | .detail(self.detail()) |
46 | .add_call_parens(self.ctx.completion, self.name, params) | 51 | .add_call_parens(self.ctx.completion, self.name, params) |
52 | .import_data(import_data) | ||
47 | .build() | 53 | .build() |
48 | } | 54 | } |
49 | 55 | ||
diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs index 96be59cc3..fead59e41 100644 --- a/crates/completion/src/render/macro_.rs +++ b/crates/completion/src/render/macro_.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! Renderer for macro invocations. | 1 | //! Renderer for macro invocations. |
2 | 2 | ||
3 | use hir::{Documentation, HasSource}; | 3 | use assists::utils::{ImportScope, MergeBehaviour}; |
4 | use hir::{Documentation, HasSource, ModPath}; | ||
4 | use syntax::display::macro_label; | 5 | use syntax::display::macro_label; |
5 | use test_utils::mark; | 6 | use test_utils::mark; |
6 | 7 | ||
@@ -11,10 +12,11 @@ use crate::{ | |||
11 | 12 | ||
12 | pub(crate) fn render_macro<'a>( | 13 | pub(crate) fn render_macro<'a>( |
13 | ctx: RenderContext<'a>, | 14 | ctx: RenderContext<'a>, |
15 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
14 | name: String, | 16 | name: String, |
15 | macro_: hir::MacroDef, | 17 | macro_: hir::MacroDef, |
16 | ) -> Option<CompletionItem> { | 18 | ) -> Option<CompletionItem> { |
17 | MacroRender::new(ctx, name, macro_).render() | 19 | MacroRender::new(ctx, name, macro_).render(import_data) |
18 | } | 20 | } |
19 | 21 | ||
20 | #[derive(Debug)] | 22 | #[derive(Debug)] |
@@ -36,7 +38,10 @@ impl<'a> MacroRender<'a> { | |||
36 | MacroRender { ctx, name, macro_, docs, bra, ket } | 38 | MacroRender { ctx, name, macro_, docs, bra, ket } |
37 | } | 39 | } |
38 | 40 | ||
39 | fn render(&self) -> Option<CompletionItem> { | 41 | fn render( |
42 | &self, | ||
43 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
44 | ) -> Option<CompletionItem> { | ||
40 | // FIXME: Currently proc-macro do not have ast-node, | 45 | // FIXME: Currently proc-macro do not have ast-node, |
41 | // such that it does not have source | 46 | // such that it does not have source |
42 | if self.macro_.is_proc_macro() { | 47 | if self.macro_.is_proc_macro() { |
@@ -48,6 +53,7 @@ impl<'a> MacroRender<'a> { | |||
48 | .kind(CompletionItemKind::Macro) | 53 | .kind(CompletionItemKind::Macro) |
49 | .set_documentation(self.docs.clone()) | 54 | .set_documentation(self.docs.clone()) |
50 | .set_deprecated(self.ctx.is_deprecated(self.macro_)) | 55 | .set_deprecated(self.ctx.is_deprecated(self.macro_)) |
56 | .import_data(import_data) | ||
51 | .detail(self.detail()); | 57 | .detail(self.detail()); |
52 | 58 | ||
53 | let needs_bang = self.needs_bang(); | 59 | let needs_bang = self.needs_bang(); |
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index 30a5e4580..37ed092ad 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -110,15 +110,9 @@ impl Crate { | |||
110 | pub fn query_external_importables( | 110 | pub fn query_external_importables( |
111 | self, | 111 | self, |
112 | db: &dyn DefDatabase, | 112 | db: &dyn DefDatabase, |
113 | query: &str, | 113 | query: import_map::Query, |
114 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | 114 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { |
115 | import_map::search_dependencies( | 115 | import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| match item { |
116 | db, | ||
117 | self.into(), | ||
118 | import_map::Query::new(query).anchor_end().case_sensitive().limit(40), | ||
119 | ) | ||
120 | .into_iter() | ||
121 | .map(|item| match item { | ||
122 | ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), | 116 | ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), |
123 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), | 117 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), |
124 | }) | 118 | }) |
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index c18c1c587..d9ad8db6f 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs | |||
@@ -1,6 +1,8 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | pub use hir_def::diagnostics::{InactiveCode, UnresolvedModule}; | 2 | pub use hir_def::diagnostics::{InactiveCode, UnresolvedModule}; |
3 | pub use hir_expand::diagnostics::{Diagnostic, DiagnosticSink, DiagnosticSinkBuilder}; | 3 | pub use hir_expand::diagnostics::{ |
4 | Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder, | ||
5 | }; | ||
4 | pub use hir_ty::diagnostics::{ | 6 | pub use hir_ty::diagnostics::{ |
5 | IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, | 7 | IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, |
6 | NoSuchField, | 8 | NoSuchField, |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 0d184379f..5fea25ef1 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -49,6 +49,7 @@ pub use hir_def::{ | |||
49 | builtin_type::BuiltinType, | 49 | builtin_type::BuiltinType, |
50 | docs::Documentation, | 50 | docs::Documentation, |
51 | find_path::PrefixKind, | 51 | find_path::PrefixKind, |
52 | import_map, | ||
52 | item_scope::ItemInNs, | 53 | item_scope::ItemInNs, |
53 | nameres::ModuleSource, | 54 | nameres::ModuleSource, |
54 | path::{ModPath, PathKind}, | 55 | path::{ModPath, PathKind}, |
diff --git a/crates/hir_expand/src/diagnostics.rs b/crates/hir_expand/src/diagnostics.rs index 78ccc212c..1043c6aeb 100644 --- a/crates/hir_expand/src/diagnostics.rs +++ b/crates/hir_expand/src/diagnostics.rs | |||
@@ -20,7 +20,7 @@ use syntax::SyntaxNodePtr; | |||
20 | 20 | ||
21 | use crate::InFile; | 21 | use crate::InFile; |
22 | 22 | ||
23 | #[derive(Copy, Clone, PartialEq)] | 23 | #[derive(Copy, Clone, Debug, PartialEq)] |
24 | pub struct DiagnosticCode(pub &'static str); | 24 | pub struct DiagnosticCode(pub &'static str); |
25 | 25 | ||
26 | impl DiagnosticCode { | 26 | impl DiagnosticCode { |
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 1c7f02763..3df73ed4f 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -10,7 +10,7 @@ mod field_shorthand; | |||
10 | use std::cell::RefCell; | 10 | use std::cell::RefCell; |
11 | 11 | ||
12 | use hir::{ | 12 | use hir::{ |
13 | diagnostics::{Diagnostic as _, DiagnosticSinkBuilder}, | 13 | diagnostics::{Diagnostic as _, DiagnosticCode, DiagnosticSinkBuilder}, |
14 | Semantics, | 14 | Semantics, |
15 | }; | 15 | }; |
16 | use ide_db::base_db::SourceDatabase; | 16 | use ide_db::base_db::SourceDatabase; |
@@ -35,15 +35,23 @@ pub struct Diagnostic { | |||
35 | pub severity: Severity, | 35 | pub severity: Severity, |
36 | pub fix: Option<Fix>, | 36 | pub fix: Option<Fix>, |
37 | pub unused: bool, | 37 | pub unused: bool, |
38 | pub code: Option<DiagnosticCode>, | ||
38 | } | 39 | } |
39 | 40 | ||
40 | impl Diagnostic { | 41 | impl Diagnostic { |
41 | fn error(range: TextRange, message: String) -> Self { | 42 | fn error(range: TextRange, message: String) -> Self { |
42 | Self { message, range, severity: Severity::Error, fix: None, unused: false } | 43 | Self { message, range, severity: Severity::Error, fix: None, unused: false, code: None } |
43 | } | 44 | } |
44 | 45 | ||
45 | fn hint(range: TextRange, message: String) -> Self { | 46 | fn hint(range: TextRange, message: String) -> Self { |
46 | Self { message, range, severity: Severity::WeakWarning, fix: None, unused: false } | 47 | Self { |
48 | message, | ||
49 | range, | ||
50 | severity: Severity::WeakWarning, | ||
51 | fix: None, | ||
52 | unused: false, | ||
53 | code: None, | ||
54 | } | ||
47 | } | 55 | } |
48 | 56 | ||
49 | fn with_fix(self, fix: Option<Fix>) -> Self { | 57 | fn with_fix(self, fix: Option<Fix>) -> Self { |
@@ -53,6 +61,10 @@ impl Diagnostic { | |||
53 | fn with_unused(self, unused: bool) -> Self { | 61 | fn with_unused(self, unused: bool) -> Self { |
54 | Self { unused, ..self } | 62 | Self { unused, ..self } |
55 | } | 63 | } |
64 | |||
65 | fn with_code(self, code: Option<DiagnosticCode>) -> Self { | ||
66 | Self { code, ..self } | ||
67 | } | ||
56 | } | 68 | } |
57 | 69 | ||
58 | #[derive(Debug)] | 70 | #[derive(Debug)] |
@@ -126,7 +138,8 @@ pub(crate) fn diagnostics( | |||
126 | // Override severity and mark as unused. | 138 | // Override severity and mark as unused. |
127 | res.borrow_mut().push( | 139 | res.borrow_mut().push( |
128 | Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message()) | 140 | Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message()) |
129 | .with_unused(true), | 141 | .with_unused(true) |
142 | .with_code(Some(d.code())), | ||
130 | ); | 143 | ); |
131 | }) | 144 | }) |
132 | // Only collect experimental diagnostics when they're enabled. | 145 | // Only collect experimental diagnostics when they're enabled. |
@@ -137,8 +150,10 @@ pub(crate) fn diagnostics( | |||
137 | let mut sink = sink_builder | 150 | let mut sink = sink_builder |
138 | // Diagnostics not handled above get no fix and default treatment. | 151 | // Diagnostics not handled above get no fix and default treatment. |
139 | .build(|d| { | 152 | .build(|d| { |
140 | res.borrow_mut() | 153 | res.borrow_mut().push( |
141 | .push(Diagnostic::error(sema.diagnostics_display_range(d).range, d.message())); | 154 | Diagnostic::error(sema.diagnostics_display_range(d).range, d.message()) |
155 | .with_code(Some(d.code())), | ||
156 | ); | ||
142 | }); | 157 | }); |
143 | 158 | ||
144 | if let Some(m) = sema.to_module_def(file_id) { | 159 | if let Some(m) = sema.to_module_def(file_id) { |
@@ -149,11 +164,15 @@ pub(crate) fn diagnostics( | |||
149 | } | 164 | } |
150 | 165 | ||
151 | fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { | 166 | fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { |
152 | Diagnostic::error(sema.diagnostics_display_range(d).range, d.message()).with_fix(d.fix(&sema)) | 167 | Diagnostic::error(sema.diagnostics_display_range(d).range, d.message()) |
168 | .with_fix(d.fix(&sema)) | ||
169 | .with_code(Some(d.code())) | ||
153 | } | 170 | } |
154 | 171 | ||
155 | fn warning_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { | 172 | fn warning_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { |
156 | Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message()).with_fix(d.fix(&sema)) | 173 | Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message()) |
174 | .with_fix(d.fix(&sema)) | ||
175 | .with_code(Some(d.code())) | ||
157 | } | 176 | } |
158 | 177 | ||
159 | fn check_unnecessary_braces_in_use_statement( | 178 | fn check_unnecessary_braces_in_use_statement( |
@@ -589,6 +608,11 @@ fn test_fn() { | |||
589 | }, | 608 | }, |
590 | ), | 609 | ), |
591 | unused: false, | 610 | unused: false, |
611 | code: Some( | ||
612 | DiagnosticCode( | ||
613 | "unresolved-module", | ||
614 | ), | ||
615 | ), | ||
592 | }, | 616 | }, |
593 | ] | 617 | ] |
594 | "#]], | 618 | "#]], |
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs index df74be00b..9d8ea7368 100644 --- a/crates/ide_db/src/imports_locator.rs +++ b/crates/ide_db/src/imports_locator.rs | |||
@@ -1,36 +1,70 @@ | |||
1 | //! This module contains an import search funcionality that is provided to the assists module. | 1 | //! This module contains an import search funcionality that is provided to the assists module. |
2 | //! Later, this should be moved away to a separate crate that is accessible from the assists module. | 2 | //! Later, this should be moved away to a separate crate that is accessible from the assists module. |
3 | 3 | ||
4 | use hir::{Crate, MacroDef, ModuleDef, Semantics}; | 4 | use hir::{import_map, Crate, MacroDef, ModuleDef, Semantics}; |
5 | use syntax::{ast, AstNode, SyntaxKind::NAME}; | 5 | use syntax::{ast, AstNode, SyntaxKind::NAME}; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | defs::{Definition, NameClass}, | 8 | defs::{Definition, NameClass}, |
9 | symbol_index::{self, FileSymbol, Query}, | 9 | symbol_index::{self, FileSymbol}, |
10 | RootDatabase, | 10 | RootDatabase, |
11 | }; | 11 | }; |
12 | use either::Either; | 12 | use either::Either; |
13 | use rustc_hash::FxHashSet; | 13 | use rustc_hash::FxHashSet; |
14 | 14 | ||
15 | pub fn find_imports<'a>( | 15 | pub fn find_exact_imports<'a>( |
16 | sema: &Semantics<'a, RootDatabase>, | 16 | sema: &Semantics<'a, RootDatabase>, |
17 | krate: Crate, | 17 | krate: Crate, |
18 | name_to_import: &str, | 18 | name_to_import: &str, |
19 | ) -> Vec<Either<ModuleDef, MacroDef>> { | 19 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { |
20 | let _p = profile::span("search_for_imports"); | 20 | let _p = profile::span("find_exact_imports"); |
21 | find_imports( | ||
22 | sema, | ||
23 | krate, | ||
24 | { | ||
25 | let mut local_query = symbol_index::Query::new(name_to_import.to_string()); | ||
26 | local_query.exact(); | ||
27 | local_query.limit(40); | ||
28 | local_query | ||
29 | }, | ||
30 | import_map::Query::new(name_to_import).anchor_end().case_sensitive().limit(40), | ||
31 | ) | ||
32 | } | ||
33 | |||
34 | pub fn find_similar_imports<'a>( | ||
35 | sema: &Semantics<'a, RootDatabase>, | ||
36 | krate: Crate, | ||
37 | name_to_import: &str, | ||
38 | limit: usize, | ||
39 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | ||
40 | let _p = profile::span("find_similar_imports"); | ||
41 | find_imports( | ||
42 | sema, | ||
43 | krate, | ||
44 | { | ||
45 | let mut local_query = symbol_index::Query::new(name_to_import.to_string()); | ||
46 | local_query.limit(limit); | ||
47 | local_query | ||
48 | }, | ||
49 | import_map::Query::new(name_to_import).limit(limit), | ||
50 | ) | ||
51 | } | ||
52 | |||
53 | fn find_imports<'a>( | ||
54 | sema: &Semantics<'a, RootDatabase>, | ||
55 | krate: Crate, | ||
56 | local_query: symbol_index::Query, | ||
57 | external_query: import_map::Query, | ||
58 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | ||
59 | let _p = profile::span("find_similar_imports"); | ||
21 | let db = sema.db; | 60 | let db = sema.db; |
22 | 61 | ||
23 | // Query dependencies first. | 62 | // Query dependencies first. |
24 | let mut candidates: FxHashSet<_> = | 63 | let mut candidates: FxHashSet<_> = |
25 | krate.query_external_importables(db, name_to_import).collect(); | 64 | krate.query_external_importables(db, external_query).collect(); |
26 | 65 | ||
27 | // Query the local crate using the symbol index. | 66 | // Query the local crate using the symbol index. |
28 | let local_results = { | 67 | let local_results = symbol_index::crate_symbols(db, krate.into(), local_query); |
29 | let mut query = Query::new(name_to_import.to_string()); | ||
30 | query.exact(); | ||
31 | query.limit(40); | ||
32 | symbol_index::crate_symbols(db, krate.into(), query) | ||
33 | }; | ||
34 | 68 | ||
35 | candidates.extend( | 69 | candidates.extend( |
36 | local_results | 70 | local_results |
@@ -43,7 +77,7 @@ pub fn find_imports<'a>( | |||
43 | }), | 77 | }), |
44 | ); | 78 | ); |
45 | 79 | ||
46 | candidates.into_iter().collect() | 80 | candidates.into_iter() |
47 | } | 81 | } |
48 | 82 | ||
49 | fn get_name_definition<'a>( | 83 | fn get_name_definition<'a>( |
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs index dbf1dc5bf..a71f96164 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs | |||
@@ -197,269 +197,280 @@ impl ProjectWorkspace { | |||
197 | proc_macro_client: &ProcMacroClient, | 197 | proc_macro_client: &ProcMacroClient, |
198 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 198 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
199 | ) -> CrateGraph { | 199 | ) -> CrateGraph { |
200 | let mut crate_graph = CrateGraph::default(); | 200 | let mut crate_graph = match self { |
201 | match self { | ||
202 | ProjectWorkspace::Json { project, sysroot } => { | 201 | ProjectWorkspace::Json { project, sysroot } => { |
203 | let sysroot_dps = sysroot | 202 | project_json_to_crate_graph(target, proc_macro_client, load, project, sysroot) |
204 | .as_ref() | ||
205 | .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load)); | ||
206 | |||
207 | let mut cfg_cache: FxHashMap<Option<&str>, Vec<CfgFlag>> = FxHashMap::default(); | ||
208 | let crates: FxHashMap<_, _> = project | ||
209 | .crates() | ||
210 | .filter_map(|(crate_id, krate)| { | ||
211 | let file_path = &krate.root_module; | ||
212 | let file_id = match load(&file_path) { | ||
213 | Some(id) => id, | ||
214 | None => { | ||
215 | log::error!("failed to load crate root {}", file_path.display()); | ||
216 | return None; | ||
217 | } | ||
218 | }; | ||
219 | |||
220 | let env = krate.env.clone().into_iter().collect(); | ||
221 | let proc_macro = krate | ||
222 | .proc_macro_dylib_path | ||
223 | .clone() | ||
224 | .map(|it| proc_macro_client.by_dylib_path(&it)); | ||
225 | |||
226 | let target = krate.target.as_deref().or(target); | ||
227 | let target_cfgs = cfg_cache | ||
228 | .entry(target) | ||
229 | .or_insert_with(|| get_rustc_cfg_options(target)); | ||
230 | |||
231 | let mut cfg_options = CfgOptions::default(); | ||
232 | cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned()); | ||
233 | |||
234 | Some(( | ||
235 | crate_id, | ||
236 | crate_graph.add_crate_root( | ||
237 | file_id, | ||
238 | krate.edition, | ||
239 | krate.display_name.clone(), | ||
240 | cfg_options, | ||
241 | env, | ||
242 | proc_macro.unwrap_or_default(), | ||
243 | ), | ||
244 | )) | ||
245 | }) | ||
246 | .collect(); | ||
247 | |||
248 | for (from, krate) in project.crates() { | ||
249 | if let Some(&from) = crates.get(&from) { | ||
250 | if let Some((public_deps, _proc_macro)) = &sysroot_dps { | ||
251 | for (name, to) in public_deps.iter() { | ||
252 | add_dep(&mut crate_graph, from, name.clone(), *to) | ||
253 | } | ||
254 | } | ||
255 | |||
256 | for dep in &krate.deps { | ||
257 | let to_crate_id = dep.crate_id; | ||
258 | if let Some(&to) = crates.get(&to_crate_id) { | ||
259 | add_dep(&mut crate_graph, from, dep.name.clone(), to) | ||
260 | } | ||
261 | } | ||
262 | } | ||
263 | } | ||
264 | } | 203 | } |
265 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } => { | 204 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } => { |
266 | let (public_deps, libproc_macro) = | 205 | cargo_to_crate_graph(target, proc_macro_client, load, cargo, sysroot, rustc) |
267 | sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load); | 206 | } |
207 | }; | ||
208 | if crate_graph.patch_cfg_if() { | ||
209 | log::debug!("Patched std to depend on cfg-if") | ||
210 | } else { | ||
211 | log::debug!("Did not patch std to depend on cfg-if") | ||
212 | } | ||
213 | crate_graph | ||
214 | } | ||
215 | } | ||
268 | 216 | ||
269 | let mut cfg_options = CfgOptions::default(); | 217 | fn project_json_to_crate_graph( |
270 | cfg_options.extend(get_rustc_cfg_options(target)); | 218 | target: Option<&str>, |
219 | proc_macro_client: &ProcMacroClient, | ||
220 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | ||
221 | project: &ProjectJson, | ||
222 | sysroot: &Option<Sysroot>, | ||
223 | ) -> CrateGraph { | ||
224 | let mut crate_graph = CrateGraph::default(); | ||
225 | let sysroot_deps = sysroot | ||
226 | .as_ref() | ||
227 | .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load)); | ||
228 | |||
229 | let mut cfg_cache: FxHashMap<Option<&str>, Vec<CfgFlag>> = FxHashMap::default(); | ||
230 | let crates: FxHashMap<CrateId, CrateId> = project | ||
231 | .crates() | ||
232 | .filter_map(|(crate_id, krate)| { | ||
233 | let file_path = &krate.root_module; | ||
234 | let file_id = load(&file_path)?; | ||
235 | Some((crate_id, krate, file_id)) | ||
236 | }) | ||
237 | .map(|(crate_id, krate, file_id)| { | ||
238 | let env = krate.env.clone().into_iter().collect(); | ||
239 | let proc_macro = | ||
240 | krate.proc_macro_dylib_path.clone().map(|it| proc_macro_client.by_dylib_path(&it)); | ||
241 | |||
242 | let target = krate.target.as_deref().or(target); | ||
243 | let target_cfgs = | ||
244 | cfg_cache.entry(target).or_insert_with(|| get_rustc_cfg_options(target)); | ||
245 | |||
246 | let mut cfg_options = CfgOptions::default(); | ||
247 | cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned()); | ||
248 | ( | ||
249 | crate_id, | ||
250 | crate_graph.add_crate_root( | ||
251 | file_id, | ||
252 | krate.edition, | ||
253 | krate.display_name.clone(), | ||
254 | cfg_options, | ||
255 | env, | ||
256 | proc_macro.unwrap_or_default(), | ||
257 | ), | ||
258 | ) | ||
259 | }) | ||
260 | .collect(); | ||
271 | 261 | ||
272 | let mut pkg_to_lib_crate = FxHashMap::default(); | 262 | for (from, krate) in project.crates() { |
263 | if let Some(&from) = crates.get(&from) { | ||
264 | if let Some((public_deps, _proc_macro)) = &sysroot_deps { | ||
265 | for (name, to) in public_deps.iter() { | ||
266 | add_dep(&mut crate_graph, from, name.clone(), *to) | ||
267 | } | ||
268 | } | ||
269 | |||
270 | for dep in &krate.deps { | ||
271 | if let Some(&to) = crates.get(&dep.crate_id) { | ||
272 | add_dep(&mut crate_graph, from, dep.name.clone(), to) | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | } | ||
277 | crate_graph | ||
278 | } | ||
273 | 279 | ||
274 | // Add test cfg for non-sysroot crates | 280 | fn cargo_to_crate_graph( |
275 | cfg_options.insert_atom("test".into()); | 281 | target: Option<&str>, |
276 | cfg_options.insert_atom("debug_assertions".into()); | 282 | proc_macro_client: &ProcMacroClient, |
283 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | ||
284 | cargo: &CargoWorkspace, | ||
285 | sysroot: &Sysroot, | ||
286 | rustc: &Option<CargoWorkspace>, | ||
287 | ) -> CrateGraph { | ||
288 | let mut crate_graph = CrateGraph::default(); | ||
289 | let (public_deps, libproc_macro) = | ||
290 | sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load); | ||
277 | 291 | ||
278 | let mut pkg_crates = FxHashMap::default(); | 292 | let mut cfg_options = CfgOptions::default(); |
293 | cfg_options.extend(get_rustc_cfg_options(target)); | ||
279 | 294 | ||
280 | // Next, create crates for each package, target pair | 295 | let mut pkg_to_lib_crate = FxHashMap::default(); |
281 | for pkg in cargo.packages() { | 296 | |
282 | let mut lib_tgt = None; | 297 | // Add test cfg for non-sysroot crates |
283 | for &tgt in cargo[pkg].targets.iter() { | 298 | cfg_options.insert_atom("test".into()); |
284 | if let Some(crate_id) = add_target_crate_root( | 299 | cfg_options.insert_atom("debug_assertions".into()); |
300 | |||
301 | let mut pkg_crates = FxHashMap::default(); | ||
302 | |||
303 | // Next, create crates for each package, target pair | ||
304 | for pkg in cargo.packages() { | ||
305 | let mut lib_tgt = None; | ||
306 | for &tgt in cargo[pkg].targets.iter() { | ||
307 | if let Some(file_id) = load(&cargo[tgt].root) { | ||
308 | let crate_id = add_target_crate_root( | ||
309 | &mut crate_graph, | ||
310 | &cargo[pkg], | ||
311 | &cfg_options, | ||
312 | proc_macro_client, | ||
313 | file_id, | ||
314 | ); | ||
315 | if cargo[tgt].kind == TargetKind::Lib { | ||
316 | lib_tgt = Some((crate_id, cargo[tgt].name.clone())); | ||
317 | pkg_to_lib_crate.insert(pkg, crate_id); | ||
318 | } | ||
319 | if cargo[tgt].is_proc_macro { | ||
320 | if let Some(proc_macro) = libproc_macro { | ||
321 | add_dep( | ||
285 | &mut crate_graph, | 322 | &mut crate_graph, |
286 | &cargo[pkg], | 323 | crate_id, |
287 | &cargo[tgt], | 324 | CrateName::new("proc_macro").unwrap(), |
288 | &cfg_options, | 325 | proc_macro, |
289 | proc_macro_client, | 326 | ); |
290 | load, | ||
291 | ) { | ||
292 | if cargo[tgt].kind == TargetKind::Lib { | ||
293 | lib_tgt = Some((crate_id, cargo[tgt].name.clone())); | ||
294 | pkg_to_lib_crate.insert(pkg, crate_id); | ||
295 | } | ||
296 | if cargo[tgt].is_proc_macro { | ||
297 | if let Some(proc_macro) = libproc_macro { | ||
298 | add_dep( | ||
299 | &mut crate_graph, | ||
300 | crate_id, | ||
301 | CrateName::new("proc_macro").unwrap(), | ||
302 | proc_macro, | ||
303 | ); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); | ||
308 | } | ||
309 | } | 327 | } |
328 | } | ||
310 | 329 | ||
311 | // Set deps to the core, std and to the lib target of the current package | 330 | pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); |
312 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { | 331 | } |
313 | if let Some((to, name)) = lib_tgt.clone() { | 332 | } |
314 | // For root projects with dashes in their name, | 333 | |
315 | // cargo metadata does not do any normalization, | 334 | // Set deps to the core, std and to the lib target of the current package |
316 | // so we do it ourselves currently | 335 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { |
317 | let name = CrateName::normalize_dashes(&name); | 336 | if let Some((to, name)) = lib_tgt.clone() { |
318 | if to != from { | 337 | if to != from { |
319 | add_dep(&mut crate_graph, from, name, to); | 338 | // For root projects with dashes in their name, |
320 | } | 339 | // cargo metadata does not do any normalization, |
321 | } | 340 | // so we do it ourselves currently |
322 | for (name, krate) in public_deps.iter() { | 341 | let name = CrateName::normalize_dashes(&name); |
323 | add_dep(&mut crate_graph, from, name.clone(), *krate); | 342 | add_dep(&mut crate_graph, from, name, to); |
324 | } | ||
325 | } | ||
326 | } | 343 | } |
344 | } | ||
345 | for (name, krate) in public_deps.iter() { | ||
346 | add_dep(&mut crate_graph, from, name.clone(), *krate); | ||
347 | } | ||
348 | } | ||
349 | } | ||
327 | 350 | ||
328 | // Now add a dep edge from all targets of upstream to the lib | 351 | // Now add a dep edge from all targets of upstream to the lib |
329 | // target of downstream. | 352 | // target of downstream. |
330 | for pkg in cargo.packages() { | 353 | for pkg in cargo.packages() { |
331 | for dep in cargo[pkg].dependencies.iter() { | 354 | for dep in cargo[pkg].dependencies.iter() { |
332 | let name = CrateName::new(&dep.name).unwrap(); | 355 | let name = CrateName::new(&dep.name).unwrap(); |
333 | if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { | 356 | if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { |
334 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { | 357 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { |
335 | add_dep(&mut crate_graph, from, name.clone(), to) | 358 | add_dep(&mut crate_graph, from, name.clone(), to) |
336 | } | 359 | } |
337 | } | 360 | } |
338 | } | 361 | } |
362 | } | ||
363 | |||
364 | let mut rustc_pkg_crates = FxHashMap::default(); | ||
365 | |||
366 | // If the user provided a path to rustc sources, we add all the rustc_private crates | ||
367 | // and create dependencies on them for the crates in the current workspace | ||
368 | if let Some(rustc_workspace) = rustc { | ||
369 | for pkg in rustc_workspace.packages() { | ||
370 | for &tgt in rustc_workspace[pkg].targets.iter() { | ||
371 | if rustc_workspace[tgt].kind != TargetKind::Lib { | ||
372 | continue; | ||
373 | } | ||
374 | // Exclude alloc / core / std | ||
375 | if rustc_workspace[tgt] | ||
376 | .root | ||
377 | .components() | ||
378 | .any(|c| c == Component::Normal("library".as_ref())) | ||
379 | { | ||
380 | continue; | ||
339 | } | 381 | } |
340 | 382 | ||
341 | let mut rustc_pkg_crates = FxHashMap::default(); | 383 | if let Some(file_id) = load(&rustc_workspace[tgt].root) { |
342 | 384 | let crate_id = add_target_crate_root( | |
343 | // If the user provided a path to rustc sources, we add all the rustc_private crates | 385 | &mut crate_graph, |
344 | // and create dependencies on them for the crates in the current workspace | 386 | &rustc_workspace[pkg], |
345 | if let Some(rustc_workspace) = rustc { | 387 | &cfg_options, |
346 | for pkg in rustc_workspace.packages() { | 388 | proc_macro_client, |
347 | for &tgt in rustc_workspace[pkg].targets.iter() { | 389 | file_id, |
348 | if rustc_workspace[tgt].kind != TargetKind::Lib { | 390 | ); |
349 | continue; | 391 | pkg_to_lib_crate.insert(pkg, crate_id); |
350 | } | 392 | // Add dependencies on the core / std / alloc for rustc |
351 | // Exclude alloc / core / std | 393 | for (name, krate) in public_deps.iter() { |
352 | if rustc_workspace[tgt] | 394 | add_dep(&mut crate_graph, crate_id, name.clone(), *krate); |
353 | .root | ||
354 | .components() | ||
355 | .any(|c| c == Component::Normal("library".as_ref())) | ||
356 | { | ||
357 | continue; | ||
358 | } | ||
359 | |||
360 | if let Some(crate_id) = add_target_crate_root( | ||
361 | &mut crate_graph, | ||
362 | &rustc_workspace[pkg], | ||
363 | &rustc_workspace[tgt], | ||
364 | &cfg_options, | ||
365 | proc_macro_client, | ||
366 | load, | ||
367 | ) { | ||
368 | pkg_to_lib_crate.insert(pkg, crate_id); | ||
369 | // Add dependencies on the core / std / alloc for rustc | ||
370 | for (name, krate) in public_deps.iter() { | ||
371 | add_dep(&mut crate_graph, crate_id, name.clone(), *krate); | ||
372 | } | ||
373 | rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); | ||
374 | } | ||
375 | } | ||
376 | } | 395 | } |
377 | // Now add a dep edge from all targets of upstream to the lib | 396 | rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); |
378 | // target of downstream. | 397 | } |
379 | for pkg in rustc_workspace.packages() { | 398 | } |
380 | for dep in rustc_workspace[pkg].dependencies.iter() { | 399 | } |
381 | let name = CrateName::new(&dep.name).unwrap(); | 400 | // Now add a dep edge from all targets of upstream to the lib |
382 | if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { | 401 | // target of downstream. |
383 | for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() { | 402 | for pkg in rustc_workspace.packages() { |
384 | add_dep(&mut crate_graph, from, name.clone(), to); | 403 | for dep in rustc_workspace[pkg].dependencies.iter() { |
385 | } | 404 | let name = CrateName::new(&dep.name).unwrap(); |
386 | } | 405 | if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { |
387 | } | 406 | for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() { |
407 | add_dep(&mut crate_graph, from, name.clone(), to); | ||
388 | } | 408 | } |
409 | } | ||
410 | } | ||
411 | } | ||
389 | 412 | ||
390 | // Add dependencies for all the crates of the current workspace to rustc_private libraries | 413 | // Add dependencies for all the crates of the current workspace to rustc_private libraries |
391 | for dep in rustc_workspace.packages() { | 414 | for dep in rustc_workspace.packages() { |
392 | let name = CrateName::normalize_dashes(&rustc_workspace[dep].name); | 415 | let name = CrateName::normalize_dashes(&rustc_workspace[dep].name); |
393 | 416 | ||
394 | if let Some(&to) = pkg_to_lib_crate.get(&dep) { | 417 | if let Some(&to) = pkg_to_lib_crate.get(&dep) { |
395 | for pkg in cargo.packages() { | 418 | for pkg in cargo.packages() { |
396 | if !cargo[pkg].is_member { | 419 | if !cargo[pkg].is_member { |
397 | continue; | 420 | continue; |
398 | } | 421 | } |
399 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { | 422 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { |
400 | add_dep(&mut crate_graph, from, name.clone(), to); | 423 | add_dep(&mut crate_graph, from, name.clone(), to); |
401 | } | ||
402 | } | ||
403 | } | ||
404 | } | 424 | } |
405 | } | 425 | } |
406 | } | 426 | } |
407 | } | 427 | } |
408 | if crate_graph.patch_cfg_if() { | ||
409 | log::debug!("Patched std to depend on cfg-if") | ||
410 | } else { | ||
411 | log::debug!("Did not patch std to depend on cfg-if") | ||
412 | } | ||
413 | crate_graph | ||
414 | } | 428 | } |
429 | crate_graph | ||
415 | } | 430 | } |
416 | 431 | ||
417 | fn add_target_crate_root( | 432 | fn add_target_crate_root( |
418 | crate_graph: &mut CrateGraph, | 433 | crate_graph: &mut CrateGraph, |
419 | pkg: &cargo_workspace::PackageData, | 434 | pkg: &cargo_workspace::PackageData, |
420 | tgt: &cargo_workspace::TargetData, | ||
421 | cfg_options: &CfgOptions, | 435 | cfg_options: &CfgOptions, |
422 | proc_macro_client: &ProcMacroClient, | 436 | proc_macro_client: &ProcMacroClient, |
423 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 437 | file_id: FileId, |
424 | ) -> Option<CrateId> { | 438 | ) -> CrateId { |
425 | let root = tgt.root.as_path(); | 439 | let edition = pkg.edition; |
426 | if let Some(file_id) = load(root) { | 440 | let cfg_options = { |
427 | let edition = pkg.edition; | 441 | let mut opts = cfg_options.clone(); |
428 | let cfg_options = { | 442 | for feature in pkg.features.iter() { |
429 | let mut opts = cfg_options.clone(); | 443 | opts.insert_key_value("feature".into(), feature.into()); |
430 | for feature in pkg.features.iter() { | 444 | } |
431 | opts.insert_key_value("feature".into(), feature.into()); | 445 | opts.extend(pkg.cfgs.iter().cloned()); |
432 | } | 446 | opts |
433 | opts.extend(pkg.cfgs.iter().cloned()); | 447 | }; |
434 | opts | 448 | let mut env = Env::default(); |
435 | }; | 449 | if let Some(out_dir) = &pkg.out_dir { |
436 | let mut env = Env::default(); | 450 | // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!() |
437 | if let Some(out_dir) = &pkg.out_dir { | 451 | if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) { |
438 | // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!() | 452 | env.set("OUT_DIR", out_dir); |
439 | if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) { | ||
440 | env.set("OUT_DIR", out_dir); | ||
441 | } | ||
442 | } | 453 | } |
443 | let proc_macro = pkg | ||
444 | .proc_macro_dylib_path | ||
445 | .as_ref() | ||
446 | .map(|it| proc_macro_client.by_dylib_path(&it)) | ||
447 | .unwrap_or_default(); | ||
448 | |||
449 | let display_name = CrateDisplayName::from_canonical_name(pkg.name.clone()); | ||
450 | let crate_id = crate_graph.add_crate_root( | ||
451 | file_id, | ||
452 | edition, | ||
453 | Some(display_name), | ||
454 | cfg_options, | ||
455 | env, | ||
456 | proc_macro.clone(), | ||
457 | ); | ||
458 | |||
459 | return Some(crate_id); | ||
460 | } | 454 | } |
461 | None | 455 | let proc_macro = pkg |
456 | .proc_macro_dylib_path | ||
457 | .as_ref() | ||
458 | .map(|it| proc_macro_client.by_dylib_path(&it)) | ||
459 | .unwrap_or_default(); | ||
460 | |||
461 | let display_name = CrateDisplayName::from_canonical_name(pkg.name.clone()); | ||
462 | let crate_id = crate_graph.add_crate_root( | ||
463 | file_id, | ||
464 | edition, | ||
465 | Some(display_name), | ||
466 | cfg_options, | ||
467 | env, | ||
468 | proc_macro.clone(), | ||
469 | ); | ||
470 | |||
471 | crate_id | ||
462 | } | 472 | } |
473 | |||
463 | fn sysroot_to_crate_graph( | 474 | fn sysroot_to_crate_graph( |
464 | crate_graph: &mut CrateGraph, | 475 | crate_graph: &mut CrateGraph, |
465 | sysroot: &Sysroot, | 476 | sysroot: &Sysroot, |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index d16796590..5fc6800cf 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -294,10 +294,6 @@ impl Config { | |||
294 | max_length: data.inlayHints_maxLength, | 294 | max_length: data.inlayHints_maxLength, |
295 | }; | 295 | }; |
296 | 296 | ||
297 | self.completion.enable_postfix_completions = data.completion_postfix_enable; | ||
298 | self.completion.add_call_parenthesis = data.completion_addCallParenthesis; | ||
299 | self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets; | ||
300 | |||
301 | self.assist.insert_use.merge = match data.assist_importMergeBehaviour { | 297 | self.assist.insert_use.merge = match data.assist_importMergeBehaviour { |
302 | MergeBehaviourDef::None => None, | 298 | MergeBehaviourDef::None => None, |
303 | MergeBehaviourDef::Full => Some(MergeBehaviour::Full), | 299 | MergeBehaviourDef::Full => Some(MergeBehaviour::Full), |
@@ -309,6 +305,11 @@ impl Config { | |||
309 | ImportPrefixDef::BySelf => PrefixKind::BySelf, | 305 | ImportPrefixDef::BySelf => PrefixKind::BySelf, |
310 | }; | 306 | }; |
311 | 307 | ||
308 | self.completion.enable_postfix_completions = data.completion_postfix_enable; | ||
309 | self.completion.add_call_parenthesis = data.completion_addCallParenthesis; | ||
310 | self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets; | ||
311 | self.completion.merge = self.assist.insert_use.merge; | ||
312 | |||
312 | self.call_info_full = data.callInfo_full; | 313 | self.call_info_full = data.callInfo_full; |
313 | 314 | ||
314 | self.lens = LensConfig { | 315 | self.lens = LensConfig { |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 4d1ebf6bf..118e7276f 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -18,7 +18,7 @@ use lsp_types::{ | |||
18 | CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, | 18 | CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, |
19 | CodeActionKind, CodeLens, Command, CompletionItem, Diagnostic, DiagnosticTag, | 19 | CodeActionKind, CodeLens, Command, CompletionItem, Diagnostic, DiagnosticTag, |
20 | DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeParams, | 20 | DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeParams, |
21 | HoverContents, Location, Position, PrepareRenameResponse, Range, RenameParams, | 21 | HoverContents, Location, NumberOrString, Position, PrepareRenameResponse, Range, RenameParams, |
22 | SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams, | 22 | SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams, |
23 | SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, | 23 | SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, |
24 | SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit, | 24 | SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit, |
@@ -573,7 +573,7 @@ pub(crate) fn handle_completion( | |||
573 | .flat_map(|item| to_proto::completion_item(&line_index, line_endings, item)) | 573 | .flat_map(|item| to_proto::completion_item(&line_index, line_endings, item)) |
574 | .collect(); | 574 | .collect(); |
575 | 575 | ||
576 | let completion_list = lsp_types::CompletionList { is_incomplete: false, items }; | 576 | let completion_list = lsp_types::CompletionList { is_incomplete: true, items }; |
577 | Ok(Some(completion_list.into())) | 577 | Ok(Some(completion_list.into())) |
578 | } | 578 | } |
579 | 579 | ||
@@ -1128,7 +1128,7 @@ pub(crate) fn publish_diagnostics( | |||
1128 | .map(|d| Diagnostic { | 1128 | .map(|d| Diagnostic { |
1129 | range: to_proto::range(&line_index, d.range), | 1129 | range: to_proto::range(&line_index, d.range), |
1130 | severity: Some(to_proto::diagnostic_severity(d.severity)), | 1130 | severity: Some(to_proto::diagnostic_severity(d.severity)), |
1131 | code: None, | 1131 | code: d.code.map(|d| d.as_str().to_owned()).map(NumberOrString::String), |
1132 | code_description: None, | 1132 | code_description: None, |
1133 | source: Some("rust-analyzer".to_string()), | 1133 | source: Some("rust-analyzer".to_string()), |
1134 | message: d.message, | 1134 | message: d.message, |
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index fa6e09f42..001bf5949 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs | |||
@@ -203,7 +203,11 @@ impl GlobalState { | |||
203 | let contents = loader.handle.load_sync(path); | 203 | let contents = loader.handle.load_sync(path); |
204 | vfs.set_file_contents(vfs_path.clone(), contents); | 204 | vfs.set_file_contents(vfs_path.clone(), contents); |
205 | } | 205 | } |
206 | vfs.file_id(&vfs_path) | 206 | let res = vfs.file_id(&vfs_path); |
207 | if res.is_none() { | ||
208 | log::error!("failed to load {}", path.display()) | ||
209 | } | ||
210 | res | ||
207 | }; | 211 | }; |
208 | for ws in workspaces.iter() { | 212 | for ws in workspaces.iter() { |
209 | crate_graph.extend(ws.to_crate_graph( | 213 | crate_graph.extend(ws.to_crate_graph( |