diff options
Diffstat (limited to 'crates')
49 files changed, 1015 insertions, 529 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index ac23e385e..c9ef4b420 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -2071,6 +2071,10 @@ impl Type { | |||
2071 | Some(adt.into()) | 2071 | Some(adt.into()) |
2072 | } | 2072 | } |
2073 | 2073 | ||
2074 | pub fn as_builtin(&self) -> Option<BuiltinType> { | ||
2075 | self.ty.as_builtin().map(|inner| BuiltinType { inner }) | ||
2076 | } | ||
2077 | |||
2074 | pub fn as_dyn_trait(&self) -> Option<Trait> { | 2078 | pub fn as_dyn_trait(&self) -> Option<Trait> { |
2075 | self.ty.dyn_trait().map(Into::into) | 2079 | self.ty.dyn_trait().map(Into::into) |
2076 | } | 2080 | } |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 8d13c7e04..cad8a7479 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -18,7 +18,7 @@ use hir_expand::{ | |||
18 | ast_id_map::FileAstId, | 18 | ast_id_map::FileAstId, |
19 | hygiene::Hygiene, | 19 | hygiene::Hygiene, |
20 | name::{name, AsName, Name}, | 20 | name::{name, AsName, Name}, |
21 | HirFileId, InFile, | 21 | FragmentKind, HirFileId, InFile, |
22 | }; | 22 | }; |
23 | use la_arena::{Arena, Idx, RawIdx}; | 23 | use la_arena::{Arena, Idx, RawIdx}; |
24 | use profile::Count; | 24 | use profile::Count; |
@@ -656,6 +656,7 @@ pub struct MacroCall { | |||
656 | /// Path to the called macro. | 656 | /// Path to the called macro. |
657 | pub path: Interned<ModPath>, | 657 | pub path: Interned<ModPath>, |
658 | pub ast_id: FileAstId<ast::MacroCall>, | 658 | pub ast_id: FileAstId<ast::MacroCall>, |
659 | pub fragment: FragmentKind, | ||
659 | } | 660 | } |
660 | 661 | ||
661 | #[derive(Debug, Clone, Eq, PartialEq)] | 662 | #[derive(Debug, Clone, Eq, PartialEq)] |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 5743b3386..fe348091d 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -624,7 +624,8 @@ impl<'a> Ctx<'a> { | |||
624 | fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> { | 624 | fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> { |
625 | let path = Interned::new(ModPath::from_src(self.db, m.path()?, &self.hygiene)?); | 625 | let path = Interned::new(ModPath::from_src(self.db, m.path()?, &self.hygiene)?); |
626 | let ast_id = self.source_ast_id_map.ast_id(m); | 626 | let ast_id = self.source_ast_id_map.ast_id(m); |
627 | let res = MacroCall { path, ast_id }; | 627 | let fragment = hir_expand::to_fragment_kind(m); |
628 | let res = MacroCall { path, ast_id, fragment }; | ||
628 | Some(id(self.data().macro_calls.alloc(res))) | 629 | Some(id(self.data().macro_calls.alloc(res))) |
629 | } | 630 | } |
630 | 631 | ||
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index da46f16f7..e96ca953f 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -62,7 +62,8 @@ use hir_expand::{ | |||
62 | ast_id_map::FileAstId, | 62 | ast_id_map::FileAstId, |
63 | eager::{expand_eager_macro, ErrorEmitted, ErrorSink}, | 63 | eager::{expand_eager_macro, ErrorEmitted, ErrorSink}, |
64 | hygiene::Hygiene, | 64 | hygiene::Hygiene, |
65 | AstId, AttrId, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, | 65 | AstId, AttrId, FragmentKind, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, |
66 | MacroDefKind, | ||
66 | }; | 67 | }; |
67 | use la_arena::Idx; | 68 | use la_arena::Idx; |
68 | use nameres::DefMap; | 69 | use nameres::DefMap; |
@@ -652,6 +653,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> { | |||
652 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, | 653 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, |
653 | mut error_sink: &mut dyn FnMut(mbe::ExpandError), | 654 | mut error_sink: &mut dyn FnMut(mbe::ExpandError), |
654 | ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> { | 655 | ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> { |
656 | let fragment = hir_expand::to_fragment_kind(self.value); | ||
655 | let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); | 657 | let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); |
656 | let h = Hygiene::new(db.upcast(), self.file_id); | 658 | let h = Hygiene::new(db.upcast(), self.file_id); |
657 | let path = self.value.path().and_then(|path| path::ModPath::from_src(db, path, &h)); | 659 | let path = self.value.path().and_then(|path| path::ModPath::from_src(db, path, &h)); |
@@ -667,6 +669,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> { | |||
667 | 669 | ||
668 | macro_call_as_call_id( | 670 | macro_call_as_call_id( |
669 | &AstIdWithPath::new(ast_id.file_id, ast_id.value, path), | 671 | &AstIdWithPath::new(ast_id.file_id, ast_id.value, path), |
672 | fragment, | ||
670 | db, | 673 | db, |
671 | krate, | 674 | krate, |
672 | resolver, | 675 | resolver, |
@@ -695,6 +698,7 @@ pub struct UnresolvedMacro { | |||
695 | 698 | ||
696 | fn macro_call_as_call_id( | 699 | fn macro_call_as_call_id( |
697 | call: &AstIdWithPath<ast::MacroCall>, | 700 | call: &AstIdWithPath<ast::MacroCall>, |
701 | fragment: FragmentKind, | ||
698 | db: &dyn db::DefDatabase, | 702 | db: &dyn db::DefDatabase, |
699 | krate: CrateId, | 703 | krate: CrateId, |
700 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, | 704 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, |
@@ -718,7 +722,11 @@ fn macro_call_as_call_id( | |||
718 | .map(MacroCallId::from) | 722 | .map(MacroCallId::from) |
719 | } else { | 723 | } else { |
720 | Ok(def | 724 | Ok(def |
721 | .as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike { ast_id: call.ast_id }) | 725 | .as_lazy_macro( |
726 | db.upcast(), | ||
727 | krate, | ||
728 | MacroCallKind::FnLike { ast_id: call.ast_id, fragment }, | ||
729 | ) | ||
722 | .into()) | 730 | .into()) |
723 | }; | 731 | }; |
724 | Ok(res) | 732 | Ok(res) |
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index 1bc72ec1f..249af6fc8 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -629,7 +629,7 @@ mod diagnostics { | |||
629 | DiagnosticKind::UnresolvedProcMacro { ast } => { | 629 | DiagnosticKind::UnresolvedProcMacro { ast } => { |
630 | let mut precise_location = None; | 630 | let mut precise_location = None; |
631 | let (file, ast, name) = match ast { | 631 | let (file, ast, name) = match ast { |
632 | MacroCallKind::FnLike { ast_id } => { | 632 | MacroCallKind::FnLike { ast_id, .. } => { |
633 | let node = ast_id.to_node(db.upcast()); | 633 | let node = ast_id.to_node(db.upcast()); |
634 | (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None) | 634 | (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None) |
635 | } | 635 | } |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 05ceb1efb..e89136ed1 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -13,7 +13,7 @@ use hir_expand::{ | |||
13 | builtin_macro::find_builtin_macro, | 13 | builtin_macro::find_builtin_macro, |
14 | name::{AsName, Name}, | 14 | name::{AsName, Name}, |
15 | proc_macro::ProcMacroExpander, | 15 | proc_macro::ProcMacroExpander, |
16 | AttrId, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, | 16 | AttrId, FragmentKind, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, |
17 | }; | 17 | }; |
18 | use hir_expand::{InFile, MacroCallLoc}; | 18 | use hir_expand::{InFile, MacroCallLoc}; |
19 | use rustc_hash::{FxHashMap, FxHashSet}; | 19 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -215,7 +215,7 @@ struct MacroDirective { | |||
215 | 215 | ||
216 | #[derive(Clone, Debug, Eq, PartialEq)] | 216 | #[derive(Clone, Debug, Eq, PartialEq)] |
217 | enum MacroDirectiveKind { | 217 | enum MacroDirectiveKind { |
218 | FnLike { ast_id: AstIdWithPath<ast::MacroCall> }, | 218 | FnLike { ast_id: AstIdWithPath<ast::MacroCall>, fragment: FragmentKind }, |
219 | Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId }, | 219 | Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId }, |
220 | } | 220 | } |
221 | 221 | ||
@@ -807,9 +807,10 @@ impl DefCollector<'_> { | |||
807 | let mut res = ReachedFixedPoint::Yes; | 807 | let mut res = ReachedFixedPoint::Yes; |
808 | macros.retain(|directive| { | 808 | macros.retain(|directive| { |
809 | match &directive.kind { | 809 | match &directive.kind { |
810 | MacroDirectiveKind::FnLike { ast_id } => { | 810 | MacroDirectiveKind::FnLike { ast_id, fragment } => { |
811 | match macro_call_as_call_id( | 811 | match macro_call_as_call_id( |
812 | ast_id, | 812 | ast_id, |
813 | *fragment, | ||
813 | self.db, | 814 | self.db, |
814 | self.def_map.krate, | 815 | self.def_map.krate, |
815 | |path| { | 816 | |path| { |
@@ -926,8 +927,9 @@ impl DefCollector<'_> { | |||
926 | 927 | ||
927 | for directive in &self.unexpanded_macros { | 928 | for directive in &self.unexpanded_macros { |
928 | match &directive.kind { | 929 | match &directive.kind { |
929 | MacroDirectiveKind::FnLike { ast_id, .. } => match macro_call_as_call_id( | 930 | MacroDirectiveKind::FnLike { ast_id, fragment } => match macro_call_as_call_id( |
930 | ast_id, | 931 | ast_id, |
932 | *fragment, | ||
931 | self.db, | 933 | self.db, |
932 | self.def_map.krate, | 934 | self.def_map.krate, |
933 | |path| { | 935 | |path| { |
@@ -1496,6 +1498,7 @@ impl ModCollector<'_, '_> { | |||
1496 | let mut error = None; | 1498 | let mut error = None; |
1497 | match macro_call_as_call_id( | 1499 | match macro_call_as_call_id( |
1498 | &ast_id, | 1500 | &ast_id, |
1501 | mac.fragment, | ||
1499 | self.def_collector.db, | 1502 | self.def_collector.db, |
1500 | self.def_collector.def_map.krate, | 1503 | self.def_collector.def_map.krate, |
1501 | |path| { | 1504 | |path| { |
@@ -1524,9 +1527,14 @@ impl ModCollector<'_, '_> { | |||
1524 | } | 1527 | } |
1525 | Ok(Err(_)) => { | 1528 | Ok(Err(_)) => { |
1526 | // Built-in macro failed eager expansion. | 1529 | // Built-in macro failed eager expansion. |
1530 | |||
1531 | // FIXME: don't parse the file here | ||
1532 | let fragment = hir_expand::to_fragment_kind( | ||
1533 | &ast_id.ast_id.to_node(self.def_collector.db.upcast()), | ||
1534 | ); | ||
1527 | self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error( | 1535 | self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error( |
1528 | self.module_id, | 1536 | self.module_id, |
1529 | MacroCallKind::FnLike { ast_id: ast_id.ast_id }, | 1537 | MacroCallKind::FnLike { ast_id: ast_id.ast_id, fragment }, |
1530 | error.unwrap().to_string(), | 1538 | error.unwrap().to_string(), |
1531 | )); | 1539 | )); |
1532 | return; | 1540 | return; |
@@ -1543,7 +1551,7 @@ impl ModCollector<'_, '_> { | |||
1543 | self.def_collector.unexpanded_macros.push(MacroDirective { | 1551 | self.def_collector.unexpanded_macros.push(MacroDirective { |
1544 | module_id: self.module_id, | 1552 | module_id: self.module_id, |
1545 | depth: self.macro_depth + 1, | 1553 | depth: self.macro_depth + 1, |
1546 | kind: MacroDirectiveKind::FnLike { ast_id }, | 1554 | kind: MacroDirectiveKind::FnLike { ast_id, fragment: mac.fragment }, |
1547 | }); | 1555 | }); |
1548 | } | 1556 | } |
1549 | 1557 | ||
diff --git a/crates/hir_def/src/nameres/tests/incremental.rs b/crates/hir_def/src/nameres/tests/incremental.rs index 227ecd162..d884a6eb4 100644 --- a/crates/hir_def/src/nameres/tests/incremental.rs +++ b/crates/hir_def/src/nameres/tests/incremental.rs | |||
@@ -137,6 +137,9 @@ m!(Z); | |||
137 | }); | 137 | }); |
138 | let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); | 138 | let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); |
139 | assert_eq!(n_recalculated_item_trees, 6); | 139 | assert_eq!(n_recalculated_item_trees, 6); |
140 | let n_reparsed_macros = | ||
141 | events.iter().filter(|it| it.contains("parse_macro_expansion")).count(); | ||
142 | assert_eq!(n_reparsed_macros, 3); | ||
140 | } | 143 | } |
141 | 144 | ||
142 | let new_text = r#" | 145 | let new_text = r#" |
@@ -155,5 +158,8 @@ m!(Z); | |||
155 | }); | 158 | }); |
156 | let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); | 159 | let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); |
157 | assert_eq!(n_recalculated_item_trees, 1); | 160 | assert_eq!(n_recalculated_item_trees, 1); |
161 | let n_reparsed_macros = | ||
162 | events.iter().filter(|it| it.contains("parse_macro_expansion")).count(); | ||
163 | assert_eq!(n_reparsed_macros, 0); | ||
158 | } | 164 | } |
159 | } | 165 | } |
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs index 179de61f9..af9802144 100644 --- a/crates/hir_expand/src/builtin_macro.rs +++ b/crates/hir_expand/src/builtin_macro.rs | |||
@@ -578,6 +578,7 @@ mod tests { | |||
578 | krate, | 578 | krate, |
579 | kind: MacroCallKind::FnLike { | 579 | kind: MacroCallKind::FnLike { |
580 | ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(¯o_call)), | 580 | ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(¯o_call)), |
581 | fragment: FragmentKind::Expr, | ||
581 | }, | 582 | }, |
582 | }; | 583 | }; |
583 | 584 | ||
@@ -788,9 +789,9 @@ mod tests { | |||
788 | r##" | 789 | r##" |
789 | #[rustc_builtin_macro] | 790 | #[rustc_builtin_macro] |
790 | macro_rules! concat {} | 791 | macro_rules! concat {} |
791 | concat!("foo", "r", 0, r#"bar"#, false); | 792 | concat!("foo", "r", 0, r#"bar"#, "\n", false); |
792 | "##, | 793 | "##, |
793 | expect![[r#""foor0barfalse""#]], | 794 | expect![[r#""foor0bar\nfalse""#]], |
794 | ); | 795 | ); |
795 | } | 796 | } |
796 | } | 797 | } |
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index d61f4b31a..6647e57e7 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -8,9 +8,7 @@ use parser::FragmentKind; | |||
8 | use syntax::{ | 8 | use syntax::{ |
9 | algo::diff, | 9 | algo::diff, |
10 | ast::{self, NameOwner}, | 10 | ast::{self, NameOwner}, |
11 | AstNode, GreenNode, Parse, | 11 | AstNode, GreenNode, Parse, SyntaxNode, SyntaxToken, |
12 | SyntaxKind::*, | ||
13 | SyntaxNode, SyntaxToken, | ||
14 | }; | 12 | }; |
15 | 13 | ||
16 | use crate::{ | 14 | use crate::{ |
@@ -160,7 +158,7 @@ pub fn expand_hypothetical( | |||
160 | 158 | ||
161 | let hypothetical_expansion = macro_def.expand(db, lazy_id, &tt); | 159 | let hypothetical_expansion = macro_def.expand(db, lazy_id, &tt); |
162 | 160 | ||
163 | let fragment_kind = to_fragment_kind(db, actual_macro_call); | 161 | let fragment_kind = macro_fragment_kind(db, actual_macro_call); |
164 | 162 | ||
165 | let (node, tmap_2) = | 163 | let (node, tmap_2) = |
166 | mbe::token_tree_to_syntax_node(&hypothetical_expansion.value, fragment_kind).ok()?; | 164 | mbe::token_tree_to_syntax_node(&hypothetical_expansion.value, fragment_kind).ok()?; |
@@ -226,7 +224,7 @@ fn parse_macro_expansion( | |||
226 | None => return ExpandResult { value: None, err: result.err }, | 224 | None => return ExpandResult { value: None, err: result.err }, |
227 | }; | 225 | }; |
228 | 226 | ||
229 | let fragment_kind = to_fragment_kind(db, macro_file.macro_call_id); | 227 | let fragment_kind = macro_fragment_kind(db, macro_file.macro_call_id); |
230 | 228 | ||
231 | log::debug!("expanded = {}", tt.as_debug_string()); | 229 | log::debug!("expanded = {}", tt.as_debug_string()); |
232 | log::debug!("kind = {:?}", fragment_kind); | 230 | log::debug!("kind = {:?}", fragment_kind); |
@@ -427,62 +425,15 @@ fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> | |||
427 | Arc::new(HygieneFrame::new(db, file_id)) | 425 | Arc::new(HygieneFrame::new(db, file_id)) |
428 | } | 426 | } |
429 | 427 | ||
430 | /// Given a `MacroCallId`, return what `FragmentKind` it belongs to. | 428 | fn macro_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind { |
431 | /// FIXME: Not completed | 429 | match id { |
432 | fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind { | 430 | MacroCallId::LazyMacro(id) => { |
433 | let lazy_id = match id { | 431 | let loc: MacroCallLoc = db.lookup_intern_macro(id); |
434 | MacroCallId::LazyMacro(id) => id, | 432 | loc.kind.fragment_kind() |
435 | MacroCallId::EagerMacro(id) => { | ||
436 | return db.lookup_intern_eager_expansion(id).fragment; | ||
437 | } | ||
438 | }; | ||
439 | let syn = db.lookup_intern_macro(lazy_id).kind.node(db).value; | ||
440 | |||
441 | let parent = match syn.parent() { | ||
442 | Some(it) => it, | ||
443 | None => return FragmentKind::Statements, | ||
444 | }; | ||
445 | |||
446 | match parent.kind() { | ||
447 | MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, | ||
448 | MACRO_STMTS => FragmentKind::Statements, | ||
449 | MACRO_PAT => FragmentKind::Pattern, | ||
450 | MACRO_TYPE => FragmentKind::Type, | ||
451 | ITEM_LIST => FragmentKind::Items, | ||
452 | LET_STMT => { | ||
453 | // FIXME: Handle LHS Pattern | ||
454 | FragmentKind::Expr | ||
455 | } | 433 | } |
456 | EXPR_STMT => FragmentKind::Statements, | 434 | MacroCallId::EagerMacro(id) => { |
457 | BLOCK_EXPR => FragmentKind::Statements, | 435 | let loc: EagerCallLoc = db.lookup_intern_eager_expansion(id); |
458 | ARG_LIST => FragmentKind::Expr, | 436 | loc.fragment |
459 | TRY_EXPR => FragmentKind::Expr, | ||
460 | TUPLE_EXPR => FragmentKind::Expr, | ||
461 | PAREN_EXPR => FragmentKind::Expr, | ||
462 | ARRAY_EXPR => FragmentKind::Expr, | ||
463 | FOR_EXPR => FragmentKind::Expr, | ||
464 | PATH_EXPR => FragmentKind::Expr, | ||
465 | CLOSURE_EXPR => FragmentKind::Expr, | ||
466 | CONDITION => FragmentKind::Expr, | ||
467 | BREAK_EXPR => FragmentKind::Expr, | ||
468 | RETURN_EXPR => FragmentKind::Expr, | ||
469 | MATCH_EXPR => FragmentKind::Expr, | ||
470 | MATCH_ARM => FragmentKind::Expr, | ||
471 | MATCH_GUARD => FragmentKind::Expr, | ||
472 | RECORD_EXPR_FIELD => FragmentKind::Expr, | ||
473 | CALL_EXPR => FragmentKind::Expr, | ||
474 | INDEX_EXPR => FragmentKind::Expr, | ||
475 | METHOD_CALL_EXPR => FragmentKind::Expr, | ||
476 | FIELD_EXPR => FragmentKind::Expr, | ||
477 | AWAIT_EXPR => FragmentKind::Expr, | ||
478 | CAST_EXPR => FragmentKind::Expr, | ||
479 | REF_EXPR => FragmentKind::Expr, | ||
480 | PREFIX_EXPR => FragmentKind::Expr, | ||
481 | RANGE_EXPR => FragmentKind::Expr, | ||
482 | BIN_EXPR => FragmentKind::Expr, | ||
483 | _ => { | ||
484 | // Unknown , Just guess it is `Items` | ||
485 | FragmentKind::Items | ||
486 | } | 437 | } |
487 | } | 438 | } |
488 | } | 439 | } |
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs index f12132f84..85491fe8b 100644 --- a/crates/hir_expand/src/eager.rs +++ b/crates/hir_expand/src/eager.rs | |||
@@ -175,8 +175,13 @@ fn lazy_expand( | |||
175 | ) -> ExpandResult<Option<InFile<SyntaxNode>>> { | 175 | ) -> ExpandResult<Option<InFile<SyntaxNode>>> { |
176 | let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value); | 176 | let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value); |
177 | 177 | ||
178 | let fragment = crate::to_fragment_kind(¯o_call.value); | ||
178 | let id: MacroCallId = def | 179 | let id: MacroCallId = def |
179 | .as_lazy_macro(db, krate, MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id) }) | 180 | .as_lazy_macro( |
181 | db, | ||
182 | krate, | ||
183 | MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id), fragment }, | ||
184 | ) | ||
180 | .into(); | 185 | .into(); |
181 | 186 | ||
182 | let err = db.macro_expand_error(id); | 187 | let err = db.macro_expand_error(id); |
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 0402640de..80ab3aeee 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -16,7 +16,9 @@ pub mod quote; | |||
16 | pub mod eager; | 16 | pub mod eager; |
17 | 17 | ||
18 | use either::Either; | 18 | use either::Either; |
19 | |||
19 | pub use mbe::{ExpandError, ExpandResult}; | 20 | pub use mbe::{ExpandError, ExpandResult}; |
21 | pub use parser::FragmentKind; | ||
20 | 22 | ||
21 | use std::hash::Hash; | 23 | use std::hash::Hash; |
22 | use std::sync::Arc; | 24 | use std::sync::Arc; |
@@ -290,7 +292,7 @@ pub struct MacroCallLoc { | |||
290 | 292 | ||
291 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 293 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
292 | pub enum MacroCallKind { | 294 | pub enum MacroCallKind { |
293 | FnLike { ast_id: AstId<ast::MacroCall> }, | 295 | FnLike { ast_id: AstId<ast::MacroCall>, fragment: FragmentKind }, |
294 | Derive { ast_id: AstId<ast::Item>, derive_name: String, derive_attr: AttrId }, | 296 | Derive { ast_id: AstId<ast::Item>, derive_name: String, derive_attr: AttrId }, |
295 | } | 297 | } |
296 | 298 | ||
@@ -324,6 +326,13 @@ impl MacroCallKind { | |||
324 | MacroCallKind::Derive { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()), | 326 | MacroCallKind::Derive { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()), |
325 | } | 327 | } |
326 | } | 328 | } |
329 | |||
330 | fn fragment_kind(&self) -> FragmentKind { | ||
331 | match self { | ||
332 | MacroCallKind::FnLike { fragment, .. } => *fragment, | ||
333 | MacroCallKind::Derive { .. } => FragmentKind::Items, | ||
334 | } | ||
335 | } | ||
327 | } | 336 | } |
328 | 337 | ||
329 | impl MacroCallId { | 338 | impl MacroCallId { |
@@ -357,7 +366,6 @@ pub struct ExpansionInfo { | |||
357 | } | 366 | } |
358 | 367 | ||
359 | pub use mbe::Origin; | 368 | pub use mbe::Origin; |
360 | use parser::FragmentKind; | ||
361 | 369 | ||
362 | impl ExpansionInfo { | 370 | impl ExpansionInfo { |
363 | pub fn call_node(&self) -> Option<InFile<SyntaxNode>> { | 371 | pub fn call_node(&self) -> Option<InFile<SyntaxNode>> { |
@@ -562,3 +570,59 @@ impl<N: AstNode> InFile<N> { | |||
562 | self.with_value(self.value.syntax()) | 570 | self.with_value(self.value.syntax()) |
563 | } | 571 | } |
564 | } | 572 | } |
573 | |||
574 | /// Given a `MacroCallId`, return what `FragmentKind` it belongs to. | ||
575 | /// FIXME: Not completed | ||
576 | pub fn to_fragment_kind(call: &ast::MacroCall) -> FragmentKind { | ||
577 | use syntax::SyntaxKind::*; | ||
578 | |||
579 | let syn = call.syntax(); | ||
580 | |||
581 | let parent = match syn.parent() { | ||
582 | Some(it) => it, | ||
583 | None => return FragmentKind::Statements, | ||
584 | }; | ||
585 | |||
586 | match parent.kind() { | ||
587 | MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, | ||
588 | MACRO_STMTS => FragmentKind::Statements, | ||
589 | MACRO_PAT => FragmentKind::Pattern, | ||
590 | MACRO_TYPE => FragmentKind::Type, | ||
591 | ITEM_LIST => FragmentKind::Items, | ||
592 | LET_STMT => { | ||
593 | // FIXME: Handle LHS Pattern | ||
594 | FragmentKind::Expr | ||
595 | } | ||
596 | EXPR_STMT => FragmentKind::Statements, | ||
597 | BLOCK_EXPR => FragmentKind::Statements, | ||
598 | ARG_LIST => FragmentKind::Expr, | ||
599 | TRY_EXPR => FragmentKind::Expr, | ||
600 | TUPLE_EXPR => FragmentKind::Expr, | ||
601 | PAREN_EXPR => FragmentKind::Expr, | ||
602 | ARRAY_EXPR => FragmentKind::Expr, | ||
603 | FOR_EXPR => FragmentKind::Expr, | ||
604 | PATH_EXPR => FragmentKind::Expr, | ||
605 | CLOSURE_EXPR => FragmentKind::Expr, | ||
606 | CONDITION => FragmentKind::Expr, | ||
607 | BREAK_EXPR => FragmentKind::Expr, | ||
608 | RETURN_EXPR => FragmentKind::Expr, | ||
609 | MATCH_EXPR => FragmentKind::Expr, | ||
610 | MATCH_ARM => FragmentKind::Expr, | ||
611 | MATCH_GUARD => FragmentKind::Expr, | ||
612 | RECORD_EXPR_FIELD => FragmentKind::Expr, | ||
613 | CALL_EXPR => FragmentKind::Expr, | ||
614 | INDEX_EXPR => FragmentKind::Expr, | ||
615 | METHOD_CALL_EXPR => FragmentKind::Expr, | ||
616 | FIELD_EXPR => FragmentKind::Expr, | ||
617 | AWAIT_EXPR => FragmentKind::Expr, | ||
618 | CAST_EXPR => FragmentKind::Expr, | ||
619 | REF_EXPR => FragmentKind::Expr, | ||
620 | PREFIX_EXPR => FragmentKind::Expr, | ||
621 | RANGE_EXPR => FragmentKind::Expr, | ||
622 | BIN_EXPR => FragmentKind::Expr, | ||
623 | _ => { | ||
624 | // Unknown , Just guess it is `Items` | ||
625 | FragmentKind::Items | ||
626 | } | ||
627 | } | ||
628 | } | ||
diff --git a/crates/hir_expand/src/quote.rs b/crates/hir_expand/src/quote.rs index c82487ef0..230a59964 100644 --- a/crates/hir_expand/src/quote.rs +++ b/crates/hir_expand/src/quote.rs | |||
@@ -196,8 +196,8 @@ impl_to_to_tokentrees! { | |||
196 | tt::Literal => self { self }; | 196 | tt::Literal => self { self }; |
197 | tt::Ident => self { self }; | 197 | tt::Ident => self { self }; |
198 | tt::Punct => self { self }; | 198 | tt::Punct => self { self }; |
199 | &str => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into(), id: tt::TokenId::unspecified()}}; | 199 | &str => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}}; |
200 | String => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into(), id: tt::TokenId::unspecified()}} | 200 | String => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}} |
201 | } | 201 | } |
202 | 202 | ||
203 | #[cfg(test)] | 203 | #[cfg(test)] |
diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs index 8c4542956..5232a7d80 100644 --- a/crates/hir_ty/src/chalk_ext.rs +++ b/crates/hir_ty/src/chalk_ext.rs | |||
@@ -1,8 +1,10 @@ | |||
1 | //! Various extensions traits for Chalk types. | 1 | //! Various extensions traits for Chalk types. |
2 | 2 | ||
3 | use chalk_ir::Mutability; | 3 | use chalk_ir::{FloatTy, IntTy, Mutability, Scalar, UintTy}; |
4 | use hir_def::{ | 4 | use hir_def::{ |
5 | type_ref::Rawness, AssocContainerId, FunctionId, GenericDefId, HasModule, Lookup, TraitId, | 5 | builtin_type::{BuiltinFloat, BuiltinInt, BuiltinType, BuiltinUint}, |
6 | type_ref::Rawness, | ||
7 | AssocContainerId, FunctionId, GenericDefId, HasModule, Lookup, TraitId, | ||
6 | }; | 8 | }; |
7 | 9 | ||
8 | use crate::{ | 10 | use crate::{ |
@@ -18,6 +20,7 @@ pub trait TyExt { | |||
18 | fn is_unknown(&self) -> bool; | 20 | fn is_unknown(&self) -> bool; |
19 | 21 | ||
20 | fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>; | 22 | fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>; |
23 | fn as_builtin(&self) -> Option<BuiltinType>; | ||
21 | fn as_tuple(&self) -> Option<&Substitution>; | 24 | fn as_tuple(&self) -> Option<&Substitution>; |
22 | fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId>; | 25 | fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId>; |
23 | fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)>; | 26 | fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)>; |
@@ -59,6 +62,35 @@ impl TyExt for Ty { | |||
59 | } | 62 | } |
60 | } | 63 | } |
61 | 64 | ||
65 | fn as_builtin(&self) -> Option<BuiltinType> { | ||
66 | match self.kind(&Interner) { | ||
67 | TyKind::Str => Some(BuiltinType::Str), | ||
68 | TyKind::Scalar(Scalar::Bool) => Some(BuiltinType::Bool), | ||
69 | TyKind::Scalar(Scalar::Char) => Some(BuiltinType::Char), | ||
70 | TyKind::Scalar(Scalar::Float(fty)) => Some(BuiltinType::Float(match fty { | ||
71 | FloatTy::F64 => BuiltinFloat::F64, | ||
72 | FloatTy::F32 => BuiltinFloat::F32, | ||
73 | })), | ||
74 | TyKind::Scalar(Scalar::Int(ity)) => Some(BuiltinType::Int(match ity { | ||
75 | IntTy::Isize => BuiltinInt::Isize, | ||
76 | IntTy::I8 => BuiltinInt::I8, | ||
77 | IntTy::I16 => BuiltinInt::I16, | ||
78 | IntTy::I32 => BuiltinInt::I32, | ||
79 | IntTy::I64 => BuiltinInt::I64, | ||
80 | IntTy::I128 => BuiltinInt::I128, | ||
81 | })), | ||
82 | TyKind::Scalar(Scalar::Uint(ity)) => Some(BuiltinType::Uint(match ity { | ||
83 | UintTy::Usize => BuiltinUint::Usize, | ||
84 | UintTy::U8 => BuiltinUint::U8, | ||
85 | UintTy::U16 => BuiltinUint::U16, | ||
86 | UintTy::U32 => BuiltinUint::U32, | ||
87 | UintTy::U64 => BuiltinUint::U64, | ||
88 | UintTy::U128 => BuiltinUint::U128, | ||
89 | })), | ||
90 | _ => None, | ||
91 | } | ||
92 | } | ||
93 | |||
62 | fn as_tuple(&self) -> Option<&Substitution> { | 94 | fn as_tuple(&self) -> Option<&Substitution> { |
63 | match self.kind(&Interner) { | 95 | match self.kind(&Interner) { |
64 | TyKind::Tuple(_, substs) => Some(substs), | 96 | TyKind::Tuple(_, substs) => Some(substs), |
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index fe2a349e6..61dcbb399 100644 --- a/crates/ide/src/join_lines.rs +++ b/crates/ide/src/join_lines.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | use std::convert::TryFrom; | ||
2 | |||
1 | use ide_assists::utils::extract_trivial_expression; | 3 | use ide_assists::utils::extract_trivial_expression; |
2 | use itertools::Itertools; | 4 | use itertools::Itertools; |
3 | use syntax::{ | 5 | use syntax::{ |
@@ -65,14 +67,6 @@ fn remove_newlines(edit: &mut TextEditBuilder, token: &SyntaxToken, range: TextR | |||
65 | 67 | ||
66 | fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextSize) { | 68 | fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextSize) { |
67 | if token.kind() != WHITESPACE || token.text().bytes().filter(|&b| b == b'\n').count() != 1 { | 69 | if token.kind() != WHITESPACE || token.text().bytes().filter(|&b| b == b'\n').count() != 1 { |
68 | let mut string_open_quote = false; | ||
69 | if let Some(string) = ast::String::cast(token.clone()) { | ||
70 | if let Some(range) = string.open_quote_text_range() { | ||
71 | cov_mark::hit!(join_string_literal); | ||
72 | string_open_quote = range.end() == offset; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | let n_spaces_after_line_break = { | 70 | let n_spaces_after_line_break = { |
77 | let suff = &token.text()[TextRange::new( | 71 | let suff = &token.text()[TextRange::new( |
78 | offset - token.text_range().start() + TextSize::of('\n'), | 72 | offset - token.text_range().start() + TextSize::of('\n'), |
@@ -81,8 +75,23 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextS | |||
81 | suff.bytes().take_while(|&b| b == b' ').count() | 75 | suff.bytes().take_while(|&b| b == b' ').count() |
82 | }; | 76 | }; |
83 | 77 | ||
78 | let mut no_space = false; | ||
79 | if let Some(string) = ast::String::cast(token.clone()) { | ||
80 | if let Some(range) = string.open_quote_text_range() { | ||
81 | cov_mark::hit!(join_string_literal_open_quote); | ||
82 | no_space |= range.end() == offset; | ||
83 | } | ||
84 | if let Some(range) = string.close_quote_text_range() { | ||
85 | cov_mark::hit!(join_string_literal_close_quote); | ||
86 | no_space |= range.start() | ||
87 | == offset | ||
88 | + TextSize::of('\n') | ||
89 | + TextSize::try_from(n_spaces_after_line_break).unwrap(); | ||
90 | } | ||
91 | } | ||
92 | |||
84 | let range = TextRange::at(offset, ((n_spaces_after_line_break + 1) as u32).into()); | 93 | let range = TextRange::at(offset, ((n_spaces_after_line_break + 1) as u32).into()); |
85 | let replace_with = if string_open_quote { "" } else { " " }; | 94 | let replace_with = if no_space { "" } else { " " }; |
86 | edit.replace(range, replace_with.to_string()); | 95 | edit.replace(range, replace_with.to_string()); |
87 | return; | 96 | return; |
88 | } | 97 | } |
@@ -797,22 +806,54 @@ fn foo() { | |||
797 | 806 | ||
798 | #[test] | 807 | #[test] |
799 | fn join_string_literal() { | 808 | fn join_string_literal() { |
800 | cov_mark::check!(join_string_literal); | 809 | { |
801 | check_join_lines( | 810 | cov_mark::check!(join_string_literal_open_quote); |
802 | r#" | 811 | check_join_lines( |
812 | r#" | ||
803 | fn main() { | 813 | fn main() { |
804 | $0" | 814 | $0" |
805 | hello | 815 | hello |
806 | "; | 816 | "; |
807 | } | 817 | } |
808 | "#, | 818 | "#, |
809 | r#" | 819 | r#" |
810 | fn main() { | 820 | fn main() { |
811 | $0"hello | 821 | $0"hello |
812 | "; | 822 | "; |
813 | } | 823 | } |
814 | "#, | 824 | "#, |
815 | ); | 825 | ); |
826 | } | ||
827 | |||
828 | { | ||
829 | cov_mark::check!(join_string_literal_close_quote); | ||
830 | check_join_lines( | ||
831 | r#" | ||
832 | fn main() { | ||
833 | $0"hello | ||
834 | "; | ||
835 | } | ||
836 | "#, | ||
837 | r#" | ||
838 | fn main() { | ||
839 | $0"hello"; | ||
840 | } | ||
841 | "#, | ||
842 | ); | ||
843 | check_join_lines( | ||
844 | r#" | ||
845 | fn main() { | ||
846 | $0r"hello | ||
847 | "; | ||
848 | } | ||
849 | "#, | ||
850 | r#" | ||
851 | fn main() { | ||
852 | $0r"hello"; | ||
853 | } | ||
854 | "#, | ||
855 | ); | ||
856 | } | ||
816 | 857 | ||
817 | check_join_lines( | 858 | check_join_lines( |
818 | r#" | 859 | r#" |
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 11ca7ec6b..ae492a264 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -65,7 +65,7 @@ pub(crate) fn find_all_refs( | |||
65 | (find_def(&sema, &syntax, position)?, false) | 65 | (find_def(&sema, &syntax, position)?, false) |
66 | }; | 66 | }; |
67 | 67 | ||
68 | let mut usages = def.usages(sema).set_scope(search_scope).all(); | 68 | let mut usages = def.usages(sema).set_scope(search_scope).include_self_refs().all(); |
69 | if is_literal_search { | 69 | if is_literal_search { |
70 | // filter for constructor-literals | 70 | // filter for constructor-literals |
71 | let refs = usages.references.values_mut(); | 71 | let refs = usages.references.values_mut(); |
@@ -1163,22 +1163,76 @@ fn foo<const FOO$0: usize>() -> usize { | |||
1163 | } | 1163 | } |
1164 | 1164 | ||
1165 | #[test] | 1165 | #[test] |
1166 | fn test_find_self_ty_in_trait_def() { | 1166 | fn test_trait() { |
1167 | check( | 1167 | check( |
1168 | r#" | 1168 | r#" |
1169 | trait Foo { | 1169 | trait Foo$0 where Self: {} |
1170 | fn f() -> Self$0; | 1170 | |
1171 | impl Foo for () {} | ||
1172 | "#, | ||
1173 | expect![[r#" | ||
1174 | Foo Trait FileId(0) 0..24 6..9 | ||
1175 | |||
1176 | FileId(0) 31..34 | ||
1177 | "#]], | ||
1178 | ); | ||
1179 | } | ||
1180 | |||
1181 | #[test] | ||
1182 | fn test_trait_self() { | ||
1183 | check( | ||
1184 | r#" | ||
1185 | trait Foo where Self$0 { | ||
1186 | fn f() -> Self; | ||
1171 | } | 1187 | } |
1188 | |||
1189 | impl Foo for () {} | ||
1172 | "#, | 1190 | "#, |
1173 | expect![[r#" | 1191 | expect![[r#" |
1174 | Self TypeParam FileId(0) 6..9 6..9 | 1192 | Self TypeParam FileId(0) 6..9 6..9 |
1175 | 1193 | ||
1176 | FileId(0) 26..30 | 1194 | FileId(0) 16..20 |
1195 | FileId(0) 37..41 | ||
1177 | "#]], | 1196 | "#]], |
1178 | ); | 1197 | ); |
1179 | } | 1198 | } |
1180 | 1199 | ||
1181 | #[test] | 1200 | #[test] |
1201 | fn test_self_ty() { | ||
1202 | check( | ||
1203 | r#" | ||
1204 | struct $0Foo; | ||
1205 | |||
1206 | impl Foo where Self: { | ||
1207 | fn f() -> Self; | ||
1208 | } | ||
1209 | "#, | ||
1210 | expect![[r#" | ||
1211 | Foo Struct FileId(0) 0..11 7..10 | ||
1212 | |||
1213 | FileId(0) 18..21 | ||
1214 | FileId(0) 28..32 | ||
1215 | FileId(0) 50..54 | ||
1216 | "#]], | ||
1217 | ); | ||
1218 | check( | ||
1219 | r#" | ||
1220 | struct Foo; | ||
1221 | |||
1222 | impl Foo where Self: { | ||
1223 | fn f() -> Self$0; | ||
1224 | } | ||
1225 | "#, | ||
1226 | expect![[r#" | ||
1227 | impl Impl FileId(0) 13..57 18..21 | ||
1228 | |||
1229 | FileId(0) 18..21 | ||
1230 | FileId(0) 28..32 | ||
1231 | FileId(0) 50..54 | ||
1232 | "#]], | ||
1233 | ); | ||
1234 | } | ||
1235 | #[test] | ||
1182 | fn test_self_variant_with_payload() { | 1236 | fn test_self_variant_with_payload() { |
1183 | check( | 1237 | check( |
1184 | r#" | 1238 | r#" |
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs index 175e7a31d..2bf953305 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/references/rename.rs | |||
@@ -1888,4 +1888,21 @@ impl Foo { | |||
1888 | "error: Cannot rename `Self`", | 1888 | "error: Cannot rename `Self`", |
1889 | ); | 1889 | ); |
1890 | } | 1890 | } |
1891 | |||
1892 | #[test] | ||
1893 | fn test_rename_ignores_self_ty() { | ||
1894 | check( | ||
1895 | "Fo0", | ||
1896 | r#" | ||
1897 | struct $0Foo; | ||
1898 | |||
1899 | impl Foo where Self: {} | ||
1900 | "#, | ||
1901 | r#" | ||
1902 | struct Fo0; | ||
1903 | |||
1904 | impl Fo0 where Self: {} | ||
1905 | "#, | ||
1906 | ); | ||
1907 | } | ||
1891 | } | 1908 | } |
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs index 82c732390..4ad49eca0 100644 --- a/crates/ide/src/typing.rs +++ b/crates/ide/src/typing.rs | |||
@@ -88,7 +88,7 @@ fn on_char_typed_inner( | |||
88 | } | 88 | } |
89 | 89 | ||
90 | /// Inserts a closing `}` when the user types an opening `{`, wrapping an existing expression in a | 90 | /// Inserts a closing `}` when the user types an opening `{`, wrapping an existing expression in a |
91 | /// block. | 91 | /// block, or a part of a `use` item. |
92 | fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<TextEdit> { | 92 | fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<TextEdit> { |
93 | if !stdx::always!(file.tree().syntax().text().char_at(offset) == Some('{')) { | 93 | if !stdx::always!(file.tree().syntax().text().char_at(offset) == Some('{')) { |
94 | return None; | 94 | return None; |
@@ -99,30 +99,59 @@ fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option< | |||
99 | // Remove the `{` to get a better parse tree, and reparse | 99 | // Remove the `{` to get a better parse tree, and reparse |
100 | let file = file.reparse(&Indel::delete(brace_token.text_range())); | 100 | let file = file.reparse(&Indel::delete(brace_token.text_range())); |
101 | 101 | ||
102 | let mut expr: ast::Expr = find_node_at_offset(file.tree().syntax(), offset)?; | 102 | if let Some(edit) = brace_expr(&file.tree(), offset) { |
103 | if expr.syntax().text_range().start() != offset { | 103 | return Some(edit); |
104 | return None; | ||
105 | } | 104 | } |
106 | 105 | ||
107 | // Enclose the outermost expression starting at `offset` | 106 | if let Some(edit) = brace_use_path(&file.tree(), offset) { |
108 | while let Some(parent) = expr.syntax().parent() { | 107 | return Some(edit); |
109 | if parent.text_range().start() != expr.syntax().text_range().start() { | 108 | } |
110 | break; | ||
111 | } | ||
112 | 109 | ||
113 | match ast::Expr::cast(parent) { | 110 | return None; |
114 | Some(parent) => expr = parent, | 111 | |
115 | None => break, | 112 | fn brace_use_path(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { |
113 | let segment: ast::PathSegment = find_node_at_offset(file.syntax(), offset)?; | ||
114 | if segment.syntax().text_range().start() != offset { | ||
115 | return None; | ||
116 | } | 116 | } |
117 | } | ||
118 | 117 | ||
119 | // If it's a statement in a block, we don't know how many statements should be included | 118 | let tree: ast::UseTree = find_node_at_offset(file.syntax(), offset)?; |
120 | if ast::ExprStmt::can_cast(expr.syntax().parent()?.kind()) { | 119 | |
121 | return None; | 120 | Some(TextEdit::insert( |
121 | tree.syntax().text_range().end() + TextSize::of("{"), | ||
122 | "}".to_string(), | ||
123 | )) | ||
122 | } | 124 | } |
123 | 125 | ||
124 | // Insert `}` right after the expression. | 126 | fn brace_expr(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { |
125 | Some(TextEdit::insert(expr.syntax().text_range().end() + TextSize::of("{"), "}".to_string())) | 127 | let mut expr: ast::Expr = find_node_at_offset(file.syntax(), offset)?; |
128 | if expr.syntax().text_range().start() != offset { | ||
129 | return None; | ||
130 | } | ||
131 | |||
132 | // Enclose the outermost expression starting at `offset` | ||
133 | while let Some(parent) = expr.syntax().parent() { | ||
134 | if parent.text_range().start() != expr.syntax().text_range().start() { | ||
135 | break; | ||
136 | } | ||
137 | |||
138 | match ast::Expr::cast(parent) { | ||
139 | Some(parent) => expr = parent, | ||
140 | None => break, | ||
141 | } | ||
142 | } | ||
143 | |||
144 | // If it's a statement in a block, we don't know how many statements should be included | ||
145 | if ast::ExprStmt::can_cast(expr.syntax().parent()?.kind()) { | ||
146 | return None; | ||
147 | } | ||
148 | |||
149 | // Insert `}` right after the expression. | ||
150 | Some(TextEdit::insert( | ||
151 | expr.syntax().text_range().end() + TextSize::of("{"), | ||
152 | "}".to_string(), | ||
153 | )) | ||
154 | } | ||
126 | } | 155 | } |
127 | 156 | ||
128 | /// Returns an edit which should be applied after `=` was typed. Primarily, | 157 | /// Returns an edit which should be applied after `=` was typed. Primarily, |
@@ -440,7 +469,7 @@ fn foo() -> { 92 } | |||
440 | } | 469 | } |
441 | 470 | ||
442 | #[test] | 471 | #[test] |
443 | fn adds_closing_brace() { | 472 | fn adds_closing_brace_for_expr() { |
444 | type_char( | 473 | type_char( |
445 | '{', | 474 | '{', |
446 | r#" | 475 | r#" |
@@ -519,4 +548,87 @@ fn f() { | |||
519 | "#, | 548 | "#, |
520 | ); | 549 | ); |
521 | } | 550 | } |
551 | |||
552 | #[test] | ||
553 | fn adds_closing_brace_for_use_tree() { | ||
554 | type_char( | ||
555 | '{', | ||
556 | r#" | ||
557 | use some::$0Path; | ||
558 | "#, | ||
559 | r#" | ||
560 | use some::{Path}; | ||
561 | "#, | ||
562 | ); | ||
563 | type_char( | ||
564 | '{', | ||
565 | r#" | ||
566 | use some::{Path, $0Other}; | ||
567 | "#, | ||
568 | r#" | ||
569 | use some::{Path, {Other}}; | ||
570 | "#, | ||
571 | ); | ||
572 | type_char( | ||
573 | '{', | ||
574 | r#" | ||
575 | use some::{$0Path, Other}; | ||
576 | "#, | ||
577 | r#" | ||
578 | use some::{{Path}, Other}; | ||
579 | "#, | ||
580 | ); | ||
581 | type_char( | ||
582 | '{', | ||
583 | r#" | ||
584 | use some::path::$0to::Item; | ||
585 | "#, | ||
586 | r#" | ||
587 | use some::path::{to::Item}; | ||
588 | "#, | ||
589 | ); | ||
590 | type_char( | ||
591 | '{', | ||
592 | r#" | ||
593 | use some::$0path::to::Item; | ||
594 | "#, | ||
595 | r#" | ||
596 | use some::{path::to::Item}; | ||
597 | "#, | ||
598 | ); | ||
599 | type_char( | ||
600 | '{', | ||
601 | r#" | ||
602 | use $0some::path::to::Item; | ||
603 | "#, | ||
604 | r#" | ||
605 | use {some::path::to::Item}; | ||
606 | "#, | ||
607 | ); | ||
608 | type_char( | ||
609 | '{', | ||
610 | r#" | ||
611 | use some::path::$0to::{Item}; | ||
612 | "#, | ||
613 | r#" | ||
614 | use some::path::{to::{Item}}; | ||
615 | "#, | ||
616 | ); | ||
617 | type_char( | ||
618 | '{', | ||
619 | r#" | ||
620 | use $0Thing as _; | ||
621 | "#, | ||
622 | r#" | ||
623 | use {Thing as _}; | ||
624 | "#, | ||
625 | ); | ||
626 | |||
627 | type_char_noop( | ||
628 | '{', | ||
629 | r#" | ||
630 | use some::pa$0th::to::Item; | ||
631 | "#, | ||
632 | ); | ||
633 | } | ||
522 | } | 634 | } |
diff --git a/crates/ide/src/typing/on_enter.rs b/crates/ide/src/typing/on_enter.rs index 7d2db201a..81c4d95b1 100644 --- a/crates/ide/src/typing/on_enter.rs +++ b/crates/ide/src/typing/on_enter.rs | |||
@@ -54,6 +54,14 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Text | |||
54 | cov_mark::hit!(indent_block_contents); | 54 | cov_mark::hit!(indent_block_contents); |
55 | return Some(edit); | 55 | return Some(edit); |
56 | } | 56 | } |
57 | |||
58 | // Typing enter after the `{` of a use tree list. | ||
59 | if let Some(edit) = find_node_at_offset(file.syntax(), position.offset - TextSize::of('{')) | ||
60 | .and_then(|list| on_enter_in_use_tree_list(list, position)) | ||
61 | { | ||
62 | cov_mark::hit!(indent_block_contents); | ||
63 | return Some(edit); | ||
64 | } | ||
57 | } | 65 | } |
58 | 66 | ||
59 | None | 67 | None |
@@ -111,6 +119,21 @@ fn on_enter_in_block(block: ast::BlockExpr, position: FilePosition) -> Option<Te | |||
111 | Some(edit) | 119 | Some(edit) |
112 | } | 120 | } |
113 | 121 | ||
122 | fn on_enter_in_use_tree_list(list: ast::UseTreeList, position: FilePosition) -> Option<TextEdit> { | ||
123 | if list.syntax().text().contains_char('\n') { | ||
124 | return None; | ||
125 | } | ||
126 | |||
127 | let indent = IndentLevel::from_node(list.syntax()); | ||
128 | let mut edit = TextEdit::insert(position.offset, format!("\n{}$0", indent + 1)); | ||
129 | edit.union(TextEdit::insert( | ||
130 | list.r_curly_token()?.text_range().start(), | ||
131 | format!("\n{}", indent), | ||
132 | )) | ||
133 | .ok()?; | ||
134 | Some(edit) | ||
135 | } | ||
136 | |||
114 | fn block_contents(block: &ast::BlockExpr) -> Option<SyntaxNode> { | 137 | fn block_contents(block: &ast::BlockExpr) -> Option<SyntaxNode> { |
115 | let mut node = block.tail_expr().map(|e| e.syntax().clone()); | 138 | let mut node = block.tail_expr().map(|e| e.syntax().clone()); |
116 | 139 | ||
@@ -484,4 +507,96 @@ fn f() {$0 | |||
484 | "#, | 507 | "#, |
485 | ); | 508 | ); |
486 | } | 509 | } |
510 | |||
511 | #[test] | ||
512 | fn indents_use_tree_list() { | ||
513 | do_check( | ||
514 | r#" | ||
515 | use crate::{$0}; | ||
516 | "#, | ||
517 | r#" | ||
518 | use crate::{ | ||
519 | $0 | ||
520 | }; | ||
521 | "#, | ||
522 | ); | ||
523 | do_check( | ||
524 | r#" | ||
525 | use crate::{$0Object, path::to::OtherThing}; | ||
526 | "#, | ||
527 | r#" | ||
528 | use crate::{ | ||
529 | $0Object, path::to::OtherThing | ||
530 | }; | ||
531 | "#, | ||
532 | ); | ||
533 | do_check( | ||
534 | r#" | ||
535 | use {crate::{$0Object, path::to::OtherThing}}; | ||
536 | "#, | ||
537 | r#" | ||
538 | use {crate::{ | ||
539 | $0Object, path::to::OtherThing | ||
540 | }}; | ||
541 | "#, | ||
542 | ); | ||
543 | do_check( | ||
544 | r#" | ||
545 | use { | ||
546 | crate::{$0Object, path::to::OtherThing} | ||
547 | }; | ||
548 | "#, | ||
549 | r#" | ||
550 | use { | ||
551 | crate::{ | ||
552 | $0Object, path::to::OtherThing | ||
553 | } | ||
554 | }; | ||
555 | "#, | ||
556 | ); | ||
557 | } | ||
558 | |||
559 | #[test] | ||
560 | fn does_not_indent_use_tree_list_when_not_at_curly_brace() { | ||
561 | do_check_noop( | ||
562 | r#" | ||
563 | use path::{Thing$0}; | ||
564 | "#, | ||
565 | ); | ||
566 | } | ||
567 | |||
568 | #[test] | ||
569 | fn does_not_indent_use_tree_list_without_curly_braces() { | ||
570 | do_check_noop( | ||
571 | r#" | ||
572 | use path::Thing$0; | ||
573 | "#, | ||
574 | ); | ||
575 | do_check_noop( | ||
576 | r#" | ||
577 | use path::$0Thing; | ||
578 | "#, | ||
579 | ); | ||
580 | do_check_noop( | ||
581 | r#" | ||
582 | use path::Thing$0}; | ||
583 | "#, | ||
584 | ); | ||
585 | do_check_noop( | ||
586 | r#" | ||
587 | use path::{$0Thing; | ||
588 | "#, | ||
589 | ); | ||
590 | } | ||
591 | |||
592 | #[test] | ||
593 | fn does_not_indent_multiline_use_tree_list() { | ||
594 | do_check_noop( | ||
595 | r#" | ||
596 | use path::{$0 | ||
597 | Thing | ||
598 | }; | ||
599 | "#, | ||
600 | ); | ||
601 | } | ||
487 | } | 602 | } |
diff --git a/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs index b5b5ada5e..70949ca35 100644 --- a/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs +++ b/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs | |||
@@ -107,7 +107,7 @@ fn edit_struct_references( | |||
107 | names: &[ast::Name], | 107 | names: &[ast::Name], |
108 | ) { | 108 | ) { |
109 | let strukt_def = Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(strukt))); | 109 | let strukt_def = Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(strukt))); |
110 | let usages = strukt_def.usages(&ctx.sema).include_self_kw_refs(true).all(); | 110 | let usages = strukt_def.usages(&ctx.sema).include_self_refs().all(); |
111 | 111 | ||
112 | let edit_node = |edit: &mut AssistBuilder, node: SyntaxNode| -> Option<()> { | 112 | let edit_node = |edit: &mut AssistBuilder, node: SyntaxNode| -> Option<()> { |
113 | match_ast! { | 113 | match_ast! { |
diff --git a/crates/ide_assists/src/handlers/early_return.rs b/crates/ide_assists/src/handlers/early_return.rs index c66f8c05d..5eb6a57f0 100644 --- a/crates/ide_assists/src/handlers/early_return.rs +++ b/crates/ide_assists/src/handlers/early_return.rs | |||
@@ -130,9 +130,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) | |||
130 | once(make::ident_pat(make::name("it")).into()), | 130 | once(make::ident_pat(make::name("it")).into()), |
131 | ); | 131 | ); |
132 | let expr = { | 132 | let expr = { |
133 | let name_ref = make::name_ref("it"); | 133 | let path = make::ext::ident_path("it"); |
134 | let segment = make::path_segment(name_ref); | ||
135 | let path = make::path_unqualified(segment); | ||
136 | make::expr_path(path) | 134 | make::expr_path(path) |
137 | }; | 135 | }; |
138 | make::match_arm(once(pat.into()), expr) | 136 | make::match_arm(once(pat.into()), expr) |
diff --git a/crates/ide_assists/src/handlers/expand_glob_import.rs b/crates/ide_assists/src/handlers/expand_glob_import.rs index e3095f26b..da8d245e5 100644 --- a/crates/ide_assists/src/handlers/expand_glob_import.rs +++ b/crates/ide_assists/src/handlers/expand_glob_import.rs | |||
@@ -65,8 +65,7 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
65 | 65 | ||
66 | let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs); | 66 | let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs); |
67 | let expanded = make::use_tree_list(names_to_import.iter().map(|n| { | 67 | let expanded = make::use_tree_list(names_to_import.iter().map(|n| { |
68 | let path = | 68 | let path = make::ext::ident_path(&n.to_string()); |
69 | make::path_unqualified(make::path_segment(make::name_ref(&n.to_string()))); | ||
70 | make::use_tree(path, None, None, false) | 69 | make::use_tree(path, None, None, false) |
71 | })) | 70 | })) |
72 | .clone_for_update(); | 71 | .clone_for_update(); |
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs index 4116985ae..6311afc1f 100644 --- a/crates/ide_assists/src/handlers/extract_function.rs +++ b/crates/ide_assists/src/handlers/extract_function.rs | |||
@@ -956,10 +956,10 @@ fn format_replacement(ctx: &AssistContext, fun: &Function, indent: IndentLevel) | |||
956 | let args = fun.params.iter().map(|param| param.to_arg(ctx)); | 956 | let args = fun.params.iter().map(|param| param.to_arg(ctx)); |
957 | let args = make::arg_list(args); | 957 | let args = make::arg_list(args); |
958 | let call_expr = if fun.self_param.is_some() { | 958 | let call_expr = if fun.self_param.is_some() { |
959 | let self_arg = make::expr_path(make_path_from_text("self")); | 959 | let self_arg = make::expr_path(make::ext::ident_path("self")); |
960 | make::expr_method_call(self_arg, &fun.name, args) | 960 | make::expr_method_call(self_arg, &fun.name, args) |
961 | } else { | 961 | } else { |
962 | let func = make::expr_path(make_path_from_text(&fun.name)); | 962 | let func = make::expr_path(make::ext::ident_path(&fun.name)); |
963 | make::expr_call(func, args) | 963 | make::expr_call(func, args) |
964 | }; | 964 | }; |
965 | 965 | ||
@@ -1054,11 +1054,11 @@ impl FlowHandler { | |||
1054 | make::expr_if(condition, block, None) | 1054 | make::expr_if(condition, block, None) |
1055 | } | 1055 | } |
1056 | FlowHandler::IfOption { action } => { | 1056 | FlowHandler::IfOption { action } => { |
1057 | let path = make_path_from_text("Some"); | 1057 | let path = make::ext::ident_path("Some"); |
1058 | let value_pat = make::ident_pat(make::name("value")); | 1058 | let value_pat = make::ident_pat(make::name("value")); |
1059 | let pattern = make::tuple_struct_pat(path, iter::once(value_pat.into())); | 1059 | let pattern = make::tuple_struct_pat(path, iter::once(value_pat.into())); |
1060 | let cond = make::condition(call_expr, Some(pattern.into())); | 1060 | let cond = make::condition(call_expr, Some(pattern.into())); |
1061 | let value = make::expr_path(make_path_from_text("value")); | 1061 | let value = make::expr_path(make::ext::ident_path("value")); |
1062 | let action_expr = action.make_result_handler(Some(value)); | 1062 | let action_expr = action.make_result_handler(Some(value)); |
1063 | let action_stmt = make::expr_stmt(action_expr); | 1063 | let action_stmt = make::expr_stmt(action_expr); |
1064 | let then = make::block_expr(iter::once(action_stmt.into()), None); | 1064 | let then = make::block_expr(iter::once(action_stmt.into()), None); |
@@ -1068,14 +1068,14 @@ impl FlowHandler { | |||
1068 | let some_name = "value"; | 1068 | let some_name = "value"; |
1069 | 1069 | ||
1070 | let some_arm = { | 1070 | let some_arm = { |
1071 | let path = make_path_from_text("Some"); | 1071 | let path = make::ext::ident_path("Some"); |
1072 | let value_pat = make::ident_pat(make::name(some_name)); | 1072 | let value_pat = make::ident_pat(make::name(some_name)); |
1073 | let pat = make::tuple_struct_pat(path, iter::once(value_pat.into())); | 1073 | let pat = make::tuple_struct_pat(path, iter::once(value_pat.into())); |
1074 | let value = make::expr_path(make_path_from_text(some_name)); | 1074 | let value = make::expr_path(make::ext::ident_path(some_name)); |
1075 | make::match_arm(iter::once(pat.into()), value) | 1075 | make::match_arm(iter::once(pat.into()), value) |
1076 | }; | 1076 | }; |
1077 | let none_arm = { | 1077 | let none_arm = { |
1078 | let path = make_path_from_text("None"); | 1078 | let path = make::ext::ident_path("None"); |
1079 | let pat = make::path_pat(path); | 1079 | let pat = make::path_pat(path); |
1080 | make::match_arm(iter::once(pat), none.make_result_handler(None)) | 1080 | make::match_arm(iter::once(pat), none.make_result_handler(None)) |
1081 | }; | 1081 | }; |
@@ -1087,17 +1087,17 @@ impl FlowHandler { | |||
1087 | let err_name = "value"; | 1087 | let err_name = "value"; |
1088 | 1088 | ||
1089 | let ok_arm = { | 1089 | let ok_arm = { |
1090 | let path = make_path_from_text("Ok"); | 1090 | let path = make::ext::ident_path("Ok"); |
1091 | let value_pat = make::ident_pat(make::name(ok_name)); | 1091 | let value_pat = make::ident_pat(make::name(ok_name)); |
1092 | let pat = make::tuple_struct_pat(path, iter::once(value_pat.into())); | 1092 | let pat = make::tuple_struct_pat(path, iter::once(value_pat.into())); |
1093 | let value = make::expr_path(make_path_from_text(ok_name)); | 1093 | let value = make::expr_path(make::ext::ident_path(ok_name)); |
1094 | make::match_arm(iter::once(pat.into()), value) | 1094 | make::match_arm(iter::once(pat.into()), value) |
1095 | }; | 1095 | }; |
1096 | let err_arm = { | 1096 | let err_arm = { |
1097 | let path = make_path_from_text("Err"); | 1097 | let path = make::ext::ident_path("Err"); |
1098 | let value_pat = make::ident_pat(make::name(err_name)); | 1098 | let value_pat = make::ident_pat(make::name(err_name)); |
1099 | let pat = make::tuple_struct_pat(path, iter::once(value_pat.into())); | 1099 | let pat = make::tuple_struct_pat(path, iter::once(value_pat.into())); |
1100 | let value = make::expr_path(make_path_from_text(err_name)); | 1100 | let value = make::expr_path(make::ext::ident_path(err_name)); |
1101 | make::match_arm(iter::once(pat.into()), err.make_result_handler(Some(value))) | 1101 | make::match_arm(iter::once(pat.into()), err.make_result_handler(Some(value))) |
1102 | }; | 1102 | }; |
1103 | let arms = make::match_arm_list(vec![ok_arm, err_arm]); | 1103 | let arms = make::match_arm_list(vec![ok_arm, err_arm]); |
@@ -1107,13 +1107,9 @@ impl FlowHandler { | |||
1107 | } | 1107 | } |
1108 | } | 1108 | } |
1109 | 1109 | ||
1110 | fn make_path_from_text(text: &str) -> ast::Path { | ||
1111 | make::path_unqualified(make::path_segment(make::name_ref(text))) | ||
1112 | } | ||
1113 | |||
1114 | fn path_expr_from_local(ctx: &AssistContext, var: Local) -> ast::Expr { | 1110 | fn path_expr_from_local(ctx: &AssistContext, var: Local) -> ast::Expr { |
1115 | let name = var.name(ctx.db()).unwrap().to_string(); | 1111 | let name = var.name(ctx.db()).unwrap().to_string(); |
1116 | make::expr_path(make_path_from_text(&name)) | 1112 | make::expr_path(make::ext::ident_path(&name)) |
1117 | } | 1113 | } |
1118 | 1114 | ||
1119 | fn format_function( | 1115 | fn format_function( |
@@ -1179,7 +1175,7 @@ fn make_ret_ty(ctx: &AssistContext, module: hir::Module, fun: &Function) -> Opti | |||
1179 | fun_ty.make_ty(ctx, module) | 1175 | fun_ty.make_ty(ctx, module) |
1180 | } | 1176 | } |
1181 | FlowHandler::Try { kind: TryKind::Option } => { | 1177 | FlowHandler::Try { kind: TryKind::Option } => { |
1182 | make::ty_generic(make::name_ref("Option"), iter::once(fun_ty.make_ty(ctx, module))) | 1178 | make::ext::ty_option(fun_ty.make_ty(ctx, module)) |
1183 | } | 1179 | } |
1184 | FlowHandler::Try { kind: TryKind::Result { ty: parent_ret_ty } } => { | 1180 | FlowHandler::Try { kind: TryKind::Result { ty: parent_ret_ty } } => { |
1185 | let handler_ty = parent_ret_ty | 1181 | let handler_ty = parent_ret_ty |
@@ -1187,29 +1183,21 @@ fn make_ret_ty(ctx: &AssistContext, module: hir::Module, fun: &Function) -> Opti | |||
1187 | .nth(1) | 1183 | .nth(1) |
1188 | .map(|ty| make_ty(&ty, ctx, module)) | 1184 | .map(|ty| make_ty(&ty, ctx, module)) |
1189 | .unwrap_or_else(make::ty_unit); | 1185 | .unwrap_or_else(make::ty_unit); |
1190 | make::ty_generic( | 1186 | make::ext::ty_result(fun_ty.make_ty(ctx, module), handler_ty) |
1191 | make::name_ref("Result"), | ||
1192 | vec![fun_ty.make_ty(ctx, module), handler_ty], | ||
1193 | ) | ||
1194 | } | 1187 | } |
1195 | FlowHandler::If { .. } => make::ty("bool"), | 1188 | FlowHandler::If { .. } => make::ext::ty_bool(), |
1196 | FlowHandler::IfOption { action } => { | 1189 | FlowHandler::IfOption { action } => { |
1197 | let handler_ty = action | 1190 | let handler_ty = action |
1198 | .expr_ty(ctx) | 1191 | .expr_ty(ctx) |
1199 | .map(|ty| make_ty(&ty, ctx, module)) | 1192 | .map(|ty| make_ty(&ty, ctx, module)) |
1200 | .unwrap_or_else(make::ty_unit); | 1193 | .unwrap_or_else(make::ty_unit); |
1201 | make::ty_generic(make::name_ref("Option"), iter::once(handler_ty)) | 1194 | make::ext::ty_option(handler_ty) |
1202 | } | ||
1203 | FlowHandler::MatchOption { .. } => { | ||
1204 | make::ty_generic(make::name_ref("Option"), iter::once(fun_ty.make_ty(ctx, module))) | ||
1205 | } | 1195 | } |
1196 | FlowHandler::MatchOption { .. } => make::ext::ty_option(fun_ty.make_ty(ctx, module)), | ||
1206 | FlowHandler::MatchResult { err } => { | 1197 | FlowHandler::MatchResult { err } => { |
1207 | let handler_ty = | 1198 | let handler_ty = |
1208 | err.expr_ty(ctx).map(|ty| make_ty(&ty, ctx, module)).unwrap_or_else(make::ty_unit); | 1199 | err.expr_ty(ctx).map(|ty| make_ty(&ty, ctx, module)).unwrap_or_else(make::ty_unit); |
1209 | make::ty_generic( | 1200 | make::ext::ty_result(fun_ty.make_ty(ctx, module), handler_ty) |
1210 | make::name_ref("Result"), | ||
1211 | vec![fun_ty.make_ty(ctx, module), handler_ty], | ||
1212 | ) | ||
1213 | } | 1201 | } |
1214 | }; | 1202 | }; |
1215 | Some(make::ret_type(ret_ty)) | 1203 | Some(make::ret_type(ret_ty)) |
@@ -1296,7 +1284,7 @@ fn make_body( | |||
1296 | TryKind::Option => "Some", | 1284 | TryKind::Option => "Some", |
1297 | TryKind::Result { .. } => "Ok", | 1285 | TryKind::Result { .. } => "Ok", |
1298 | }; | 1286 | }; |
1299 | let func = make::expr_path(make_path_from_text(constructor)); | 1287 | let func = make::expr_path(make::ext::ident_path(constructor)); |
1300 | let args = make::arg_list(iter::once(tail_expr)); | 1288 | let args = make::arg_list(iter::once(tail_expr)); |
1301 | make::expr_call(func, args) | 1289 | make::expr_call(func, args) |
1302 | }) | 1290 | }) |
@@ -1306,16 +1294,16 @@ fn make_body( | |||
1306 | with_tail_expr(block, lit_false.into()) | 1294 | with_tail_expr(block, lit_false.into()) |
1307 | } | 1295 | } |
1308 | FlowHandler::IfOption { .. } => { | 1296 | FlowHandler::IfOption { .. } => { |
1309 | let none = make::expr_path(make_path_from_text("None")); | 1297 | let none = make::expr_path(make::ext::ident_path("None")); |
1310 | with_tail_expr(block, none) | 1298 | with_tail_expr(block, none) |
1311 | } | 1299 | } |
1312 | FlowHandler::MatchOption { .. } => map_tail_expr(block, |tail_expr| { | 1300 | FlowHandler::MatchOption { .. } => map_tail_expr(block, |tail_expr| { |
1313 | let some = make::expr_path(make_path_from_text("Some")); | 1301 | let some = make::expr_path(make::ext::ident_path("Some")); |
1314 | let args = make::arg_list(iter::once(tail_expr)); | 1302 | let args = make::arg_list(iter::once(tail_expr)); |
1315 | make::expr_call(some, args) | 1303 | make::expr_call(some, args) |
1316 | }), | 1304 | }), |
1317 | FlowHandler::MatchResult { .. } => map_tail_expr(block, |tail_expr| { | 1305 | FlowHandler::MatchResult { .. } => map_tail_expr(block, |tail_expr| { |
1318 | let ok = make::expr_path(make_path_from_text("Ok")); | 1306 | let ok = make::expr_path(make::ext::ident_path("Ok")); |
1319 | let args = make::arg_list(iter::once(tail_expr)); | 1307 | let args = make::arg_list(iter::once(tail_expr)); |
1320 | make::expr_call(ok, args) | 1308 | make::expr_call(ok, args) |
1321 | }), | 1309 | }), |
@@ -1483,13 +1471,13 @@ fn make_rewritten_flow(handler: &FlowHandler, arg_expr: Option<ast::Expr>) -> Op | |||
1483 | FlowHandler::IfOption { .. } => { | 1471 | FlowHandler::IfOption { .. } => { |
1484 | let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new())); | 1472 | let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new())); |
1485 | let args = make::arg_list(iter::once(expr)); | 1473 | let args = make::arg_list(iter::once(expr)); |
1486 | make::expr_call(make::expr_path(make_path_from_text("Some")), args) | 1474 | make::expr_call(make::expr_path(make::ext::ident_path("Some")), args) |
1487 | } | 1475 | } |
1488 | FlowHandler::MatchOption { .. } => make::expr_path(make_path_from_text("None")), | 1476 | FlowHandler::MatchOption { .. } => make::expr_path(make::ext::ident_path("None")), |
1489 | FlowHandler::MatchResult { .. } => { | 1477 | FlowHandler::MatchResult { .. } => { |
1490 | let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new())); | 1478 | let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new())); |
1491 | let args = make::arg_list(iter::once(expr)); | 1479 | let args = make::arg_list(iter::once(expr)); |
1492 | make::expr_call(make::expr_path(make_path_from_text("Err")), args) | 1480 | make::expr_call(make::expr_path(make::ext::ident_path("Err")), args) |
1493 | } | 1481 | } |
1494 | }; | 1482 | }; |
1495 | Some(make::expr_return(Some(value)).clone_for_update()) | 1483 | Some(make::expr_return(Some(value)).clone_for_update()) |
diff --git a/crates/ide_assists/src/handlers/extract_variable.rs b/crates/ide_assists/src/handlers/extract_variable.rs index 136b9a55b..ae084c86c 100644 --- a/crates/ide_assists/src/handlers/extract_variable.rs +++ b/crates/ide_assists/src/handlers/extract_variable.rs | |||
@@ -54,7 +54,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
54 | 54 | ||
55 | let var_name = match &field_shorthand { | 55 | let var_name = match &field_shorthand { |
56 | Some(it) => it.to_string(), | 56 | Some(it) => it.to_string(), |
57 | None => suggest_name::variable(&to_extract, &ctx.sema), | 57 | None => suggest_name::for_variable(&to_extract, &ctx.sema), |
58 | }; | 58 | }; |
59 | let expr_range = match &field_shorthand { | 59 | let expr_range = match &field_shorthand { |
60 | Some(it) => it.syntax().text_range().cover(to_extract.syntax().text_range()), | 60 | Some(it) => it.syntax().text_range().cover(to_extract.syntax().text_range()), |
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs index 6f95b1a07..bc9fc524b 100644 --- a/crates/ide_assists/src/handlers/generate_function.rs +++ b/crates/ide_assists/src/handlers/generate_function.rs | |||
@@ -175,7 +175,7 @@ impl FunctionBuilder { | |||
175 | } | 175 | } |
176 | 176 | ||
177 | fn render(self) -> FunctionTemplate { | 177 | fn render(self) -> FunctionTemplate { |
178 | let placeholder_expr = make::expr_todo(); | 178 | let placeholder_expr = make::ext::expr_todo(); |
179 | let fn_body = make::block_expr(vec![], Some(placeholder_expr)); | 179 | let fn_body = make::block_expr(vec![], Some(placeholder_expr)); |
180 | let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None }; | 180 | let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None }; |
181 | let mut fn_def = make::fn_( | 181 | let mut fn_def = make::fn_( |
diff --git a/crates/ide_assists/src/handlers/introduce_named_lifetime.rs b/crates/ide_assists/src/handlers/introduce_named_lifetime.rs index 9f4f71d6c..68bc15120 100644 --- a/crates/ide_assists/src/handlers/introduce_named_lifetime.rs +++ b/crates/ide_assists/src/handlers/introduce_named_lifetime.rs | |||
@@ -89,14 +89,12 @@ fn generate_fn_def_assist( | |||
89 | let loc_needing_lifetime = | 89 | let loc_needing_lifetime = |
90 | loc_needing_lifetime.and_then(|it| it.make_mut(builder).to_position()); | 90 | loc_needing_lifetime.and_then(|it| it.make_mut(builder).to_position()); |
91 | 91 | ||
92 | add_lifetime_param(fn_def.get_or_create_generic_param_list(), new_lifetime_param); | 92 | fn_def.get_or_create_generic_param_list().add_generic_param( |
93 | ted::replace( | 93 | make::lifetime_param(new_lifetime_param.clone()).clone_for_update().into(), |
94 | lifetime.syntax(), | ||
95 | make_ast_lifetime(new_lifetime_param).clone_for_update().syntax(), | ||
96 | ); | 94 | ); |
97 | loc_needing_lifetime.map(|position| { | 95 | ted::replace(lifetime.syntax(), new_lifetime_param.clone_for_update().syntax()); |
98 | ted::insert(position, make_ast_lifetime(new_lifetime_param).clone_for_update().syntax()) | 96 | loc_needing_lifetime |
99 | }); | 97 | .map(|position| ted::insert(position, new_lifetime_param.clone_for_update().syntax())); |
100 | }) | 98 | }) |
101 | } | 99 | } |
102 | 100 | ||
@@ -112,11 +110,10 @@ fn generate_impl_def_assist( | |||
112 | let impl_def = builder.make_ast_mut(impl_def); | 110 | let impl_def = builder.make_ast_mut(impl_def); |
113 | let lifetime = builder.make_ast_mut(lifetime); | 111 | let lifetime = builder.make_ast_mut(lifetime); |
114 | 112 | ||
115 | add_lifetime_param(impl_def.get_or_create_generic_param_list(), new_lifetime_param); | 113 | impl_def.get_or_create_generic_param_list().add_generic_param( |
116 | ted::replace( | 114 | make::lifetime_param(new_lifetime_param.clone()).clone_for_update().into(), |
117 | lifetime.syntax(), | ||
118 | make_ast_lifetime(new_lifetime_param).clone_for_update().syntax(), | ||
119 | ); | 115 | ); |
116 | ted::replace(lifetime.syntax(), new_lifetime_param.clone_for_update().syntax()); | ||
120 | }) | 117 | }) |
121 | } | 118 | } |
122 | 119 | ||
@@ -124,31 +121,16 @@ fn generate_impl_def_assist( | |||
124 | /// which is not in the list | 121 | /// which is not in the list |
125 | fn generate_unique_lifetime_param_name( | 122 | fn generate_unique_lifetime_param_name( |
126 | existing_type_param_list: Option<ast::GenericParamList>, | 123 | existing_type_param_list: Option<ast::GenericParamList>, |
127 | ) -> Option<char> { | 124 | ) -> Option<ast::Lifetime> { |
128 | match existing_type_param_list { | 125 | match existing_type_param_list { |
129 | Some(type_params) => { | 126 | Some(type_params) => { |
130 | let used_lifetime_params: FxHashSet<_> = type_params | 127 | let used_lifetime_params: FxHashSet<_> = |
131 | .lifetime_params() | 128 | type_params.lifetime_params().map(|p| p.syntax().text().to_string()).collect(); |
132 | .map(|p| p.syntax().text().to_string()[1..].to_owned()) | 129 | ('a'..='z').map(|it| format!("'{}", it)).find(|it| !used_lifetime_params.contains(it)) |
133 | .collect(); | ||
134 | (b'a'..=b'z').map(char::from).find(|c| !used_lifetime_params.contains(&c.to_string())) | ||
135 | } | 130 | } |
136 | None => Some('a'), | 131 | None => Some("'a".to_string()), |
137 | } | 132 | } |
138 | } | 133 | .map(|it| make::lifetime(&it)) |
139 | |||
140 | fn add_lifetime_param(type_params: ast::GenericParamList, new_lifetime_param: char) { | ||
141 | let generic_param = | ||
142 | make::generic_param(format!("'{}", new_lifetime_param), None).clone_for_update(); | ||
143 | type_params.add_generic_param(generic_param); | ||
144 | } | ||
145 | |||
146 | fn make_ast_lifetime(new_lifetime_param: char) -> ast::Lifetime { | ||
147 | make::generic_param(format!("'{}", new_lifetime_param), None) | ||
148 | .syntax() | ||
149 | .descendants() | ||
150 | .find_map(ast::Lifetime::cast) | ||
151 | .unwrap() | ||
152 | } | 134 | } |
153 | 135 | ||
154 | enum NeedsLifetime { | 136 | enum NeedsLifetime { |
diff --git a/crates/ide_assists/src/handlers/merge_imports.rs b/crates/ide_assists/src/handlers/merge_imports.rs index add7b8e37..3cd090737 100644 --- a/crates/ide_assists/src/handlers/merge_imports.rs +++ b/crates/ide_assists/src/handlers/merge_imports.rs | |||
@@ -27,14 +27,14 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<() | |||
27 | if let Some(use_item) = tree.syntax().parent().and_then(ast::Use::cast) { | 27 | if let Some(use_item) = tree.syntax().parent().and_then(ast::Use::cast) { |
28 | let (merged, to_remove) = | 28 | let (merged, to_remove) = |
29 | next_prev().filter_map(|dir| neighbor(&use_item, dir)).find_map(|use_item2| { | 29 | next_prev().filter_map(|dir| neighbor(&use_item, dir)).find_map(|use_item2| { |
30 | try_merge_imports(&use_item, &use_item2, MergeBehavior::Full).zip(Some(use_item2)) | 30 | try_merge_imports(&use_item, &use_item2, MergeBehavior::Crate).zip(Some(use_item2)) |
31 | })?; | 31 | })?; |
32 | 32 | ||
33 | imports = Some((use_item, merged, to_remove)); | 33 | imports = Some((use_item, merged, to_remove)); |
34 | } else { | 34 | } else { |
35 | let (merged, to_remove) = | 35 | let (merged, to_remove) = |
36 | next_prev().filter_map(|dir| neighbor(&tree, dir)).find_map(|use_tree| { | 36 | next_prev().filter_map(|dir| neighbor(&tree, dir)).find_map(|use_tree| { |
37 | try_merge_trees(&tree, &use_tree, MergeBehavior::Full).zip(Some(use_tree)) | 37 | try_merge_trees(&tree, &use_tree, MergeBehavior::Crate).zip(Some(use_tree)) |
38 | })?; | 38 | })?; |
39 | 39 | ||
40 | uses = Some((tree.clone(), merged, to_remove)) | 40 | uses = Some((tree.clone(), merged, to_remove)) |
diff --git a/crates/ide_assists/src/handlers/move_bounds.rs b/crates/ide_assists/src/handlers/move_bounds.rs index 011a28d44..fa3f76609 100644 --- a/crates/ide_assists/src/handlers/move_bounds.rs +++ b/crates/ide_assists/src/handlers/move_bounds.rs | |||
@@ -63,11 +63,7 @@ pub(crate) fn move_bounds_to_where_clause(acc: &mut Assists, ctx: &AssistContext | |||
63 | } | 63 | } |
64 | 64 | ||
65 | fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> { | 65 | fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> { |
66 | let path = { | 66 | let path = make::ext::ident_path(¶m.name()?.syntax().to_string()); |
67 | let name_ref = make::name_ref(¶m.name()?.syntax().to_string()); | ||
68 | let segment = make::path_segment(name_ref); | ||
69 | make::path_unqualified(segment) | ||
70 | }; | ||
71 | let predicate = make::where_pred(path, param.type_bound_list()?.bounds()); | 67 | let predicate = make::where_pred(path, param.type_bound_list()?.bounds()); |
72 | Some(predicate.clone_for_update()) | 68 | Some(predicate.clone_for_update()) |
73 | } | 69 | } |
diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs index 694d897d1..10d9cec31 100644 --- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs | |||
@@ -84,7 +84,7 @@ pub(crate) fn replace_derive_with_manual_impl( | |||
84 | add_assist(acc, ctx, &attr, &args, &trait_path, Some(trait_), &adt)?; | 84 | add_assist(acc, ctx, &attr, &args, &trait_path, Some(trait_), &adt)?; |
85 | } | 85 | } |
86 | if no_traits_found { | 86 | if no_traits_found { |
87 | let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_name))); | 87 | let trait_path = make::ext::ident_path(trait_name); |
88 | add_assist(acc, ctx, &attr, &args, &trait_path, None, &adt)?; | 88 | add_assist(acc, ctx, &attr, &args, &trait_path, None, &adt)?; |
89 | } | 89 | } |
90 | Some(()) | 90 | Some(()) |
@@ -159,10 +159,8 @@ fn impl_def_from_trait( | |||
159 | if trait_items.is_empty() { | 159 | if trait_items.is_empty() { |
160 | return None; | 160 | return None; |
161 | } | 161 | } |
162 | let impl_def = make::impl_trait( | 162 | let impl_def = |
163 | trait_path.clone(), | 163 | make::impl_trait(trait_path.clone(), make::ext::ident_path(&annotated_name.text())); |
164 | make::path_unqualified(make::path_segment(make::name_ref(&annotated_name.text()))), | ||
165 | ); | ||
166 | let (impl_def, first_assoc_item) = | 164 | let (impl_def, first_assoc_item) = |
167 | add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope); | 165 | add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope); |
168 | Some((impl_def, first_assoc_item)) | 166 | Some((impl_def, first_assoc_item)) |
diff --git a/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs b/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs index ff25b61ea..15420aedf 100644 --- a/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs +++ b/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs | |||
@@ -1,6 +1,9 @@ | |||
1 | use syntax::ast::{self, edit::AstNodeEdit, make, AstNode, GenericParamsOwner}; | 1 | use syntax::{ |
2 | ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode}, | ||
3 | ted, | ||
4 | }; | ||
2 | 5 | ||
3 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 6 | use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists}; |
4 | 7 | ||
5 | // Assist: replace_impl_trait_with_generic | 8 | // Assist: replace_impl_trait_with_generic |
6 | // | 9 | // |
@@ -17,30 +20,29 @@ pub(crate) fn replace_impl_trait_with_generic( | |||
17 | acc: &mut Assists, | 20 | acc: &mut Assists, |
18 | ctx: &AssistContext, | 21 | ctx: &AssistContext, |
19 | ) -> Option<()> { | 22 | ) -> Option<()> { |
20 | let type_impl_trait = ctx.find_node_at_offset::<ast::ImplTraitType>()?; | 23 | let impl_trait_type = ctx.find_node_at_offset::<ast::ImplTraitType>()?; |
21 | let type_param = type_impl_trait.syntax().parent().and_then(ast::Param::cast)?; | 24 | let param = impl_trait_type.syntax().parent().and_then(ast::Param::cast)?; |
22 | let type_fn = type_param.syntax().ancestors().find_map(ast::Fn::cast)?; | 25 | let fn_ = param.syntax().ancestors().find_map(ast::Fn::cast)?; |
23 | 26 | ||
24 | let impl_trait_ty = type_impl_trait.type_bound_list()?; | 27 | let type_bound_list = impl_trait_type.type_bound_list()?; |
25 | 28 | ||
26 | let target = type_fn.syntax().text_range(); | 29 | let target = fn_.syntax().text_range(); |
27 | acc.add( | 30 | acc.add( |
28 | AssistId("replace_impl_trait_with_generic", AssistKind::RefactorRewrite), | 31 | AssistId("replace_impl_trait_with_generic", AssistKind::RefactorRewrite), |
29 | "Replace impl trait with generic", | 32 | "Replace impl trait with generic", |
30 | target, | 33 | target, |
31 | |edit| { | 34 | |edit| { |
32 | let generic_letter = impl_trait_ty.to_string().chars().next().unwrap().to_string(); | 35 | let impl_trait_type = edit.make_ast_mut(impl_trait_type); |
36 | let fn_ = edit.make_ast_mut(fn_); | ||
33 | 37 | ||
34 | let generic_param_list = type_fn | 38 | let type_param_name = suggest_name::for_generic_parameter(&impl_trait_type); |
35 | .generic_param_list() | ||
36 | .unwrap_or_else(|| make::generic_param_list(None)) | ||
37 | .append_param(make::generic_param(generic_letter.clone(), Some(impl_trait_ty))); | ||
38 | 39 | ||
39 | let new_type_fn = type_fn | 40 | let type_param = make::type_param(make::name(&type_param_name), Some(type_bound_list)) |
40 | .replace_descendant::<ast::Type>(type_impl_trait.into(), make::ty(&generic_letter)) | 41 | .clone_for_update(); |
41 | .with_generic_param_list(generic_param_list); | 42 | let new_ty = make::ty(&type_param_name).clone_for_update(); |
42 | 43 | ||
43 | edit.replace_ast(type_fn.clone(), new_type_fn); | 44 | ted::replace(impl_trait_type.syntax(), new_ty.syntax()); |
45 | fn_.get_or_create_generic_param_list().add_generic_param(type_param.into()) | ||
44 | }, | 46 | }, |
45 | ) | 47 | ) |
46 | } | 48 | } |
@@ -55,12 +57,8 @@ mod tests { | |||
55 | fn replace_impl_trait_with_generic_params() { | 57 | fn replace_impl_trait_with_generic_params() { |
56 | check_assist( | 58 | check_assist( |
57 | replace_impl_trait_with_generic, | 59 | replace_impl_trait_with_generic, |
58 | r#" | 60 | r#"fn foo<G>(bar: $0impl Bar) {}"#, |
59 | fn foo<G>(bar: $0impl Bar) {} | 61 | r#"fn foo<G, B: Bar>(bar: B) {}"#, |
60 | "#, | ||
61 | r#" | ||
62 | fn foo<G, B: Bar>(bar: B) {} | ||
63 | "#, | ||
64 | ); | 62 | ); |
65 | } | 63 | } |
66 | 64 | ||
@@ -68,12 +66,8 @@ mod tests { | |||
68 | fn replace_impl_trait_without_generic_params() { | 66 | fn replace_impl_trait_without_generic_params() { |
69 | check_assist( | 67 | check_assist( |
70 | replace_impl_trait_with_generic, | 68 | replace_impl_trait_with_generic, |
71 | r#" | 69 | r#"fn foo(bar: $0impl Bar) {}"#, |
72 | fn foo(bar: $0impl Bar) {} | 70 | r#"fn foo<B: Bar>(bar: B) {}"#, |
73 | "#, | ||
74 | r#" | ||
75 | fn foo<B: Bar>(bar: B) {} | ||
76 | "#, | ||
77 | ); | 71 | ); |
78 | } | 72 | } |
79 | 73 | ||
@@ -81,12 +75,8 @@ mod tests { | |||
81 | fn replace_two_impl_trait_with_generic_params() { | 75 | fn replace_two_impl_trait_with_generic_params() { |
82 | check_assist( | 76 | check_assist( |
83 | replace_impl_trait_with_generic, | 77 | replace_impl_trait_with_generic, |
84 | r#" | 78 | r#"fn foo<G>(foo: impl Foo, bar: $0impl Bar) {}"#, |
85 | fn foo<G>(foo: impl Foo, bar: $0impl Bar) {} | 79 | r#"fn foo<G, B: Bar>(foo: impl Foo, bar: B) {}"#, |
86 | "#, | ||
87 | r#" | ||
88 | fn foo<G, B: Bar>(foo: impl Foo, bar: B) {} | ||
89 | "#, | ||
90 | ); | 80 | ); |
91 | } | 81 | } |
92 | 82 | ||
@@ -94,12 +84,8 @@ mod tests { | |||
94 | fn replace_impl_trait_with_empty_generic_params() { | 84 | fn replace_impl_trait_with_empty_generic_params() { |
95 | check_assist( | 85 | check_assist( |
96 | replace_impl_trait_with_generic, | 86 | replace_impl_trait_with_generic, |
97 | r#" | 87 | r#"fn foo<>(bar: $0impl Bar) {}"#, |
98 | fn foo<>(bar: $0impl Bar) {} | 88 | r#"fn foo<B: Bar>(bar: B) {}"#, |
99 | "#, | ||
100 | r#" | ||
101 | fn foo<B: Bar>(bar: B) {} | ||
102 | "#, | ||
103 | ); | 89 | ); |
104 | } | 90 | } |
105 | 91 | ||
@@ -108,13 +94,13 @@ mod tests { | |||
108 | check_assist( | 94 | check_assist( |
109 | replace_impl_trait_with_generic, | 95 | replace_impl_trait_with_generic, |
110 | r#" | 96 | r#" |
111 | fn foo< | 97 | fn foo< |
112 | >(bar: $0impl Bar) {} | 98 | >(bar: $0impl Bar) {} |
113 | "#, | 99 | "#, |
114 | r#" | 100 | r#" |
115 | fn foo<B: Bar | 101 | fn foo<B: Bar |
116 | >(bar: B) {} | 102 | >(bar: B) {} |
117 | "#, | 103 | "#, |
118 | ); | 104 | ); |
119 | } | 105 | } |
120 | 106 | ||
@@ -123,12 +109,8 @@ mod tests { | |||
123 | fn replace_impl_trait_with_exist_generic_letter() { | 109 | fn replace_impl_trait_with_exist_generic_letter() { |
124 | check_assist( | 110 | check_assist( |
125 | replace_impl_trait_with_generic, | 111 | replace_impl_trait_with_generic, |
126 | r#" | 112 | r#"fn foo<B>(bar: $0impl Bar) {}"#, |
127 | fn foo<B>(bar: $0impl Bar) {} | 113 | r#"fn foo<B, C: Bar>(bar: C) {}"#, |
128 | "#, | ||
129 | r#" | ||
130 | fn foo<B, C: Bar>(bar: C) {} | ||
131 | "#, | ||
132 | ); | 114 | ); |
133 | } | 115 | } |
134 | 116 | ||
@@ -137,19 +119,19 @@ mod tests { | |||
137 | check_assist( | 119 | check_assist( |
138 | replace_impl_trait_with_generic, | 120 | replace_impl_trait_with_generic, |
139 | r#" | 121 | r#" |
140 | fn foo< | 122 | fn foo< |
141 | G: Foo, | 123 | G: Foo, |
142 | F, | 124 | F, |
143 | H, | 125 | H, |
144 | >(bar: $0impl Bar) {} | 126 | >(bar: $0impl Bar) {} |
145 | "#, | 127 | "#, |
146 | r#" | 128 | r#" |
147 | fn foo< | 129 | fn foo< |
148 | G: Foo, | 130 | G: Foo, |
149 | F, | 131 | F, |
150 | H, B: Bar | 132 | H, B: Bar, |
151 | >(bar: B) {} | 133 | >(bar: B) {} |
152 | "#, | 134 | "#, |
153 | ); | 135 | ); |
154 | } | 136 | } |
155 | 137 | ||
@@ -157,12 +139,8 @@ mod tests { | |||
157 | fn replace_impl_trait_multiple() { | 139 | fn replace_impl_trait_multiple() { |
158 | check_assist( | 140 | check_assist( |
159 | replace_impl_trait_with_generic, | 141 | replace_impl_trait_with_generic, |
160 | r#" | 142 | r#"fn foo(bar: $0impl Foo + Bar) {}"#, |
161 | fn foo(bar: $0impl Foo + Bar) {} | 143 | r#"fn foo<F: Foo + Bar>(bar: F) {}"#, |
162 | "#, | ||
163 | r#" | ||
164 | fn foo<F: Foo + Bar>(bar: F) {} | ||
165 | "#, | ||
166 | ); | 144 | ); |
167 | } | 145 | } |
168 | } | 146 | } |
diff --git a/crates/ide_assists/src/handlers/replace_let_with_if_let.rs b/crates/ide_assists/src/handlers/replace_let_with_if_let.rs index be7e724b5..1ad0fa816 100644 --- a/crates/ide_assists/src/handlers/replace_let_with_if_let.rs +++ b/crates/ide_assists/src/handlers/replace_let_with_if_let.rs | |||
@@ -50,22 +50,19 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) -> | |||
50 | "Replace with if-let", | 50 | "Replace with if-let", |
51 | target, | 51 | target, |
52 | |edit| { | 52 | |edit| { |
53 | let with_placeholder: ast::Pat = match happy_variant { | 53 | let pat = match happy_variant { |
54 | None => make::wildcard_pat().into(), | 54 | None => original_pat, |
55 | Some(var_name) => make::tuple_struct_pat( | 55 | Some(var_name) => { |
56 | make::path_unqualified(make::path_segment(make::name_ref(var_name))), | 56 | make::tuple_struct_pat(make::ext::ident_path(var_name), once(original_pat)) |
57 | once(make::wildcard_pat().into()), | 57 | .into() |
58 | ) | 58 | } |
59 | .into(), | ||
60 | }; | 59 | }; |
60 | |||
61 | let block = | 61 | let block = |
62 | make::block_expr(None, None).indent(IndentLevel::from_node(let_stmt.syntax())); | 62 | make::ext::empty_block_expr().indent(IndentLevel::from_node(let_stmt.syntax())); |
63 | let if_ = make::expr_if(make::condition(init, Some(with_placeholder)), block, None); | 63 | let if_ = make::expr_if(make::condition(init, Some(pat)), block, None); |
64 | let stmt = make::expr_stmt(if_); | 64 | let stmt = make::expr_stmt(if_); |
65 | 65 | ||
66 | let placeholder = stmt.syntax().descendants().find_map(ast::WildcardPat::cast).unwrap(); | ||
67 | let stmt = stmt.replace_descendant(placeholder.into(), original_pat); | ||
68 | |||
69 | edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt)); | 66 | edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt)); |
70 | }, | 67 | }, |
71 | ) | 68 | ) |
diff --git a/crates/ide_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ide_assists/src/handlers/replace_unwrap_with_match.rs index a986a6ae8..0fec961b4 100644 --- a/crates/ide_assists/src/handlers/replace_unwrap_with_match.rs +++ b/crates/ide_assists/src/handlers/replace_unwrap_with_match.rs | |||
@@ -32,7 +32,7 @@ use ide_db::ty_filter::TryEnum; | |||
32 | // fn main() { | 32 | // fn main() { |
33 | // let x: Result<i32, i32> = Result::Ok(92); | 33 | // let x: Result<i32, i32> = Result::Ok(92); |
34 | // let y = match x { | 34 | // let y = match x { |
35 | // Ok(a) => a, | 35 | // Ok(it) => it, |
36 | // $0_ => unreachable!(), | 36 | // $0_ => unreachable!(), |
37 | // }; | 37 | // }; |
38 | // } | 38 | // } |
@@ -52,16 +52,17 @@ pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext) | |||
52 | "Replace unwrap with match", | 52 | "Replace unwrap with match", |
53 | target, | 53 | target, |
54 | |builder| { | 54 | |builder| { |
55 | let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); | 55 | let ok_path = make::ext::ident_path(happy_variant); |
56 | let it = make::ident_pat(make::name("a")).into(); | 56 | let it = make::ident_pat(make::name("it")).into(); |
57 | let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); | 57 | let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); |
58 | 58 | ||
59 | let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); | 59 | let bind_path = make::ext::ident_path("it"); |
60 | let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); | 60 | let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); |
61 | 61 | ||
62 | let unreachable_call = make::expr_unreachable(); | 62 | let err_arm = make::match_arm( |
63 | let err_arm = | 63 | iter::once(make::wildcard_pat().into()), |
64 | make::match_arm(iter::once(make::wildcard_pat().into()), unreachable_call); | 64 | make::ext::expr_unreachable(), |
65 | ); | ||
65 | 66 | ||
66 | let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); | 67 | let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); |
67 | let match_expr = make::expr_match(caller.clone(), match_arm_list) | 68 | let match_expr = make::expr_match(caller.clone(), match_arm_list) |
@@ -110,7 +111,7 @@ fn i<T>(a: T) -> T { a } | |||
110 | fn main() { | 111 | fn main() { |
111 | let x: Result<i32, i32> = Result::Ok(92); | 112 | let x: Result<i32, i32> = Result::Ok(92); |
112 | let y = match i(x) { | 113 | let y = match i(x) { |
113 | Ok(a) => a, | 114 | Ok(it) => it, |
114 | $0_ => unreachable!(), | 115 | $0_ => unreachable!(), |
115 | }; | 116 | }; |
116 | } | 117 | } |
@@ -136,7 +137,7 @@ fn i<T>(a: T) -> T { a } | |||
136 | fn main() { | 137 | fn main() { |
137 | let x = Option::Some(92); | 138 | let x = Option::Some(92); |
138 | let y = match i(x) { | 139 | let y = match i(x) { |
139 | Some(a) => a, | 140 | Some(it) => it, |
140 | $0_ => unreachable!(), | 141 | $0_ => unreachable!(), |
141 | }; | 142 | }; |
142 | } | 143 | } |
@@ -162,7 +163,7 @@ fn i<T>(a: T) -> T { a } | |||
162 | fn main() { | 163 | fn main() { |
163 | let x: Result<i32, i32> = Result::Ok(92); | 164 | let x: Result<i32, i32> = Result::Ok(92); |
164 | let y = match i(x) { | 165 | let y = match i(x) { |
165 | Ok(a) => a, | 166 | Ok(it) => it, |
166 | $0_ => unreachable!(), | 167 | $0_ => unreachable!(), |
167 | }.count_zeroes(); | 168 | }.count_zeroes(); |
168 | } | 169 | } |
diff --git a/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs b/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs index e838630ea..2f1da82c7 100644 --- a/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs +++ b/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs | |||
@@ -54,9 +54,7 @@ pub(crate) fn wrap_return_type_in_result(acc: &mut Assists, ctx: &AssistContext) | |||
54 | 54 | ||
55 | for ret_expr_arg in tail_return_expr_collector.exprs_to_wrap { | 55 | for ret_expr_arg in tail_return_expr_collector.exprs_to_wrap { |
56 | let ok_wrapped = make::expr_call( | 56 | let ok_wrapped = make::expr_call( |
57 | make::expr_path(make::path_unqualified(make::path_segment(make::name_ref( | 57 | make::expr_path(make::ext::ident_path("Ok")), |
58 | "Ok", | ||
59 | )))), | ||
60 | make::arg_list(iter::once(ret_expr_arg.clone())), | 58 | make::arg_list(iter::once(ret_expr_arg.clone())), |
61 | ); | 59 | ); |
62 | builder.replace_ast(ret_expr_arg, ok_wrapped); | 60 | builder.replace_ast(ret_expr_arg, ok_wrapped); |
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs index 9c2847998..0d3969c36 100644 --- a/crates/ide_assists/src/tests.rs +++ b/crates/ide_assists/src/tests.rs | |||
@@ -21,7 +21,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { | |||
21 | snippet_cap: SnippetCap::new(true), | 21 | snippet_cap: SnippetCap::new(true), |
22 | allowed: None, | 22 | allowed: None, |
23 | insert_use: InsertUseConfig { | 23 | insert_use: InsertUseConfig { |
24 | merge: Some(MergeBehavior::Full), | 24 | merge: Some(MergeBehavior::Crate), |
25 | prefix_kind: hir::PrefixKind::Plain, | 25 | prefix_kind: hir::PrefixKind::Plain, |
26 | group: true, | 26 | group: true, |
27 | }, | 27 | }, |
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs index 59bcef8fb..49c1a9776 100644 --- a/crates/ide_assists/src/tests/generated.rs +++ b/crates/ide_assists/src/tests/generated.rs | |||
@@ -1531,7 +1531,7 @@ enum Result<T, E> { Ok(T), Err(E) } | |||
1531 | fn main() { | 1531 | fn main() { |
1532 | let x: Result<i32, i32> = Result::Ok(92); | 1532 | let x: Result<i32, i32> = Result::Ok(92); |
1533 | let y = match x { | 1533 | let y = match x { |
1534 | Ok(a) => a, | 1534 | Ok(it) => it, |
1535 | $0_ => unreachable!(), | 1535 | $0_ => unreachable!(), |
1536 | }; | 1536 | }; |
1537 | } | 1537 | } |
diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs index 5a90ad715..0dcf20c61 100644 --- a/crates/ide_assists/src/utils.rs +++ b/crates/ide_assists/src/utils.rs | |||
@@ -159,8 +159,8 @@ pub fn add_trait_assoc_items_to_impl( | |||
159 | match fn_def.body() { | 159 | match fn_def.body() { |
160 | Some(_) => fn_def, | 160 | Some(_) => fn_def, |
161 | None => { | 161 | None => { |
162 | let body = | 162 | let body = make::block_expr(None, Some(make::ext::expr_todo())) |
163 | make::block_expr(None, Some(make::expr_todo())).indent(edit::IndentLevel(1)); | 163 | .indent(edit::IndentLevel(1)); |
164 | fn_def.with_body(body) | 164 | fn_def.with_body(body) |
165 | } | 165 | } |
166 | } | 166 | } |
diff --git a/crates/ide_assists/src/utils/suggest_name.rs b/crates/ide_assists/src/utils/suggest_name.rs index deafcd630..b3aabeab3 100644 --- a/crates/ide_assists/src/utils/suggest_name.rs +++ b/crates/ide_assists/src/utils/suggest_name.rs | |||
@@ -6,7 +6,7 @@ use itertools::Itertools; | |||
6 | use stdx::to_lower_snake_case; | 6 | use stdx::to_lower_snake_case; |
7 | use syntax::{ | 7 | use syntax::{ |
8 | ast::{self, NameOwner}, | 8 | ast::{self, NameOwner}, |
9 | match_ast, AstNode, | 9 | match_ast, AstNode, SmolStr, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | /// Trait names, that will be ignored when in `impl Trait` and `dyn Trait` | 12 | /// Trait names, that will be ignored when in `impl Trait` and `dyn Trait` |
@@ -57,6 +57,14 @@ const USELESS_METHODS: &[&str] = &[ | |||
57 | "iter_mut", | 57 | "iter_mut", |
58 | ]; | 58 | ]; |
59 | 59 | ||
60 | pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr { | ||
61 | let c = ty | ||
62 | .type_bound_list() | ||
63 | .and_then(|bounds| bounds.syntax().text().char_at(0.into())) | ||
64 | .unwrap_or('T'); | ||
65 | c.encode_utf8(&mut [0; 4]).into() | ||
66 | } | ||
67 | |||
60 | /// Suggest name of variable for given expression | 68 | /// Suggest name of variable for given expression |
61 | /// | 69 | /// |
62 | /// **NOTE**: it is caller's responsibility to guarantee uniqueness of the name. | 70 | /// **NOTE**: it is caller's responsibility to guarantee uniqueness of the name. |
@@ -75,7 +83,8 @@ const USELESS_METHODS: &[&str] = &[ | |||
75 | /// It also applies heuristics to filter out less informative names | 83 | /// It also applies heuristics to filter out less informative names |
76 | /// | 84 | /// |
77 | /// Currently it sticks to the first name found. | 85 | /// Currently it sticks to the first name found. |
78 | pub(crate) fn variable(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> String { | 86 | // FIXME: Microoptimize and return a `SmolStr` here. |
87 | pub(crate) fn for_variable(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> String { | ||
79 | // `from_param` does not benifit from stripping | 88 | // `from_param` does not benifit from stripping |
80 | // it need the largest context possible | 89 | // it need the largest context possible |
81 | // so we check firstmost | 90 | // so we check firstmost |
@@ -276,7 +285,7 @@ mod tests { | |||
276 | frange.range, | 285 | frange.range, |
277 | "selection is not an expression(yet contained in one)" | 286 | "selection is not an expression(yet contained in one)" |
278 | ); | 287 | ); |
279 | let name = variable(&expr, &sema); | 288 | let name = for_variable(&expr, &sema); |
280 | assert_eq!(&name, expected); | 289 | assert_eq!(&name, expected); |
281 | } | 290 | } |
282 | 291 | ||
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index e32633565..645349215 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs | |||
@@ -80,7 +80,7 @@ pub use crate::{ | |||
80 | // | 80 | // |
81 | // And the auto import completions, enabled with the `rust-analyzer.completion.autoimport.enable` setting and the corresponding LSP client capabilities. | 81 | // And the auto import completions, enabled with the `rust-analyzer.completion.autoimport.enable` setting and the corresponding LSP client capabilities. |
82 | // Those are the additional completion options with automatic `use` import and options from all project importable items, | 82 | // Those are the additional completion options with automatic `use` import and options from all project importable items, |
83 | // fuzzy matched agains the completion imput. | 83 | // fuzzy matched against the completion input. |
84 | // | 84 | // |
85 | // image::https://user-images.githubusercontent.com/48062697/113020667-b72ab880-917a-11eb-8778-716cf26a0eb3.gif[] | 85 | // image::https://user-images.githubusercontent.com/48062697/113020667-b72ab880-917a-11eb-8778-716cf26a0eb3.gif[] |
86 | 86 | ||
diff --git a/crates/ide_completion/src/test_utils.rs b/crates/ide_completion/src/test_utils.rs index c9857ec5f..939fb2d47 100644 --- a/crates/ide_completion/src/test_utils.rs +++ b/crates/ide_completion/src/test_utils.rs | |||
@@ -20,7 +20,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { | |||
20 | add_call_argument_snippets: true, | 20 | add_call_argument_snippets: true, |
21 | snippet_cap: SnippetCap::new(true), | 21 | snippet_cap: SnippetCap::new(true), |
22 | insert_use: InsertUseConfig { | 22 | insert_use: InsertUseConfig { |
23 | merge: Some(MergeBehavior::Full), | 23 | merge: Some(MergeBehavior::Crate), |
24 | prefix_kind: PrefixKind::Plain, | 24 | prefix_kind: PrefixKind::Plain, |
25 | group: true, | 25 | group: true, |
26 | }, | 26 | }, |
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs index 048c213e2..248227d29 100644 --- a/crates/ide_db/src/helpers/insert_use/tests.rs +++ b/crates/ide_db/src/helpers/insert_use/tests.rs | |||
@@ -44,7 +44,7 @@ fn insert_not_group_empty() { | |||
44 | 44 | ||
45 | #[test] | 45 | #[test] |
46 | fn insert_existing() { | 46 | fn insert_existing() { |
47 | check_full("std::fs", "use std::fs;", "use std::fs;") | 47 | check_crate("std::fs", "use std::fs;", "use std::fs;") |
48 | } | 48 | } |
49 | 49 | ||
50 | #[test] | 50 | #[test] |
@@ -249,7 +249,7 @@ use self::fmt;", | |||
249 | 249 | ||
250 | #[test] | 250 | #[test] |
251 | fn insert_no_imports() { | 251 | fn insert_no_imports() { |
252 | check_full( | 252 | check_crate( |
253 | "foo::bar", | 253 | "foo::bar", |
254 | "fn main() {}", | 254 | "fn main() {}", |
255 | r"use foo::bar; | 255 | r"use foo::bar; |
@@ -263,7 +263,7 @@ fn insert_empty_file() { | |||
263 | cov_mark::check!(insert_group_empty_file); | 263 | cov_mark::check!(insert_group_empty_file); |
264 | // empty files will get two trailing newlines | 264 | // empty files will get two trailing newlines |
265 | // this is due to the test case insert_no_imports above | 265 | // this is due to the test case insert_no_imports above |
266 | check_full( | 266 | check_crate( |
267 | "foo::bar", | 267 | "foo::bar", |
268 | "", | 268 | "", |
269 | r"use foo::bar; | 269 | r"use foo::bar; |
@@ -290,7 +290,7 @@ fn insert_empty_module() { | |||
290 | #[test] | 290 | #[test] |
291 | fn insert_after_inner_attr() { | 291 | fn insert_after_inner_attr() { |
292 | cov_mark::check!(insert_group_empty_inner_attr); | 292 | cov_mark::check!(insert_group_empty_inner_attr); |
293 | check_full( | 293 | check_crate( |
294 | "foo::bar", | 294 | "foo::bar", |
295 | r"#![allow(unused_imports)]", | 295 | r"#![allow(unused_imports)]", |
296 | r"#![allow(unused_imports)] | 296 | r"#![allow(unused_imports)] |
@@ -301,7 +301,7 @@ use foo::bar;", | |||
301 | 301 | ||
302 | #[test] | 302 | #[test] |
303 | fn insert_after_inner_attr2() { | 303 | fn insert_after_inner_attr2() { |
304 | check_full( | 304 | check_crate( |
305 | "foo::bar", | 305 | "foo::bar", |
306 | r"#![allow(unused_imports)] | 306 | r"#![allow(unused_imports)] |
307 | 307 | ||
@@ -371,12 +371,12 @@ fn main() {}"#, | |||
371 | 371 | ||
372 | #[test] | 372 | #[test] |
373 | fn merge_groups() { | 373 | fn merge_groups() { |
374 | check_last("std::io", r"use std::fmt;", r"use std::{fmt, io};") | 374 | check_module("std::io", r"use std::fmt;", r"use std::{fmt, io};") |
375 | } | 375 | } |
376 | 376 | ||
377 | #[test] | 377 | #[test] |
378 | fn merge_groups_last() { | 378 | fn merge_groups_last() { |
379 | check_last( | 379 | check_module( |
380 | "std::io", | 380 | "std::io", |
381 | r"use std::fmt::{Result, Display};", | 381 | r"use std::fmt::{Result, Display};", |
382 | r"use std::fmt::{Result, Display}; | 382 | r"use std::fmt::{Result, Display}; |
@@ -386,12 +386,12 @@ use std::io;", | |||
386 | 386 | ||
387 | #[test] | 387 | #[test] |
388 | fn merge_last_into_self() { | 388 | fn merge_last_into_self() { |
389 | check_last("foo::bar::baz", r"use foo::bar;", r"use foo::bar::{self, baz};"); | 389 | check_module("foo::bar::baz", r"use foo::bar;", r"use foo::bar::{self, baz};"); |
390 | } | 390 | } |
391 | 391 | ||
392 | #[test] | 392 | #[test] |
393 | fn merge_groups_full() { | 393 | fn merge_groups_full() { |
394 | check_full( | 394 | check_crate( |
395 | "std::io", | 395 | "std::io", |
396 | r"use std::fmt::{Result, Display};", | 396 | r"use std::fmt::{Result, Display};", |
397 | r"use std::{fmt::{Result, Display}, io};", | 397 | r"use std::{fmt::{Result, Display}, io};", |
@@ -400,17 +400,21 @@ fn merge_groups_full() { | |||
400 | 400 | ||
401 | #[test] | 401 | #[test] |
402 | fn merge_groups_long_full() { | 402 | fn merge_groups_long_full() { |
403 | check_full("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Baz, Qux};") | 403 | check_crate("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Baz, Qux};") |
404 | } | 404 | } |
405 | 405 | ||
406 | #[test] | 406 | #[test] |
407 | fn merge_groups_long_last() { | 407 | fn merge_groups_long_last() { |
408 | check_last("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Baz, Qux};") | 408 | check_module( |
409 | "std::foo::bar::Baz", | ||
410 | r"use std::foo::bar::Qux;", | ||
411 | r"use std::foo::bar::{Baz, Qux};", | ||
412 | ) | ||
409 | } | 413 | } |
410 | 414 | ||
411 | #[test] | 415 | #[test] |
412 | fn merge_groups_long_full_list() { | 416 | fn merge_groups_long_full_list() { |
413 | check_full( | 417 | check_crate( |
414 | "std::foo::bar::Baz", | 418 | "std::foo::bar::Baz", |
415 | r"use std::foo::bar::{Qux, Quux};", | 419 | r"use std::foo::bar::{Qux, Quux};", |
416 | r"use std::foo::bar::{Baz, Quux, Qux};", | 420 | r"use std::foo::bar::{Baz, Quux, Qux};", |
@@ -419,7 +423,7 @@ fn merge_groups_long_full_list() { | |||
419 | 423 | ||
420 | #[test] | 424 | #[test] |
421 | fn merge_groups_long_last_list() { | 425 | fn merge_groups_long_last_list() { |
422 | check_last( | 426 | check_module( |
423 | "std::foo::bar::Baz", | 427 | "std::foo::bar::Baz", |
424 | r"use std::foo::bar::{Qux, Quux};", | 428 | r"use std::foo::bar::{Qux, Quux};", |
425 | r"use std::foo::bar::{Baz, Quux, Qux};", | 429 | r"use std::foo::bar::{Baz, Quux, Qux};", |
@@ -428,7 +432,7 @@ fn merge_groups_long_last_list() { | |||
428 | 432 | ||
429 | #[test] | 433 | #[test] |
430 | fn merge_groups_long_full_nested() { | 434 | fn merge_groups_long_full_nested() { |
431 | check_full( | 435 | check_crate( |
432 | "std::foo::bar::Baz", | 436 | "std::foo::bar::Baz", |
433 | r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", | 437 | r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", |
434 | r"use std::foo::bar::{Baz, Qux, quux::{Fez, Fizz}};", | 438 | r"use std::foo::bar::{Baz, Qux, quux::{Fez, Fizz}};", |
@@ -437,7 +441,7 @@ fn merge_groups_long_full_nested() { | |||
437 | 441 | ||
438 | #[test] | 442 | #[test] |
439 | fn merge_groups_long_last_nested() { | 443 | fn merge_groups_long_last_nested() { |
440 | check_last( | 444 | check_module( |
441 | "std::foo::bar::Baz", | 445 | "std::foo::bar::Baz", |
442 | r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", | 446 | r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", |
443 | r"use std::foo::bar::Baz; | 447 | r"use std::foo::bar::Baz; |
@@ -447,7 +451,7 @@ use std::foo::bar::{Qux, quux::{Fez, Fizz}};", | |||
447 | 451 | ||
448 | #[test] | 452 | #[test] |
449 | fn merge_groups_full_nested_deep() { | 453 | fn merge_groups_full_nested_deep() { |
450 | check_full( | 454 | check_crate( |
451 | "std::foo::bar::quux::Baz", | 455 | "std::foo::bar::quux::Baz", |
452 | r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", | 456 | r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", |
453 | r"use std::foo::bar::{Qux, quux::{Baz, Fez, Fizz}};", | 457 | r"use std::foo::bar::{Qux, quux::{Baz, Fez, Fizz}};", |
@@ -456,7 +460,7 @@ fn merge_groups_full_nested_deep() { | |||
456 | 460 | ||
457 | #[test] | 461 | #[test] |
458 | fn merge_groups_full_nested_long() { | 462 | fn merge_groups_full_nested_long() { |
459 | check_full( | 463 | check_crate( |
460 | "std::foo::bar::Baz", | 464 | "std::foo::bar::Baz", |
461 | r"use std::{foo::bar::Qux};", | 465 | r"use std::{foo::bar::Qux};", |
462 | r"use std::{foo::bar::{Baz, Qux}};", | 466 | r"use std::{foo::bar::{Baz, Qux}};", |
@@ -465,7 +469,7 @@ fn merge_groups_full_nested_long() { | |||
465 | 469 | ||
466 | #[test] | 470 | #[test] |
467 | fn merge_groups_last_nested_long() { | 471 | fn merge_groups_last_nested_long() { |
468 | check_full( | 472 | check_crate( |
469 | "std::foo::bar::Baz", | 473 | "std::foo::bar::Baz", |
470 | r"use std::{foo::bar::Qux};", | 474 | r"use std::{foo::bar::Qux};", |
471 | r"use std::{foo::bar::{Baz, Qux}};", | 475 | r"use std::{foo::bar::{Baz, Qux}};", |
@@ -474,7 +478,7 @@ fn merge_groups_last_nested_long() { | |||
474 | 478 | ||
475 | #[test] | 479 | #[test] |
476 | fn merge_groups_skip_pub() { | 480 | fn merge_groups_skip_pub() { |
477 | check_full( | 481 | check_crate( |
478 | "std::io", | 482 | "std::io", |
479 | r"pub use std::fmt::{Result, Display};", | 483 | r"pub use std::fmt::{Result, Display};", |
480 | r"pub use std::fmt::{Result, Display}; | 484 | r"pub use std::fmt::{Result, Display}; |
@@ -484,7 +488,7 @@ use std::io;", | |||
484 | 488 | ||
485 | #[test] | 489 | #[test] |
486 | fn merge_groups_skip_pub_crate() { | 490 | fn merge_groups_skip_pub_crate() { |
487 | check_full( | 491 | check_crate( |
488 | "std::io", | 492 | "std::io", |
489 | r"pub(crate) use std::fmt::{Result, Display};", | 493 | r"pub(crate) use std::fmt::{Result, Display};", |
490 | r"pub(crate) use std::fmt::{Result, Display}; | 494 | r"pub(crate) use std::fmt::{Result, Display}; |
@@ -494,7 +498,7 @@ use std::io;", | |||
494 | 498 | ||
495 | #[test] | 499 | #[test] |
496 | fn merge_groups_skip_attributed() { | 500 | fn merge_groups_skip_attributed() { |
497 | check_full( | 501 | check_crate( |
498 | "std::io", | 502 | "std::io", |
499 | r#" | 503 | r#" |
500 | #[cfg(feature = "gated")] use std::fmt::{Result, Display}; | 504 | #[cfg(feature = "gated")] use std::fmt::{Result, Display}; |
@@ -509,7 +513,7 @@ use std::io; | |||
509 | #[test] | 513 | #[test] |
510 | #[ignore] // FIXME: Support this | 514 | #[ignore] // FIXME: Support this |
511 | fn split_out_merge() { | 515 | fn split_out_merge() { |
512 | check_last( | 516 | check_module( |
513 | "std::fmt::Result", | 517 | "std::fmt::Result", |
514 | r"use std::{fmt, io};", | 518 | r"use std::{fmt, io};", |
515 | r"use std::fmt::{self, Result}; | 519 | r"use std::fmt::{self, Result}; |
@@ -519,29 +523,33 @@ use std::io;", | |||
519 | 523 | ||
520 | #[test] | 524 | #[test] |
521 | fn merge_into_module_import() { | 525 | fn merge_into_module_import() { |
522 | check_full("std::fmt::Result", r"use std::{fmt, io};", r"use std::{fmt::{self, Result}, io};") | 526 | check_crate("std::fmt::Result", r"use std::{fmt, io};", r"use std::{fmt::{self, Result}, io};") |
523 | } | 527 | } |
524 | 528 | ||
525 | #[test] | 529 | #[test] |
526 | fn merge_groups_self() { | 530 | fn merge_groups_self() { |
527 | check_full("std::fmt::Debug", r"use std::fmt;", r"use std::fmt::{self, Debug};") | 531 | check_crate("std::fmt::Debug", r"use std::fmt;", r"use std::fmt::{self, Debug};") |
528 | } | 532 | } |
529 | 533 | ||
530 | #[test] | 534 | #[test] |
531 | fn merge_mod_into_glob() { | 535 | fn merge_mod_into_glob() { |
532 | check_full("token::TokenKind", r"use token::TokenKind::*;", r"use token::TokenKind::{*, self};") | 536 | check_crate( |
537 | "token::TokenKind", | ||
538 | r"use token::TokenKind::*;", | ||
539 | r"use token::TokenKind::{*, self};", | ||
540 | ) | ||
533 | // FIXME: have it emit `use token::TokenKind::{self, *}`? | 541 | // FIXME: have it emit `use token::TokenKind::{self, *}`? |
534 | } | 542 | } |
535 | 543 | ||
536 | #[test] | 544 | #[test] |
537 | fn merge_self_glob() { | 545 | fn merge_self_glob() { |
538 | check_full("self", r"use self::*;", r"use self::{*, self};") | 546 | check_crate("self", r"use self::*;", r"use self::{*, self};") |
539 | // FIXME: have it emit `use {self, *}`? | 547 | // FIXME: have it emit `use {self, *}`? |
540 | } | 548 | } |
541 | 549 | ||
542 | #[test] | 550 | #[test] |
543 | fn merge_glob_nested() { | 551 | fn merge_glob_nested() { |
544 | check_full( | 552 | check_crate( |
545 | "foo::bar::quux::Fez", | 553 | "foo::bar::quux::Fez", |
546 | r"use foo::bar::{Baz, quux::*};", | 554 | r"use foo::bar::{Baz, quux::*};", |
547 | r"use foo::bar::{Baz, quux::{self::*, Fez}};", | 555 | r"use foo::bar::{Baz, quux::{self::*, Fez}};", |
@@ -550,7 +558,7 @@ fn merge_glob_nested() { | |||
550 | 558 | ||
551 | #[test] | 559 | #[test] |
552 | fn merge_nested_considers_first_segments() { | 560 | fn merge_nested_considers_first_segments() { |
553 | check_full( | 561 | check_crate( |
554 | "hir_ty::display::write_bounds_like_dyn_trait", | 562 | "hir_ty::display::write_bounds_like_dyn_trait", |
555 | r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter}, method_resolution};", | 563 | r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter}, method_resolution};", |
556 | r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter, write_bounds_like_dyn_trait}, method_resolution};", | 564 | r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter, write_bounds_like_dyn_trait}, method_resolution};", |
@@ -559,7 +567,7 @@ fn merge_nested_considers_first_segments() { | |||
559 | 567 | ||
560 | #[test] | 568 | #[test] |
561 | fn skip_merge_last_too_long() { | 569 | fn skip_merge_last_too_long() { |
562 | check_last( | 570 | check_module( |
563 | "foo::bar", | 571 | "foo::bar", |
564 | r"use foo::bar::baz::Qux;", | 572 | r"use foo::bar::baz::Qux;", |
565 | r"use foo::bar; | 573 | r"use foo::bar; |
@@ -569,7 +577,7 @@ use foo::bar::baz::Qux;", | |||
569 | 577 | ||
570 | #[test] | 578 | #[test] |
571 | fn skip_merge_last_too_long2() { | 579 | fn skip_merge_last_too_long2() { |
572 | check_last( | 580 | check_module( |
573 | "foo::bar::baz::Qux", | 581 | "foo::bar::baz::Qux", |
574 | r"use foo::bar;", | 582 | r"use foo::bar;", |
575 | r"use foo::bar; | 583 | r"use foo::bar; |
@@ -592,7 +600,7 @@ fn merge_last_fail() { | |||
592 | check_merge_only_fail( | 600 | check_merge_only_fail( |
593 | r"use foo::bar::{baz::{Qux, Fez}};", | 601 | r"use foo::bar::{baz::{Qux, Fez}};", |
594 | r"use foo::bar::{baaz::{Quux, Feez}};", | 602 | r"use foo::bar::{baaz::{Quux, Feez}};", |
595 | MergeBehavior::Last, | 603 | MergeBehavior::Module, |
596 | ); | 604 | ); |
597 | } | 605 | } |
598 | 606 | ||
@@ -601,7 +609,7 @@ fn merge_last_fail1() { | |||
601 | check_merge_only_fail( | 609 | check_merge_only_fail( |
602 | r"use foo::bar::{baz::{Qux, Fez}};", | 610 | r"use foo::bar::{baz::{Qux, Fez}};", |
603 | r"use foo::bar::baaz::{Quux, Feez};", | 611 | r"use foo::bar::baaz::{Quux, Feez};", |
604 | MergeBehavior::Last, | 612 | MergeBehavior::Module, |
605 | ); | 613 | ); |
606 | } | 614 | } |
607 | 615 | ||
@@ -610,7 +618,7 @@ fn merge_last_fail2() { | |||
610 | check_merge_only_fail( | 618 | check_merge_only_fail( |
611 | r"use foo::bar::baz::{Qux, Fez};", | 619 | r"use foo::bar::baz::{Qux, Fez};", |
612 | r"use foo::bar::{baaz::{Quux, Feez}};", | 620 | r"use foo::bar::{baaz::{Quux, Feez}};", |
613 | MergeBehavior::Last, | 621 | MergeBehavior::Module, |
614 | ); | 622 | ); |
615 | } | 623 | } |
616 | 624 | ||
@@ -619,7 +627,7 @@ fn merge_last_fail3() { | |||
619 | check_merge_only_fail( | 627 | check_merge_only_fail( |
620 | r"use foo::bar::baz::{Qux, Fez};", | 628 | r"use foo::bar::baz::{Qux, Fez};", |
621 | r"use foo::bar::baaz::{Quux, Feez};", | 629 | r"use foo::bar::baaz::{Quux, Feez};", |
622 | MergeBehavior::Last, | 630 | MergeBehavior::Module, |
623 | ); | 631 | ); |
624 | } | 632 | } |
625 | 633 | ||
@@ -648,12 +656,12 @@ fn check( | |||
648 | assert_eq_text!(ra_fixture_after, &result); | 656 | assert_eq_text!(ra_fixture_after, &result); |
649 | } | 657 | } |
650 | 658 | ||
651 | fn check_full(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | 659 | fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
652 | check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Full), false, true) | 660 | check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Crate), false, true) |
653 | } | 661 | } |
654 | 662 | ||
655 | fn check_last(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | 663 | fn check_module(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
656 | check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Last), false, true) | 664 | check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Module), false, true) |
657 | } | 665 | } |
658 | 666 | ||
659 | fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | 667 | fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
diff --git a/crates/ide_db/src/helpers/merge_imports.rs b/crates/ide_db/src/helpers/merge_imports.rs index 3f5bbef7f..af2a51a4d 100644 --- a/crates/ide_db/src/helpers/merge_imports.rs +++ b/crates/ide_db/src/helpers/merge_imports.rs | |||
@@ -9,19 +9,19 @@ use syntax::ast::{ | |||
9 | /// What type of merges are allowed. | 9 | /// What type of merges are allowed. |
10 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | 10 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
11 | pub enum MergeBehavior { | 11 | pub enum MergeBehavior { |
12 | /// Merge everything together creating deeply nested imports. | 12 | /// Merge imports from the same crate into a single use statement. |
13 | Full, | 13 | Crate, |
14 | /// Only merge the last import level, doesn't allow import nesting. | 14 | /// Merge imports from the same module into a single use statement. |
15 | Last, | 15 | Module, |
16 | } | 16 | } |
17 | 17 | ||
18 | impl MergeBehavior { | 18 | impl MergeBehavior { |
19 | #[inline] | 19 | #[inline] |
20 | fn is_tree_allowed(&self, tree: &ast::UseTree) -> bool { | 20 | fn is_tree_allowed(&self, tree: &ast::UseTree) -> bool { |
21 | match self { | 21 | match self { |
22 | MergeBehavior::Full => true, | 22 | MergeBehavior::Crate => true, |
23 | // only simple single segment paths are allowed | 23 | // only simple single segment paths are allowed |
24 | MergeBehavior::Last => { | 24 | MergeBehavior::Module => { |
25 | tree.use_tree_list().is_none() && tree.path().map(path_len) <= Some(1) | 25 | tree.use_tree_list().is_none() && tree.path().map(path_len) <= Some(1) |
26 | } | 26 | } |
27 | } | 27 | } |
@@ -137,7 +137,7 @@ fn recursive_merge( | |||
137 | None, | 137 | None, |
138 | false, | 138 | false, |
139 | ); | 139 | ); |
140 | use_trees.insert(idx, make::glob_use_tree()); | 140 | use_trees.insert(idx, make::use_tree_glob()); |
141 | continue; | 141 | continue; |
142 | } | 142 | } |
143 | 143 | ||
@@ -153,7 +153,7 @@ fn recursive_merge( | |||
153 | } | 153 | } |
154 | } | 154 | } |
155 | Err(_) | 155 | Err(_) |
156 | if merge == MergeBehavior::Last | 156 | if merge == MergeBehavior::Module |
157 | && use_trees.len() > 0 | 157 | && use_trees.len() > 0 |
158 | && rhs_t.use_tree_list().is_some() => | 158 | && rhs_t.use_tree_list().is_some() => |
159 | { | 159 | { |
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs index 8f899ea56..67840602b 100644 --- a/crates/ide_db/src/search.rs +++ b/crates/ide_db/src/search.rs | |||
@@ -233,6 +233,13 @@ impl Definition { | |||
233 | }; | 233 | }; |
234 | } | 234 | } |
235 | 235 | ||
236 | if let Definition::SelfType(impl_) = self { | ||
237 | return match impl_.source(db).map(|src| src.value.syntax().text_range()) { | ||
238 | Some(range) => SearchScope::file_range(FileRange { file_id, range }), | ||
239 | None => SearchScope::single_file(file_id), | ||
240 | }; | ||
241 | } | ||
242 | |||
236 | if let Definition::GenericParam(hir::GenericParam::LifetimeParam(param)) = self { | 243 | if let Definition::GenericParam(hir::GenericParam::LifetimeParam(param)) = self { |
237 | let range = match param.parent(db) { | 244 | let range = match param.parent(db) { |
238 | hir::GenericDef::Function(it) => { | 245 | hir::GenericDef::Function(it) => { |
@@ -297,7 +304,7 @@ impl Definition { | |||
297 | } | 304 | } |
298 | 305 | ||
299 | pub fn usages<'a>(&'a self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> { | 306 | pub fn usages<'a>(&'a self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> { |
300 | FindUsages { def: self, sema, scope: None, include_self_kw_refs: false } | 307 | FindUsages { def: self, sema, scope: None, include_self_kw_refs: None } |
301 | } | 308 | } |
302 | } | 309 | } |
303 | 310 | ||
@@ -305,12 +312,13 @@ pub struct FindUsages<'a> { | |||
305 | def: &'a Definition, | 312 | def: &'a Definition, |
306 | sema: &'a Semantics<'a, RootDatabase>, | 313 | sema: &'a Semantics<'a, RootDatabase>, |
307 | scope: Option<SearchScope>, | 314 | scope: Option<SearchScope>, |
308 | include_self_kw_refs: bool, | 315 | include_self_kw_refs: Option<hir::Type>, |
309 | } | 316 | } |
310 | 317 | ||
311 | impl<'a> FindUsages<'a> { | 318 | impl<'a> FindUsages<'a> { |
312 | pub fn include_self_kw_refs(mut self, include: bool) -> FindUsages<'a> { | 319 | /// Enable searching for `Self` when the definition is a type. |
313 | self.include_self_kw_refs = include; | 320 | pub fn include_self_refs(mut self) -> FindUsages<'a> { |
321 | self.include_self_kw_refs = def_to_ty(self.sema, self.def); | ||
314 | self | 322 | self |
315 | } | 323 | } |
316 | 324 | ||
@@ -354,13 +362,18 @@ impl<'a> FindUsages<'a> { | |||
354 | } | 362 | } |
355 | }; | 363 | }; |
356 | 364 | ||
357 | let name = match self.def.name(sema.db) { | 365 | let name = self.def.name(sema.db).or_else(|| { |
358 | Some(it) => it.to_string(), | 366 | self.include_self_kw_refs.as_ref().and_then(|ty| { |
367 | ty.as_adt() | ||
368 | .map(|adt| adt.name(self.sema.db)) | ||
369 | .or_else(|| ty.as_builtin().map(|builtin| builtin.name())) | ||
370 | }) | ||
371 | }); | ||
372 | let name = match name { | ||
373 | Some(name) => name.to_string(), | ||
359 | None => return, | 374 | None => return, |
360 | }; | 375 | }; |
361 | 376 | let name = name.as_str(); | |
362 | let pat = name.as_str(); | ||
363 | let search_for_self = self.include_self_kw_refs; | ||
364 | 377 | ||
365 | for (file_id, search_range) in search_scope { | 378 | for (file_id, search_range) in search_scope { |
366 | let text = sema.db.file_text(file_id); | 379 | let text = sema.db.file_text(file_id); |
@@ -369,51 +382,63 @@ impl<'a> FindUsages<'a> { | |||
369 | 382 | ||
370 | let tree = Lazy::new(|| sema.parse(file_id).syntax().clone()); | 383 | let tree = Lazy::new(|| sema.parse(file_id).syntax().clone()); |
371 | 384 | ||
372 | let mut handle_match = |idx: usize| -> bool { | 385 | for (idx, _) in text.match_indices(name) { |
373 | let offset: TextSize = idx.try_into().unwrap(); | 386 | let offset: TextSize = idx.try_into().unwrap(); |
374 | if !search_range.contains_inclusive(offset) { | 387 | if !search_range.contains_inclusive(offset) { |
375 | return false; | 388 | continue; |
376 | } | 389 | } |
377 | 390 | ||
378 | if let Some(name) = sema.find_node_at_offset_with_descend(&tree, offset) { | 391 | if let Some(name) = sema.find_node_at_offset_with_descend(&tree, offset) { |
379 | match name { | 392 | if match name { |
380 | ast::NameLike::NameRef(name_ref) => { | 393 | ast::NameLike::NameRef(name_ref) => self.found_name_ref(&name_ref, sink), |
381 | if self.found_name_ref(&name_ref, sink) { | 394 | ast::NameLike::Name(name) => self.found_name(&name, sink), |
382 | return true; | 395 | ast::NameLike::Lifetime(lifetime) => self.found_lifetime(&lifetime, sink), |
383 | } | 396 | } { |
384 | } | 397 | return; |
385 | ast::NameLike::Name(name) => { | ||
386 | if self.found_name(&name, sink) { | ||
387 | return true; | ||
388 | } | ||
389 | } | ||
390 | ast::NameLike::Lifetime(lifetime) => { | ||
391 | if self.found_lifetime(&lifetime, sink) { | ||
392 | return true; | ||
393 | } | ||
394 | } | ||
395 | } | 398 | } |
396 | } | 399 | } |
397 | |||
398 | return false; | ||
399 | }; | ||
400 | |||
401 | for (idx, _) in text.match_indices(pat) { | ||
402 | if handle_match(idx) { | ||
403 | return; | ||
404 | } | ||
405 | } | 400 | } |
406 | 401 | if let Some(self_ty) = &self.include_self_kw_refs { | |
407 | if search_for_self { | ||
408 | for (idx, _) in text.match_indices("Self") { | 402 | for (idx, _) in text.match_indices("Self") { |
409 | if handle_match(idx) { | 403 | let offset: TextSize = idx.try_into().unwrap(); |
410 | return; | 404 | if !search_range.contains_inclusive(offset) { |
405 | continue; | ||
406 | } | ||
407 | |||
408 | if let Some(ast::NameLike::NameRef(name_ref)) = | ||
409 | sema.find_node_at_offset_with_descend(&tree, offset) | ||
410 | { | ||
411 | if self.found_self_ty_name_ref(&self_ty, &name_ref, sink) { | ||
412 | return; | ||
413 | } | ||
411 | } | 414 | } |
412 | } | 415 | } |
413 | } | 416 | } |
414 | } | 417 | } |
415 | } | 418 | } |
416 | 419 | ||
420 | fn found_self_ty_name_ref( | ||
421 | &self, | ||
422 | self_ty: &hir::Type, | ||
423 | name_ref: &ast::NameRef, | ||
424 | sink: &mut dyn FnMut(FileId, FileReference) -> bool, | ||
425 | ) -> bool { | ||
426 | match NameRefClass::classify(self.sema, &name_ref) { | ||
427 | Some(NameRefClass::Definition(Definition::SelfType(impl_))) | ||
428 | if impl_.self_ty(self.sema.db) == *self_ty => | ||
429 | { | ||
430 | let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); | ||
431 | let reference = FileReference { | ||
432 | range, | ||
433 | name: ast::NameLike::NameRef(name_ref.clone()), | ||
434 | access: None, | ||
435 | }; | ||
436 | sink(file_id, reference) | ||
437 | } | ||
438 | _ => false, | ||
439 | } | ||
440 | } | ||
441 | |||
417 | fn found_lifetime( | 442 | fn found_lifetime( |
418 | &self, | 443 | &self, |
419 | lifetime: &ast::Lifetime, | 444 | lifetime: &ast::Lifetime, |
@@ -429,7 +454,7 @@ impl<'a> FindUsages<'a> { | |||
429 | }; | 454 | }; |
430 | sink(file_id, reference) | 455 | sink(file_id, reference) |
431 | } | 456 | } |
432 | _ => false, // not a usage | 457 | _ => false, |
433 | } | 458 | } |
434 | } | 459 | } |
435 | 460 | ||
@@ -448,42 +473,35 @@ impl<'a> FindUsages<'a> { | |||
448 | }; | 473 | }; |
449 | sink(file_id, reference) | 474 | sink(file_id, reference) |
450 | } | 475 | } |
451 | Some(NameRefClass::Definition(Definition::SelfType(impl_))) => { | 476 | Some(NameRefClass::Definition(def)) if self.include_self_kw_refs.is_some() => { |
452 | let ty = impl_.self_ty(self.sema.db); | 477 | if self.include_self_kw_refs == def_to_ty(self.sema, &def) { |
453 | 478 | let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); | |
454 | if let Some(adt) = ty.as_adt() { | 479 | let reference = FileReference { |
455 | if &Definition::ModuleDef(ModuleDef::Adt(adt)) == self.def { | 480 | range, |
456 | let FileRange { file_id, range } = | 481 | name: ast::NameLike::NameRef(name_ref.clone()), |
457 | self.sema.original_range(name_ref.syntax()); | 482 | access: reference_access(&def, &name_ref), |
458 | let reference = FileReference { | 483 | }; |
459 | range, | 484 | sink(file_id, reference) |
460 | name: ast::NameLike::NameRef(name_ref.clone()), | 485 | } else { |
461 | access: None, | 486 | false |
462 | }; | ||
463 | return sink(file_id, reference); | ||
464 | } | ||
465 | } | 487 | } |
466 | |||
467 | false | ||
468 | } | 488 | } |
469 | Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => { | 489 | Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => { |
470 | let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); | 490 | let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); |
471 | let reference = match self.def { | 491 | let access = match self.def { |
472 | Definition::Field(_) if &field == self.def => FileReference { | 492 | Definition::Field(_) if &field == self.def => { |
473 | range, | 493 | reference_access(&field, &name_ref) |
474 | name: ast::NameLike::NameRef(name_ref.clone()), | 494 | } |
475 | access: reference_access(&field, &name_ref), | 495 | Definition::Local(l) if &local == l => { |
476 | }, | 496 | reference_access(&Definition::Local(local), &name_ref) |
477 | Definition::Local(l) if &local == l => FileReference { | 497 | } |
478 | range, | 498 | _ => return false, |
479 | name: ast::NameLike::NameRef(name_ref.clone()), | ||
480 | access: reference_access(&Definition::Local(local), &name_ref), | ||
481 | }, | ||
482 | _ => return false, // not a usage | ||
483 | }; | 499 | }; |
500 | let reference = | ||
501 | FileReference { range, name: ast::NameLike::NameRef(name_ref.clone()), access }; | ||
484 | sink(file_id, reference) | 502 | sink(file_id, reference) |
485 | } | 503 | } |
486 | _ => false, // not a usage | 504 | _ => false, |
487 | } | 505 | } |
488 | } | 506 | } |
489 | 507 | ||
@@ -513,11 +531,30 @@ impl<'a> FindUsages<'a> { | |||
513 | FileReference { range, name: ast::NameLike::Name(name.clone()), access: None }; | 531 | FileReference { range, name: ast::NameLike::Name(name.clone()), access: None }; |
514 | sink(file_id, reference) | 532 | sink(file_id, reference) |
515 | } | 533 | } |
516 | _ => false, // not a usage | 534 | _ => false, |
517 | } | 535 | } |
518 | } | 536 | } |
519 | } | 537 | } |
520 | 538 | ||
539 | fn def_to_ty(sema: &Semantics<RootDatabase>, def: &Definition) -> Option<hir::Type> { | ||
540 | match def { | ||
541 | Definition::ModuleDef(def) => match def { | ||
542 | ModuleDef::Adt(adt) => Some(adt.ty(sema.db)), | ||
543 | ModuleDef::TypeAlias(it) => Some(it.ty(sema.db)), | ||
544 | ModuleDef::BuiltinType(it) => { | ||
545 | let graph = sema.db.crate_graph(); | ||
546 | let krate = graph.iter().next()?; | ||
547 | let root_file = graph[krate].root_file_id; | ||
548 | let module = sema.to_module_def(root_file)?; | ||
549 | Some(it.ty(sema.db, module)) | ||
550 | } | ||
551 | _ => None, | ||
552 | }, | ||
553 | Definition::SelfType(it) => Some(it.self_ty(sema.db)), | ||
554 | _ => None, | ||
555 | } | ||
556 | } | ||
557 | |||
521 | fn reference_access(def: &Definition, name_ref: &ast::NameRef) -> Option<ReferenceAccess> { | 558 | fn reference_access(def: &Definition, name_ref: &ast::NameRef) -> Option<ReferenceAccess> { |
522 | // Only Locals and Fields have accesses for now. | 559 | // Only Locals and Fields have accesses for now. |
523 | if !matches!(def, Definition::Local(_) | Definition::Field(_)) { | 560 | if !matches!(def, Definition::Local(_) | Definition::Field(_)) { |
diff --git a/crates/ide_db/src/ty_filter.rs b/crates/ide_db/src/ty_filter.rs index 988ecd060..00678bf3e 100644 --- a/crates/ide_db/src/ty_filter.rs +++ b/crates/ide_db/src/ty_filter.rs | |||
@@ -43,7 +43,7 @@ impl TryEnum { | |||
43 | pub fn sad_pattern(self) -> ast::Pat { | 43 | pub fn sad_pattern(self) -> ast::Pat { |
44 | match self { | 44 | match self { |
45 | TryEnum::Result => make::tuple_struct_pat( | 45 | TryEnum::Result => make::tuple_struct_pat( |
46 | make::path_unqualified(make::path_segment(make::name_ref("Err"))), | 46 | make::ext::ident_path("Err"), |
47 | iter::once(make::wildcard_pat().into()), | 47 | iter::once(make::wildcard_pat().into()), |
48 | ) | 48 | ) |
49 | .into(), | 49 | .into(), |
@@ -54,12 +54,12 @@ impl TryEnum { | |||
54 | pub fn happy_pattern(self) -> ast::Pat { | 54 | pub fn happy_pattern(self) -> ast::Pat { |
55 | match self { | 55 | match self { |
56 | TryEnum::Result => make::tuple_struct_pat( | 56 | TryEnum::Result => make::tuple_struct_pat( |
57 | make::path_unqualified(make::path_segment(make::name_ref("Ok"))), | 57 | make::ext::ident_path("Ok"), |
58 | iter::once(make::wildcard_pat().into()), | 58 | iter::once(make::wildcard_pat().into()), |
59 | ) | 59 | ) |
60 | .into(), | 60 | .into(), |
61 | TryEnum::Option => make::tuple_struct_pat( | 61 | TryEnum::Option => make::tuple_struct_pat( |
62 | make::path_unqualified(make::path_segment(make::name_ref("Some"))), | 62 | make::ext::ident_path("Some"), |
63 | iter::once(make::wildcard_pat().into()), | 63 | iter::once(make::wildcard_pat().into()), |
64 | ) | 64 | ) |
65 | .into(), | 65 | .into(), |
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index bc6e20341..b18699b77 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs | |||
@@ -201,31 +201,12 @@ impl CargoWorkspace { | |||
201 | if let Some(parent) = cargo_toml.parent() { | 201 | if let Some(parent) = cargo_toml.parent() { |
202 | meta.current_dir(parent.to_path_buf()); | 202 | meta.current_dir(parent.to_path_buf()); |
203 | } | 203 | } |
204 | let target = if let Some(target) = config.target.as_ref() { | 204 | let target = if let Some(target) = &config.target { |
205 | Some(target.clone()) | 205 | Some(target.clone()) |
206 | } else if let stdout @ Some(_) = cargo_config_build_target(cargo_toml) { | ||
207 | stdout | ||
206 | } else { | 208 | } else { |
207 | // cargo metadata defaults to giving information for _all_ targets. | 209 | rustc_discover_host_triple(cargo_toml) |
208 | // In the absence of a preference from the user, we use the host platform. | ||
209 | let mut rustc = Command::new(toolchain::rustc()); | ||
210 | rustc.current_dir(cargo_toml.parent().unwrap()).arg("-vV"); | ||
211 | log::debug!("Discovering host platform by {:?}", rustc); | ||
212 | match utf8_stdout(rustc) { | ||
213 | Ok(stdout) => { | ||
214 | let field = "host: "; | ||
215 | let target = stdout.lines().find_map(|l| l.strip_prefix(field)); | ||
216 | if let Some(target) = target { | ||
217 | Some(target.to_string()) | ||
218 | } else { | ||
219 | // If we fail to resolve the host platform, it's not the end of the world. | ||
220 | log::info!("rustc -vV did not report host platform, got:\n{}", stdout); | ||
221 | None | ||
222 | } | ||
223 | } | ||
224 | Err(e) => { | ||
225 | log::warn!("Failed to discover host platform: {}", e); | ||
226 | None | ||
227 | } | ||
228 | } | ||
229 | }; | 210 | }; |
230 | if let Some(target) = target { | 211 | if let Some(target) = target { |
231 | meta.other_options(vec![String::from("--filter-platform"), target]); | 212 | meta.other_options(vec![String::from("--filter-platform"), target]); |
@@ -368,3 +349,43 @@ impl CargoWorkspace { | |||
368 | self.packages.iter().filter(|(_, v)| v.name == name).count() == 1 | 349 | self.packages.iter().filter(|(_, v)| v.name == name).count() == 1 |
369 | } | 350 | } |
370 | } | 351 | } |
352 | |||
353 | fn rustc_discover_host_triple(cargo_toml: &AbsPath) -> Option<String> { | ||
354 | let mut rustc = Command::new(toolchain::rustc()); | ||
355 | rustc.current_dir(cargo_toml.parent().unwrap()).arg("-vV"); | ||
356 | log::debug!("Discovering host platform by {:?}", rustc); | ||
357 | match utf8_stdout(rustc) { | ||
358 | Ok(stdout) => { | ||
359 | let field = "host: "; | ||
360 | let target = stdout.lines().find_map(|l| l.strip_prefix(field)); | ||
361 | if let Some(target) = target { | ||
362 | Some(target.to_string()) | ||
363 | } else { | ||
364 | // If we fail to resolve the host platform, it's not the end of the world. | ||
365 | log::info!("rustc -vV did not report host platform, got:\n{}", stdout); | ||
366 | None | ||
367 | } | ||
368 | } | ||
369 | Err(e) => { | ||
370 | log::warn!("Failed to discover host platform: {}", e); | ||
371 | None | ||
372 | } | ||
373 | } | ||
374 | } | ||
375 | |||
376 | fn cargo_config_build_target(cargo_toml: &AbsPath) -> Option<String> { | ||
377 | let mut cargo_config = Command::new(toolchain::cargo()); | ||
378 | cargo_config | ||
379 | .current_dir(cargo_toml.parent().unwrap()) | ||
380 | .args(&["-Z", "unstable-options", "config", "get", "build.target"]) | ||
381 | .env("RUSTC_BOOTSTRAP", "1"); | ||
382 | // if successful we receive `build.target = "target-triple"` | ||
383 | log::debug!("Discovering cargo config target by {:?}", cargo_config); | ||
384 | match utf8_stdout(cargo_config) { | ||
385 | Ok(stdout) => stdout | ||
386 | .strip_prefix("build.target = \"") | ||
387 | .and_then(|stdout| stdout.strip_suffix('"')) | ||
388 | .map(ToOwned::to_owned), | ||
389 | Err(_) => None, | ||
390 | } | ||
391 | } | ||
diff --git a/crates/project_model/src/rustc_cfg.rs b/crates/project_model/src/rustc_cfg.rs index 312708575..012eab256 100644 --- a/crates/project_model/src/rustc_cfg.rs +++ b/crates/project_model/src/rustc_cfg.rs | |||
@@ -2,9 +2,12 @@ | |||
2 | 2 | ||
3 | use std::process::Command; | 3 | use std::process::Command; |
4 | 4 | ||
5 | use anyhow::Result; | ||
6 | use paths::AbsPath; | ||
7 | |||
5 | use crate::{cfg_flag::CfgFlag, utf8_stdout}; | 8 | use crate::{cfg_flag::CfgFlag, utf8_stdout}; |
6 | 9 | ||
7 | pub(crate) fn get(target: Option<&str>) -> Vec<CfgFlag> { | 10 | pub(crate) fn get(cargo_toml: Option<&AbsPath>, target: Option<&str>) -> Vec<CfgFlag> { |
8 | let _p = profile::span("rustc_cfg::get"); | 11 | let _p = profile::span("rustc_cfg::get"); |
9 | let mut res = Vec::with_capacity(6 * 2 + 1); | 12 | let mut res = Vec::with_capacity(6 * 2 + 1); |
10 | 13 | ||
@@ -16,19 +19,39 @@ pub(crate) fn get(target: Option<&str>) -> Vec<CfgFlag> { | |||
16 | } | 19 | } |
17 | } | 20 | } |
18 | 21 | ||
19 | let rustc_cfgs = { | 22 | match get_rust_cfgs(cargo_toml, target) { |
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())), | 23 | Ok(rustc_cfgs) => res.extend(rustc_cfgs.lines().map(|it| it.parse().unwrap())), |
30 | Err(e) => log::error!("failed to get rustc cfgs: {:#}", e), | 24 | Err(e) => log::error!("failed to get rustc cfgs: {:#}", e), |
31 | } | 25 | } |
32 | 26 | ||
33 | res | 27 | res |
34 | } | 28 | } |
29 | |||
30 | fn get_rust_cfgs(cargo_toml: Option<&AbsPath>, target: Option<&str>) -> Result<String> { | ||
31 | let cargo_rust_cfgs = match cargo_toml { | ||
32 | Some(cargo_toml) => { | ||
33 | let mut cargo_config = Command::new(toolchain::cargo()); | ||
34 | cargo_config | ||
35 | .current_dir(cargo_toml.parent().unwrap()) | ||
36 | .args(&["-Z", "unstable-options", "rustc", "--print", "cfg"]) | ||
37 | .env("RUSTC_BOOTSTRAP", "1"); | ||
38 | if let Some(target) = target { | ||
39 | cargo_config.args(&["--target", target]); | ||
40 | } | ||
41 | utf8_stdout(cargo_config).ok() | ||
42 | } | ||
43 | None => None, | ||
44 | }; | ||
45 | match cargo_rust_cfgs { | ||
46 | Some(stdout) => Ok(stdout), | ||
47 | None => { | ||
48 | // using unstable cargo features failed, fall back to using plain rustc | ||
49 | let mut cmd = Command::new(toolchain::rustc()); | ||
50 | cmd.args(&["--print", "cfg", "-O"]); | ||
51 | if let Some(target) = target { | ||
52 | cmd.args(&["--target", target]); | ||
53 | } | ||
54 | utf8_stdout(cmd) | ||
55 | } | ||
56 | } | ||
57 | } | ||
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs index 2fcd0f8fa..84c702fdf 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs | |||
@@ -143,7 +143,8 @@ impl ProjectWorkspace { | |||
143 | } else { | 143 | } else { |
144 | None | 144 | None |
145 | }; | 145 | }; |
146 | let rustc_cfg = rustc_cfg::get(config.target.as_deref()); | 146 | |
147 | let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref()); | ||
147 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } | 148 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } |
148 | } | 149 | } |
149 | }; | 150 | }; |
@@ -159,7 +160,7 @@ impl ProjectWorkspace { | |||
159 | Some(path) => Some(Sysroot::load(path)?), | 160 | Some(path) => Some(Sysroot::load(path)?), |
160 | None => None, | 161 | None => None, |
161 | }; | 162 | }; |
162 | let rustc_cfg = rustc_cfg::get(target); | 163 | let rustc_cfg = rustc_cfg::get(None, target); |
163 | Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }) | 164 | Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }) |
164 | } | 165 | } |
165 | 166 | ||
@@ -310,7 +311,7 @@ fn project_json_to_crate_graph( | |||
310 | 311 | ||
311 | let target_cfgs = match krate.target.as_deref() { | 312 | let target_cfgs = match krate.target.as_deref() { |
312 | Some(target) => { | 313 | Some(target) => { |
313 | cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(Some(target))) | 314 | cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(None, Some(target))) |
314 | } | 315 | } |
315 | None => &rustc_cfg, | 316 | None => &rustc_cfg, |
316 | }; | 317 | }; |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 8879a9161..d83670bda 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -36,7 +36,7 @@ config_data! { | |||
36 | struct ConfigData { | 36 | struct ConfigData { |
37 | /// The strategy to use when inserting new imports or merging imports. | 37 | /// The strategy to use when inserting new imports or merging imports. |
38 | assist_importMergeBehavior | | 38 | assist_importMergeBehavior | |
39 | assist_importMergeBehaviour: MergeBehaviorDef = "\"full\"", | 39 | assist_importMergeBehaviour: MergeBehaviorDef = "\"crate\"", |
40 | /// The path structure for newly inserted paths to use. | 40 | /// The path structure for newly inserted paths to use. |
41 | assist_importPrefix: ImportPrefixDef = "\"plain\"", | 41 | assist_importPrefix: ImportPrefixDef = "\"plain\"", |
42 | /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines. | 42 | /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines. |
@@ -604,8 +604,8 @@ impl Config { | |||
604 | InsertUseConfig { | 604 | InsertUseConfig { |
605 | merge: match self.data.assist_importMergeBehavior { | 605 | merge: match self.data.assist_importMergeBehavior { |
606 | MergeBehaviorDef::None => None, | 606 | MergeBehaviorDef::None => None, |
607 | MergeBehaviorDef::Full => Some(MergeBehavior::Full), | 607 | MergeBehaviorDef::Crate => Some(MergeBehavior::Crate), |
608 | MergeBehaviorDef::Last => Some(MergeBehavior::Last), | 608 | MergeBehaviorDef::Module => Some(MergeBehavior::Module), |
609 | }, | 609 | }, |
610 | prefix_kind: match self.data.assist_importPrefix { | 610 | prefix_kind: match self.data.assist_importPrefix { |
611 | ImportPrefixDef::Plain => PrefixKind::Plain, | 611 | ImportPrefixDef::Plain => PrefixKind::Plain, |
@@ -709,8 +709,10 @@ enum ManifestOrProjectJson { | |||
709 | #[serde(rename_all = "snake_case")] | 709 | #[serde(rename_all = "snake_case")] |
710 | enum MergeBehaviorDef { | 710 | enum MergeBehaviorDef { |
711 | None, | 711 | None, |
712 | Full, | 712 | #[serde(alias = "full")] |
713 | Last, | 713 | Crate, |
714 | #[serde(alias = "last")] | ||
715 | Module, | ||
714 | } | 716 | } |
715 | 717 | ||
716 | #[derive(Deserialize, Debug, Clone)] | 718 | #[derive(Deserialize, Debug, Clone)] |
@@ -867,11 +869,11 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json | |||
867 | }, | 869 | }, |
868 | "MergeBehaviorDef" => set! { | 870 | "MergeBehaviorDef" => set! { |
869 | "type": "string", | 871 | "type": "string", |
870 | "enum": ["none", "full", "last"], | 872 | "enum": ["none", "crate", "module"], |
871 | "enumDescriptions": [ | 873 | "enumDescriptions": [ |
872 | "No merging", | 874 | "Do not merge imports at all.", |
873 | "Merge all layers of the import trees", | 875 | "Merge imports from the same crate into a single `use` statement.", |
874 | "Only merge the last layer of the import trees" | 876 | "Merge imports from the same module into a single `use` statement." |
875 | ], | 877 | ], |
876 | }, | 878 | }, |
877 | "ImportPrefixDef" => set! { | 879 | "ImportPrefixDef" => set! { |
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs index 3dcbe397a..56de9681c 100644 --- a/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/crates/rust-analyzer/src/integrated_benchmarks.rs | |||
@@ -133,7 +133,7 @@ fn integrated_completion_benchmark() { | |||
133 | add_call_argument_snippets: true, | 133 | add_call_argument_snippets: true, |
134 | snippet_cap: SnippetCap::new(true), | 134 | snippet_cap: SnippetCap::new(true), |
135 | insert_use: InsertUseConfig { | 135 | insert_use: InsertUseConfig { |
136 | merge: Some(MergeBehavior::Full), | 136 | merge: Some(MergeBehavior::Crate), |
137 | prefix_kind: hir::PrefixKind::ByCrate, | 137 | prefix_kind: hir::PrefixKind::ByCrate, |
138 | group: true, | 138 | group: true, |
139 | }, | 139 | }, |
@@ -166,7 +166,7 @@ fn integrated_completion_benchmark() { | |||
166 | add_call_argument_snippets: true, | 166 | add_call_argument_snippets: true, |
167 | snippet_cap: SnippetCap::new(true), | 167 | snippet_cap: SnippetCap::new(true), |
168 | insert_use: InsertUseConfig { | 168 | insert_use: InsertUseConfig { |
169 | merge: Some(MergeBehavior::Full), | 169 | merge: Some(MergeBehavior::Crate), |
170 | prefix_kind: hir::PrefixKind::ByCrate, | 170 | prefix_kind: hir::PrefixKind::ByCrate, |
171 | group: true, | 171 | group: true, |
172 | }, | 172 | }, |
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index 04f97f368..168355555 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs | |||
@@ -195,18 +195,13 @@ impl ast::GenericParamList { | |||
195 | pub fn add_generic_param(&self, generic_param: ast::GenericParam) { | 195 | pub fn add_generic_param(&self, generic_param: ast::GenericParam) { |
196 | match self.generic_params().last() { | 196 | match self.generic_params().last() { |
197 | Some(last_param) => { | 197 | Some(last_param) => { |
198 | let mut elems = Vec::new(); | 198 | let position = Position::after(last_param.syntax()); |
199 | if !last_param | 199 | let elements = vec![ |
200 | .syntax() | 200 | make::token(T![,]).into(), |
201 | .siblings_with_tokens(Direction::Next) | 201 | make::tokens::single_space().into(), |
202 | .any(|it| it.kind() == T![,]) | 202 | generic_param.syntax().clone().into(), |
203 | { | 203 | ]; |
204 | elems.push(make::token(T![,]).into()); | 204 | ted::insert_all(position, elements); |
205 | elems.push(make::tokens::single_space().into()); | ||
206 | }; | ||
207 | elems.push(generic_param.syntax().clone().into()); | ||
208 | let after_last_param = Position::after(last_param.syntax()); | ||
209 | ted::insert_all(after_last_param, elems); | ||
210 | } | 205 | } |
211 | None => { | 206 | None => { |
212 | let after_l_angle = Position::after(self.l_angle_token().unwrap()); | 207 | let after_l_angle = Position::after(self.l_angle_token().unwrap()); |
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 5a6687397..1998ad1f6 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs | |||
@@ -3,25 +3,55 @@ | |||
3 | //! | 3 | //! |
4 | //! Note that all functions here intended to be stupid constructors, which just | 4 | //! Note that all functions here intended to be stupid constructors, which just |
5 | //! assemble a finish node from immediate children. If you want to do something | 5 | //! assemble a finish node from immediate children. If you want to do something |
6 | //! smarter than that, it probably doesn't belong in this module. | 6 | //! smarter than that, it belongs to the `ext` submodule. |
7 | //! | 7 | //! |
8 | //! Keep in mind that `from_text` functions should be kept private. The public | 8 | //! Keep in mind that `from_text` functions should be kept private. The public |
9 | //! API should require to assemble every node piecewise. The trick of | 9 | //! API should require to assemble every node piecewise. The trick of |
10 | //! `parse(format!())` we use internally is an implementation detail -- long | 10 | //! `parse(format!())` we use internally is an implementation detail -- long |
11 | //! term, it will be replaced with direct tree manipulation. | 11 | //! term, it will be replaced with direct tree manipulation. |
12 | use itertools::Itertools; | 12 | use itertools::Itertools; |
13 | use stdx::format_to; | 13 | use stdx::{format_to, never}; |
14 | 14 | ||
15 | use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, SyntaxToken}; | 15 | use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, SyntaxToken}; |
16 | 16 | ||
17 | /// While the parent module defines basic atomic "constructors", the `ext` | ||
18 | /// module defines shortcuts for common things. | ||
19 | /// | ||
20 | /// It's named `ext` rather than `shortcuts` just to keep it short. | ||
21 | pub mod ext { | ||
22 | use super::*; | ||
23 | |||
24 | pub fn ident_path(ident: &str) -> ast::Path { | ||
25 | path_unqualified(path_segment(name_ref(ident))) | ||
26 | } | ||
27 | |||
28 | pub fn expr_unreachable() -> ast::Expr { | ||
29 | expr_from_text("unreachable!()") | ||
30 | } | ||
31 | pub fn expr_todo() -> ast::Expr { | ||
32 | expr_from_text("todo!()") | ||
33 | } | ||
34 | pub fn empty_block_expr() -> ast::BlockExpr { | ||
35 | block_expr(None, None) | ||
36 | } | ||
37 | |||
38 | pub fn ty_bool() -> ast::Type { | ||
39 | ty_path(ident_path("bool")) | ||
40 | } | ||
41 | pub fn ty_option(t: ast::Type) -> ast::Type { | ||
42 | ty_from_text(&format!("Option<{}>", t)) | ||
43 | } | ||
44 | pub fn ty_result(t: ast::Type, e: ast::Type) -> ast::Type { | ||
45 | ty_from_text(&format!("Result<{}, {}>", t, e)) | ||
46 | } | ||
47 | } | ||
48 | |||
17 | pub fn name(text: &str) -> ast::Name { | 49 | pub fn name(text: &str) -> ast::Name { |
18 | ast_from_text(&format!("mod {}{};", raw_ident_esc(text), text)) | 50 | ast_from_text(&format!("mod {}{};", raw_ident_esc(text), text)) |
19 | } | 51 | } |
20 | |||
21 | pub fn name_ref(text: &str) -> ast::NameRef { | 52 | pub fn name_ref(text: &str) -> ast::NameRef { |
22 | ast_from_text(&format!("fn f() {{ {}{}; }}", raw_ident_esc(text), text)) | 53 | ast_from_text(&format!("fn f() {{ {}{}; }}", raw_ident_esc(text), text)) |
23 | } | 54 | } |
24 | |||
25 | fn raw_ident_esc(ident: &str) -> &'static str { | 55 | fn raw_ident_esc(ident: &str) -> &'static str { |
26 | let is_keyword = parser::SyntaxKind::from_keyword(ident).is_some(); | 56 | let is_keyword = parser::SyntaxKind::from_keyword(ident).is_some(); |
27 | if is_keyword && !matches!(ident, "self" | "crate" | "super" | "Self") { | 57 | if is_keyword && !matches!(ident, "self" | "crate" | "super" | "Self") { |
@@ -31,13 +61,23 @@ fn raw_ident_esc(ident: &str) -> &'static str { | |||
31 | } | 61 | } |
32 | } | 62 | } |
33 | 63 | ||
64 | pub fn lifetime(text: &str) -> ast::Lifetime { | ||
65 | let mut text = text; | ||
66 | let tmp; | ||
67 | if never!(!text.starts_with('\'')) { | ||
68 | tmp = format!("'{}", text); | ||
69 | text = &tmp; | ||
70 | } | ||
71 | ast_from_text(&format!("fn f<{}>() {{ }}", text)) | ||
72 | } | ||
73 | |||
34 | // FIXME: replace stringly-typed constructor with a family of typed ctors, a-la | 74 | // FIXME: replace stringly-typed constructor with a family of typed ctors, a-la |
35 | // `expr_xxx`. | 75 | // `expr_xxx`. |
36 | pub fn ty(text: &str) -> ast::Type { | 76 | pub fn ty(text: &str) -> ast::Type { |
37 | ast_from_text(&format!("fn f() -> {} {{}}", text)) | 77 | ty_from_text(text) |
38 | } | 78 | } |
39 | pub fn ty_unit() -> ast::Type { | 79 | pub fn ty_unit() -> ast::Type { |
40 | ty("()") | 80 | ty_from_text("()") |
41 | } | 81 | } |
42 | pub fn ty_tuple(types: impl IntoIterator<Item = ast::Type>) -> ast::Type { | 82 | pub fn ty_tuple(types: impl IntoIterator<Item = ast::Type>) -> ast::Type { |
43 | let mut count: usize = 0; | 83 | let mut count: usize = 0; |
@@ -46,15 +86,16 @@ pub fn ty_tuple(types: impl IntoIterator<Item = ast::Type>) -> ast::Type { | |||
46 | contents.push(','); | 86 | contents.push(','); |
47 | } | 87 | } |
48 | 88 | ||
49 | ty(&format!("({})", contents)) | 89 | ty_from_text(&format!("({})", contents)) |
50 | } | ||
51 | // FIXME: handle path to type | ||
52 | pub fn ty_generic(name: ast::NameRef, types: impl IntoIterator<Item = ast::Type>) -> ast::Type { | ||
53 | let contents = types.into_iter().join(", "); | ||
54 | ty(&format!("{}<{}>", name, contents)) | ||
55 | } | 90 | } |
56 | pub fn ty_ref(target: ast::Type, exclusive: bool) -> ast::Type { | 91 | pub fn ty_ref(target: ast::Type, exclusive: bool) -> ast::Type { |
57 | ty(&if exclusive { format!("&mut {}", target) } else { format!("&{}", target) }) | 92 | ty_from_text(&if exclusive { format!("&mut {}", target) } else { format!("&{}", target) }) |
93 | } | ||
94 | pub fn ty_path(path: ast::Path) -> ast::Type { | ||
95 | ty_from_text(&path.to_string()) | ||
96 | } | ||
97 | fn ty_from_text(text: &str) -> ast::Type { | ||
98 | ast_from_text(&format!("type _T = {};", text)) | ||
58 | } | 99 | } |
59 | 100 | ||
60 | pub fn assoc_item_list() -> ast::AssocItemList { | 101 | pub fn assoc_item_list() -> ast::AssocItemList { |
@@ -88,7 +129,7 @@ pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path { | |||
88 | pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { | 129 | pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { |
89 | ast_from_text(&format!("{}::{}", qual, segment)) | 130 | ast_from_text(&format!("{}::{}", qual, segment)) |
90 | } | 131 | } |
91 | 132 | // FIXME: path concatenation operation doesn't make sense as AST op. | |
92 | pub fn path_concat(first: ast::Path, second: ast::Path) -> ast::Path { | 133 | pub fn path_concat(first: ast::Path, second: ast::Path) -> ast::Path { |
93 | ast_from_text(&format!("{}::{}", first, second)) | 134 | ast_from_text(&format!("{}::{}", first, second)) |
94 | } | 135 | } |
@@ -104,15 +145,14 @@ pub fn path_from_segments( | |||
104 | format!("use {};", segments) | 145 | format!("use {};", segments) |
105 | }) | 146 | }) |
106 | } | 147 | } |
107 | 148 | // FIXME: should not be pub | |
108 | pub fn path_from_text(text: &str) -> ast::Path { | 149 | pub fn path_from_text(text: &str) -> ast::Path { |
109 | ast_from_text(&format!("fn main() {{ let test = {}; }}", text)) | 150 | ast_from_text(&format!("fn main() {{ let test = {}; }}", text)) |
110 | } | 151 | } |
111 | 152 | ||
112 | pub fn glob_use_tree() -> ast::UseTree { | 153 | pub fn use_tree_glob() -> ast::UseTree { |
113 | ast_from_text("use *;") | 154 | ast_from_text("use *;") |
114 | } | 155 | } |
115 | |||
116 | pub fn use_tree( | 156 | pub fn use_tree( |
117 | path: ast::Path, | 157 | path: ast::Path, |
118 | use_tree_list: Option<ast::UseTreeList>, | 158 | use_tree_list: Option<ast::UseTreeList>, |
@@ -207,15 +247,6 @@ pub fn expr_literal(text: &str) -> ast::Literal { | |||
207 | pub fn expr_empty_block() -> ast::Expr { | 247 | pub fn expr_empty_block() -> ast::Expr { |
208 | expr_from_text("{}") | 248 | expr_from_text("{}") |
209 | } | 249 | } |
210 | pub fn expr_unimplemented() -> ast::Expr { | ||
211 | expr_from_text("unimplemented!()") | ||
212 | } | ||
213 | pub fn expr_unreachable() -> ast::Expr { | ||
214 | expr_from_text("unreachable!()") | ||
215 | } | ||
216 | pub fn expr_todo() -> ast::Expr { | ||
217 | expr_from_text("todo!()") | ||
218 | } | ||
219 | pub fn expr_path(path: ast::Path) -> ast::Expr { | 250 | pub fn expr_path(path: ast::Path) -> ast::Expr { |
220 | expr_from_text(&path.to_string()) | 251 | expr_from_text(&path.to_string()) |
221 | } | 252 | } |
@@ -444,17 +475,6 @@ pub fn expr_stmt(expr: ast::Expr) -> ast::ExprStmt { | |||
444 | ast_from_text(&format!("fn f() {{ {}{} (); }}", expr, semi)) | 475 | ast_from_text(&format!("fn f() {{ {}{} (); }}", expr, semi)) |
445 | } | 476 | } |
446 | 477 | ||
447 | pub fn token(kind: SyntaxKind) -> SyntaxToken { | ||
448 | tokens::SOURCE_FILE | ||
449 | .tree() | ||
450 | .syntax() | ||
451 | .clone_for_update() | ||
452 | .descendants_with_tokens() | ||
453 | .filter_map(|it| it.into_token()) | ||
454 | .find(|it| it.kind() == kind) | ||
455 | .unwrap_or_else(|| panic!("unhandled token: {:?}", kind)) | ||
456 | } | ||
457 | |||
458 | pub fn param(pat: ast::Pat, ty: ast::Type) -> ast::Param { | 478 | pub fn param(pat: ast::Pat, ty: ast::Type) -> ast::Param { |
459 | ast_from_text(&format!("fn f({}: {}) {{ }}", pat, ty)) | 479 | ast_from_text(&format!("fn f({}: {}) {{ }}", pat, ty)) |
460 | } | 480 | } |
@@ -476,7 +496,7 @@ pub fn param_list( | |||
476 | ast_from_text(&list) | 496 | ast_from_text(&list) |
477 | } | 497 | } |
478 | 498 | ||
479 | pub fn generic_param(name: String, ty: Option<ast::TypeBoundList>) -> ast::GenericParam { | 499 | pub fn type_param(name: ast::Name, ty: Option<ast::TypeBoundList>) -> ast::TypeParam { |
480 | let bound = match ty { | 500 | let bound = match ty { |
481 | Some(it) => format!(": {}", it), | 501 | Some(it) => format!(": {}", it), |
482 | None => String::new(), | 502 | None => String::new(), |
@@ -484,6 +504,10 @@ pub fn generic_param(name: String, ty: Option<ast::TypeBoundList>) -> ast::Gener | |||
484 | ast_from_text(&format!("fn f<{}{}>() {{ }}", name, bound)) | 504 | ast_from_text(&format!("fn f<{}{}>() {{ }}", name, bound)) |
485 | } | 505 | } |
486 | 506 | ||
507 | pub fn lifetime_param(lifetime: ast::Lifetime) -> ast::LifetimeParam { | ||
508 | ast_from_text(&format!("fn f<{}>() {{ }}", lifetime)) | ||
509 | } | ||
510 | |||
487 | pub fn generic_param_list( | 511 | pub fn generic_param_list( |
488 | pats: impl IntoIterator<Item = ast::GenericParam>, | 512 | pats: impl IntoIterator<Item = ast::GenericParam>, |
489 | ) -> ast::GenericParamList { | 513 | ) -> ast::GenericParamList { |
@@ -588,6 +612,17 @@ fn unroot(n: SyntaxNode) -> SyntaxNode { | |||
588 | SyntaxNode::new_root(n.green().into()) | 612 | SyntaxNode::new_root(n.green().into()) |
589 | } | 613 | } |
590 | 614 | ||
615 | pub fn token(kind: SyntaxKind) -> SyntaxToken { | ||
616 | tokens::SOURCE_FILE | ||
617 | .tree() | ||
618 | .syntax() | ||
619 | .clone_for_update() | ||
620 | .descendants_with_tokens() | ||
621 | .filter_map(|it| it.into_token()) | ||
622 | .find(|it| it.kind() == kind) | ||
623 | .unwrap_or_else(|| panic!("unhandled token: {:?}", kind)) | ||
624 | } | ||
625 | |||
591 | pub mod tokens { | 626 | pub mod tokens { |
592 | use once_cell::sync::Lazy; | 627 | use once_cell::sync::Lazy; |
593 | 628 | ||