From b8a99692d12189406cad7215530fb5103e6c4b5d Mon Sep 17 00:00:00 2001 From: Lukas Tobias Wirth Date: Tue, 18 May 2021 20:10:39 +0200 Subject: [PATCH] Implement import-granularity guessing --- crates/ide_db/src/helpers/insert_use.rs | 35 +++++++++++++++++++++++-- 1 file 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 a4eb31815e9..4852121a1d3 100644 --- a/crates/ide_db/src/helpers/insert_use.rs +++ b/crates/ide_db/src/helpers/insert_use.rs @@ -4,7 +4,7 @@ use hir::Semantics; use syntax::{ algo, - ast::{self, make, AstNode, PathSegmentKind}, + ast::{self, make, AstNode, ModuleItemOwner, PathSegmentKind}, ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken, }; @@ -88,15 +88,46 @@ pub fn clone_for_update(&self) -> Self { ImportScope::Module(item_list) => ImportScope::Module(item_list.clone_for_update()), } } + + fn guess_merge_behavior_from_scope(&self) -> Option { + let use_stmt = |item| match item { + ast::Item::Use(use_) => use_.use_tree(), + _ => None, + }; + let use_stmts = match self { + ImportScope::File(f) => f.items(), + ImportScope::Module(m) => m.items(), + } + .filter_map(use_stmt); + let mut res = None; + for tree in use_stmts { + if let Some(list) = tree.use_tree_list() { + if list.use_trees().any(|tree| tree.use_tree_list().is_some()) { + // double nested tree list, can only be a crate style import at this point + return Some(MergeBehavior::Crate); + } + // has to be at least a module style based import, might be crate style tho so look further + res = Some(MergeBehavior::Module); + } + } + res + } } /// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig) { let _p = profile::span("insert_use"); + let mb = match cfg.granularity { + ImportGranularity::Preserve => scope.guess_merge_behavior_from_scope(), + ImportGranularity::Crate => Some(MergeBehavior::Crate), + ImportGranularity::Module => Some(MergeBehavior::Module), + ImportGranularity::Item => None, + }; + let use_item = make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update(); // merge into existing imports if possible - if let Some(mb) = cfg.granularity.merge_behavior() { + if let Some(mb) = mb { for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) { if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) { ted::replace(existing_use.syntax(), merged.syntax());