aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_db
diff options
context:
space:
mode:
authorLukas Tobias Wirth <[email protected]>2021-05-18 19:10:39 +0100
committerLukas Tobias Wirth <[email protected]>2021-05-18 19:10:39 +0100
commitb8a99692d12189406cad7215530fb5103e6c4b5d (patch)
tree140a957cdf1661ba5b99ece3f9f81ad2f8d695bc /crates/ide_db
parent64f7072c255bd97a58b8344d0beeae281b8f7e13 (diff)
Implement import-granularity guessing
Diffstat (limited to 'crates/ide_db')
-rw-r--r--crates/ide_db/src/helpers/insert_use.rs35
1 files changed, 33 insertions, 2 deletions
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index a4eb31815..4852121a1 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -4,7 +4,7 @@ use std::cmp::Ordering;
4use hir::Semantics; 4use hir::Semantics;
5use syntax::{ 5use syntax::{
6 algo, 6 algo,
7 ast::{self, make, AstNode, PathSegmentKind}, 7 ast::{self, make, AstNode, ModuleItemOwner, PathSegmentKind},
8 ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken, 8 ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken,
9}; 9};
10 10
@@ -88,15 +88,46 @@ impl ImportScope {
88 ImportScope::Module(item_list) => ImportScope::Module(item_list.clone_for_update()), 88 ImportScope::Module(item_list) => ImportScope::Module(item_list.clone_for_update()),
89 } 89 }
90 } 90 }
91
92 fn guess_merge_behavior_from_scope(&self) -> Option<MergeBehavior> {
93 let use_stmt = |item| match item {
94 ast::Item::Use(use_) => use_.use_tree(),
95 _ => None,
96 };
97 let use_stmts = match self {
98 ImportScope::File(f) => f.items(),
99 ImportScope::Module(m) => m.items(),
100 }
101 .filter_map(use_stmt);
102 let mut res = None;
103 for tree in use_stmts {
104 if let Some(list) = tree.use_tree_list() {
105 if list.use_trees().any(|tree| tree.use_tree_list().is_some()) {
106 // double nested tree list, can only be a crate style import at this point
107 return Some(MergeBehavior::Crate);
108 }
109 // has to be at least a module style based import, might be crate style tho so look further
110 res = Some(MergeBehavior::Module);
111 }
112 }
113 res
114 }
91} 115}
92 116
93/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. 117/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur.
94pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig) { 118pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig) {
95 let _p = profile::span("insert_use"); 119 let _p = profile::span("insert_use");
120 let mb = match cfg.granularity {
121 ImportGranularity::Preserve => scope.guess_merge_behavior_from_scope(),
122 ImportGranularity::Crate => Some(MergeBehavior::Crate),
123 ImportGranularity::Module => Some(MergeBehavior::Module),
124 ImportGranularity::Item => None,
125 };
126
96 let use_item = 127 let use_item =
97 make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update(); 128 make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update();
98 // merge into existing imports if possible 129 // merge into existing imports if possible
99 if let Some(mb) = cfg.granularity.merge_behavior() { 130 if let Some(mb) = mb {
100 for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) { 131 for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) {
101 if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) { 132 if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) {
102 ted::replace(existing_use.syntax(), merged.syntax()); 133 ted::replace(existing_use.syntax(), merged.syntax());