Skip to content

Commit 0d3bad8

Browse files
bors[bot]Veykril
andauthored
Merge #9335
9335: feat: Don't insert imports outside of cfg attributed items r=Veykril a=Veykril Closes #6939 Co-authored-by: Lukas Wirth <[email protected]>
2 parents d9666ce + 344cb5e commit 0d3bad8

File tree

4 files changed

+118
-32
lines changed

4 files changed

+118
-32
lines changed

crates/ide_assists/src/handlers/auto_import.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
103103
let scope = match scope.clone() {
104104
ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
105105
ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
106+
ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
106107
};
107108
insert_use(&scope, mod_path_to_ast(&import.import_path), &ctx.config.insert_use);
108109
},
@@ -991,6 +992,64 @@ mod foo {}
991992
const _: () = {
992993
Foo
993994
};
995+
"#,
996+
);
997+
}
998+
999+
#[test]
1000+
fn respects_cfg_attr() {
1001+
check_assist(
1002+
auto_import,
1003+
r#"
1004+
mod bar {
1005+
pub struct Bar;
1006+
}
1007+
1008+
#[cfg(test)]
1009+
fn foo() {
1010+
Bar$0
1011+
}
1012+
"#,
1013+
r#"
1014+
mod bar {
1015+
pub struct Bar;
1016+
}
1017+
1018+
#[cfg(test)]
1019+
fn foo() {
1020+
use bar::Bar;
1021+
1022+
Bar
1023+
}
1024+
"#,
1025+
);
1026+
}
1027+
1028+
#[test]
1029+
fn respects_cfg_attr2() {
1030+
check_assist(
1031+
auto_import,
1032+
r#"
1033+
mod bar {
1034+
pub struct Bar;
1035+
}
1036+
1037+
#[cfg(test)]
1038+
const FOO: Bar = {
1039+
Bar$0
1040+
}
1041+
"#,
1042+
r#"
1043+
mod bar {
1044+
pub struct Bar;
1045+
}
1046+
1047+
#[cfg(test)]
1048+
const FOO: Bar = {
1049+
use bar::Bar;
1050+
1051+
Bar
1052+
}
9941053
"#,
9951054
);
9961055
}

crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,20 @@ pub(crate) fn replace_qualified_name_with_use(
3232

3333
let target = path.syntax().text_range();
3434
let scope = ImportScope::find_insert_use_container_with_macros(path.syntax(), &ctx.sema)?;
35-
let syntax = scope.as_syntax_node();
3635
acc.add(
3736
AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite),
3837
"Replace qualified path with use",
3938
target,
4039
|builder| {
4140
// Now that we've brought the name into scope, re-qualify all paths that could be
4241
// affected (that is, all paths inside the node we added the `use` to).
43-
let syntax = builder.make_syntax_mut(syntax.clone());
44-
if let Some(ref import_scope) = ImportScope::from(syntax.clone()) {
45-
shorten_paths(&syntax, &path.clone_for_update());
46-
insert_use(import_scope, path, &ctx.config.insert_use);
47-
}
42+
let scope = match scope {
43+
ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
44+
ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
45+
ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
46+
};
47+
shorten_paths(scope.as_syntax_node(), &path.clone_for_update());
48+
insert_use(&scope, path, &ctx.config.insert_use);
4849
},
4950
)
5051
}

crates/ide_db/src/helpers/insert_use.rs

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use hir::Semantics;
55
use syntax::{
66
algo,
77
ast::{self, make, AstNode, AttrsOwner, ModuleItemOwner, PathSegmentKind, VisibilityOwner},
8-
ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken,
8+
match_ast, ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken,
99
};
1010

