diff options
Diffstat (limited to 'crates')
59 files changed, 866 insertions, 476 deletions
diff --git a/crates/assists/src/assist_config.rs b/crates/assists/src/assist_config.rs index 4fe8ea761..9cabf037c 100644 --- a/crates/assists/src/assist_config.rs +++ b/crates/assists/src/assist_config.rs | |||
@@ -4,7 +4,7 @@ | |||
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 | //! assists if we are allowed to. | 5 | //! assists if we are allowed to. |
6 | 6 | ||
7 | use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap}; | 7 | use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap}; |
8 | 8 | ||
9 | use crate::AssistKind; | 9 | use crate::AssistKind; |
10 | 10 | ||
@@ -14,9 +14,3 @@ pub struct AssistConfig { | |||
14 | pub allowed: Option<Vec<AssistKind>>, | 14 | pub allowed: Option<Vec<AssistKind>>, |
15 | pub insert_use: InsertUseConfig, | 15 | pub insert_use: InsertUseConfig, |
16 | } | 16 | } |
17 | |||
18 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
19 | pub struct InsertUseConfig { | ||
20 | pub merge: Option<MergeBehavior>, | ||
21 | pub prefix_kind: hir::PrefixKind, | ||
22 | } | ||
diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs index 55620f0f3..4e2a4fcd9 100644 --- a/crates/assists/src/handlers/auto_import.rs +++ b/crates/assists/src/handlers/auto_import.rs | |||
@@ -1,13 +1,11 @@ | |||
1 | use ide_db::helpers::{ | 1 | use ide_db::helpers::{ |
2 | import_assets::{ImportAssets, ImportCandidate}, | ||
2 | insert_use::{insert_use, ImportScope}, | 3 | insert_use::{insert_use, ImportScope}, |
3 | mod_path_to_ast, | 4 | mod_path_to_ast, |
4 | }; | 5 | }; |
5 | use syntax::ast; | 6 | use syntax::ast; |
6 | 7 | ||
7 | use crate::{ | 8 | use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; |
8 | utils::import_assets::{ImportAssets, ImportCandidate}, | ||
9 | AssistContext, AssistId, AssistKind, Assists, GroupLabel, | ||
10 | }; | ||
11 | 9 | ||
12 | // Feature: Auto Import | 10 | // Feature: Auto Import |
13 | // | 11 | // |
@@ -121,8 +119,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
121 | 119 | ||
122 | fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel { | 120 | fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel { |
123 | let name = match import_candidate { | 121 | let name = match import_candidate { |
124 | ImportCandidate::UnqualifiedName(candidate) | 122 | ImportCandidate::Path(candidate) => format!("Import {}", &candidate.name), |
125 | | ImportCandidate::QualifierStart(candidate) => format!("Import {}", &candidate.name), | ||
126 | ImportCandidate::TraitAssocItem(candidate) => { | 123 | ImportCandidate::TraitAssocItem(candidate) => { |
127 | format!("Import a trait for item {}", &candidate.name) | 124 | format!("Import a trait for item {}", &candidate.name) |
128 | } | 125 | } |
diff --git a/crates/assists/src/handlers/qualify_path.rs b/crates/assists/src/handlers/qualify_path.rs index f7fbf37f4..a7d9fd4dc 100644 --- a/crates/assists/src/handlers/qualify_path.rs +++ b/crates/assists/src/handlers/qualify_path.rs | |||
@@ -1,7 +1,10 @@ | |||
1 | use std::iter; | 1 | use std::iter; |
2 | 2 | ||
3 | use hir::AsName; | 3 | use hir::AsName; |
4 | use ide_db::helpers::mod_path_to_ast; | 4 | use ide_db::helpers::{ |
5 | import_assets::{ImportAssets, ImportCandidate}, | ||
6 | mod_path_to_ast, | ||
7 | }; | ||
5 | use ide_db::RootDatabase; | 8 | use ide_db::RootDatabase; |
6 | use syntax::{ | 9 | use syntax::{ |
7 | ast, | 10 | ast, |
@@ -12,7 +15,6 @@ use test_utils::mark; | |||
12 | 15 | ||
13 | use crate::{ | 16 | use crate::{ |
14 | assist_context::{AssistContext, Assists}, | 17 | assist_context::{AssistContext, Assists}, |
15 | utils::import_assets::{ImportAssets, ImportCandidate}, | ||
16 | AssistId, AssistKind, GroupLabel, | 18 | AssistId, AssistKind, GroupLabel, |
17 | }; | 19 | }; |
18 | 20 | ||
@@ -53,17 +55,18 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
53 | let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range; | 55 | let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range; |
54 | 56 | ||
55 | let qualify_candidate = match candidate { | 57 | let qualify_candidate = match candidate { |
56 | ImportCandidate::QualifierStart(_) => { | 58 | ImportCandidate::Path(candidate) => { |
57 | mark::hit!(qualify_path_qualifier_start); | 59 | if candidate.qualifier.is_some() { |
58 | let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; | 60 | mark::hit!(qualify_path_qualifier_start); |
59 | let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?); | 61 | let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; |
60 | QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list()) | 62 | let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?); |
61 | } | 63 | QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list()) |
62 | ImportCandidate::UnqualifiedName(_) => { | 64 | } else { |
63 | mark::hit!(qualify_path_unqualified_name); | 65 | mark::hit!(qualify_path_unqualified_name); |
64 | let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; | 66 | let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; |
65 | let generics = path.segment()?.generic_arg_list(); | 67 | let generics = path.segment()?.generic_arg_list(); |
66 | QualifyCandidate::UnqualifiedName(generics) | 68 | QualifyCandidate::UnqualifiedName(generics) |
69 | } | ||
67 | } | 70 | } |
68 | ImportCandidate::TraitAssocItem(_) => { | 71 | ImportCandidate::TraitAssocItem(_) => { |
69 | mark::hit!(qualify_path_trait_assoc_item); | 72 | mark::hit!(qualify_path_trait_assoc_item); |
@@ -186,7 +189,7 @@ fn item_as_trait(item: hir::ItemInNs) -> Option<hir::Trait> { | |||
186 | 189 | ||
187 | fn group_label(candidate: &ImportCandidate) -> GroupLabel { | 190 | fn group_label(candidate: &ImportCandidate) -> GroupLabel { |
188 | let name = match candidate { | 191 | let name = match candidate { |
189 | ImportCandidate::UnqualifiedName(it) | ImportCandidate::QualifierStart(it) => &it.name, | 192 | ImportCandidate::Path(it) => &it.name, |
190 | ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => &it.name, | 193 | ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => &it.name, |
191 | }; | 194 | }; |
192 | GroupLabel(format!("Qualify {}", name)) | 195 | GroupLabel(format!("Qualify {}", name)) |
@@ -194,8 +197,13 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel { | |||
194 | 197 | ||
195 | fn label(candidate: &ImportCandidate, import: &hir::ModPath) -> String { | 198 | fn label(candidate: &ImportCandidate, import: &hir::ModPath) -> String { |
196 | match candidate { | 199 | match candidate { |
197 | ImportCandidate::UnqualifiedName(_) => format!("Qualify as `{}`", &import), | 200 | ImportCandidate::Path(candidate) => { |
198 | ImportCandidate::QualifierStart(_) => format!("Qualify with `{}`", &import), | 201 | if candidate.qualifier.is_some() { |
202 | format!("Qualify with `{}`", &import) | ||
203 | } else { | ||
204 | format!("Qualify as `{}`", &import) | ||
205 | } | ||
206 | } | ||
199 | ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", &import), | 207 | ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", &import), |
200 | ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", &import), | 208 | ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", &import), |
201 | } | 209 | } |
diff --git a/crates/assists/src/handlers/unmerge_use.rs b/crates/assists/src/handlers/unmerge_use.rs new file mode 100644 index 000000000..3dbef8e51 --- /dev/null +++ b/crates/assists/src/handlers/unmerge_use.rs | |||
@@ -0,0 +1,231 @@ | |||
1 | use syntax::{ | ||
2 | algo::SyntaxRewriter, | ||
3 | ast::{self, edit::AstNodeEdit, VisibilityOwner}, | ||
4 | AstNode, SyntaxKind, | ||
5 | }; | ||
6 | use test_utils::mark; | ||
7 | |||
8 | use crate::{ | ||
9 | assist_context::{AssistContext, Assists}, | ||
10 | AssistId, AssistKind, | ||
11 | }; | ||
12 | |||
13 | // Assist: unmerge_use | ||
14 | // | ||
15 | // Extracts single use item from use list. | ||
16 | // | ||
17 | // ``` | ||
18 | // use std::fmt::{Debug, Display$0}; | ||
19 | // ``` | ||
20 | // -> | ||
21 | // ``` | ||
22 | // use std::fmt::{Debug}; | ||
23 | // use std::fmt::Display; | ||
24 | // ``` | ||
25 | pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
26 | let tree: ast::UseTree = ctx.find_node_at_offset()?; | ||
27 | |||
28 | let tree_list = tree.syntax().parent().and_then(ast::UseTreeList::cast)?; | ||
29 | if tree_list.use_trees().count() < 2 { | ||
30 | mark::hit!(skip_single_use_item); | ||
31 | return None; | ||
32 | } | ||
33 | |||
34 | let use_: ast::Use = tree_list.syntax().ancestors().find_map(ast::Use::cast)?; | ||
35 | let path = resolve_full_path(&tree)?; | ||
36 | |||
37 | let target = tree.syntax().text_range(); | ||
38 | acc.add( | ||
39 | AssistId("unmerge_use", AssistKind::RefactorRewrite), | ||
40 | "Unmerge use", | ||
41 | target, | ||
42 | |builder| { | ||
43 | let new_use = ast::make::use_( | ||
44 | use_.visibility(), | ||
45 | ast::make::use_tree( | ||
46 | path, | ||
47 | tree.use_tree_list(), | ||
48 | tree.rename(), | ||
49 | tree.star_token().is_some(), | ||
50 | ), | ||
51 | ); | ||
52 | |||
53 | let mut rewriter = SyntaxRewriter::default(); | ||
54 | rewriter += tree.remove(); | ||
55 | rewriter.insert_after(use_.syntax(), &ast::make::tokens::single_newline()); | ||
56 | if let ident_level @ 1..=usize::MAX = use_.indent_level().0 as usize { | ||
57 | rewriter.insert_after( | ||
58 | use_.syntax(), | ||
59 | &ast::make::tokens::whitespace(&" ".repeat(4 * ident_level)), | ||
60 | ); | ||
61 | } | ||
62 | rewriter.insert_after(use_.syntax(), new_use.syntax()); | ||
63 | |||
64 | builder.rewrite(rewriter); | ||
65 | }, | ||
66 | ) | ||
67 | } | ||
68 | |||
69 | fn resolve_full_path(tree: &ast::UseTree) -> Option<ast::Path> { | ||
70 | let mut paths = tree | ||
71 | .syntax() | ||
72 | .ancestors() | ||
73 | .take_while(|n| n.kind() != SyntaxKind::USE_KW) | ||
74 | .filter_map(ast::UseTree::cast) | ||
75 | .filter_map(|t| t.path()); | ||
76 | |||
77 | let mut final_path = paths.next()?; | ||
78 | for path in paths { | ||
79 | final_path = ast::make::path_concat(path, final_path) | ||
80 | } | ||
81 | Some(final_path) | ||
82 | } | ||
83 | |||
84 | #[cfg(test)] | ||
85 | mod tests { | ||
86 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
87 | |||
88 | use super::*; | ||
89 | |||
90 | #[test] | ||
91 | fn skip_single_use_item() { | ||
92 | mark::check!(skip_single_use_item); | ||
93 | check_assist_not_applicable( | ||
94 | unmerge_use, | ||
95 | r" | ||
96 | use std::fmt::Debug$0; | ||
97 | ", | ||
98 | ); | ||
99 | check_assist_not_applicable( | ||
100 | unmerge_use, | ||
101 | r" | ||
102 | use std::fmt::{Debug$0}; | ||
103 | ", | ||
104 | ); | ||
105 | check_assist_not_applicable( | ||
106 | unmerge_use, | ||
107 | r" | ||
108 | use std::fmt::Debug as Dbg$0; | ||
109 | ", | ||
110 | ); | ||
111 | } | ||
112 | |||
113 | #[test] | ||
114 | fn skip_single_glob_import() { | ||
115 | check_assist_not_applicable( | ||
116 | unmerge_use, | ||
117 | r" | ||
118 | use std::fmt::*$0; | ||
119 | ", | ||
120 | ); | ||
121 | } | ||
122 | |||
123 | #[test] | ||
124 | fn unmerge_use_item() { | ||
125 | check_assist( | ||
126 | unmerge_use, | ||
127 | r" | ||
128 | use std::fmt::{Debug, Display$0}; | ||
129 | ", | ||
130 | r" | ||
131 | use std::fmt::{Debug}; | ||
132 | use std::fmt::Display; | ||
133 | ", | ||
134 | ); | ||
135 | |||
136 | check_assist( | ||
137 | unmerge_use, | ||
138 | r" | ||
139 | use std::fmt::{Debug, format$0, Display}; | ||
140 | ", | ||
141 | r" | ||
142 | use std::fmt::{Debug, Display}; | ||
143 | use std::fmt::format; | ||
144 | ", | ||
145 | ); | ||
146 | } | ||
147 | |||
148 | #[test] | ||
149 | fn unmerge_glob_import() { | ||
150 | check_assist( | ||
151 | unmerge_use, | ||
152 | r" | ||
153 | use std::fmt::{*$0, Display}; | ||
154 | ", | ||
155 | r" | ||
156 | use std::fmt::{Display}; | ||
157 | use std::fmt::*; | ||
158 | ", | ||
159 | ); | ||
160 | } | ||
161 | |||
162 | #[test] | ||
163 | fn unmerge_renamed_use_item() { | ||
164 | check_assist( | ||
165 | unmerge_use, | ||
166 | r" | ||
167 | use std::fmt::{Debug, Display as Disp$0}; | ||
168 | ", | ||
169 | r" | ||
170 | use std::fmt::{Debug}; | ||
171 | use std::fmt::Display as Disp; | ||
172 | ", | ||
173 | ); | ||
174 | } | ||
175 | |||
176 | #[test] | ||
177 | fn unmerge_indented_use_item() { | ||
178 | check_assist( | ||
179 | unmerge_use, | ||
180 | r" | ||
181 | mod format { | ||
182 | use std::fmt::{Debug, Display$0 as Disp, format}; | ||
183 | } | ||
184 | ", | ||
185 | r" | ||
186 | mod format { | ||
187 | use std::fmt::{Debug, format}; | ||
188 | use std::fmt::Display as Disp; | ||
189 | } | ||
190 | ", | ||
191 | ); | ||
192 | } | ||
193 | |||
194 | #[test] | ||
195 | fn unmerge_nested_use_item() { | ||
196 | check_assist( | ||
197 | unmerge_use, | ||
198 | r" | ||
199 | use foo::bar::{baz::{qux$0, foobar}, barbaz}; | ||
200 | ", | ||
201 | r" | ||
202 | use foo::bar::{baz::{foobar}, barbaz}; | ||
203 | use foo::bar::baz::qux; | ||
204 | ", | ||
205 | ); | ||
206 | check_assist( | ||
207 | unmerge_use, | ||
208 | r" | ||
209 | use foo::bar::{baz$0::{qux, foobar}, barbaz}; | ||
210 | ", | ||
211 | r" | ||
212 | use foo::bar::{barbaz}; | ||
213 | use foo::bar::baz::{qux, foobar}; | ||
214 | ", | ||
215 | ); | ||
216 | } | ||
217 | |||
218 | #[test] | ||
219 | fn unmerge_use_item_with_visibility() { | ||
220 | check_assist( | ||
221 | unmerge_use, | ||
222 | r" | ||
223 | pub use std::fmt::{Debug, Display$0}; | ||
224 | ", | ||
225 | r" | ||
226 | pub use std::fmt::{Debug}; | ||
227 | pub use std::fmt::Display; | ||
228 | ", | ||
229 | ); | ||
230 | } | ||
231 | } | ||
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs index 1080294ab..14178a651 100644 --- a/crates/assists/src/lib.rs +++ b/crates/assists/src/lib.rs | |||
@@ -24,7 +24,7 @@ use syntax::TextRange; | |||
24 | 24 | ||
25 | pub(crate) use crate::assist_context::{AssistContext, Assists}; | 25 | pub(crate) use crate::assist_context::{AssistContext, Assists}; |
26 | 26 | ||
27 | pub use assist_config::{AssistConfig, InsertUseConfig}; | 27 | pub use assist_config::AssistConfig; |
28 | 28 | ||
29 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 29 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
30 | pub enum AssistKind { | 30 | pub enum AssistKind { |
@@ -156,6 +156,7 @@ mod handlers { | |||
156 | mod replace_unwrap_with_match; | 156 | mod replace_unwrap_with_match; |
157 | mod split_import; | 157 | mod split_import; |
158 | mod toggle_ignore; | 158 | mod toggle_ignore; |
159 | mod unmerge_use; | ||
159 | mod unwrap_block; | 160 | mod unwrap_block; |
160 | mod wrap_return_type_in_result; | 161 | mod wrap_return_type_in_result; |
161 | 162 | ||
@@ -213,6 +214,7 @@ mod handlers { | |||
213 | replace_unwrap_with_match::replace_unwrap_with_match, | 214 | replace_unwrap_with_match::replace_unwrap_with_match, |
214 | split_import::split_import, | 215 | split_import::split_import, |
215 | toggle_ignore::toggle_ignore, | 216 | toggle_ignore::toggle_ignore, |
217 | unmerge_use::unmerge_use, | ||
216 | unwrap_block::unwrap_block, | 218 | unwrap_block::unwrap_block, |
217 | wrap_return_type_in_result::wrap_return_type_in_result, | 219 | wrap_return_type_in_result::wrap_return_type_in_result, |
218 | // These are manually sorted for better priorities | 220 | // These are manually sorted for better priorities |
diff --git a/crates/assists/src/tests.rs b/crates/assists/src/tests.rs index 71431b406..32bd8698b 100644 --- a/crates/assists/src/tests.rs +++ b/crates/assists/src/tests.rs | |||
@@ -3,16 +3,17 @@ mod generated; | |||
3 | use hir::Semantics; | 3 | use hir::Semantics; |
4 | use ide_db::{ | 4 | use ide_db::{ |
5 | base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}, | 5 | base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}, |
6 | helpers::{insert_use::MergeBehavior, SnippetCap}, | 6 | helpers::{ |
7 | insert_use::{InsertUseConfig, MergeBehavior}, | ||
8 | SnippetCap, | ||
9 | }, | ||
7 | source_change::FileSystemEdit, | 10 | source_change::FileSystemEdit, |
8 | RootDatabase, | 11 | RootDatabase, |
9 | }; | 12 | }; |
10 | use syntax::TextRange; | 13 | use syntax::TextRange; |
11 | use test_utils::{assert_eq_text, extract_offset, extract_range}; | 14 | use test_utils::{assert_eq_text, extract_offset, extract_range}; |
12 | 15 | ||
13 | use crate::{ | 16 | use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, Assists}; |
14 | handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, Assists, InsertUseConfig, | ||
15 | }; | ||
16 | use stdx::{format_to, trim_indent}; | 17 | use stdx::{format_to, trim_indent}; |
17 | 18 | ||
18 | pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { | 19 | pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { |
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs index 217f577eb..d48d063b4 100644 --- a/crates/assists/src/tests/generated.rs +++ b/crates/assists/src/tests/generated.rs | |||
@@ -1138,6 +1138,20 @@ fn arithmetics { | |||
1138 | } | 1138 | } |
1139 | 1139 | ||
1140 | #[test] | 1140 | #[test] |
1141 | fn doctest_unmerge_use() { | ||
1142 | check_doc_test( | ||
1143 | "unmerge_use", | ||
1144 | r#####" | ||
1145 | use std::fmt::{Debug, Display$0}; | ||
1146 | "#####, | ||
1147 | r#####" | ||
1148 | use std::fmt::{Debug}; | ||
1149 | use std::fmt::Display; | ||
1150 | "#####, | ||
1151 | ) | ||
1152 | } | ||
1153 | |||
1154 | #[test] | ||
1141 | fn doctest_unwrap_block() { | 1155 | fn doctest_unwrap_block() { |
1142 | check_doc_test( | 1156 | check_doc_test( |
1143 | "unwrap_block", | 1157 | "unwrap_block", |
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index 9ea96eb73..fc9f83bab 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -1,5 +1,4 @@ | |||
1 | //! Assorted functions shared by several assists. | 1 | //! Assorted functions shared by several assists. |
2 | pub(crate) mod import_assets; | ||
3 | 2 | ||
4 | use std::ops; | 3 | use std::ops; |
5 | 4 | ||
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index 00c9e76f0..c3ce6e51d 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs | |||
@@ -13,6 +13,7 @@ pub(crate) mod postfix; | |||
13 | pub(crate) mod macro_in_item_position; | 13 | pub(crate) mod macro_in_item_position; |
14 | pub(crate) mod trait_impl; | 14 | pub(crate) mod trait_impl; |
15 | pub(crate) mod mod_; | 15 | pub(crate) mod mod_; |
16 | pub(crate) mod flyimport; | ||
16 | 17 | ||
17 | use hir::{ModPath, ScopeDef, Type}; | 18 | use hir::{ModPath, ScopeDef, Type}; |
18 | 19 | ||
diff --git a/crates/completion/src/completions/flyimport.rs b/crates/completion/src/completions/flyimport.rs new file mode 100644 index 000000000..222809638 --- /dev/null +++ b/crates/completion/src/completions/flyimport.rs | |||
@@ -0,0 +1,291 @@ | |||
1 | //! Feature: completion with imports-on-the-fly | ||
2 | //! | ||
3 | //! When completing names in the current scope, proposes additional imports from other modules or crates, | ||
4 | //! if they can be qualified in the scope and their name contains all symbols from the completion input | ||
5 | //! (case-insensitive, in any order or places). | ||
6 | //! | ||
7 | //! ``` | ||
8 | //! fn main() { | ||
9 | //! pda$0 | ||
10 | //! } | ||
11 | //! # pub mod std { pub mod marker { pub struct PhantomData { } } } | ||
12 | //! ``` | ||
13 | //! -> | ||
14 | //! ``` | ||
15 | //! use std::marker::PhantomData; | ||
16 | //! | ||
17 | //! fn main() { | ||
18 | //! PhantomData | ||
19 | //! } | ||
20 | //! # pub mod std { pub mod marker { pub struct PhantomData { } } } | ||
21 | //! ``` | ||
22 | //! | ||
23 | //! .Fuzzy search details | ||
24 | //! | ||
25 | //! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only | ||
26 | //! (i.e. in `HashMap` in the `std::collections::HashMap` path). | ||
27 | //! For the same reasons, avoids searching for any imports for inputs with their length less that 2 symbols. | ||
28 | //! | ||
29 | //! .Import configuration | ||
30 | //! | ||
31 | //! It is possible to configure how use-trees are merged with the `importMergeBehavior` setting. | ||
32 | //! Mimics the corresponding behavior of the `Auto Import` feature. | ||
33 | //! | ||
34 | //! .LSP and performance implications | ||
35 | //! | ||
36 | //! The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits` | ||
37 | //! (case sensitive) resolve client capability in its client capabilities. | ||
38 | //! This way the server is able to defer the costly computations, doing them for a selected completion item only. | ||
39 | //! For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones, | ||
40 | //! which might be slow ergo the feature is automatically disabled. | ||
41 | //! | ||
42 | //! .Feature toggle | ||
43 | //! | ||
44 | //! The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.enableAutoimportCompletions` flag. | ||
45 | //! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding | ||
46 | //! capability enabled. | ||
47 | |||
48 | use either::Either; | ||
49 | use hir::{ModPath, ScopeDef}; | ||
50 | use ide_db::{helpers::insert_use::ImportScope, imports_locator}; | ||
51 | use syntax::AstNode; | ||
52 | use test_utils::mark; | ||
53 | |||
54 | use crate::{ | ||
55 | context::CompletionContext, | ||
56 | render::{render_resolution_with_import, RenderContext}, | ||
57 | ImportEdit, | ||
58 | }; | ||
59 | |||
60 | use super::Completions; | ||
61 | |||
62 | pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | ||
63 | if !ctx.config.enable_autoimport_completions { | ||
64 | return None; | ||
65 | } | ||
66 | if ctx.attribute_under_caret.is_some() || ctx.mod_declaration_under_caret.is_some() { | ||
67 | return None; | ||
68 | } | ||
69 | let potential_import_name = ctx.token.to_string(); | ||
70 | if potential_import_name.len() < 2 { | ||
71 | return None; | ||
72 | } | ||
73 | let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.to_string()); | ||
74 | |||
75 | let current_module = ctx.scope.module()?; | ||
76 | let anchor = ctx.name_ref_syntax.as_ref()?; | ||
77 | let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; | ||
78 | |||
79 | let user_input_lowercased = potential_import_name.to_lowercase(); | ||
80 | let mut all_mod_paths = imports_locator::find_similar_imports( | ||
81 | &ctx.sema, | ||
82 | ctx.krate?, | ||
83 | Some(40), | ||
84 | potential_import_name, | ||
85 | true, | ||
86 | true, | ||
87 | ) | ||
88 | .filter_map(|import_candidate| { | ||
89 | Some(match import_candidate { | ||
90 | Either::Left(module_def) => { | ||
91 | (current_module.find_use_path(ctx.db, module_def)?, ScopeDef::ModuleDef(module_def)) | ||
92 | } | ||
93 | Either::Right(macro_def) => { | ||
94 | (current_module.find_use_path(ctx.db, macro_def)?, ScopeDef::MacroDef(macro_def)) | ||
95 | } | ||
96 | }) | ||
97 | }) | ||
98 | .filter(|(mod_path, _)| mod_path.len() > 1) | ||
99 | .collect::<Vec<_>>(); | ||
100 | |||
101 | all_mod_paths.sort_by_cached_key(|(mod_path, _)| { | ||
102 | compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased) | ||
103 | }); | ||
104 | |||
105 | acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| { | ||
106 | render_resolution_with_import( | ||
107 | RenderContext::new(ctx), | ||
108 | ImportEdit { import_path, import_scope: import_scope.clone() }, | ||
109 | &definition, | ||
110 | ) | ||
111 | })); | ||
112 | Some(()) | ||
113 | } | ||
114 | |||
115 | fn compute_fuzzy_completion_order_key( | ||
116 | proposed_mod_path: &ModPath, | ||
117 | user_input_lowercased: &str, | ||
118 | ) -> usize { | ||
119 | mark::hit!(certain_fuzzy_order_test); | ||
120 | let proposed_import_name = match proposed_mod_path.segments.last() { | ||
121 | Some(name) => name.to_string().to_lowercase(), | ||
122 | None => return usize::MAX, | ||
123 | }; | ||
124 | match proposed_import_name.match_indices(user_input_lowercased).next() { | ||
125 | Some((first_matching_index, _)) => first_matching_index, | ||
126 | None => usize::MAX, | ||
127 | } | ||
128 | } | ||
129 | |||
130 | #[cfg(test)] | ||
131 | mod tests { | ||
132 | use expect_test::{expect, Expect}; | ||
133 | use test_utils::mark; | ||
134 | |||
135 | use crate::{ | ||
136 | item::CompletionKind, | ||
137 | test_utils::{check_edit, completion_list}, | ||
138 | }; | ||
139 | |||
140 | fn check(ra_fixture: &str, expect: Expect) { | ||
141 | let actual = completion_list(ra_fixture, CompletionKind::Magic); | ||
142 | expect.assert_eq(&actual); | ||
143 | } | ||
144 | |||
145 | #[test] | ||
146 | fn function_fuzzy_completion() { | ||
147 | check_edit( | ||
148 | "stdin", | ||
149 | r#" | ||
150 | //- /lib.rs crate:dep | ||
151 | pub mod io { | ||
152 | pub fn stdin() {} | ||
153 | }; | ||
154 | |||
155 | //- /main.rs crate:main deps:dep | ||
156 | fn main() { | ||
157 | stdi$0 | ||
158 | } | ||
159 | "#, | ||
160 | r#" | ||
161 | use dep::io::stdin; | ||
162 | |||
163 | fn main() { | ||
164 | stdin()$0 | ||
165 | } | ||
166 | "#, | ||
167 | ); | ||
168 | } | ||
169 | |||
170 | #[test] | ||
171 | fn macro_fuzzy_completion() { | ||
172 | check_edit( | ||
173 | "macro_with_curlies!", | ||
174 | r#" | ||
175 | //- /lib.rs crate:dep | ||
176 | /// Please call me as macro_with_curlies! {} | ||
177 | #[macro_export] | ||
178 | macro_rules! macro_with_curlies { | ||
179 | () => {} | ||
180 | } | ||
181 | |||
182 | //- /main.rs crate:main deps:dep | ||
183 | fn main() { | ||
184 | curli$0 | ||
185 | } | ||
186 | "#, | ||
187 | r#" | ||
188 | use dep::macro_with_curlies; | ||
189 | |||
190 | fn main() { | ||
191 | macro_with_curlies! {$0} | ||
192 | } | ||
193 | "#, | ||
194 | ); | ||
195 | } | ||
196 | |||
197 | #[test] | ||
198 | fn struct_fuzzy_completion() { | ||
199 | check_edit( | ||
200 | "ThirdStruct", | ||
201 | r#" | ||
202 | //- /lib.rs crate:dep | ||
203 | pub struct FirstStruct; | ||
204 | pub mod some_module { | ||
205 | pub struct SecondStruct; | ||
206 | pub struct ThirdStruct; | ||
207 | } | ||
208 | |||
209 | //- /main.rs crate:main deps:dep | ||
210 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
211 | |||
212 | fn main() { | ||
213 | this$0 | ||
214 | } | ||
215 | "#, | ||
216 | r#" | ||
217 | use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}}; | ||
218 | |||
219 | fn main() { | ||
220 | ThirdStruct | ||
221 | } | ||
222 | "#, | ||
223 | ); | ||
224 | } | ||
225 | |||
226 | #[test] | ||
227 | fn fuzzy_completions_come_in_specific_order() { | ||
228 | mark::check!(certain_fuzzy_order_test); | ||
229 | check( | ||
230 | r#" | ||
231 | //- /lib.rs crate:dep | ||
232 | pub struct FirstStruct; | ||
233 | pub mod some_module { | ||
234 | // already imported, omitted | ||
235 | pub struct SecondStruct; | ||
236 | // does not contain all letters from the query, omitted | ||
237 | pub struct UnrelatedOne; | ||
238 | // contains all letters from the query, but not in sequence, displayed last | ||
239 | pub struct ThiiiiiirdStruct; | ||
240 | // contains all letters from the query, but not in the beginning, displayed second | ||
241 | pub struct AfterThirdStruct; | ||
242 | // contains all letters from the query in the begginning, displayed first | ||
243 | pub struct ThirdStruct; | ||
244 | } | ||
245 | |||
246 | //- /main.rs crate:main deps:dep | ||
247 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
248 | |||
249 | fn main() { | ||
250 | hir$0 | ||
251 | } | ||
252 | "#, | ||
253 | expect![[r#" | ||
254 | st dep::some_module::ThirdStruct | ||
255 | st dep::some_module::AfterThirdStruct | ||
256 | st dep::some_module::ThiiiiiirdStruct | ||
257 | "#]], | ||
258 | ); | ||
259 | } | ||
260 | |||
261 | #[test] | ||
262 | fn does_not_propose_names_in_scope() { | ||
263 | check( | ||
264 | r#" | ||
265 | //- /lib.rs crate:dep | ||
266 | pub mod test_mod { | ||
267 | pub trait TestTrait { | ||
268 | const SPECIAL_CONST: u8; | ||
269 | type HumbleType; | ||
270 | fn weird_function(); | ||
271 | fn random_method(&self); | ||
272 | } | ||
273 | pub struct TestStruct {} | ||
274 | impl TestTrait for TestStruct { | ||
275 | const SPECIAL_CONST: u8 = 42; | ||
276 | type HumbleType = (); | ||
277 | fn weird_function() {} | ||
278 | fn random_method(&self) {} | ||
279 | } | ||
280 | } | ||
281 | |||
282 | //- /main.rs crate:main deps:dep | ||
283 | use dep::test_mod::TestStruct; | ||
284 | fn main() { | ||
285 | TestSt$0 | ||
286 | } | ||
287 | "#, | ||
288 | expect![[r#""#]], | ||
289 | ); | ||
290 | } | ||
291 | } | ||
diff --git a/crates/completion/src/completions/keyword.rs b/crates/completion/src/completions/keyword.rs index c1af348dc..47e146128 100644 --- a/crates/completion/src/completions/keyword.rs +++ b/crates/completion/src/completions/keyword.rs | |||
@@ -99,7 +99,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
99 | add_keyword(ctx, acc, "else if", "else if $0 {}"); | 99 | add_keyword(ctx, acc, "else if", "else if $0 {}"); |
100 | } | 100 | } |
101 | if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { | 101 | if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { |
102 | add_keyword(ctx, acc, "mod", "mod $0 {}"); | 102 | add_keyword(ctx, acc, "mod", "mod $0"); |
103 | } | 103 | } |
104 | if ctx.bind_pat_parent || ctx.ref_pat_parent { | 104 | if ctx.bind_pat_parent || ctx.ref_pat_parent { |
105 | add_keyword(ctx, acc, "mut", "mut "); | 105 | add_keyword(ctx, acc, "mut", "mut "); |
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs index 53e1391f3..ac5596ca4 100644 --- a/crates/completion/src/completions/unqualified_path.rs +++ b/crates/completion/src/completions/unqualified_path.rs | |||
@@ -2,17 +2,11 @@ | |||
2 | 2 | ||
3 | use std::iter; | 3 | use std::iter; |
4 | 4 | ||
5 | use either::Either; | 5 | use hir::{Adt, ModuleDef, ScopeDef, Type}; |
6 | use hir::{Adt, ModPath, ModuleDef, ScopeDef, Type}; | ||
7 | use ide_db::helpers::insert_use::ImportScope; | ||
8 | use ide_db::imports_locator; | ||
9 | use syntax::AstNode; | 6 | use syntax::AstNode; |
10 | use test_utils::mark; | 7 | use test_utils::mark; |
11 | 8 | ||
12 | use crate::{ | 9 | use crate::{CompletionContext, Completions}; |
13 | render::{render_resolution_with_import, RenderContext}, | ||
14 | CompletionContext, Completions, ImportEdit, | ||
15 | }; | ||
16 | 10 | ||
17 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 11 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
18 | if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { | 12 | if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { |
@@ -45,10 +39,6 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
45 | } | 39 | } |
46 | acc.add_resolution(ctx, name.to_string(), &res) | 40 | acc.add_resolution(ctx, name.to_string(), &res) |
47 | }); | 41 | }); |
48 | |||
49 | if ctx.config.enable_autoimport_completions { | ||
50 | fuzzy_completion(acc, ctx); | ||
51 | } | ||
52 | } | 42 | } |
53 | 43 | ||
54 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { | 44 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { |
@@ -77,124 +67,13 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T | |||
77 | } | 67 | } |
78 | } | 68 | } |
79 | 69 | ||
80 | // Feature: Fuzzy Completion and Autoimports | ||
81 | // | ||
82 | // When completing names in the current scope, proposes additional imports from other modules or crates, | ||
83 | // if they can be qualified in the scope and their name contains all symbols from the completion input | ||
84 | // (case-insensitive, in any order or places). | ||
85 | // | ||
86 | // ``` | ||
87 | // fn main() { | ||
88 | // pda$0 | ||
89 | // } | ||
90 | // # pub mod std { pub mod marker { pub struct PhantomData { } } } | ||
91 | // ``` | ||
92 | // -> | ||
93 | // ``` | ||
94 | // use std::marker::PhantomData; | ||
95 | // | ||
96 | // fn main() { | ||
97 | // PhantomData | ||
98 | // } | ||
99 | // # pub mod std { pub mod marker { pub struct PhantomData { } } } | ||
100 | // ``` | ||
101 | // | ||
102 | // .Fuzzy search details | ||
103 | // | ||
104 | // To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only | ||
105 | // (i.e. in `HashMap` in the `std::collections::HashMap` path). | ||
106 | // For the same reasons, avoids searching for any imports for inputs with their length less that 2 symbols. | ||
107 | // | ||
108 | // .Merge Behavior | ||
109 | // | ||
110 | // It is possible to configure how use-trees are merged with the `importMergeBehavior` setting. | ||
111 | // Mimics the corresponding behavior of the `Auto Import` feature. | ||
112 | // | ||
113 | // .LSP and performance implications | ||
114 | // | ||
115 | // The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits` | ||
116 | // (case sensitive) resolve client capability in its client capabilities. | ||
117 | // This way the server is able to defer the costly computations, doing them for a selected completion item only. | ||
118 | // For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones, | ||
119 | // which might be slow ergo the feature is automatically disabled. | ||
120 | // | ||
121 | // .Feature toggle | ||
122 | // | ||
123 | // The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.enableAutoimportCompletions` flag. | ||
124 | // Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding | ||
125 | // capability enabled. | ||
126 | fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | ||
127 | let potential_import_name = ctx.token.to_string(); | ||
128 | let _p = profile::span("fuzzy_completion").detail(|| potential_import_name.clone()); | ||
129 | |||
130 | if potential_import_name.len() < 2 { | ||
131 | return None; | ||
132 | } | ||
133 | |||
134 | let current_module = ctx.scope.module()?; | ||
135 | let anchor = ctx.name_ref_syntax.as_ref()?; | ||
136 | let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; | ||
137 | |||
138 | let user_input_lowercased = potential_import_name.to_lowercase(); | ||
139 | let mut all_mod_paths = imports_locator::find_similar_imports( | ||
140 | &ctx.sema, | ||
141 | ctx.krate?, | ||
142 | Some(40), | ||
143 | potential_import_name, | ||
144 | true, | ||
145 | true, | ||
146 | ) | ||
147 | .filter_map(|import_candidate| { | ||
148 | Some(match import_candidate { | ||
149 | Either::Left(module_def) => { | ||
150 | (current_module.find_use_path(ctx.db, module_def)?, ScopeDef::ModuleDef(module_def)) | ||
151 | } | ||
152 | Either::Right(macro_def) => { | ||
153 | (current_module.find_use_path(ctx.db, macro_def)?, ScopeDef::MacroDef(macro_def)) | ||
154 | } | ||
155 | }) | ||
156 | }) | ||
157 | .filter(|(mod_path, _)| mod_path.len() > 1) | ||
158 | .collect::<Vec<_>>(); | ||
159 | |||
160 | all_mod_paths.sort_by_cached_key(|(mod_path, _)| { | ||
161 | compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased) | ||
162 | }); | ||
163 | |||
164 | acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| { | ||
165 | render_resolution_with_import( | ||
166 | RenderContext::new(ctx), | ||
167 | ImportEdit { import_path, import_scope: import_scope.clone() }, | ||
168 | &definition, | ||
169 | ) | ||
170 | })); | ||
171 | Some(()) | ||
172 | } | ||
173 | |||
174 | fn compute_fuzzy_completion_order_key( | ||
175 | proposed_mod_path: &ModPath, | ||
176 | user_input_lowercased: &str, | ||
177 | ) -> usize { | ||
178 | mark::hit!(certain_fuzzy_order_test); | ||
179 | let proposed_import_name = match proposed_mod_path.segments.last() { | ||
180 | Some(name) => name.to_string().to_lowercase(), | ||
181 | None => return usize::MAX, | ||
182 | }; | ||
183 | match proposed_import_name.match_indices(user_input_lowercased).next() { | ||
184 | Some((first_matching_index, _)) => first_matching_index, | ||
185 | None => usize::MAX, | ||
186 | } | ||
187 | } | ||
188 | |||
189 | #[cfg(test)] | 70 | #[cfg(test)] |
190 | mod tests { | 71 | mod tests { |
191 | use expect_test::{expect, Expect}; | 72 | use expect_test::{expect, Expect}; |
192 | use test_utils::mark; | 73 | use test_utils::mark; |
193 | 74 | ||
194 | use crate::{ | 75 | use crate::{ |
195 | test_utils::{ | 76 | test_utils::{check_edit, completion_list_with_config, TEST_CONFIG}, |
196 | check_edit, check_edit_with_config, completion_list_with_config, TEST_CONFIG, | ||
197 | }, | ||
198 | CompletionConfig, CompletionKind, | 77 | CompletionConfig, CompletionKind, |
199 | }; | 78 | }; |
200 | 79 | ||
@@ -855,128 +734,4 @@ impl My$0 | |||
855 | "#]], | 734 | "#]], |
856 | ) | 735 | ) |
857 | } | 736 | } |
858 | |||
859 | #[test] | ||
860 | fn function_fuzzy_completion() { | ||
861 | check_edit_with_config( | ||
862 | TEST_CONFIG, | ||
863 | "stdin", | ||
864 | r#" | ||
865 | //- /lib.rs crate:dep | ||
866 | pub mod io { | ||
867 | pub fn stdin() {} | ||
868 | }; | ||
869 | |||
870 | //- /main.rs crate:main deps:dep | ||
871 | fn main() { | ||
872 | stdi$0 | ||
873 | } | ||
874 | "#, | ||
875 | r#" | ||
876 | use dep::io::stdin; | ||
877 | |||
878 | fn main() { | ||
879 | stdin()$0 | ||
880 | } | ||
881 | "#, | ||
882 | ); | ||
883 | } | ||
884 | |||
885 | #[test] | ||
886 | fn macro_fuzzy_completion() { | ||
887 | check_edit_with_config( | ||
888 | TEST_CONFIG, | ||
889 | "macro_with_curlies!", | ||
890 | r#" | ||
891 | //- /lib.rs crate:dep | ||
892 | /// Please call me as macro_with_curlies! {} | ||
893 | #[macro_export] | ||
894 | macro_rules! macro_with_curlies { | ||
895 | () => {} | ||
896 | } | ||
897 | |||
898 | //- /main.rs crate:main deps:dep | ||
899 | fn main() { | ||
900 | curli$0 | ||
901 | } | ||
902 | "#, | ||
903 | r#" | ||
904 | use dep::macro_with_curlies; | ||
905 | |||
906 | fn main() { | ||
907 | macro_with_curlies! {$0} | ||
908 | } | ||
909 | "#, | ||
910 | ); | ||
911 | } | ||
912 | |||
913 | #[test] | ||
914 | fn struct_fuzzy_completion() { | ||
915 | check_edit_with_config( | ||
916 | TEST_CONFIG, | ||
917 | "ThirdStruct", | ||
918 | r#" | ||
919 | //- /lib.rs crate:dep | ||
920 | pub struct FirstStruct; | ||
921 | pub mod some_module { | ||
922 | pub struct SecondStruct; | ||
923 | pub struct ThirdStruct; | ||
924 | } | ||
925 | |||
926 | //- /main.rs crate:main deps:dep | ||
927 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
928 | |||
929 | fn main() { | ||
930 | this$0 | ||
931 | } | ||
932 | "#, | ||
933 | r#" | ||
934 | use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}}; | ||
935 | |||
936 | fn main() { | ||
937 | ThirdStruct | ||
938 | } | ||
939 | "#, | ||
940 | ); | ||
941 | } | ||
942 | |||
943 | #[test] | ||
944 | fn fuzzy_completions_come_in_specific_order() { | ||
945 | mark::check!(certain_fuzzy_order_test); | ||
946 | check_with_config( | ||
947 | TEST_CONFIG, | ||
948 | r#" | ||
949 | //- /lib.rs crate:dep | ||
950 | pub struct FirstStruct; | ||
951 | pub mod some_module { | ||
952 | // already imported, omitted | ||
953 | pub struct SecondStruct; | ||
954 | // does not contain all letters from the query, omitted | ||
955 | pub struct UnrelatedOne; | ||
956 | // contains all letters from the query, but not in sequence, displayed last | ||
957 | pub struct ThiiiiiirdStruct; | ||
958 | // contains all letters from the query, but not in the beginning, displayed second | ||
959 | pub struct AfterThirdStruct; | ||
960 | // contains all letters from the query in the begginning, displayed first | ||
961 | pub struct ThirdStruct; | ||
962 | } | ||
963 | |||
964 | //- /main.rs crate:main deps:dep | ||
965 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
966 | |||
967 | fn main() { | ||
968 | hir$0 | ||
969 | } | ||
970 | "#, | ||
971 | expect![[r#" | ||
972 | fn main() fn main() | ||
973 | st SecondStruct | ||
974 | st FirstStruct | ||
975 | md dep | ||
976 | st dep::some_module::ThirdStruct | ||
977 | st dep::some_module::AfterThirdStruct | ||
978 | st dep::some_module::ThiiiiiirdStruct | ||
979 | "#]], | ||
980 | ); | ||
981 | } | ||
982 | } | 737 | } |
diff --git a/crates/completion/src/config.rs b/crates/completion/src/config.rs index b4439b7d1..58fc700f3 100644 --- a/crates/completion/src/config.rs +++ b/crates/completion/src/config.rs | |||
@@ -4,7 +4,7 @@ | |||
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 ide_db::helpers::{insert_use::MergeBehavior, SnippetCap}; | 7 | use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap}; |
8 | 8 | ||
9 | #[derive(Clone, Debug, PartialEq, Eq)] | 9 | #[derive(Clone, Debug, PartialEq, Eq)] |
10 | pub struct CompletionConfig { | 10 | pub struct CompletionConfig { |
@@ -13,5 +13,5 @@ pub struct CompletionConfig { | |||
13 | pub add_call_parenthesis: bool, | 13 | pub add_call_parenthesis: bool, |
14 | pub add_call_argument_snippets: bool, | 14 | pub add_call_argument_snippets: bool, |
15 | pub snippet_cap: Option<SnippetCap>, | 15 | pub snippet_cap: Option<SnippetCap>, |
16 | pub merge: Option<MergeBehavior>, | 16 | pub insert_use: InsertUseConfig, |
17 | } | 17 | } |
diff --git a/crates/completion/src/item.rs b/crates/completion/src/item.rs index 0134ff219..5d91d3a5c 100644 --- a/crates/completion/src/item.rs +++ b/crates/completion/src/item.rs | |||
@@ -398,7 +398,9 @@ impl Builder { | |||
398 | pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder { | 398 | pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder { |
399 | self.detail = detail.map(Into::into); | 399 | self.detail = detail.map(Into::into); |
400 | if let Some(detail) = &self.detail { | 400 | if let Some(detail) = &self.detail { |
401 | assert_never!(detail.contains('\n'), "multiline detail: {}", detail); | 401 | if assert_never!(detail.contains('\n'), "multiline detail: {}", detail) { |
402 | self.detail = Some(detail.splitn(2, '\n').next().unwrap().to_string()); | ||
403 | } | ||
402 | } | 404 | } |
403 | self | 405 | self |
404 | } | 406 | } |
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs index 6cba88a6b..ee1b822e7 100644 --- a/crates/completion/src/lib.rs +++ b/crates/completion/src/lib.rs | |||
@@ -127,6 +127,7 @@ pub fn completions( | |||
127 | completions::macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx); | 127 | completions::macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx); |
128 | completions::trait_impl::complete_trait_impl(&mut acc, &ctx); | 128 | completions::trait_impl::complete_trait_impl(&mut acc, &ctx); |
129 | completions::mod_::complete_mod(&mut acc, &ctx); | 129 | completions::mod_::complete_mod(&mut acc, &ctx); |
130 | completions::flyimport::import_on_the_fly(&mut acc, &ctx); | ||
130 | 131 | ||
131 | Some(acc) | 132 | Some(acc) |
132 | } | 133 | } |
@@ -153,7 +154,9 @@ pub fn resolve_completion_edits( | |||
153 | }) | 154 | }) |
154 | .find(|mod_path| mod_path.to_string() == full_import_path)?; | 155 | .find(|mod_path| mod_path.to_string() == full_import_path)?; |
155 | 156 | ||
156 | ImportEdit { import_path, import_scope }.to_text_edit(config.merge).map(|edit| vec![edit]) | 157 | ImportEdit { import_path, import_scope } |
158 | .to_text_edit(config.insert_use.merge) | ||
159 | .map(|edit| vec![edit]) | ||
157 | } | 160 | } |
158 | 161 | ||
159 | #[cfg(test)] | 162 | #[cfg(test)] |
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs index e93c59f71..820dd01d1 100644 --- a/crates/completion/src/render.rs +++ b/crates/completion/src/render.rs | |||
@@ -51,11 +51,16 @@ pub(crate) fn render_resolution_with_import<'a>( | |||
51 | import_edit: ImportEdit, | 51 | import_edit: ImportEdit, |
52 | resolution: &ScopeDef, | 52 | resolution: &ScopeDef, |
53 | ) -> Option<CompletionItem> { | 53 | ) -> Option<CompletionItem> { |
54 | Render::new(ctx).render_resolution( | 54 | Render::new(ctx) |
55 | import_edit.import_path.segments.last()?.to_string(), | 55 | .render_resolution( |
56 | Some(import_edit), | 56 | import_edit.import_path.segments.last()?.to_string(), |
57 | resolution, | 57 | Some(import_edit), |
58 | ) | 58 | resolution, |
59 | ) | ||
60 | .map(|mut item| { | ||
61 | item.completion_kind = CompletionKind::Magic; | ||
62 | item | ||
63 | }) | ||
59 | } | 64 | } |
60 | 65 | ||
61 | /// Interface for data and methods required for items rendering. | 66 | /// Interface for data and methods required for items rendering. |
diff --git a/crates/completion/src/test_utils.rs b/crates/completion/src/test_utils.rs index 3f4b9d4ac..6ea6da989 100644 --- a/crates/completion/src/test_utils.rs +++ b/crates/completion/src/test_utils.rs | |||
@@ -1,9 +1,12 @@ | |||
1 | //! Runs completion for testing purposes. | 1 | //! Runs completion for testing purposes. |
2 | 2 | ||
3 | use hir::Semantics; | 3 | use hir::{PrefixKind, Semantics}; |
4 | use ide_db::{ | 4 | use ide_db::{ |
5 | base_db::{fixture::ChangeFixture, FileLoader, FilePosition}, | 5 | base_db::{fixture::ChangeFixture, FileLoader, FilePosition}, |
6 | helpers::{insert_use::MergeBehavior, SnippetCap}, | 6 | helpers::{ |
7 | insert_use::{InsertUseConfig, MergeBehavior}, | ||
8 | SnippetCap, | ||
9 | }, | ||
7 | RootDatabase, | 10 | RootDatabase, |
8 | }; | 11 | }; |
9 | use itertools::Itertools; | 12 | use itertools::Itertools; |
@@ -19,7 +22,10 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { | |||
19 | add_call_parenthesis: true, | 22 | add_call_parenthesis: true, |
20 | add_call_argument_snippets: true, | 23 | add_call_argument_snippets: true, |
21 | snippet_cap: SnippetCap::new(true), | 24 | snippet_cap: SnippetCap::new(true), |
22 | merge: Some(MergeBehavior::Full), | 25 | insert_use: InsertUseConfig { |
26 | merge: Some(MergeBehavior::Full), | ||
27 | prefix_kind: PrefixKind::Plain, | ||
28 | }, | ||
23 | }; | 29 | }; |
24 | 30 | ||
25 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. | 31 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. |
@@ -110,7 +116,7 @@ pub(crate) fn check_edit_with_config( | |||
110 | 116 | ||
111 | let mut combined_edit = completion.text_edit().to_owned(); | 117 | let mut combined_edit = completion.text_edit().to_owned(); |
112 | if let Some(import_text_edit) = | 118 | if let Some(import_text_edit) = |
113 | completion.import_to_add().and_then(|edit| edit.to_text_edit(config.merge)) | 119 | completion.import_to_add().and_then(|edit| edit.to_text_edit(config.insert_use.merge)) |
114 | { | 120 | { |
115 | combined_edit.union(import_text_edit).expect( | 121 | combined_edit.union(import_text_edit).expect( |
116 | "Failed to apply completion resolve changes: change ranges overlap, but should not", | 122 | "Failed to apply completion resolve changes: change ranges overlap, but should not", |
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml index 5d21283f7..535221294 100644 --- a/crates/hir_def/Cargo.toml +++ b/crates/hir_def/Cargo.toml | |||
@@ -20,7 +20,7 @@ fst = { version = "0.4", default-features = false } | |||
20 | itertools = "0.10.0" | 20 | itertools = "0.10.0" |
21 | indexmap = "1.4.0" | 21 | indexmap = "1.4.0" |
22 | smallvec = "1.4.0" | 22 | smallvec = "1.4.0" |
23 | la-arena = "0.1.0" | 23 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
24 | 24 | ||
25 | stdx = { path = "../stdx", version = "0.0.0" } | 25 | stdx = { path = "../stdx", version = "0.0.0" } |
26 | base_db = { path = "../base_db", version = "0.0.0" } | 26 | base_db = { path = "../base_db", version = "0.0.0" } |
diff --git a/crates/hir_def/src/adt.rs b/crates/hir_def/src/adt.rs index 237c3d3f9..06f0b9b18 100644 --- a/crates/hir_def/src/adt.rs +++ b/crates/hir_def/src/adt.rs | |||
@@ -8,7 +8,7 @@ use hir_expand::{ | |||
8 | name::{AsName, Name}, | 8 | name::{AsName, Name}, |
9 | InFile, | 9 | InFile, |
10 | }; | 10 | }; |
11 | use la_arena::{map::ArenaMap, Arena}; | 11 | use la_arena::{Arena, ArenaMap}; |
12 | use syntax::ast::{self, NameOwner, VisibilityOwner}; | 12 | use syntax::ast::{self, NameOwner, VisibilityOwner}; |
13 | use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}; | 13 | use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}; |
14 | 14 | ||
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 5a86823c2..1b09ff816 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -7,7 +7,7 @@ use cfg::{CfgExpr, CfgOptions}; | |||
7 | use either::Either; | 7 | use either::Either; |
8 | use hir_expand::{hygiene::Hygiene, name::AsName, AstId, InFile}; | 8 | use hir_expand::{hygiene::Hygiene, name::AsName, AstId, InFile}; |
9 | use itertools::Itertools; | 9 | use itertools::Itertools; |
10 | use la_arena::map::ArenaMap; | 10 | use la_arena::ArenaMap; |
11 | use mbe::ast_to_token_tree; | 11 | use mbe::ast_to_token_tree; |
12 | use syntax::{ | 12 | use syntax::{ |
13 | ast::{self, AstNode, AttrsOwner}, | 13 | ast::{self, AstNode, AttrsOwner}, |
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index 43ee57277..344f0b6c0 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs | |||
@@ -16,7 +16,7 @@ use hir_expand::{ | |||
16 | ast_id_map::AstIdMap, diagnostics::DiagnosticSink, hygiene::Hygiene, AstId, ExpandResult, | 16 | ast_id_map::AstIdMap, diagnostics::DiagnosticSink, hygiene::Hygiene, AstId, ExpandResult, |
17 | HirFileId, InFile, MacroDefId, | 17 | HirFileId, InFile, MacroDefId, |
18 | }; | 18 | }; |
19 | use la_arena::{map::ArenaMap, Arena}; | 19 | use la_arena::{Arena, ArenaMap}; |
20 | use rustc_hash::FxHashMap; | 20 | use rustc_hash::FxHashMap; |
21 | use syntax::{ast, AstNode, AstPtr}; | 21 | use syntax::{ast, AstNode, AstPtr}; |
22 | use test_utils::mark; | 22 | use test_utils::mark; |
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs index 0506a7274..6ef9fe790 100644 --- a/crates/hir_def/src/db.rs +++ b/crates/hir_def/src/db.rs | |||
@@ -3,7 +3,7 @@ use std::sync::Arc; | |||
3 | 3 | ||
4 | use base_db::{salsa, CrateId, SourceDatabase, Upcast}; | 4 | use base_db::{salsa, CrateId, SourceDatabase, Upcast}; |
5 | use hir_expand::{db::AstDatabase, HirFileId}; | 5 | use hir_expand::{db::AstDatabase, HirFileId}; |
6 | use la_arena::map::ArenaMap; | 6 | use la_arena::ArenaMap; |
7 | use syntax::SmolStr; | 7 | use syntax::SmolStr; |
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs index a293df9f1..5be838f4a 100644 --- a/crates/hir_def/src/expr.rs +++ b/crates/hir_def/src/expr.rs | |||
@@ -13,7 +13,7 @@ | |||
13 | //! See also a neighboring `body` module. | 13 | //! See also a neighboring `body` module. |
14 | 14 | ||
15 | use hir_expand::name::Name; | 15 | use hir_expand::name::Name; |
16 | use la_arena::{Idx, RawId}; | 16 | use la_arena::{Idx, RawIdx}; |
17 | use syntax::ast::RangeOp; | 17 | use syntax::ast::RangeOp; |
18 | 18 | ||
19 | use crate::{ | 19 | use crate::{ |
@@ -24,7 +24,7 @@ use crate::{ | |||
24 | 24 | ||
25 | pub type ExprId = Idx<Expr>; | 25 | pub type ExprId = Idx<Expr>; |
26 | pub(crate) fn dummy_expr_id() -> ExprId { | 26 | pub(crate) fn dummy_expr_id() -> ExprId { |
27 | ExprId::from_raw(RawId::from(!0)) | 27 | ExprId::from_raw(RawIdx::from(!0)) |
28 | } | 28 | } |
29 | 29 | ||
30 | pub type PatId = Idx<Pat>; | 30 | pub type PatId = Idx<Pat>; |
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs index 75eab791a..3ace3be1f 100644 --- a/crates/hir_def/src/generics.rs +++ b/crates/hir_def/src/generics.rs | |||
@@ -10,7 +10,7 @@ use hir_expand::{ | |||
10 | name::{name, AsName, Name}, | 10 | name::{name, AsName, Name}, |
11 | InFile, | 11 | InFile, |
12 | }; | 12 | }; |
13 | use la_arena::{map::ArenaMap, Arena}; | 13 | use la_arena::{Arena, ArenaMap}; |
14 | use syntax::ast::{self, GenericParamsOwner, NameOwner, TypeBoundsOwner}; | 14 | use syntax::ast::{self, GenericParamsOwner, NameOwner, TypeBoundsOwner}; |
15 | 15 | ||
16 | use crate::{ | 16 | use crate::{ |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 91e42aa0d..9a433b61c 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -20,7 +20,7 @@ use hir_expand::{ | |||
20 | name::{name, AsName, Name}, | 20 | name::{name, AsName, Name}, |
21 | HirFileId, InFile, | 21 | HirFileId, InFile, |
22 | }; | 22 | }; |
23 | use la_arena::{Arena, Idx, RawId}; | 23 | use la_arena::{Arena, Idx, RawIdx}; |
24 | use rustc_hash::FxHashMap; | 24 | use rustc_hash::FxHashMap; |
25 | use smallvec::SmallVec; | 25 | use smallvec::SmallVec; |
26 | use syntax::{ast, match_ast}; | 26 | use syntax::{ast, match_ast}; |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 3b206ef85..5e71ca42c 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -683,12 +683,12 @@ impl Ctx { | |||
683 | } | 683 | } |
684 | 684 | ||
685 | fn next_field_idx(&self) -> Idx<Field> { | 685 | fn next_field_idx(&self) -> Idx<Field> { |
686 | Idx::from_raw(RawId::from( | 686 | Idx::from_raw(RawIdx::from( |
687 | self.tree.data.as_ref().map_or(0, |data| data.fields.len() as u32), | 687 | self.tree.data.as_ref().map_or(0, |data| data.fields.len() as u32), |
688 | )) | 688 | )) |
689 | } | 689 | } |
690 | fn next_variant_idx(&self) -> Idx<Variant> { | 690 | fn next_variant_idx(&self) -> Idx<Variant> { |
691 | Idx::from_raw(RawId::from( | 691 | Idx::from_raw(RawIdx::from( |
692 | self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32), | 692 | self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32), |
693 | )) | 693 | )) |
694 | } | 694 | } |
diff --git a/crates/hir_def/src/src.rs b/crates/hir_def/src/src.rs index eb29265d9..751d4c052 100644 --- a/crates/hir_def/src/src.rs +++ b/crates/hir_def/src/src.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! Utilities for mapping between hir IDs and the surface syntax. | 1 | //! Utilities for mapping between hir IDs and the surface syntax. |
2 | 2 | ||
3 | use hir_expand::InFile; | 3 | use hir_expand::InFile; |
4 | use la_arena::map::ArenaMap; | 4 | use la_arena::ArenaMap; |
5 | 5 | ||
6 | use crate::{db::DefDatabase, item_tree::ItemTreeNode, AssocItemLoc, ItemLoc}; | 6 | use crate::{db::DefDatabase, item_tree::ItemTreeNode, AssocItemLoc, ItemLoc}; |
7 | 7 | ||
diff --git a/crates/hir_def/src/trace.rs b/crates/hir_def/src/trace.rs index 0a9beae8e..6e6ceb8e4 100644 --- a/crates/hir_def/src/trace.rs +++ b/crates/hir_def/src/trace.rs | |||
@@ -9,7 +9,7 @@ | |||
9 | //! absolute offsets. The `Trace` structure (inspired, at least in name, by | 9 | //! absolute offsets. The `Trace` structure (inspired, at least in name, by |
10 | //! Kotlin's `BindingTrace`) allows use the same code to compute both | 10 | //! Kotlin's `BindingTrace`) allows use the same code to compute both |
11 | //! projections. | 11 | //! projections. |
12 | use la_arena::{map::ArenaMap, Arena, Idx, RawId}; | 12 | use la_arena::{Arena, ArenaMap, Idx, RawIdx}; |
13 | 13 | ||
14 | pub(crate) struct Trace<T, V> { | 14 | pub(crate) struct Trace<T, V> { |
15 | arena: Option<Arena<T>>, | 15 | arena: Option<Arena<T>>, |
@@ -30,7 +30,7 @@ impl<T, V> Trace<T, V> { | |||
30 | let id = if let Some(arena) = &mut self.arena { | 30 | let id = if let Some(arena) = &mut self.arena { |
31 | arena.alloc(data()) | 31 | arena.alloc(data()) |
32 | } else { | 32 | } else { |
33 | let id = Idx::<T>::from_raw(RawId::from(self.len)); | 33 | let id = Idx::<T>::from_raw(RawIdx::from(self.len)); |
34 | self.len += 1; | 34 | self.len += 1; |
35 | id | 35 | id |
36 | }; | 36 | }; |
diff --git a/crates/hir_expand/Cargo.toml b/crates/hir_expand/Cargo.toml index b535a3d4f..5271110d2 100644 --- a/crates/hir_expand/Cargo.toml +++ b/crates/hir_expand/Cargo.toml | |||
@@ -13,7 +13,7 @@ doctest = false | |||
13 | log = "0.4.8" | 13 | log = "0.4.8" |
14 | either = "1.5.3" | 14 | either = "1.5.3" |
15 | rustc-hash = "1.0.0" | 15 | rustc-hash = "1.0.0" |
16 | la-arena = "0.1.0" | 16 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
17 | 17 | ||
18 | base_db = { path = "../base_db", version = "0.0.0" } | 18 | base_db = { path = "../base_db", version = "0.0.0" } |
19 | syntax = { path = "../syntax", version = "0.0.0" } | 19 | syntax = { path = "../syntax", version = "0.0.0" } |
diff --git a/crates/hir_expand/src/ast_id_map.rs b/crates/hir_expand/src/ast_id_map.rs index f4f6e11fd..2401b0cc5 100644 --- a/crates/hir_expand/src/ast_id_map.rs +++ b/crates/hir_expand/src/ast_id_map.rs | |||
@@ -72,10 +72,12 @@ impl AstIdMap { | |||
72 | // get lower ids then children. That is, adding a new child does not | 72 | // get lower ids then children. That is, adding a new child does not |
73 | // change parent's id. This means that, say, adding a new function to a | 73 | // change parent's id. This means that, say, adding a new function to a |
74 | // trait does not change ids of top-level items, which helps caching. | 74 | // trait does not change ids of top-level items, which helps caching. |
75 | bfs(node, |it| { | 75 | bdfs(node, |it| match ast::Item::cast(it) { |
76 | if let Some(module_item) = ast::Item::cast(it) { | 76 | Some(module_item) => { |
77 | res.alloc(module_item.syntax()); | 77 | res.alloc(module_item.syntax()); |
78 | true | ||
78 | } | 79 | } |
80 | None => false, | ||
79 | }); | 81 | }); |
80 | res | 82 | res |
81 | } | 83 | } |
@@ -105,14 +107,30 @@ impl AstIdMap { | |||
105 | } | 107 | } |
106 | } | 108 | } |
107 | 109 | ||
108 | /// Walks the subtree in bfs order, calling `f` for each node. | 110 | /// Walks the subtree in bdfs order, calling `f` for each node. What is bdfs |
109 | fn bfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode)) { | 111 | /// order? It is a mix of breadth-first and depth first orders. Nodes for which |
112 | /// `f` returns true are visited breadth-first, all the other nodes are explored | ||
113 | /// depth-first. | ||
114 | /// | ||
115 | /// In other words, the size of the bfs queue is bound by the number of "true" | ||
116 | /// nodes. | ||
117 | fn bdfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode) -> bool) { | ||
110 | let mut curr_layer = vec![node.clone()]; | 118 | let mut curr_layer = vec![node.clone()]; |
111 | let mut next_layer = vec![]; | 119 | let mut next_layer = vec![]; |
112 | while !curr_layer.is_empty() { | 120 | while !curr_layer.is_empty() { |
113 | curr_layer.drain(..).for_each(|node| { | 121 | curr_layer.drain(..).for_each(|node| { |
114 | next_layer.extend(node.children()); | 122 | let mut preorder = node.preorder(); |
115 | f(node); | 123 | while let Some(event) = preorder.next() { |
124 | match event { | ||
125 | syntax::WalkEvent::Enter(node) => { | ||
126 | if f(node.clone()) { | ||
127 | next_layer.extend(node.children()); | ||
128 | preorder.skip_subtree(); | ||
129 | } | ||
130 | } | ||
131 | syntax::WalkEvent::Leave(_) => {} | ||
132 | } | ||
133 | } | ||
116 | }); | 134 | }); |
117 | std::mem::swap(&mut curr_layer, &mut next_layer); | 135 | std::mem::swap(&mut curr_layer, &mut next_layer); |
118 | } | 136 | } |
diff --git a/crates/hir_expand/src/proc_macro.rs b/crates/hir_expand/src/proc_macro.rs index 1923daca5..75e950816 100644 --- a/crates/hir_expand/src/proc_macro.rs +++ b/crates/hir_expand/src/proc_macro.rs | |||
@@ -135,7 +135,6 @@ mod tests { | |||
135 | let result = format!("{:#?}", remove_derive_attrs(&tt).unwrap()); | 135 | let result = format!("{:#?}", remove_derive_attrs(&tt).unwrap()); |
136 | 136 | ||
137 | assert_eq_text!( | 137 | assert_eq_text!( |
138 | &result, | ||
139 | r#" | 138 | r#" |
140 | SUBTREE $ | 139 | SUBTREE $ |
141 | PUNCH # [alone] 0 | 140 | PUNCH # [alone] 0 |
@@ -150,7 +149,8 @@ SUBTREE $ | |||
150 | PUNCH : [alone] 19 | 149 | PUNCH : [alone] 19 |
151 | IDENT u32 20 | 150 | IDENT u32 20 |
152 | "# | 151 | "# |
153 | .trim() | 152 | .trim(), |
153 | &result | ||
154 | ); | 154 | ); |
155 | } | 155 | } |
156 | } | 156 | } |
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index 436c1405b..98434b741 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -20,7 +20,7 @@ scoped-tls = "1" | |||
20 | chalk-solve = { version = "0.47", default-features = false } | 20 | chalk-solve = { version = "0.47", default-features = false } |
21 | chalk-ir = "0.47" | 21 | chalk-ir = "0.47" |
22 | chalk-recursive = "0.47" | 22 | chalk-recursive = "0.47" |
23 | la-arena = "0.1.0" | 23 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
24 | 24 | ||
25 | stdx = { path = "../stdx", version = "0.0.0" } | 25 | stdx = { path = "../stdx", version = "0.0.0" } |
26 | hir_def = { path = "../hir_def", version = "0.0.0" } | 26 | hir_def = { path = "../hir_def", version = "0.0.0" } |
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs index b0e2a3b7d..b3af82444 100644 --- a/crates/hir_ty/src/db.rs +++ b/crates/hir_ty/src/db.rs | |||
@@ -7,7 +7,7 @@ use hir_def::{ | |||
7 | db::DefDatabase, expr::ExprId, ConstParamId, DefWithBodyId, FunctionId, GenericDefId, ImplId, | 7 | db::DefDatabase, expr::ExprId, ConstParamId, DefWithBodyId, FunctionId, GenericDefId, ImplId, |
8 | LocalFieldId, TypeParamId, VariantId, | 8 | LocalFieldId, TypeParamId, VariantId, |
9 | }; | 9 | }; |
10 | use la_arena::map::ArenaMap; | 10 | use la_arena::ArenaMap; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | method_resolution::{InherentImpls, TraitImpls}, | 13 | method_resolution::{InherentImpls, TraitImpls}, |
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index 46a806b9a..d08867c70 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs | |||
@@ -30,7 +30,7 @@ use hir_def::{ | |||
30 | TypeAliasId, VariantId, | 30 | TypeAliasId, VariantId, |
31 | }; | 31 | }; |
32 | use hir_expand::{diagnostics::DiagnosticSink, name::name}; | 32 | use hir_expand::{diagnostics::DiagnosticSink, name::name}; |
33 | use la_arena::map::ArenaMap; | 33 | use la_arena::ArenaMap; |
34 | use rustc_hash::FxHashMap; | 34 | use rustc_hash::FxHashMap; |
35 | use stdx::impl_from; | 35 | use stdx::impl_from; |
36 | use syntax::SmolStr; | 36 | use syntax::SmolStr; |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index 68d16f89a..7a734c8b9 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -20,7 +20,7 @@ use hir_def::{ | |||
20 | TypeAliasId, TypeParamId, UnionId, VariantId, | 20 | TypeAliasId, TypeParamId, UnionId, VariantId, |
21 | }; | 21 | }; |
22 | use hir_expand::name::Name; | 22 | use hir_expand::name::Name; |
23 | use la_arena::map::ArenaMap; | 23 | use la_arena::ArenaMap; |
24 | use smallvec::SmallVec; | 24 | use smallvec::SmallVec; |
25 | use stdx::impl_from; | 25 | use stdx::impl_from; |
26 | use test_utils::mark; | 26 | use test_utils::mark; |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index afd552008..6c94c26b5 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -80,24 +80,21 @@ pub use crate::{ | |||
80 | HlRange, | 80 | HlRange, |
81 | }, | 81 | }, |
82 | }; | 82 | }; |
83 | pub use assists::{Assist, AssistConfig, AssistId, AssistKind, InsertUseConfig}; | 83 | pub use assists::{Assist, AssistConfig, AssistId, AssistKind}; |
84 | pub use completion::{ | 84 | pub use completion::{ |
85 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, | 85 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, |
86 | InsertTextFormat, | 86 | InsertTextFormat, |
87 | }; | 87 | }; |
88 | pub use hir::{Documentation, Semantics}; | 88 | pub use hir::{Documentation, Semantics}; |
89 | pub use ide_db::base_db::{ | ||
90 | Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot, | ||
91 | SourceRootId, | ||
92 | }; | ||
93 | pub use ide_db::{ | 89 | pub use ide_db::{ |
90 | base_db::{ | ||
91 | Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, | ||
92 | SourceRoot, SourceRootId, | ||
93 | }, | ||
94 | call_info::CallInfo, | 94 | call_info::CallInfo, |
95 | search::{FileReference, ReferenceAccess, ReferenceKind}, | ||
96 | }; | ||
97 | pub use ide_db::{ | ||
98 | label::Label, | 95 | label::Label, |
99 | line_index::{LineCol, LineIndex}, | 96 | line_index::{LineCol, LineIndex}, |
100 | search::SearchScope, | 97 | search::{FileReference, ReferenceAccess, ReferenceKind, SearchScope}, |
101 | source_change::{FileSystemEdit, SourceChange}, | 98 | source_change::{FileSystemEdit, SourceChange}, |
102 | symbol_index::Query, | 99 | symbol_index::Query, |
103 | RootDatabase, | 100 | RootDatabase, |
diff --git a/crates/ide/src/syntax_tree.rs b/crates/ide/src/syntax_tree.rs index 1d4bac7ad..4c63d3023 100644 --- a/crates/ide/src/syntax_tree.rs +++ b/crates/ide/src/syntax_tree.rs | |||
@@ -111,7 +111,6 @@ mod tests { | |||
111 | let syn = analysis.syntax_tree(file_id, None).unwrap(); | 111 | let syn = analysis.syntax_tree(file_id, None).unwrap(); |
112 | 112 | ||
113 | assert_eq_text!( | 113 | assert_eq_text!( |
114 | syn.trim(), | ||
115 | r#" | 114 | r#" |
116 | [email protected] | 115 | [email protected] |
117 | [email protected] | 116 | [email protected] |
@@ -127,7 +126,8 @@ [email protected] | |||
127 | [email protected] "{" | 126 | [email protected] "{" |
128 | [email protected] "}" | 127 | [email protected] "}" |
129 | "# | 128 | "# |
130 | .trim() | 129 | .trim(), |
130 | syn.trim() | ||
131 | ); | 131 | ); |
132 | 132 | ||
133 | let (analysis, file_id) = fixture::file( | 133 | let (analysis, file_id) = fixture::file( |
@@ -143,7 +143,6 @@ fn test() { | |||
143 | let syn = analysis.syntax_tree(file_id, None).unwrap(); | 143 | let syn = analysis.syntax_tree(file_id, None).unwrap(); |
144 | 144 | ||
145 | assert_eq_text!( | 145 | assert_eq_text!( |
146 | syn.trim(), | ||
147 | r#" | 146 | r#" |
148 | [email protected] | 147 | [email protected] |
149 | [email protected] | 148 | [email protected] |
@@ -176,7 +175,8 @@ [email protected] | |||
176 | [email protected] "\n" | 175 | [email protected] "\n" |
177 | [email protected] "}" | 176 | [email protected] "}" |
178 | "# | 177 | "# |
179 | .trim() | 178 | .trim(), |
179 | syn.trim() | ||
180 | ); | 180 | ); |
181 | } | 181 | } |
182 | 182 | ||
@@ -186,7 +186,6 @@ [email protected] | |||
186 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); | 186 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); |
187 | 187 | ||
188 | assert_eq_text!( | 188 | assert_eq_text!( |
189 | syn.trim(), | ||
190 | r#" | 189 | r#" |
191 | [email protected] | 190 | [email protected] |
192 | [email protected] "fn" | 191 | [email protected] "fn" |
@@ -201,7 +200,8 @@ [email protected] | |||
201 | [email protected] "{" | 200 | [email protected] "{" |
202 | [email protected] "}" | 201 | [email protected] "}" |
203 | "# | 202 | "# |
204 | .trim() | 203 | .trim(), |
204 | syn.trim() | ||
205 | ); | 205 | ); |
206 | 206 | ||
207 | let (analysis, range) = fixture::range( | 207 | let (analysis, range) = fixture::range( |
@@ -216,7 +216,6 @@ [email protected] | |||
216 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); | 216 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); |
217 | 217 | ||
218 | assert_eq_text!( | 218 | assert_eq_text!( |
219 | syn.trim(), | ||
220 | r#" | 219 | r#" |
221 | [email protected] | 220 | [email protected] |
222 | [email protected] | 221 | [email protected] |
@@ -234,7 +233,8 @@ [email protected] | |||
234 | [email protected] ")" | 233 | [email protected] ")" |
235 | [email protected] ";" | 234 | [email protected] ";" |
236 | "# | 235 | "# |
237 | .trim() | 236 | .trim(), |
237 | syn.trim() | ||
238 | ); | 238 | ); |
239 | } | 239 | } |
240 | 240 | ||
@@ -253,7 +253,6 @@ fn bar() { | |||
253 | ); | 253 | ); |
254 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); | 254 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); |
255 | assert_eq_text!( | 255 | assert_eq_text!( |
256 | syn.trim(), | ||
257 | r#" | 256 | r#" |
258 | [email protected] | 257 | [email protected] |
259 | [email protected] | 258 | [email protected] |
@@ -270,7 +269,8 @@ [email protected] | |||
270 | [email protected] "\n" | 269 | [email protected] "\n" |
271 | [email protected] "}" | 270 | [email protected] "}" |
272 | "# | 271 | "# |
273 | .trim() | 272 | .trim(), |
273 | syn.trim() | ||
274 | ); | 274 | ); |
275 | 275 | ||
276 | // With a raw string | 276 | // With a raw string |
@@ -287,7 +287,6 @@ fn bar() { | |||
287 | ); | 287 | ); |
288 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); | 288 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); |
289 | assert_eq_text!( | 289 | assert_eq_text!( |
290 | syn.trim(), | ||
291 | r#" | 290 | r#" |
292 | [email protected] | 291 | [email protected] |
293 | [email protected] | 292 | [email protected] |
@@ -304,7 +303,8 @@ [email protected] | |||
304 | [email protected] "\n" | 303 | [email protected] "\n" |
305 | [email protected] "}" | 304 | [email protected] "}" |
306 | "# | 305 | "# |
307 | .trim() | 306 | .trim(), |
307 | syn.trim() | ||
308 | ); | 308 | ); |
309 | 309 | ||
310 | // With a raw string | 310 | // With a raw string |
@@ -320,7 +320,6 @@ fn bar() { | |||
320 | ); | 320 | ); |
321 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); | 321 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); |
322 | assert_eq_text!( | 322 | assert_eq_text!( |
323 | syn.trim(), | ||
324 | r#" | 323 | r#" |
325 | [email protected] | 324 | [email protected] |
326 | [email protected] | 325 | [email protected] |
@@ -351,7 +350,8 @@ [email protected] | |||
351 | [email protected] "\n" | 350 | [email protected] "\n" |
352 | [email protected] "}" | 351 | [email protected] "}" |
353 | "# | 352 | "# |
354 | .trim() | 353 | .trim(), |
354 | syn.trim() | ||
355 | ); | 355 | ); |
356 | } | 356 | } |
357 | } | 357 | } |
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs index c6763ae36..0dcc4dd29 100644 --- a/crates/ide_db/src/helpers.rs +++ b/crates/ide_db/src/helpers.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | //! A module with ide helpers for high-level ide features. | 1 | //! A module with ide helpers for high-level ide features. |
2 | pub mod insert_use; | 2 | pub mod insert_use; |
3 | pub mod import_assets; | ||
3 | 4 | ||
4 | use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait}; | 5 | use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait}; |
5 | use syntax::ast::{self, make}; | 6 | use syntax::ast::{self, make}; |
diff --git a/crates/assists/src/utils/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs index 4ce82c1ba..edc3da318 100644 --- a/crates/assists/src/utils/import_assets.rs +++ b/crates/ide_db/src/helpers/import_assets.rs | |||
@@ -1,19 +1,17 @@ | |||
1 | //! Look up accessible paths for items. | 1 | //! Look up accessible paths for items. |
2 | use either::Either; | 2 | use either::Either; |
3 | use hir::{AsAssocItem, AssocItemContainer, ModuleDef, Semantics}; | 3 | use hir::{AsAssocItem, AssocItemContainer, ModuleDef, Semantics}; |
4 | use ide_db::{imports_locator, RootDatabase}; | ||
5 | use rustc_hash::FxHashSet; | 4 | use rustc_hash::FxHashSet; |
6 | use syntax::{ast, AstNode, SyntaxNode}; | 5 | use syntax::{ast, AstNode, SyntaxNode}; |
7 | 6 | ||
8 | use crate::assist_config::InsertUseConfig; | 7 | use crate::{imports_locator, RootDatabase}; |
8 | |||
9 | use super::insert_use::InsertUseConfig; | ||
9 | 10 | ||
10 | #[derive(Debug)] | 11 | #[derive(Debug)] |
11 | pub(crate) enum ImportCandidate { | 12 | pub enum ImportCandidate { |
12 | /// Simple name like 'HashMap' | 13 | // A path, qualified (`std::collections::HashMap`) or not (`HashMap`). |
13 | UnqualifiedName(PathImportCandidate), | 14 | Path(PathImportCandidate), |
14 | /// First part of the qualified name. | ||
15 | /// For 'std::collections::HashMap', that will be 'std'. | ||
16 | QualifierStart(PathImportCandidate), | ||
17 | /// A trait associated function (with no self parameter) or associated constant. | 15 | /// A trait associated function (with no self parameter) or associated constant. |
18 | /// For 'test_mod::TestEnum::test_function', `ty` is the `test_mod::TestEnum` expression type | 16 | /// For 'test_mod::TestEnum::test_function', `ty` is the `test_mod::TestEnum` expression type |
19 | /// and `name` is the `test_function` | 17 | /// and `name` is the `test_function` |
@@ -25,25 +23,26 @@ pub(crate) enum ImportCandidate { | |||
25 | } | 23 | } |
26 | 24 | ||
27 | #[derive(Debug)] | 25 | #[derive(Debug)] |
28 | pub(crate) struct TraitImportCandidate { | 26 | pub struct TraitImportCandidate { |
29 | pub(crate) ty: hir::Type, | 27 | pub ty: hir::Type, |
30 | pub(crate) name: ast::NameRef, | 28 | pub name: ast::NameRef, |
31 | } | 29 | } |
32 | 30 | ||
33 | #[derive(Debug)] | 31 | #[derive(Debug)] |
34 | pub(crate) struct PathImportCandidate { | 32 | pub struct PathImportCandidate { |
35 | pub(crate) name: ast::NameRef, | 33 | pub qualifier: Option<ast::Path>, |
34 | pub name: ast::NameRef, | ||
36 | } | 35 | } |
37 | 36 | ||
38 | #[derive(Debug)] | 37 | #[derive(Debug)] |
39 | pub(crate) struct ImportAssets { | 38 | pub struct ImportAssets { |
40 | import_candidate: ImportCandidate, | 39 | import_candidate: ImportCandidate, |
41 | module_with_name_to_import: hir::Module, | 40 | module_with_name_to_import: hir::Module, |
42 | syntax_under_caret: SyntaxNode, | 41 | syntax_under_caret: SyntaxNode, |
43 | } | 42 | } |
44 | 43 | ||
45 | impl ImportAssets { | 44 | impl ImportAssets { |
46 | pub(crate) fn for_method_call( | 45 | pub fn for_method_call( |
47 | method_call: ast::MethodCallExpr, | 46 | method_call: ast::MethodCallExpr, |
48 | sema: &Semantics<RootDatabase>, | 47 | sema: &Semantics<RootDatabase>, |
49 | ) -> Option<Self> { | 48 | ) -> Option<Self> { |
@@ -56,7 +55,7 @@ impl ImportAssets { | |||
56 | }) | 55 | }) |
57 | } | 56 | } |
58 | 57 | ||
59 | pub(crate) fn for_regular_path( | 58 | pub fn for_regular_path( |
60 | path_under_caret: ast::Path, | 59 | path_under_caret: ast::Path, |
61 | sema: &Semantics<RootDatabase>, | 60 | sema: &Semantics<RootDatabase>, |
62 | ) -> Option<Self> { | 61 | ) -> Option<Self> { |
@@ -73,24 +72,23 @@ impl ImportAssets { | |||
73 | }) | 72 | }) |
74 | } | 73 | } |
75 | 74 | ||
76 | pub(crate) fn syntax_under_caret(&self) -> &SyntaxNode { | 75 | pub fn syntax_under_caret(&self) -> &SyntaxNode { |
77 | &self.syntax_under_caret | 76 | &self.syntax_under_caret |
78 | } | 77 | } |
79 | 78 | ||
80 | pub(crate) fn import_candidate(&self) -> &ImportCandidate { | 79 | pub fn import_candidate(&self) -> &ImportCandidate { |
81 | &self.import_candidate | 80 | &self.import_candidate |
82 | } | 81 | } |
83 | 82 | ||
84 | fn get_search_query(&self) -> &str { | 83 | fn get_search_query(&self) -> &str { |
85 | match &self.import_candidate { | 84 | match &self.import_candidate { |
86 | ImportCandidate::UnqualifiedName(candidate) | 85 | ImportCandidate::Path(candidate) => candidate.name.text(), |
87 | | ImportCandidate::QualifierStart(candidate) => candidate.name.text(), | ||
88 | ImportCandidate::TraitAssocItem(candidate) | 86 | ImportCandidate::TraitAssocItem(candidate) |
89 | | ImportCandidate::TraitMethod(candidate) => candidate.name.text(), | 87 | | ImportCandidate::TraitMethod(candidate) => candidate.name.text(), |
90 | } | 88 | } |
91 | } | 89 | } |
92 | 90 | ||
93 | pub(crate) fn search_for_imports( | 91 | pub fn search_for_imports( |
94 | &self, | 92 | &self, |
95 | sema: &Semantics<RootDatabase>, | 93 | sema: &Semantics<RootDatabase>, |
96 | config: &InsertUseConfig, | 94 | config: &InsertUseConfig, |
@@ -101,7 +99,7 @@ impl ImportAssets { | |||
101 | 99 | ||
102 | /// This may return non-absolute paths if a part of the returned path is already imported into scope. | 100 | /// This may return non-absolute paths if a part of the returned path is already imported into scope. |
103 | #[allow(dead_code)] | 101 | #[allow(dead_code)] |
104 | pub(crate) fn search_for_relative_paths( | 102 | pub fn search_for_relative_paths( |
105 | &self, | 103 | &self, |
106 | sema: &Semantics<RootDatabase>, | 104 | sema: &Semantics<RootDatabase>, |
107 | ) -> Vec<(hir::ModPath, hir::ItemInNs)> { | 105 | ) -> Vec<(hir::ModPath, hir::ItemInNs)> { |
@@ -253,10 +251,14 @@ impl ImportCandidate { | |||
253 | _ => return None, | 251 | _ => return None, |
254 | } | 252 | } |
255 | } else { | 253 | } else { |
256 | ImportCandidate::QualifierStart(PathImportCandidate { name: qualifier_start }) | 254 | ImportCandidate::Path(PathImportCandidate { |
255 | qualifier: Some(qualifier), | ||
256 | name: qualifier_start, | ||
257 | }) | ||
257 | } | 258 | } |
258 | } else { | 259 | } else { |
259 | ImportCandidate::UnqualifiedName(PathImportCandidate { | 260 | ImportCandidate::Path(PathImportCandidate { |
261 | qualifier: None, | ||
260 | name: segment.syntax().descendants().find_map(ast::NameRef::cast)?, | 262 | name: segment.syntax().descendants().find_map(ast::NameRef::cast)?, |
261 | }) | 263 | }) |
262 | }; | 264 | }; |
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs index 0c180e9bc..877d4f1c7 100644 --- a/crates/ide_db/src/helpers/insert_use.rs +++ b/crates/ide_db/src/helpers/insert_use.rs | |||
@@ -15,6 +15,12 @@ use syntax::{ | |||
15 | }; | 15 | }; |
16 | use test_utils::mark; | 16 | use test_utils::mark; |
17 | 17 | ||
18 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
19 | pub struct InsertUseConfig { | ||
20 | pub merge: Option<MergeBehavior>, | ||
21 | pub prefix_kind: hir::PrefixKind, | ||
22 | } | ||
23 | |||
18 | #[derive(Debug, Clone)] | 24 | #[derive(Debug, Clone)] |
19 | pub enum ImportScope { | 25 | pub enum ImportScope { |
20 | File(ast::SourceFile), | 26 | File(ast::SourceFile), |
@@ -97,7 +103,7 @@ pub fn insert_use<'a>( | |||
97 | ) -> SyntaxRewriter<'a> { | 103 | ) -> SyntaxRewriter<'a> { |
98 | let _p = profile::span("insert_use"); | 104 | let _p = profile::span("insert_use"); |
99 | let mut rewriter = SyntaxRewriter::default(); | 105 | let mut rewriter = SyntaxRewriter::default(); |
100 | let use_item = make::use_(make::use_tree(path.clone(), None, None, false)); | 106 | let use_item = make::use_(None, make::use_tree(path.clone(), None, None, false)); |
101 | // merge into existing imports if possible | 107 | // merge into existing imports if possible |
102 | if let Some(mb) = merge { | 108 | if let Some(mb) = merge { |
103 | for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) { | 109 | for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) { |
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs index a603fe87f..4bbe66f1f 100644 --- a/crates/ide_db/src/helpers/insert_use/tests.rs +++ b/crates/ide_db/src/helpers/insert_use/tests.rs | |||
@@ -599,7 +599,7 @@ fn check( | |||
599 | 599 | ||
600 | let rewriter = insert_use(&file, path, mb); | 600 | let rewriter = insert_use(&file, path, mb); |
601 | let result = rewriter.rewrite(file.as_syntax_node()).to_string(); | 601 | let result = rewriter.rewrite(file.as_syntax_node()).to_string(); |
602 | assert_eq_text!(&result, ra_fixture_after); | 602 | assert_eq_text!(ra_fixture_after, &result); |
603 | } | 603 | } |
604 | 604 | ||
605 | fn check_full(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | 605 | fn check_full(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs index e9f23adf8..d111fba92 100644 --- a/crates/ide_db/src/imports_locator.rs +++ b/crates/ide_db/src/imports_locator.rs | |||
@@ -12,6 +12,8 @@ use crate::{ | |||
12 | use either::Either; | 12 | use either::Either; |
13 | use rustc_hash::FxHashSet; | 13 | use rustc_hash::FxHashSet; |
14 | 14 | ||
15 | const QUERY_SEARCH_LIMIT: usize = 40; | ||
16 | |||
15 | pub fn find_exact_imports<'a>( | 17 | pub fn find_exact_imports<'a>( |
16 | sema: &Semantics<'a, RootDatabase>, | 18 | sema: &Semantics<'a, RootDatabase>, |
17 | krate: Crate, | 19 | krate: Crate, |
@@ -24,11 +26,11 @@ pub fn find_exact_imports<'a>( | |||
24 | { | 26 | { |
25 | let mut local_query = symbol_index::Query::new(name_to_import.clone()); | 27 | let mut local_query = symbol_index::Query::new(name_to_import.clone()); |
26 | local_query.exact(); | 28 | local_query.exact(); |
27 | local_query.limit(40); | 29 | local_query.limit(QUERY_SEARCH_LIMIT); |
28 | local_query | 30 | local_query |
29 | }, | 31 | }, |
30 | import_map::Query::new(name_to_import) | 32 | import_map::Query::new(name_to_import) |
31 | .limit(40) | 33 | .limit(QUERY_SEARCH_LIMIT) |
32 | .name_only() | 34 | .name_only() |
33 | .search_mode(import_map::SearchMode::Equals) | 35 | .search_mode(import_map::SearchMode::Equals) |
34 | .case_sensitive(), | 36 | .case_sensitive(), |
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs index 9ff901e97..bd2977ebd 100644 --- a/crates/mbe/src/tests.rs +++ b/crates/mbe/src/tests.rs | |||
@@ -261,7 +261,6 @@ fn test_expr_order() { | |||
261 | 261 | ||
262 | let dump = format!("{:#?}", expanded); | 262 | let dump = format!("{:#?}", expanded); |
263 | assert_eq_text!( | 263 | assert_eq_text!( |
264 | dump.trim(), | ||
265 | r#"[email protected] | 264 | r#"[email protected] |
266 | [email protected] | 265 | [email protected] |
267 | [email protected] "fn" | 266 | [email protected] "fn" |
@@ -285,6 +284,7 @@ fn test_expr_order() { | |||
285 | [email protected] "2" | 284 | [email protected] "2" |
286 | [email protected] ";" | 285 | [email protected] ";" |
287 | [email protected] "}""#, | 286 | [email protected] "}""#, |
287 | dump.trim() | ||
288 | ); | 288 | ); |
289 | } | 289 | } |
290 | 290 | ||
@@ -989,7 +989,6 @@ fn test_tt_composite2() { | |||
989 | 989 | ||
990 | let res = format!("{:#?}", &node); | 990 | let res = format!("{:#?}", &node); |
991 | assert_eq_text!( | 991 | assert_eq_text!( |
992 | res.trim(), | ||
993 | r###"[email protected] | 992 | r###"[email protected] |
994 | [email protected] | 993 | [email protected] |
995 | [email protected] | 994 | [email protected] |
@@ -1003,7 +1002,8 @@ fn test_tt_composite2() { | |||
1003 | [email protected] ">" | 1002 | [email protected] ">" |
1004 | [email protected] " " | 1003 | [email protected] " " |
1005 | [email protected] "#" | 1004 | [email protected] "#" |
1006 | [email protected] ")""### | 1005 | [email protected] ")""###, |
1006 | res.trim() | ||
1007 | ); | 1007 | ); |
1008 | } | 1008 | } |
1009 | 1009 | ||
@@ -1742,7 +1742,7 @@ impl MacroFixture { | |||
1742 | fn assert_expand(&self, invocation: &str, expected: &str) { | 1742 | fn assert_expand(&self, invocation: &str, expected: &str) { |
1743 | let expansion = self.expand_tt(invocation); | 1743 | let expansion = self.expand_tt(invocation); |
1744 | let actual = format!("{:?}", expansion); | 1744 | let actual = format!("{:?}", expansion); |
1745 | test_utils::assert_eq_text!(&actual.trim(), &expected.trim()); | 1745 | test_utils::assert_eq_text!(&expected.trim(), &actual.trim()); |
1746 | } | 1746 | } |
1747 | 1747 | ||
1748 | fn assert_expand_items(&self, invocation: &str, expected: &str) -> &MacroFixture { | 1748 | fn assert_expand_items(&self, invocation: &str, expected: &str) -> &MacroFixture { |
@@ -1941,7 +1941,6 @@ fn test_no_space_after_semi_colon() { | |||
1941 | 1941 | ||
1942 | let dump = format!("{:#?}", expanded); | 1942 | let dump = format!("{:#?}", expanded); |
1943 | assert_eq_text!( | 1943 | assert_eq_text!( |
1944 | dump.trim(), | ||
1945 | r###"[email protected] | 1944 | r###"[email protected] |
1946 | [email protected] | 1945 | [email protected] |
1947 | [email protected] | 1946 | [email protected] |
@@ -1981,6 +1980,7 @@ fn test_no_space_after_semi_colon() { | |||
1981 | [email protected] | 1980 | [email protected] |
1982 | [email protected] "f" | 1981 | [email protected] "f" |
1983 | [email protected] ";""###, | 1982 | [email protected] ";""###, |
1983 | dump.trim() | ||
1984 | ); | 1984 | ); |
1985 | } | 1985 | } |
1986 | 1986 | ||
diff --git a/crates/parser/src/syntax_kind.rs b/crates/parser/src/syntax_kind.rs index 63204436c..9ea0e4f9b 100644 --- a/crates/parser/src/syntax_kind.rs +++ b/crates/parser/src/syntax_kind.rs | |||
@@ -6,6 +6,7 @@ mod generated; | |||
6 | pub use self::generated::SyntaxKind; | 6 | pub use self::generated::SyntaxKind; |
7 | 7 | ||
8 | impl From<u16> for SyntaxKind { | 8 | impl From<u16> for SyntaxKind { |
9 | #[inline] | ||
9 | fn from(d: u16) -> SyntaxKind { | 10 | fn from(d: u16) -> SyntaxKind { |
10 | assert!(d <= (SyntaxKind::__LAST as u16)); | 11 | assert!(d <= (SyntaxKind::__LAST as u16)); |
11 | unsafe { std::mem::transmute::<u16, SyntaxKind>(d) } | 12 | unsafe { std::mem::transmute::<u16, SyntaxKind>(d) } |
@@ -13,12 +14,14 @@ impl From<u16> for SyntaxKind { | |||
13 | } | 14 | } |
14 | 15 | ||
15 | impl From<SyntaxKind> for u16 { | 16 | impl From<SyntaxKind> for u16 { |
17 | #[inline] | ||
16 | fn from(k: SyntaxKind) -> u16 { | 18 | fn from(k: SyntaxKind) -> u16 { |
17 | k as u16 | 19 | k as u16 |
18 | } | 20 | } |
19 | } | 21 | } |
20 | 22 | ||
21 | impl SyntaxKind { | 23 | impl SyntaxKind { |
24 | #[inline] | ||
22 | pub fn is_trivia(self) -> bool { | 25 | pub fn is_trivia(self) -> bool { |
23 | matches!(self, SyntaxKind::WHITESPACE | SyntaxKind::COMMENT) | 26 | matches!(self, SyntaxKind::WHITESPACE | SyntaxKind::COMMENT) |
24 | } | 27 | } |
diff --git a/crates/proc_macro_api/Cargo.toml b/crates/proc_macro_api/Cargo.toml index 1af2bbca7..078568cb2 100644 --- a/crates/proc_macro_api/Cargo.toml +++ b/crates/proc_macro_api/Cargo.toml | |||
@@ -11,7 +11,7 @@ doctest = false | |||
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | serde = { version = "1.0", features = ["derive"] } | 13 | serde = { version = "1.0", features = ["derive"] } |
14 | serde_json = "1.0" | 14 | serde_json = { version = "1.0", features = ["unbounded_depth"] } |
15 | log = "0.4.8" | 15 | log = "0.4.8" |
16 | crossbeam-channel = "0.5.0" | 16 | crossbeam-channel = "0.5.0" |
17 | jod-thread = "0.1.1" | 17 | jod-thread = "0.1.1" |
diff --git a/crates/proc_macro_srv/src/tests/mod.rs b/crates/proc_macro_srv/src/tests/mod.rs index 1a827cbd7..fd54f8dfd 100644 --- a/crates/proc_macro_srv/src/tests/mod.rs +++ b/crates/proc_macro_srv/src/tests/mod.rs | |||
@@ -38,9 +38,9 @@ fn test_derive_proc_macro_list() { | |||
38 | let res = list("serde_derive", "1").join("\n"); | 38 | let res = list("serde_derive", "1").join("\n"); |
39 | 39 | ||
40 | assert_eq_text!( | 40 | assert_eq_text!( |
41 | &res, | ||
42 | r#"Serialize [CustomDerive] | 41 | r#"Serialize [CustomDerive] |
43 | Deserialize [CustomDerive]"# | 42 | Deserialize [CustomDerive]"#, |
43 | &res | ||
44 | ); | 44 | ); |
45 | } | 45 | } |
46 | 46 | ||
@@ -50,9 +50,9 @@ fn list_test_macros() { | |||
50 | let res = list("proc_macro_test", "0.0.0").join("\n"); | 50 | let res = list("proc_macro_test", "0.0.0").join("\n"); |
51 | 51 | ||
52 | assert_eq_text!( | 52 | assert_eq_text!( |
53 | &res, | ||
54 | r#"function_like_macro [FuncLike] | 53 | r#"function_like_macro [FuncLike] |
55 | attribute_macro [Attr] | 54 | attribute_macro [Attr] |
56 | DummyTrait [CustomDerive]"# | 55 | DummyTrait [CustomDerive]"#, |
56 | &res | ||
57 | ); | 57 | ); |
58 | } | 58 | } |
diff --git a/crates/proc_macro_srv/src/tests/utils.rs b/crates/proc_macro_srv/src/tests/utils.rs index 36942147d..196abb8fc 100644 --- a/crates/proc_macro_srv/src/tests/utils.rs +++ b/crates/proc_macro_srv/src/tests/utils.rs | |||
@@ -52,7 +52,7 @@ pub fn assert_expand( | |||
52 | let fixture = parse_string(ra_fixture).unwrap(); | 52 | let fixture = parse_string(ra_fixture).unwrap(); |
53 | 53 | ||
54 | let res = expander.expand(macro_name, &fixture.subtree, None).unwrap(); | 54 | let res = expander.expand(macro_name, &fixture.subtree, None).unwrap(); |
55 | assert_eq_text!(&format!("{:?}", res), &expect.trim()); | 55 | assert_eq_text!(&expect.trim(), &format!("{:?}", res)); |
56 | } | 56 | } |
57 | 57 | ||
58 | pub fn list(crate_name: &str, version: &str) -> Vec<String> { | 58 | pub fn list(crate_name: &str, version: &str) -> Vec<String> { |
diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml index 096233a09..9c7ce26be 100644 --- a/crates/profile/Cargo.toml +++ b/crates/profile/Cargo.toml | |||
@@ -13,7 +13,7 @@ doctest = false | |||
13 | once_cell = "1.3.1" | 13 | once_cell = "1.3.1" |
14 | cfg-if = "1" | 14 | cfg-if = "1" |
15 | libc = "0.2.73" | 15 | libc = "0.2.73" |
16 | la-arena = "0.1.0" | 16 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
17 | 17 | ||
18 | [target.'cfg(target_os = "linux")'.dependencies] | 18 | [target.'cfg(target_os = "linux")'.dependencies] |
19 | perf-event = "0.4" | 19 | perf-event = "0.4" |
diff --git a/crates/project_model/Cargo.toml b/crates/project_model/Cargo.toml index 51e7a7070..293cb5bfe 100644 --- a/crates/project_model/Cargo.toml +++ b/crates/project_model/Cargo.toml | |||
@@ -17,7 +17,7 @@ serde = { version = "1.0.106", features = ["derive"] } | |||
17 | serde_json = "1.0.48" | 17 | serde_json = "1.0.48" |
18 | anyhow = "1.0.26" | 18 | anyhow = "1.0.26" |
19 | itertools = "0.10.0" | 19 | itertools = "0.10.0" |
20 | la-arena = "0.1.0" | 20 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
21 | 21 | ||
22 | cfg = { path = "../cfg", version = "0.0.0" } | 22 | cfg = { path = "../cfg", version = "0.0.0" } |
23 | base_db = { path = "../base_db", version = "0.0.0" } | 23 | base_db = { path = "../base_db", version = "0.0.0" } |
@@ -25,3 +25,4 @@ toolchain = { path = "../toolchain", version = "0.0.0" } | |||
25 | proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" } | 25 | proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" } |
26 | paths = { path = "../paths", version = "0.0.0" } | 26 | paths = { path = "../paths", version = "0.0.0" } |
27 | stdx = { path = "../stdx", version = "0.0.0" } | 27 | stdx = { path = "../stdx", version = "0.0.0" } |
28 | profile = { path = "../profile", version = "0.0.0" } | ||
diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs index aabb7a47d..970a7e140 100644 --- a/crates/project_model/src/lib.rs +++ b/crates/project_model/src/lib.rs | |||
@@ -5,6 +5,7 @@ mod cfg_flag; | |||
5 | mod project_json; | 5 | mod project_json; |
6 | mod sysroot; | 6 | mod sysroot; |
7 | mod workspace; | 7 | mod workspace; |
8 | mod rustc_cfg; | ||
8 | 9 | ||
9 | use std::{ | 10 | use std::{ |
10 | fs::{read_dir, ReadDir}, | 11 | fs::{read_dir, ReadDir}, |
diff --git a/crates/project_model/src/rustc_cfg.rs b/crates/project_model/src/rustc_cfg.rs new file mode 100644 index 000000000..4a7bd8ae3 --- /dev/null +++ b/crates/project_model/src/rustc_cfg.rs | |||
@@ -0,0 +1,34 @@ | |||
1 | //! Runs `rustc --print cfg` to get built-in cfg flags. | ||
2 | |||
3 | use std::process::Command; | ||
4 | |||
5 | use crate::{cfg_flag::CfgFlag, utf8_stdout}; | ||
6 | |||
7 | pub(crate) fn get(target: Option<&str>) -> Vec<CfgFlag> { | ||
8 | let _p = profile::span("rustc_cfg::get"); | ||
9 | let mut res = Vec::new(); | ||
10 | |||
11 | // Some nightly-only cfgs, which are required for stdlib | ||
12 | res.push(CfgFlag::Atom("target_thread_local".into())); | ||
13 | for &ty in ["8", "16", "32", "64", "cas", "ptr"].iter() { | ||
14 | for &key in ["target_has_atomic", "target_has_atomic_load_store"].iter() { | ||
15 | res.push(CfgFlag::KeyValue { key: key.to_string(), value: ty.into() }); | ||
16 | } | ||
17 | } | ||
18 | |||
19 | let rustc_cfgs = { | ||
20 | let mut cmd = Command::new(toolchain::rustc()); | ||
21 | cmd.args(&["--print", "cfg", "-O"]); | ||
22 | if let Some(target) = target { | ||
23 | cmd.args(&["--target", target]); | ||
24 | } | ||
25 | utf8_stdout(cmd) | ||
26 | }; | ||
27 | |||
28 | match rustc_cfgs { | ||
29 | Ok(rustc_cfgs) => res.extend(rustc_cfgs.lines().map(|it| it.parse().unwrap())), | ||
30 | Err(e) => log::error!("failed to get rustc cfgs: {:#}", e), | ||
31 | } | ||
32 | |||
33 | res | ||
34 | } | ||
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs index 06a0be284..8e0481ae9 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs | |||
@@ -16,7 +16,7 @@ use proc_macro_api::ProcMacroClient; | |||
16 | use rustc_hash::{FxHashMap, FxHashSet}; | 16 | use rustc_hash::{FxHashMap, FxHashSet}; |
17 | 17 | ||
18 | use crate::{ | 18 | use crate::{ |
19 | cargo_workspace, cfg_flag::CfgFlag, sysroot::SysrootCrate, utf8_stdout, CargoConfig, | 19 | cargo_workspace, cfg_flag::CfgFlag, rustc_cfg, sysroot::SysrootCrate, utf8_stdout, CargoConfig, |
20 | CargoWorkspace, ProjectJson, ProjectManifest, Sysroot, TargetKind, | 20 | CargoWorkspace, ProjectJson, ProjectManifest, Sysroot, TargetKind, |
21 | }; | 21 | }; |
22 | 22 | ||
@@ -34,15 +34,25 @@ pub struct PackageRoot { | |||
34 | #[derive(Clone, Eq, PartialEq)] | 34 | #[derive(Clone, Eq, PartialEq)] |
35 | pub enum ProjectWorkspace { | 35 | pub enum ProjectWorkspace { |
36 | /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. | 36 | /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. |
37 | Cargo { cargo: CargoWorkspace, sysroot: Sysroot, rustc: Option<CargoWorkspace> }, | 37 | Cargo { |
38 | cargo: CargoWorkspace, | ||
39 | sysroot: Sysroot, | ||
40 | rustc: Option<CargoWorkspace>, | ||
41 | /// Holds cfg flags for the current target. We get those by running | ||
42 | /// `rustc --print cfg`. | ||
43 | /// | ||
44 | /// FIXME: make this a per-crate map, as, eg, build.rs might have a | ||
45 | /// different target. | ||
46 | rustc_cfg: Vec<CfgFlag>, | ||
47 | }, | ||
38 | /// Project workspace was manually specified using a `rust-project.json` file. | 48 | /// Project workspace was manually specified using a `rust-project.json` file. |
39 | Json { project: ProjectJson, sysroot: Option<Sysroot> }, | 49 | Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> }, |
40 | } | 50 | } |
41 | 51 | ||
42 | impl fmt::Debug for ProjectWorkspace { | 52 | impl fmt::Debug for ProjectWorkspace { |
43 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 53 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
44 | match self { | 54 | match self { |
45 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } => f | 55 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => f |
46 | .debug_struct("Cargo") | 56 | .debug_struct("Cargo") |
47 | .field("n_packages", &cargo.packages().len()) | 57 | .field("n_packages", &cargo.packages().len()) |
48 | .field("n_sysroot_crates", &sysroot.crates().len()) | 58 | .field("n_sysroot_crates", &sysroot.crates().len()) |
@@ -50,13 +60,15 @@ impl fmt::Debug for ProjectWorkspace { | |||
50 | "n_rustc_compiler_crates", | 60 | "n_rustc_compiler_crates", |
51 | &rustc.as_ref().map_or(0, |rc| rc.packages().len()), | 61 | &rustc.as_ref().map_or(0, |rc| rc.packages().len()), |
52 | ) | 62 | ) |
63 | .field("rustc_cfg", rustc_cfg) | ||
53 | .finish(), | 64 | .finish(), |
54 | ProjectWorkspace::Json { project, sysroot } => { | 65 | ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { |
55 | let mut debug_struct = f.debug_struct("Json"); | 66 | let mut debug_struct = f.debug_struct("Json"); |
56 | debug_struct.field("n_crates", &project.n_crates()); | 67 | debug_struct.field("n_crates", &project.n_crates()); |
57 | if let Some(sysroot) = sysroot { | 68 | if let Some(sysroot) = sysroot { |
58 | debug_struct.field("n_sysroot_crates", &sysroot.crates().len()); | 69 | debug_struct.field("n_sysroot_crates", &sysroot.crates().len()); |
59 | } | 70 | } |
71 | debug_struct.field("rustc_cfg", rustc_cfg); | ||
60 | debug_struct.finish() | 72 | debug_struct.finish() |
61 | } | 73 | } |
62 | } | 74 | } |
@@ -79,7 +91,7 @@ impl ProjectWorkspace { | |||
79 | })?; | 91 | })?; |
80 | let project_location = project_json.parent().unwrap().to_path_buf(); | 92 | let project_location = project_json.parent().unwrap().to_path_buf(); |
81 | let project_json = ProjectJson::new(&project_location, data); | 93 | let project_json = ProjectJson::new(&project_location, data); |
82 | ProjectWorkspace::load_inline(project_json)? | 94 | ProjectWorkspace::load_inline(project_json, config.target.as_deref())? |
83 | } | 95 | } |
84 | ProjectManifest::CargoToml(cargo_toml) => { | 96 | ProjectManifest::CargoToml(cargo_toml) => { |
85 | let cargo_version = utf8_stdout({ | 97 | let cargo_version = utf8_stdout({ |
@@ -117,21 +129,24 @@ impl ProjectWorkspace { | |||
117 | } else { | 129 | } else { |
118 | None | 130 | None |
119 | }; | 131 | }; |
120 | 132 | let rustc_cfg = rustc_cfg::get(config.target.as_deref()); | |
121 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } | 133 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } |
122 | } | 134 | } |
123 | }; | 135 | }; |
124 | 136 | ||
125 | Ok(res) | 137 | Ok(res) |
126 | } | 138 | } |
127 | 139 | ||
128 | pub fn load_inline(project_json: ProjectJson) -> Result<ProjectWorkspace> { | 140 | pub fn load_inline( |
141 | project_json: ProjectJson, | ||
142 | target: Option<&str>, | ||
143 | ) -> Result<ProjectWorkspace> { | ||
129 | let sysroot = match &project_json.sysroot_src { | 144 | let sysroot = match &project_json.sysroot_src { |
130 | Some(path) => Some(Sysroot::load(path)?), | 145 | Some(path) => Some(Sysroot::load(path)?), |
131 | None => None, | 146 | None => None, |
132 | }; | 147 | }; |
133 | 148 | let rustc_cfg = rustc_cfg::get(target); | |
134 | Ok(ProjectWorkspace::Json { project: project_json, sysroot }) | 149 | Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }) |
135 | } | 150 | } |
136 | 151 | ||
137 | /// Returns the roots for the current `ProjectWorkspace` | 152 | /// Returns the roots for the current `ProjectWorkspace` |
@@ -139,7 +154,7 @@ impl ProjectWorkspace { | |||
139 | /// the root is a member of the current workspace | 154 | /// the root is a member of the current workspace |
140 | pub fn to_roots(&self) -> Vec<PackageRoot> { | 155 | pub fn to_roots(&self) -> Vec<PackageRoot> { |
141 | match self { | 156 | match self { |
142 | ProjectWorkspace::Json { project, sysroot } => project | 157 | ProjectWorkspace::Json { project, sysroot, rustc_cfg: _ } => project |
143 | .crates() | 158 | .crates() |
144 | .map(|(_, krate)| PackageRoot { | 159 | .map(|(_, krate)| PackageRoot { |
145 | is_member: krate.is_workspace_member, | 160 | is_member: krate.is_workspace_member, |
@@ -156,7 +171,7 @@ impl ProjectWorkspace { | |||
156 | }) | 171 | }) |
157 | })) | 172 | })) |
158 | .collect::<Vec<_>>(), | 173 | .collect::<Vec<_>>(), |
159 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } => cargo | 174 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _ } => cargo |
160 | .packages() | 175 | .packages() |
161 | .map(|pkg| { | 176 | .map(|pkg| { |
162 | let is_member = cargo[pkg].is_member; | 177 | let is_member = cargo[pkg].is_member; |
@@ -194,7 +209,7 @@ impl ProjectWorkspace { | |||
194 | pub fn n_packages(&self) -> usize { | 209 | pub fn n_packages(&self) -> usize { |
195 | match self { | 210 | match self { |
196 | ProjectWorkspace::Json { project, .. } => project.n_crates(), | 211 | ProjectWorkspace::Json { project, .. } => project.n_crates(), |
197 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } => { | 212 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => { |
198 | let rustc_package_len = rustc.as_ref().map_or(0, |rc| rc.packages().len()); | 213 | let rustc_package_len = rustc.as_ref().map_or(0, |rc| rc.packages().len()); |
199 | cargo.packages().len() + sysroot.crates().len() + rustc_package_len | 214 | cargo.packages().len() + sysroot.crates().len() + rustc_package_len |
200 | } | 215 | } |
@@ -203,22 +218,31 @@ impl ProjectWorkspace { | |||
203 | 218 | ||
204 | pub fn to_crate_graph( | 219 | pub fn to_crate_graph( |
205 | &self, | 220 | &self, |
206 | target: Option<&str>, | ||
207 | proc_macro_client: Option<&ProcMacroClient>, | 221 | proc_macro_client: Option<&ProcMacroClient>, |
208 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 222 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
209 | ) -> CrateGraph { | 223 | ) -> CrateGraph { |
224 | let _p = profile::span("ProjectWorkspace::to_crate_graph"); | ||
210 | let proc_macro_loader = |path: &Path| match proc_macro_client { | 225 | let proc_macro_loader = |path: &Path| match proc_macro_client { |
211 | Some(client) => client.by_dylib_path(path), | 226 | Some(client) => client.by_dylib_path(path), |
212 | None => Vec::new(), | 227 | None => Vec::new(), |
213 | }; | 228 | }; |
214 | 229 | ||
215 | let mut crate_graph = match self { | 230 | let mut crate_graph = match self { |
216 | ProjectWorkspace::Json { project, sysroot } => { | 231 | ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph( |
217 | project_json_to_crate_graph(target, &proc_macro_loader, load, project, sysroot) | 232 | rustc_cfg.clone(), |
218 | } | 233 | &proc_macro_loader, |
219 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } => { | 234 | load, |
220 | cargo_to_crate_graph(target, &proc_macro_loader, load, cargo, sysroot, rustc) | 235 | project, |
221 | } | 236 | sysroot, |
237 | ), | ||
238 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => cargo_to_crate_graph( | ||
239 | rustc_cfg.clone(), | ||
240 | &proc_macro_loader, | ||
241 | load, | ||
242 | cargo, | ||
243 | sysroot, | ||
244 | rustc, | ||
245 | ), | ||
222 | }; | 246 | }; |
223 | if crate_graph.patch_cfg_if() { | 247 | if crate_graph.patch_cfg_if() { |
224 | log::debug!("Patched std to depend on cfg-if") | 248 | log::debug!("Patched std to depend on cfg-if") |
@@ -230,7 +254,7 @@ impl ProjectWorkspace { | |||
230 | } | 254 | } |
231 | 255 | ||
232 | fn project_json_to_crate_graph( | 256 | fn project_json_to_crate_graph( |
233 | target: Option<&str>, | 257 | rustc_cfg: Vec<CfgFlag>, |
234 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, | 258 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, |
235 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 259 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
236 | project: &ProjectJson, | 260 | project: &ProjectJson, |
@@ -239,9 +263,9 @@ fn project_json_to_crate_graph( | |||
239 | let mut crate_graph = CrateGraph::default(); | 263 | let mut crate_graph = CrateGraph::default(); |
240 | let sysroot_deps = sysroot | 264 | let sysroot_deps = sysroot |
241 | .as_ref() | 265 | .as_ref() |
242 | .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load)); | 266 | .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load)); |
243 | 267 | ||
244 | let mut cfg_cache: FxHashMap<Option<&str>, Vec<CfgFlag>> = FxHashMap::default(); | 268 | let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default(); |
245 | let crates: FxHashMap<CrateId, CrateId> = project | 269 | let crates: FxHashMap<CrateId, CrateId> = project |
246 | .crates() | 270 | .crates() |
247 | .filter_map(|(crate_id, krate)| { | 271 | .filter_map(|(crate_id, krate)| { |
@@ -253,9 +277,12 @@ fn project_json_to_crate_graph( | |||
253 | let env = krate.env.clone().into_iter().collect(); | 277 | let env = krate.env.clone().into_iter().collect(); |
254 | let proc_macro = krate.proc_macro_dylib_path.clone().map(|it| proc_macro_loader(&it)); | 278 | let proc_macro = krate.proc_macro_dylib_path.clone().map(|it| proc_macro_loader(&it)); |
255 | 279 | ||
256 | let target = krate.target.as_deref().or(target); | 280 | let target_cfgs = match krate.target.as_deref() { |
257 | let target_cfgs = | 281 | Some(target) => { |
258 | cfg_cache.entry(target).or_insert_with(|| get_rustc_cfg_options(target)); | 282 | cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(Some(target))) |
283 | } | ||
284 | None => &rustc_cfg, | ||
285 | }; | ||
259 | 286 | ||
260 | let mut cfg_options = CfgOptions::default(); | 287 | let mut cfg_options = CfgOptions::default(); |
261 | cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned()); | 288 | cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned()); |
@@ -292,19 +319,20 @@ fn project_json_to_crate_graph( | |||
292 | } | 319 | } |
293 | 320 | ||
294 | fn cargo_to_crate_graph( | 321 | fn cargo_to_crate_graph( |
295 | target: Option<&str>, | 322 | rustc_cfg: Vec<CfgFlag>, |
296 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, | 323 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, |
297 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 324 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
298 | cargo: &CargoWorkspace, | 325 | cargo: &CargoWorkspace, |
299 | sysroot: &Sysroot, | 326 | sysroot: &Sysroot, |
300 | rustc: &Option<CargoWorkspace>, | 327 | rustc: &Option<CargoWorkspace>, |
301 | ) -> CrateGraph { | 328 | ) -> CrateGraph { |
329 | let _p = profile::span("cargo_to_crate_graph"); | ||
302 | let mut crate_graph = CrateGraph::default(); | 330 | let mut crate_graph = CrateGraph::default(); |
303 | let (public_deps, libproc_macro) = | 331 | let (public_deps, libproc_macro) = |
304 | sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load); | 332 | sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load); |
305 | 333 | ||
306 | let mut cfg_options = CfgOptions::default(); | 334 | let mut cfg_options = CfgOptions::default(); |
307 | cfg_options.extend(get_rustc_cfg_options(target)); | 335 | cfg_options.extend(rustc_cfg); |
308 | 336 | ||
309 | let mut pkg_to_lib_crate = FxHashMap::default(); | 337 | let mut pkg_to_lib_crate = FxHashMap::default(); |
310 | 338 | ||
@@ -490,11 +518,12 @@ fn add_target_crate_root( | |||
490 | fn sysroot_to_crate_graph( | 518 | fn sysroot_to_crate_graph( |
491 | crate_graph: &mut CrateGraph, | 519 | crate_graph: &mut CrateGraph, |
492 | sysroot: &Sysroot, | 520 | sysroot: &Sysroot, |
493 | target: Option<&str>, | 521 | rustc_cfg: Vec<CfgFlag>, |
494 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 522 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
495 | ) -> (Vec<(CrateName, CrateId)>, Option<CrateId>) { | 523 | ) -> (Vec<(CrateName, CrateId)>, Option<CrateId>) { |
524 | let _p = profile::span("sysroot_to_crate_graph"); | ||
496 | let mut cfg_options = CfgOptions::default(); | 525 | let mut cfg_options = CfgOptions::default(); |
497 | cfg_options.extend(get_rustc_cfg_options(target)); | 526 | cfg_options.extend(rustc_cfg); |
498 | let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = sysroot | 527 | let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = sysroot |
499 | .crates() | 528 | .crates() |
500 | .filter_map(|krate| { | 529 | .filter_map(|krate| { |
@@ -533,34 +562,6 @@ fn sysroot_to_crate_graph( | |||
533 | (public_deps, libproc_macro) | 562 | (public_deps, libproc_macro) |
534 | } | 563 | } |
535 | 564 | ||
536 | fn get_rustc_cfg_options(target: Option<&str>) -> Vec<CfgFlag> { | ||
537 | let mut res = Vec::new(); | ||
538 | |||
539 | // Some nightly-only cfgs, which are required for stdlib | ||
540 | res.push(CfgFlag::Atom("target_thread_local".into())); | ||
541 | for &ty in ["8", "16", "32", "64", "cas", "ptr"].iter() { | ||
542 | for &key in ["target_has_atomic", "target_has_atomic_load_store"].iter() { | ||
543 | res.push(CfgFlag::KeyValue { key: key.to_string(), value: ty.into() }); | ||
544 | } | ||
545 | } | ||
546 | |||
547 | let rustc_cfgs = { | ||
548 | let mut cmd = Command::new(toolchain::rustc()); | ||
549 | cmd.args(&["--print", "cfg", "-O"]); | ||
550 | if let Some(target) = target { | ||
551 | cmd.args(&["--target", target]); | ||
552 | } | ||
553 | utf8_stdout(cmd) | ||
554 | }; | ||
555 | |||
556 | match rustc_cfgs { | ||
557 | Ok(rustc_cfgs) => res.extend(rustc_cfgs.lines().map(|it| it.parse().unwrap())), | ||
558 | Err(e) => log::error!("failed to get rustc cfgs: {:#}", e), | ||
559 | } | ||
560 | |||
561 | res | ||
562 | } | ||
563 | |||
564 | fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) { | 565 | fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) { |
565 | if let Err(err) = graph.add_dep(from, name, to) { | 566 | if let Err(err) = graph.add_dep(from, name, to) { |
566 | log::error!("{}", err) | 567 | log::error!("{}", err) |
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs index 7d3fda7a8..a02c8327f 100644 --- a/crates/rust-analyzer/src/cli/analysis_bench.rs +++ b/crates/rust-analyzer/src/cli/analysis_bench.rs | |||
@@ -3,6 +3,7 @@ | |||
3 | use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant}; | 3 | use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant}; |
4 | 4 | ||
5 | use anyhow::{bail, format_err, Result}; | 5 | use anyhow::{bail, format_err, Result}; |
6 | use hir::PrefixKind; | ||
6 | use ide::{ | 7 | use ide::{ |
7 | Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol, | 8 | Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol, |
8 | }; | 9 | }; |
@@ -11,7 +12,7 @@ use ide_db::{ | |||
11 | salsa::{Database, Durability}, | 12 | salsa::{Database, Durability}, |
12 | FileId, | 13 | FileId, |
13 | }, | 14 | }, |
14 | helpers::SnippetCap, | 15 | helpers::{insert_use::InsertUseConfig, SnippetCap}, |
15 | }; | 16 | }; |
16 | use vfs::AbsPathBuf; | 17 | use vfs::AbsPathBuf; |
17 | 18 | ||
@@ -96,7 +97,7 @@ impl BenchCmd { | |||
96 | add_call_parenthesis: true, | 97 | add_call_parenthesis: true, |
97 | add_call_argument_snippets: true, | 98 | add_call_argument_snippets: true, |
98 | snippet_cap: SnippetCap::new(true), | 99 | snippet_cap: SnippetCap::new(true), |
99 | merge: None, | 100 | insert_use: InsertUseConfig { merge: None, prefix_kind: PrefixKind::Plain }, |
100 | }; | 101 | }; |
101 | let res = do_work(&mut host, file_id, |analysis| { | 102 | let res = do_work(&mut host, file_id, |analysis| { |
102 | analysis.completions(&options, file_position) | 103 | analysis.completions(&options, file_position) |
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 31a16ca46..16ccab781 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs | |||
@@ -39,7 +39,7 @@ pub fn load_cargo( | |||
39 | None | 39 | None |
40 | }; | 40 | }; |
41 | 41 | ||
42 | let crate_graph = ws.to_crate_graph(None, proc_macro_client.as_ref(), &mut |path: &AbsPath| { | 42 | let crate_graph = ws.to_crate_graph(proc_macro_client.as_ref(), &mut |path: &AbsPath| { |
43 | let contents = loader.load_sync(path); | 43 | let contents = loader.load_sync(path); |
44 | let path = vfs::VfsPath::from(path.to_path_buf()); | 44 | let path = vfs::VfsPath::from(path.to_path_buf()); |
45 | vfs.set_file_contents(path.clone(), contents); | 45 | vfs.set_file_contents(path.clone(), contents); |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 27b92a5a9..ce9655818 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -11,11 +11,11 @@ use std::{convert::TryFrom, ffi::OsString, iter, path::PathBuf}; | |||
11 | 11 | ||
12 | use flycheck::FlycheckConfig; | 12 | use flycheck::FlycheckConfig; |
13 | use hir::PrefixKind; | 13 | use hir::PrefixKind; |
14 | use ide::{ | 14 | use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig}; |
15 | AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig, | 15 | use ide_db::helpers::{ |
16 | InsertUseConfig, | 16 | insert_use::{InsertUseConfig, MergeBehavior}, |
17 | SnippetCap, | ||
17 | }; | 18 | }; |
18 | use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap}; | ||
19 | use itertools::Itertools; | 19 | use itertools::Itertools; |
20 | use lsp_types::{ClientCapabilities, MarkupKind}; | 20 | use lsp_types::{ClientCapabilities, MarkupKind}; |
21 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; | 21 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; |
@@ -542,11 +542,18 @@ impl Config { | |||
542 | max_length: self.data.inlayHints_maxLength, | 542 | max_length: self.data.inlayHints_maxLength, |
543 | } | 543 | } |
544 | } | 544 | } |
545 | fn merge_behavior(&self) -> Option<MergeBehavior> { | 545 | fn insert_use_config(&self) -> InsertUseConfig { |
546 | match self.data.assist_importMergeBehavior { | 546 | InsertUseConfig { |
547 | MergeBehaviorDef::None => None, | 547 | merge: match self.data.assist_importMergeBehavior { |
548 | MergeBehaviorDef::Full => Some(MergeBehavior::Full), | 548 | MergeBehaviorDef::None => None, |
549 | MergeBehaviorDef::Last => Some(MergeBehavior::Last), | 549 | MergeBehaviorDef::Full => Some(MergeBehavior::Full), |
550 | MergeBehaviorDef::Last => Some(MergeBehavior::Last), | ||
551 | }, | ||
552 | prefix_kind: match self.data.assist_importPrefix { | ||
553 | ImportPrefixDef::Plain => PrefixKind::Plain, | ||
554 | ImportPrefixDef::ByCrate => PrefixKind::ByCrate, | ||
555 | ImportPrefixDef::BySelf => PrefixKind::BySelf, | ||
556 | }, | ||
550 | } | 557 | } |
551 | } | 558 | } |
552 | pub fn completion(&self) -> CompletionConfig { | 559 | pub fn completion(&self) -> CompletionConfig { |
@@ -556,7 +563,7 @@ impl Config { | |||
556 | && completion_item_edit_resolve(&self.caps), | 563 | && completion_item_edit_resolve(&self.caps), |
557 | add_call_parenthesis: self.data.completion_addCallParenthesis, | 564 | add_call_parenthesis: self.data.completion_addCallParenthesis, |
558 | add_call_argument_snippets: self.data.completion_addCallArgumentSnippets, | 565 | add_call_argument_snippets: self.data.completion_addCallArgumentSnippets, |
559 | merge: self.merge_behavior(), | 566 | insert_use: self.insert_use_config(), |
560 | snippet_cap: SnippetCap::new(try_or!( | 567 | snippet_cap: SnippetCap::new(try_or!( |
561 | self.caps | 568 | self.caps |
562 | .text_document | 569 | .text_document |
@@ -575,7 +582,11 @@ impl Config { | |||
575 | snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")), | 582 | snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")), |
576 | allowed: None, | 583 | allowed: None, |
577 | insert_use: InsertUseConfig { | 584 | insert_use: InsertUseConfig { |
578 | merge: self.merge_behavior(), | 585 | merge: match self.data.assist_importMergeBehavior { |
586 | MergeBehaviorDef::None => None, | ||
587 | MergeBehaviorDef::Full => Some(MergeBehavior::Full), | ||
588 | MergeBehaviorDef::Last => Some(MergeBehavior::Last), | ||
589 | }, | ||
579 | prefix_kind: match self.data.assist_importPrefix { | 590 | prefix_kind: match self.data.assist_importPrefix { |
580 | ImportPrefixDef::Plain => PrefixKind::Plain, | 591 | ImportPrefixDef::Plain => PrefixKind::Plain, |
581 | ImportPrefixDef::ByCrate => PrefixKind::ByCrate, | 592 | ImportPrefixDef::ByCrate => PrefixKind::ByCrate, |
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 97e20362f..dabfb4241 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs | |||
@@ -135,7 +135,10 @@ impl GlobalState { | |||
135 | ) | 135 | ) |
136 | } | 136 | } |
137 | LinkedProject::InlineJsonProject(it) => { | 137 | LinkedProject::InlineJsonProject(it) => { |
138 | project_model::ProjectWorkspace::load_inline(it.clone()) | 138 | project_model::ProjectWorkspace::load_inline( |
139 | it.clone(), | ||
140 | cargo_config.target.as_deref(), | ||
141 | ) | ||
139 | } | 142 | } |
140 | }) | 143 | }) |
141 | .collect::<Vec<_>>(); | 144 | .collect::<Vec<_>>(); |
@@ -253,11 +256,7 @@ impl GlobalState { | |||
253 | res | 256 | res |
254 | }; | 257 | }; |
255 | for ws in workspaces.iter() { | 258 | for ws in workspaces.iter() { |
256 | crate_graph.extend(ws.to_crate_graph( | 259 | crate_graph.extend(ws.to_crate_graph(self.proc_macro_client.as_ref(), &mut load)); |
257 | self.config.cargo().target.as_deref(), | ||
258 | self.proc_macro_client.as_ref(), | ||
259 | &mut load, | ||
260 | )); | ||
261 | } | 260 | } |
262 | 261 | ||
263 | crate_graph | 262 | crate_graph |
@@ -274,6 +273,7 @@ impl GlobalState { | |||
274 | } | 273 | } |
275 | 274 | ||
276 | fn reload_flycheck(&mut self) { | 275 | fn reload_flycheck(&mut self) { |
276 | let _p = profile::span("GlobalState::reload_flycheck"); | ||
277 | let config = match self.config.flycheck() { | 277 | let config = match self.config.flycheck() { |
278 | Some(it) => it, | 278 | Some(it) => it, |
279 | None => { | 279 | None => { |
@@ -288,9 +288,7 @@ impl GlobalState { | |||
288 | .iter() | 288 | .iter() |
289 | .enumerate() | 289 | .enumerate() |
290 | .filter_map(|(id, w)| match w { | 290 | .filter_map(|(id, w)| match w { |
291 | ProjectWorkspace::Cargo { cargo, sysroot: _, rustc: _ } => { | 291 | ProjectWorkspace::Cargo { cargo, .. } => Some((id, cargo.workspace_root())), |
292 | Some((id, cargo.workspace_root())) | ||
293 | } | ||
294 | ProjectWorkspace::Json { project, .. } => { | 292 | ProjectWorkspace::Json { project, .. } => { |
295 | // Enable flychecks for json projects if a custom flycheck command was supplied | 293 | // Enable flychecks for json projects if a custom flycheck command was supplied |
296 | // in the workspace configuration. | 294 | // in the workspace configuration. |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index dc67d19a7..1ff2d3fea 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -861,8 +861,9 @@ pub(crate) fn rename_error(err: RenameError) -> crate::LspError { | |||
861 | 861 | ||
862 | #[cfg(test)] | 862 | #[cfg(test)] |
863 | mod tests { | 863 | mod tests { |
864 | use hir::PrefixKind; | ||
864 | use ide::Analysis; | 865 | use ide::Analysis; |
865 | use ide_db::helpers::SnippetCap; | 866 | use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap}; |
866 | 867 | ||
867 | use super::*; | 868 | use super::*; |
868 | 869 | ||
@@ -887,7 +888,7 @@ mod tests { | |||
887 | add_call_parenthesis: true, | 888 | add_call_parenthesis: true, |
888 | add_call_argument_snippets: true, | 889 | add_call_argument_snippets: true, |
889 | snippet_cap: SnippetCap::new(true), | 890 | snippet_cap: SnippetCap::new(true), |
890 | merge: None, | 891 | insert_use: InsertUseConfig { merge: None, prefix_kind: PrefixKind::Plain }, |
891 | }, | 892 | }, |
892 | ide_db::base_db::FilePosition { file_id, offset }, | 893 | ide_db::base_db::FilePosition { file_id, offset }, |
893 | ) | 894 | ) |
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index ad8b797fe..52394b337 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml | |||
@@ -12,7 +12,7 @@ doctest = false | |||
12 | 12 | ||
13 | [dependencies] | 13 | [dependencies] |
14 | itertools = "0.10.0" | 14 | itertools = "0.10.0" |
15 | rowan = "0.10.1" | 15 | rowan = "0.10.3" |
16 | rustc_lexer = { version = "697.0.0", package = "rustc-ap-rustc_lexer" } | 16 | rustc_lexer = { version = "697.0.0", package = "rustc-ap-rustc_lexer" } |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | arrayvec = "0.5.1" | 18 | arrayvec = "0.5.1" |
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 1ed8a96e5..9ffc3ae11 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs | |||
@@ -108,8 +108,12 @@ pub fn use_tree_list(use_trees: impl IntoIterator<Item = ast::UseTree>) -> ast:: | |||
108 | ast_from_text(&format!("use {{{}}};", use_trees)) | 108 | ast_from_text(&format!("use {{{}}};", use_trees)) |
109 | } | 109 | } |
110 | 110 | ||
111 | pub fn use_(use_tree: ast::UseTree) -> ast::Use { | 111 | pub fn use_(visibility: Option<ast::Visibility>, use_tree: ast::UseTree) -> ast::Use { |
112 | ast_from_text(&format!("use {};", use_tree)) | 112 | let visibility = match visibility { |
113 | None => String::new(), | ||
114 | Some(it) => format!("{} ", it), | ||
115 | }; | ||
116 | ast_from_text(&format!("{}use {};", visibility, use_tree)) | ||
113 | } | 117 | } |
114 | 118 | ||
115 | pub fn record_expr_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordExprField { | 119 | pub fn record_expr_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordExprField { |