aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide_assists/src/handlers/auto_import.rs2
-rw-r--r--crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs2
-rw-r--r--crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs2
-rw-r--r--crates/ide_assists/src/tests.rs1
-rw-r--r--crates/ide_completion/src/item.rs2
-rw-r--r--crates/ide_completion/src/tests.rs1
-rw-r--r--crates/ide_db/src/helpers/insert_use.rs8
-rw-r--r--crates/ide_db/src/helpers/insert_use/tests.rs72
-rw-r--r--crates/rust-analyzer/src/config.rs4
-rw-r--r--crates/rust-analyzer/src/integrated_benchmarks.rs2
-rw-r--r--crates/rust-analyzer/src/to_proto.rs1
-rw-r--r--crates/syntax/src/ast/node_ext.rs9
-rw-r--r--docs/user/generated_config.adoc5
-rw-r--r--editors/code/package.json5
14 files changed, 99 insertions, 17 deletions
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index d4748ef3a..6c7348178 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -104,7 +104,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
104 ImportScope::File(it) => ImportScope::File(builder.make_mut(it)), 104 ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
105 ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)), 105 ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
106 }; 106 };
107 insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use); 107 insert_use(&scope, mod_path_to_ast(&import.import_path), &ctx.config.insert_use);
108 }, 108 },
109 ); 109 );
110 } 110 }
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
index 6c6ff16c2..430710448 100644
--- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -236,7 +236,7 @@ fn apply_references(
236 import: Option<(ImportScope, hir::ModPath)>, 236 import: Option<(ImportScope, hir::ModPath)>,
237) { 237) {
238 if let Some((scope, path)) = import { 238 if let Some((scope, path)) = import {
239 insert_use(&scope, mod_path_to_ast(&path), insert_use_cfg); 239 insert_use(&scope, mod_path_to_ast(&path), &insert_use_cfg);
240 } 240 }
241 // deep clone to prevent cycle 241 // deep clone to prevent cycle
242 let path = make::path_from_segments(iter::once(segment.clone_subtree()), false); 242 let path = make::path_from_segments(iter::once(segment.clone_subtree()), false);
diff --git a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
index 39f5eb4ff..26019c793 100644
--- a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -43,7 +43,7 @@ pub(crate) fn replace_qualified_name_with_use(
43 let syntax = builder.make_syntax_mut(syntax.clone()); 43 let syntax = builder.make_syntax_mut(syntax.clone());
44 if let Some(ref import_scope) = ImportScope::from(syntax.clone()) { 44 if let Some(ref import_scope) = ImportScope::from(syntax.clone()) {
45 shorten_paths(&syntax, &path.clone_for_update()); 45 shorten_paths(&syntax, &path.clone_for_update());
46 insert_use(import_scope, path, ctx.config.insert_use); 46 insert_use(import_scope, path, &ctx.config.insert_use);
47 } 47 }
48 }, 48 },
49 ) 49 )
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs
index 4e96ff1ec..841537c77 100644
--- a/crates/ide_assists/src/tests.rs
+++ b/crates/ide_assists/src/tests.rs
@@ -28,6 +28,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
28 prefix_kind: hir::PrefixKind::Plain, 28 prefix_kind: hir::PrefixKind::Plain,
29 enforce_granularity: true, 29 enforce_granularity: true,
30 group: true, 30 group: true,
31 skip_glob_imports: true,
31 }, 32 },
32}; 33};
33 34
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index 99edb9499..ae63d132e 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -378,7 +378,7 @@ impl ImportEdit {
378 let _p = profile::span("ImportEdit::to_text_edit"); 378 let _p = profile::span("ImportEdit::to_text_edit");
379 379
380 let new_ast = self.scope.clone_for_update(); 380 let new_ast = self.scope.clone_for_update();
381 insert_use::insert_use(&new_ast, mod_path_to_ast(&self.import.import_path), cfg); 381 insert_use::insert_use(&new_ast, mod_path_to_ast(&self.import.import_path), &cfg);
382 let mut import_insert = TextEdit::builder(); 382 let mut import_insert = TextEdit::builder();
383 algo::diff(self.scope.as_syntax_node(), new_ast.as_syntax_node()) 383 algo::diff(self.scope.as_syntax_node(), new_ast.as_syntax_node())
384 .into_text_edit(&mut import_insert); 384 .into_text_edit(&mut import_insert);
diff --git a/crates/ide_completion/src/tests.rs b/crates/ide_completion/src/tests.rs
index 1ea6017ce..211c89c40 100644
--- a/crates/ide_completion/src/tests.rs
+++ b/crates/ide_completion/src/tests.rs
@@ -36,6 +36,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
36 prefix_kind: PrefixKind::Plain, 36 prefix_kind: PrefixKind::Plain,
37 enforce_granularity: true, 37 enforce_granularity: true,
38 group: true, 38 group: true,
39 skip_glob_imports: true,
39 }, 40 },
40}; 41};
41 42
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index 10bbafe77..4da058cb2 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -36,6 +36,7 @@ pub struct InsertUseConfig {
36 pub enforce_granularity: bool, 36 pub enforce_granularity: bool,
37 pub prefix_kind: PrefixKind, 37 pub prefix_kind: PrefixKind,
38 pub group: bool, 38 pub group: bool,
39 pub skip_glob_imports: bool,
39} 40}
40 41
41#[derive(Debug, Clone)] 42#[derive(Debug, Clone)]
@@ -153,7 +154,7 @@ enum ImportGranularityGuess {
153} 154}
154 155
155/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. 156/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur.
156pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig) { 157pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) {
157 let _p = profile::span("insert_use"); 158 let _p = profile::span("insert_use");
158 let mut mb = match cfg.granularity { 159 let mut mb = match cfg.granularity {
159 ImportGranularity::Crate => Some(MergeBehavior::Crate), 160 ImportGranularity::Crate => Some(MergeBehavior::Crate),
@@ -175,7 +176,10 @@ pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig
175 make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update(); 176 make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update();
176 // merge into existing imports if possible 177 // merge into existing imports if possible
177 if let Some(mb) = mb { 178 if let Some(mb) = mb {
178 for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) { 179 let filter = |it: &_| !(cfg.skip_glob_imports && ast::Use::is_simple_glob(it));
180 for existing_use in
181 scope.as_syntax_node().children().filter_map(ast::Use::cast).filter(filter)
182 {
179 if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) { 183 if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) {
180 ted::replace(existing_use.syntax(), merged.syntax()); 184 ted::replace(existing_use.syntax(), merged.syntax());
181 return; 185 return;
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs
index 5a88ec742..263edcdc9 100644
--- a/crates/ide_db/src/helpers/insert_use/tests.rs
+++ b/crates/ide_db/src/helpers/insert_use/tests.rs
@@ -4,6 +4,23 @@ use hir::PrefixKind;
4use test_utils::assert_eq_text; 4use test_utils::assert_eq_text;
5 5
6#[test] 6#[test]
7fn insert_skips_lone_glob_imports() {
8 check(
9 "use foo::baz::A",
10 r"
11use foo::bar::*;
12",
13 r"
14use foo::bar::*;
15use foo::baz::A;
16",
17 ImportGranularity::Crate,
18 false,
19 false,
20 );
21}
22
23#[test]
7fn insert_not_group() { 24fn insert_not_group() {
8 cov_mark::check!(insert_no_grouping_last); 25 cov_mark::check!(insert_no_grouping_last);
9 check( 26 check(
@@ -534,17 +551,37 @@ fn merge_groups_self() {
534 551
535#[test] 552#[test]
536fn merge_mod_into_glob() { 553fn merge_mod_into_glob() {
537 check_crate( 554 check_with_config(
538 "token::TokenKind", 555 "token::TokenKind",
539 r"use token::TokenKind::*;", 556 r"use token::TokenKind::*;",
540 r"use token::TokenKind::{*, self};", 557 r"use token::TokenKind::{*, self};",
558 false,
559 &InsertUseConfig {
560 granularity: ImportGranularity::Crate,
561 enforce_granularity: true,
562 prefix_kind: PrefixKind::Plain,
563 group: false,
564 skip_glob_imports: false,
565 },
541 ) 566 )
542 // FIXME: have it emit `use token::TokenKind::{self, *}`? 567 // FIXME: have it emit `use token::TokenKind::{self, *}`?
543} 568}
544 569
545#[test] 570#[test]
546fn merge_self_glob() { 571fn merge_self_glob() {
547 check_crate("self", r"use self::*;", r"use self::{*, self};") 572 check_with_config(
573 "self",
574 r"use self::*;",
575 r"use self::{*, self};",
576 false,
577 &InsertUseConfig {
578 granularity: ImportGranularity::Crate,
579 enforce_granularity: true,
580 prefix_kind: PrefixKind::Plain,
581 group: false,
582 skip_glob_imports: false,
583 },
584 )
548 // FIXME: have it emit `use {self, *}`? 585 // FIXME: have it emit `use {self, *}`?
549} 586}
550 587
@@ -757,13 +794,12 @@ use foo::bar::qux;
757 ); 794 );
758} 795}
759 796
760fn check( 797fn check_with_config(
761 path: &str, 798 path: &str,
762 ra_fixture_before: &str, 799 ra_fixture_before: &str,
763 ra_fixture_after: &str, 800 ra_fixture_after: &str,
764 granularity: ImportGranularity,
765 module: bool, 801 module: bool,
766 group: bool, 802 config: &InsertUseConfig,
767) { 803) {
768 let mut syntax = ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone(); 804 let mut syntax = ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone();
769 if module { 805 if module {
@@ -777,18 +813,32 @@ fn check(
777 .find_map(ast::Path::cast) 813 .find_map(ast::Path::cast)
778 .unwrap(); 814 .unwrap();
779 815
780 insert_use( 816 insert_use(&file, path, config);
781 &file, 817 let result = file.as_syntax_node().to_string();
818 assert_eq_text!(ra_fixture_after, &result);
819}
820
821fn check(
822 path: &str,
823 ra_fixture_before: &str,
824 ra_fixture_after: &str,
825 granularity: ImportGranularity,
826 module: bool,
827 group: bool,
828) {
829 check_with_config(
782 path, 830 path,
783 InsertUseConfig { 831 ra_fixture_before,
832 ra_fixture_after,
833 module,
834 &InsertUseConfig {
784 granularity, 835 granularity,
785 enforce_granularity: true, 836 enforce_granularity: true,
786 prefix_kind: PrefixKind::Plain, 837 prefix_kind: PrefixKind::Plain,
787 group, 838 group,
839 skip_glob_imports: true,
788 }, 840 },
789 ); 841 )
790 let result = file.as_syntax_node().to_string();
791 assert_eq_text!(ra_fixture_after, &result);
792} 842}
793 843
794fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 844fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index c4757a1cb..16c295639 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -44,6 +44,9 @@ config_data! {
44 assist_importPrefix: ImportPrefixDef = "\"plain\"", 44 assist_importPrefix: ImportPrefixDef = "\"plain\"",
45 /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines. 45 /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.
46 assist_importGroup: bool = "true", 46 assist_importGroup: bool = "true",
47 /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
48 assist_allowMergingIntoGlobImports: bool = "true",
49
47 /// Show function name and docs in parameter hints. 50 /// Show function name and docs in parameter hints.
48 callInfo_full: bool = "true", 51 callInfo_full: bool = "true",
49 52
@@ -672,6 +675,7 @@ impl Config {
672 ImportPrefixDef::BySelf => PrefixKind::BySelf, 675 ImportPrefixDef::BySelf => PrefixKind::BySelf,
673 }, 676 },
674 group: self.data.assist_importGroup, 677 group: self.data.assist_importGroup,
678 skip_glob_imports: !self.data.assist_allowMergingIntoGlobImports,
675 } 679 }
676 } 680 }
677 pub fn completion(&self) -> CompletionConfig { 681 pub fn completion(&self) -> CompletionConfig {
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index 8ddeb59f7..f8afc930a 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -143,6 +143,7 @@ fn integrated_completion_benchmark() {
143 prefix_kind: hir::PrefixKind::ByCrate, 143 prefix_kind: hir::PrefixKind::ByCrate,
144 enforce_granularity: true, 144 enforce_granularity: true,
145 group: true, 145 group: true,
146 skip_glob_imports: true,
146 }, 147 },
147 }; 148 };
148 let position = 149 let position =
@@ -178,6 +179,7 @@ fn integrated_completion_benchmark() {
178 prefix_kind: hir::PrefixKind::ByCrate, 179 prefix_kind: hir::PrefixKind::ByCrate,
179 enforce_granularity: true, 180 enforce_granularity: true,
180 group: true, 181 group: true,
182 skip_glob_imports: true,
181 }, 183 },
182 }; 184 };
183 let position = 185 let position =
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index e53cd3c7b..310d8c6d2 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -1187,6 +1187,7 @@ mod tests {
1187 prefix_kind: PrefixKind::Plain, 1187 prefix_kind: PrefixKind::Plain,
1188 enforce_granularity: true, 1188 enforce_granularity: true,
1189 group: true, 1189 group: true,
1190 skip_glob_imports: true,
1190 }, 1191 },
1191 }, 1192 },
1192 ide_db::base_db::FilePosition { file_id, offset }, 1193 ide_db::base_db::FilePosition { file_id, offset },
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index b057e6624..3c92a486f 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -281,6 +281,15 @@ impl ast::Path {
281 successors(self.qualifier(), |p| p.qualifier()) 281 successors(self.qualifier(), |p| p.qualifier())
282 } 282 }
283} 283}
284
285impl ast::Use {
286 pub fn is_simple_glob(&self) -> bool {
287 self.use_tree()
288 .map(|use_tree| use_tree.use_tree_list().is_none() && use_tree.star_token().is_some())
289 .unwrap_or(false)
290 }
291}
292
284impl ast::UseTree { 293impl ast::UseTree {
285 pub fn is_simple_path(&self) -> bool { 294 pub fn is_simple_path(&self) -> bool {
286 self.use_tree_list().is_none() && self.star_token().is_none() 295 self.use_tree_list().is_none() && self.star_token().is_none()
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 34a91486b..18ea77266 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -18,6 +18,11 @@ The path structure for newly inserted paths to use.
18-- 18--
19Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines. 19Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.
20-- 20--
21[[rust-analyzer.assist.allowMergingIntoGlobImports]]rust-analyzer.assist.allowMergingIntoGlobImports (default: `true`)::
22+
23--
24Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
25--
21[[rust-analyzer.callInfo.full]]rust-analyzer.callInfo.full (default: `true`):: 26[[rust-analyzer.callInfo.full]]rust-analyzer.callInfo.full (default: `true`)::
22+ 27+
23-- 28--
diff --git a/editors/code/package.json b/editors/code/package.json
index 1fac700be..c077bd2c0 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -432,6 +432,11 @@
432 "default": true, 432 "default": true,
433 "type": "boolean" 433 "type": "boolean"
434 }, 434 },
435 "rust-analyzer.assist.allowMergingIntoGlobImports": {
436 "markdownDescription": "Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.",
437 "default": true,
438 "type": "boolean"
439 },
435 "rust-analyzer.callInfo.full": { 440 "rust-analyzer.callInfo.full": {
436 "markdownDescription": "Show function name and docs in parameter hints.", 441 "markdownDescription": "Show function name and docs in parameter hints.",
437 "default": true, 442 "default": true,