1111
use crate::{
@@ -43,16 +43,32 @@ pub struct InsertUseConfig {
4343
pub enum ImportScope {
4444
File(ast::SourceFile),
4545
Module(ast::ItemList),
46+
Block(ast::BlockExpr),
4647
}
4748

4849
impl ImportScope {
49-
pub fn from(syntax: SyntaxNode) -> Option<Self> {
50-
if let Some(module) = ast::Module::cast(syntax.clone()) {
51-
module.item_list().map(ImportScope::Module)
52-
} else if let this @ Some(_) = ast::SourceFile::cast(syntax.clone()) {
53-
this.map(ImportScope::File)
54-
} else {
55-
ast::ItemList::cast(syntax).map(ImportScope::Module)
50+
fn from(syntax: SyntaxNode) -> Option<Self> {
51+
fn contains_cfg_attr(attrs: &dyn AttrsOwner) -> bool {
52+
attrs
53+
.attrs()
54+
.any(|attr| attr.as_simple_call().map_or(false, |(ident, _)| ident == "cfg"))
55+
}
56+
match_ast! {
57+
match syntax {
58+
ast::Module(module) => module.item_list().map(ImportScope::Module),
59+
ast::SourceFile(file) => Some(ImportScope::File(file)),
60+
ast::Fn(func) => contains_cfg_attr(&func).then(|| func.body().map(ImportScope::Block)).flatten(),
61+
ast::Const(konst) => contains_cfg_attr(&konst).then(|| match konst.body()? {
62+
ast::Expr::BlockExpr(block) => Some(block),
63+
_ => None,
64+
}).flatten().map(ImportScope::Block),
65+
ast::Static(statik) => contains_cfg_attr(&statik).then(|| match statik.body()? {
66+
ast::Expr::BlockExpr(block) => Some(block),
67+
_ => None,
68+
}).flatten().map(ImportScope::Block),
69+
_ => None,
70+
71+
}
5672
}
5773
}
5874

@@ -73,13 +89,15 @@ impl ImportScope {
7389
match self {
7490
ImportScope::File(file) => file.syntax(),
7591
ImportScope::Module(item_list) => item_list.syntax(),
92+
ImportScope::Block(block) => block.syntax(),
7693
}
7794
}
7895

7996
pub fn clone_for_update(&self) -> Self {
8097
match self {
8198
ImportScope::File(file) => ImportScope::File(file.clone_for_update()),
8299
ImportScope::Module(item_list) => ImportScope::Module(item_list.clone_for_update()),
100+
ImportScope::Block(block) => ImportScope::Block(block.clone_for_update()),
83101
}
84102
}
85103

@@ -96,6 +114,7 @@ impl ImportScope {
96114
let mut use_stmts = match self {
97115
ImportScope::File(f) => f.items(),
98116
ImportScope::Module(m) => m.items(),
117+
ImportScope::Block(b) => b.items(),
99118
}
100119
.filter_map(use_stmt);
101120
let mut res = ImportGranularityGuess::Unknown;
@@ -319,28 +338,29 @@ fn insert_use_(
319338
ted::insert(ted::Position::after(last_inner_element), make::tokens::single_newline());
320339
return;
321340
}
322-
match scope {
341+
let l_curly = match scope {
323342
ImportScope::File(_) => {
324343
cov_mark::hit!(insert_group_empty_file);
325344
ted::insert(ted::Position::first_child_of(scope_syntax), make::tokens::blank_line());
326-
ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax())
345+
ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax());
346+
return;
327347
}
348+
// don't insert the imports before the item list/block expr's opening curly brace
349+
ImportScope::Module(item_list) => item_list.l_curly_token(),
328350
// don't insert the imports before the item list's opening curly brace
329-
ImportScope::Module(item_list) => match item_list.l_curly_token() {
330-
Some(b) => {
331-
cov_mark::hit!(insert_group_empty_module);
332-
ted::insert(ted::Position::after(&b), make::tokens::single_newline());
333-
ted::insert(ted::Position::after(&b), use_item.syntax());
334-
}
335-
None => {
336-
// This should never happens, broken module syntax node
337-
ted::insert(
338-
ted::Position::first_child_of(scope_syntax),
339-
make::tokens::blank_line(),
340-
);
341-
ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax());
342-
}
343-
},
351+
ImportScope::Block(block) => block.l_curly_token(),
352+
};
353+
match l_curly {
354+
Some(b) => {
355+
cov_mark::hit!(insert_group_empty_module);
356+
ted::insert(ted::Position::after(&b), make::tokens::single_newline());
357+
ted::insert(ted::Position::after(&b), use_item.syntax());
358+
}
359+
None => {
360+
// This should never happens, broken module syntax node
361+
ted::insert(ted::Position::first_child_of(scope_syntax), make::tokens::blank_line());
362+
ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax());
363+
}
344364
}
345365
}
346366

crates/syntax/src/ast/node_ext.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use parser::SyntaxKind;
88
use rowan::{GreenNodeData, GreenTokenData};
99

1010
use crate::{
11-
ast::{self, support, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode},
11+
ast::{self, support, AstChildren, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode},
1212
NodeOrToken, SmolStr, SyntaxElement, SyntaxToken, TokenText, T,
1313
};
1414

@@ -45,6 +45,12 @@ fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> {
4545
}
4646
}
4747

48+
impl ast::BlockExpr {
49+
pub fn items(&self) -> AstChildren<ast::Item> {
50+
support::children(self.syntax())
51+
}
52+
}
53+
4854
#[derive(Debug, PartialEq, Eq, Clone)]
4955
pub enum Macro {
5056
MacroRules(ast::MacroRules),

0 commit comments

Comments
 (0)