diff options
Diffstat (limited to 'crates')
102 files changed, 1421 insertions, 676 deletions
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs index 5f77a0b1f..980a0ed98 100644 --- a/crates/base_db/src/lib.rs +++ b/crates/base_db/src/lib.rs | |||
@@ -59,6 +59,8 @@ pub trait CheckCanceled { | |||
59 | Self: Sized + panic::RefUnwindSafe, | 59 | Self: Sized + panic::RefUnwindSafe, |
60 | F: FnOnce(&Self) -> T + panic::UnwindSafe, | 60 | F: FnOnce(&Self) -> T + panic::UnwindSafe, |
61 | { | 61 | { |
62 | // Uncomment to debug missing cancellations. | ||
63 | // let _span = profile::heartbeat_span(); | ||
62 | panic::catch_unwind(|| f(self)).map_err(|err| match err.downcast::<Canceled>() { | 64 | panic::catch_unwind(|| f(self)).map_err(|err| match err.downcast::<Canceled>() { |
63 | Ok(canceled) => *canceled, | 65 | Ok(canceled) => *canceled, |
64 | Err(payload) => panic::resume_unwind(payload), | 66 | Err(payload) => panic::resume_unwind(payload), |
@@ -68,6 +70,7 @@ pub trait CheckCanceled { | |||
68 | 70 | ||
69 | impl<T: salsa::Database> CheckCanceled for T { | 71 | impl<T: salsa::Database> CheckCanceled for T { |
70 | fn check_canceled(&self) { | 72 | fn check_canceled(&self) { |
73 | // profile::heartbeat(); | ||
71 | if self.salsa_runtime().is_current_revision_canceled() { | 74 | if self.salsa_runtime().is_current_revision_canceled() { |
72 | Canceled::throw() | 75 | Canceled::throw() |
73 | } | 76 | } |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 4ee08ef21..97f162315 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -44,6 +44,7 @@ use hir_def::{ | |||
44 | per_ns::PerNs, | 44 | per_ns::PerNs, |
45 | resolver::{HasResolver, Resolver}, | 45 | resolver::{HasResolver, Resolver}, |
46 | src::HasSource as _, | 46 | src::HasSource as _, |
47 | type_ref::TraitRef, | ||
47 | AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, | 48 | AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, |
48 | DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, | 49 | DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, |
49 | LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, | 50 | LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, |
@@ -1573,9 +1574,9 @@ impl Impl { | |||
1573 | }; | 1574 | }; |
1574 | 1575 | ||
1575 | let filter = |impl_def: &Impl| { | 1576 | let filter = |impl_def: &Impl| { |
1576 | let target_ty = impl_def.target_ty(db); | 1577 | let self_ty = impl_def.self_ty(db); |
1577 | let rref = target_ty.remove_ref(); | 1578 | let rref = self_ty.remove_ref(); |
1578 | ty.equals_ctor(rref.as_ref().map_or(&target_ty.ty, |it| &it.ty)) | 1579 | ty.equals_ctor(rref.as_ref().map_or(&self_ty.ty, |it| &it.ty)) |
1579 | }; | 1580 | }; |
1580 | 1581 | ||
1581 | let mut all = Vec::new(); | 1582 | let mut all = Vec::new(); |
@@ -1613,16 +1614,16 @@ impl Impl { | |||
1613 | 1614 | ||
1614 | // FIXME: the return type is wrong. This should be a hir version of | 1615 | // FIXME: the return type is wrong. This should be a hir version of |
1615 | // `TraitRef` (ie, resolved `TypeRef`). | 1616 | // `TraitRef` (ie, resolved `TypeRef`). |
1616 | pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> { | 1617 | pub fn trait_(self, db: &dyn HirDatabase) -> Option<TraitRef> { |
1617 | db.impl_data(self.id).target_trait.clone() | 1618 | db.impl_data(self.id).target_trait.clone() |
1618 | } | 1619 | } |
1619 | 1620 | ||
1620 | pub fn target_ty(self, db: &dyn HirDatabase) -> Type { | 1621 | pub fn self_ty(self, db: &dyn HirDatabase) -> Type { |
1621 | let impl_data = db.impl_data(self.id); | 1622 | let impl_data = db.impl_data(self.id); |
1622 | let resolver = self.id.resolver(db.upcast()); | 1623 | let resolver = self.id.resolver(db.upcast()); |
1623 | let krate = self.id.lookup(db.upcast()).container.krate(); | 1624 | let krate = self.id.lookup(db.upcast()).container.krate(); |
1624 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | 1625 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); |
1625 | let ty = ctx.lower_ty(&impl_data.target_type); | 1626 | let ty = ctx.lower_ty(&impl_data.self_ty); |
1626 | Type::new_with_resolver_inner(db, krate, &resolver, ty) | 1627 | Type::new_with_resolver_inner(db, krate, &resolver, ty) |
1627 | } | 1628 | } |
1628 | 1629 | ||
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 1198e3f0b..d3caeef4e 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -445,7 +445,7 @@ impl<'db> SemanticsImpl<'db> { | |||
445 | } | 445 | } |
446 | }; | 446 | }; |
447 | gpl.lifetime_params() | 447 | gpl.lifetime_params() |
448 | .find(|tp| tp.lifetime().as_ref().map(|lt| lt.text()) == Some(text)) | 448 | .find(|tp| tp.lifetime().as_ref().map(|lt| lt.text()).as_ref() == Some(&text)) |
449 | })?; | 449 | })?; |
450 | let src = self.find_file(lifetime_param.syntax().clone()).with_value(lifetime_param); | 450 | let src = self.find_file(lifetime_param.syntax().clone()).with_value(lifetime_param); |
451 | ToDef::to_def(self, src) | 451 | ToDef::to_def(self, src) |
@@ -768,7 +768,7 @@ to_def_impls![ | |||
768 | (crate::TypeParam, ast::TypeParam, type_param_to_def), | 768 | (crate::TypeParam, ast::TypeParam, type_param_to_def), |
769 | (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def), | 769 | (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def), |
770 | (crate::ConstParam, ast::ConstParam, const_param_to_def), | 770 | (crate::ConstParam, ast::ConstParam, const_param_to_def), |
771 | (crate::MacroDef, ast::MacroRules, macro_rules_to_def), | 771 | (crate::MacroDef, ast::Macro, macro_to_def), |
772 | (crate::Local, ast::IdentPat, bind_pat_to_def), | 772 | (crate::Local, ast::IdentPat, bind_pat_to_def), |
773 | (crate::Local, ast::SelfParam, self_param_to_def), | 773 | (crate::Local, ast::SelfParam, self_param_to_def), |
774 | (crate::Label, ast::Label, label_to_def), | 774 | (crate::Label, ast::Label, label_to_def), |
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 762809fcd..9a5a2255f 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs | |||
@@ -191,10 +191,7 @@ impl SourceToDefCtx<'_, '_> { | |||
191 | } | 191 | } |
192 | 192 | ||
193 | // FIXME: use DynMap as well? | 193 | // FIXME: use DynMap as well? |
194 | pub(super) fn macro_rules_to_def( | 194 | pub(super) fn macro_to_def(&mut self, src: InFile<ast::Macro>) -> Option<MacroDefId> { |
195 | &mut self, | ||
196 | src: InFile<ast::MacroRules>, | ||
197 | ) -> Option<MacroDefId> { | ||
198 | let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value); | 195 | let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value); |
199 | let ast_id = AstId::new(src.file_id, file_ast_id.upcast()); | 196 | let ast_id = AstId::new(src.file_id, file_ast_id.upcast()); |
200 | let kind = MacroDefKind::Declarative(ast_id); | 197 | let kind = MacroDefKind::Declarative(ast_id); |
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 19f5065d1..229e81dd4 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs | |||
@@ -74,6 +74,7 @@ pub(super) fn lower( | |||
74 | _c: Count::new(), | 74 | _c: Count::new(), |
75 | }, | 75 | }, |
76 | expander, | 76 | expander, |
77 | statements_in_scope: Vec::new(), | ||
77 | } | 78 | } |
78 | .collect(params, body) | 79 | .collect(params, body) |
79 | } | 80 | } |
@@ -83,6 +84,7 @@ struct ExprCollector<'a> { | |||
83 | expander: Expander, | 84 | expander: Expander, |
84 | body: Body, | 85 | body: Body, |
85 | source_map: BodySourceMap, | 86 | source_map: BodySourceMap, |
87 | statements_in_scope: Vec<Statement>, | ||
86 | } | 88 | } |
87 | 89 | ||
88 | impl ExprCollector<'_> { | 90 | impl ExprCollector<'_> { |
@@ -533,15 +535,13 @@ impl ExprCollector<'_> { | |||
533 | ids[0] | 535 | ids[0] |
534 | } | 536 | } |
535 | ast::Expr::MacroStmts(e) => { | 537 | ast::Expr::MacroStmts(e) => { |
536 | // FIXME: these statements should be held by some hir containter | 538 | e.statements().for_each(|s| self.collect_stmt(s)); |
537 | for stmt in e.statements() { | 539 | let tail = e |
538 | self.collect_stmt(stmt); | 540 | .expr() |
539 | } | 541 | .map(|e| self.collect_expr(e)) |
540 | if let Some(expr) = e.expr() { | 542 | .unwrap_or_else(|| self.alloc_expr(Expr::Missing, syntax_ptr.clone())); |
541 | self.collect_expr(expr) | 543 | |
542 | } else { | 544 | self.alloc_expr(Expr::MacroStmts { tail }, syntax_ptr) |
543 | self.alloc_expr(Expr::Missing, syntax_ptr) | ||
544 | } | ||
545 | } | 545 | } |
546 | }) | 546 | }) |
547 | } | 547 | } |
@@ -618,58 +618,54 @@ impl ExprCollector<'_> { | |||
618 | } | 618 | } |
619 | } | 619 | } |
620 | 620 | ||
621 | fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> { | 621 | fn collect_stmt(&mut self, s: ast::Stmt) { |
622 | let stmt = match s { | 622 | match s { |
623 | ast::Stmt::LetStmt(stmt) => { | 623 | ast::Stmt::LetStmt(stmt) => { |
624 | self.check_cfg(&stmt)?; | 624 | if self.check_cfg(&stmt).is_none() { |
625 | 625 | return; | |
626 | } | ||
626 | let pat = self.collect_pat_opt(stmt.pat()); | 627 | let pat = self.collect_pat_opt(stmt.pat()); |
627 | let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); | 628 | let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); |
628 | let initializer = stmt.initializer().map(|e| self.collect_expr(e)); | 629 | let initializer = stmt.initializer().map(|e| self.collect_expr(e)); |
629 | vec![Statement::Let { pat, type_ref, initializer }] | 630 | self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer }); |
630 | } | 631 | } |
631 | ast::Stmt::ExprStmt(stmt) => { | 632 | ast::Stmt::ExprStmt(stmt) => { |
632 | self.check_cfg(&stmt)?; | 633 | if self.check_cfg(&stmt).is_none() { |
634 | return; | ||
635 | } | ||
633 | 636 | ||
634 | // Note that macro could be expended to multiple statements | 637 | // Note that macro could be expended to multiple statements |
635 | if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { | 638 | if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { |
636 | let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); | 639 | let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); |
637 | let mut stmts = vec![]; | ||
638 | 640 | ||
639 | self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| { | 641 | self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| { |
640 | match expansion { | 642 | match expansion { |
641 | Some(expansion) => { | 643 | Some(expansion) => { |
642 | let statements: ast::MacroStmts = expansion; | 644 | let statements: ast::MacroStmts = expansion; |
643 | 645 | ||
644 | statements.statements().for_each(|stmt| { | 646 | statements.statements().for_each(|stmt| this.collect_stmt(stmt)); |
645 | if let Some(mut r) = this.collect_stmt(stmt) { | ||
646 | stmts.append(&mut r); | ||
647 | } | ||
648 | }); | ||
649 | if let Some(expr) = statements.expr() { | 647 | if let Some(expr) = statements.expr() { |
650 | stmts.push(Statement::Expr(this.collect_expr(expr))); | 648 | let expr = this.collect_expr(expr); |
649 | this.statements_in_scope.push(Statement::Expr(expr)); | ||
651 | } | 650 | } |
652 | } | 651 | } |
653 | None => { | 652 | None => { |
654 | stmts.push(Statement::Expr( | 653 | let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone()); |
655 | this.alloc_expr(Expr::Missing, syntax_ptr.clone()), | 654 | this.statements_in_scope.push(Statement::Expr(expr)); |
656 | )); | ||
657 | } | 655 | } |
658 | } | 656 | } |
659 | }); | 657 | }); |
660 | stmts | ||
661 | } else { | 658 | } else { |
662 | vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))] | 659 | let expr = self.collect_expr_opt(stmt.expr()); |
660 | self.statements_in_scope.push(Statement::Expr(expr)); | ||
663 | } | 661 | } |
664 | } | 662 | } |
665 | ast::Stmt::Item(item) => { | 663 | ast::Stmt::Item(item) => { |
666 | self.check_cfg(&item)?; | 664 | if self.check_cfg(&item).is_none() { |
667 | 665 | return; | |
668 | return None; | 666 | } |
669 | } | 667 | } |
670 | }; | 668 | } |
671 | |||
672 | Some(stmt) | ||
673 | } | 669 | } |
674 | 670 | ||
675 | fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId { | 671 | fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId { |
@@ -685,10 +681,12 @@ impl ExprCollector<'_> { | |||
685 | let module = if has_def_map { def_map.root() } else { self.expander.module }; | 681 | let module = if has_def_map { def_map.root() } else { self.expander.module }; |
686 | let prev_def_map = mem::replace(&mut self.expander.def_map, def_map); | 682 | let prev_def_map = mem::replace(&mut self.expander.def_map, def_map); |
687 | let prev_local_module = mem::replace(&mut self.expander.module, module); | 683 | let prev_local_module = mem::replace(&mut self.expander.module, module); |
684 | let prev_statements = std::mem::take(&mut self.statements_in_scope); | ||
685 | |||
686 | block.statements().for_each(|s| self.collect_stmt(s)); | ||
688 | 687 | ||
689 | let statements = | ||
690 | block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect(); | ||
691 | let tail = block.tail_expr().map(|e| self.collect_expr(e)); | 688 | let tail = block.tail_expr().map(|e| self.collect_expr(e)); |
689 | let statements = std::mem::replace(&mut self.statements_in_scope, prev_statements); | ||
692 | let syntax_node_ptr = AstPtr::new(&block.into()); | 690 | let syntax_node_ptr = AstPtr::new(&block.into()); |
693 | let expr_id = self.alloc_expr( | 691 | let expr_id = self.alloc_expr( |
694 | Expr::Block { id: block_id, statements, tail, label: None }, | 692 | Expr::Block { id: block_id, statements, tail, label: None }, |
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs index 0be868ba2..214bcc648 100644 --- a/crates/hir_def/src/data.rs +++ b/crates/hir_def/src/data.rs | |||
@@ -10,7 +10,7 @@ use crate::{ | |||
10 | body::Expander, | 10 | body::Expander, |
11 | db::DefDatabase, | 11 | db::DefDatabase, |
12 | item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem, Param}, | 12 | item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem, Param}, |
13 | type_ref::{TypeBound, TypeRef}, | 13 | type_ref::{TraitRef, TypeBound, TypeRef}, |
14 | visibility::RawVisibility, | 14 | visibility::RawVisibility, |
15 | AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, | 15 | AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, |
16 | Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, | 16 | Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, |
@@ -156,8 +156,8 @@ impl TraitData { | |||
156 | 156 | ||
157 | #[derive(Debug, Clone, PartialEq, Eq)] | 157 | #[derive(Debug, Clone, PartialEq, Eq)] |
158 | pub struct ImplData { | 158 | pub struct ImplData { |
159 | pub target_trait: Option<TypeRef>, | 159 | pub target_trait: Option<TraitRef>, |
160 | pub target_type: TypeRef, | 160 | pub self_ty: TypeRef, |
161 | pub items: Vec<AssocItemId>, | 161 | pub items: Vec<AssocItemId>, |
162 | pub is_negative: bool, | 162 | pub is_negative: bool, |
163 | } | 163 | } |
@@ -170,7 +170,7 @@ impl ImplData { | |||
170 | let item_tree = impl_loc.id.item_tree(db); | 170 | let item_tree = impl_loc.id.item_tree(db); |
171 | let impl_def = &item_tree[impl_loc.id.value]; | 171 | let impl_def = &item_tree[impl_loc.id.value]; |
172 | let target_trait = impl_def.target_trait.map(|id| item_tree[id].clone()); | 172 | let target_trait = impl_def.target_trait.map(|id| item_tree[id].clone()); |
173 | let target_type = item_tree[impl_def.target_type].clone(); | 173 | let self_ty = item_tree[impl_def.self_ty].clone(); |
174 | let is_negative = impl_def.is_negative; | 174 | let is_negative = impl_def.is_negative; |
175 | let module_id = impl_loc.container; | 175 | let module_id = impl_loc.container; |
176 | let container = AssocContainerId::ImplId(id); | 176 | let container = AssocContainerId::ImplId(id); |
@@ -187,7 +187,7 @@ impl ImplData { | |||
187 | ); | 187 | ); |
188 | let items = items.into_iter().map(|(_, item)| item).collect(); | 188 | let items = items.into_iter().map(|(_, item)| item).collect(); |
189 | 189 | ||
190 | Arc::new(ImplData { target_trait, target_type, items, is_negative }) | 190 | Arc::new(ImplData { target_trait, self_ty, items, is_negative }) |
191 | } | 191 | } |
192 | } | 192 | } |
193 | 193 | ||
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs index 24be93773..6c7376fad 100644 --- a/crates/hir_def/src/expr.rs +++ b/crates/hir_def/src/expr.rs | |||
@@ -171,6 +171,9 @@ pub enum Expr { | |||
171 | Unsafe { | 171 | Unsafe { |
172 | body: ExprId, | 172 | body: ExprId, |
173 | }, | 173 | }, |
174 | MacroStmts { | ||
175 | tail: ExprId, | ||
176 | }, | ||
174 | Array(Array), | 177 | Array(Array), |
175 | Literal(Literal), | 178 | Literal(Literal), |
176 | } | 179 | } |
@@ -357,6 +360,7 @@ impl Expr { | |||
357 | f(*repeat) | 360 | f(*repeat) |
358 | } | 361 | } |
359 | }, | 362 | }, |
363 | Expr::MacroStmts { tail } => f(*tail), | ||
360 | Expr::Literal(_) => {} | 364 | Expr::Literal(_) => {} |
361 | } | 365 | } |
362 | } | 366 | } |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index ae2475b4e..5449bbf5d 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -31,7 +31,7 @@ use crate::{ | |||
31 | db::DefDatabase, | 31 | db::DefDatabase, |
32 | generics::GenericParams, | 32 | generics::GenericParams, |
33 | path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, | 33 | path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, |
34 | type_ref::{Mutability, TypeBound, TypeRef}, | 34 | type_ref::{Mutability, TraitRef, TypeBound, TypeRef}, |
35 | visibility::RawVisibility, | 35 | visibility::RawVisibility, |
36 | }; | 36 | }; |
37 | 37 | ||
@@ -110,15 +110,6 @@ impl ItemTree { | |||
110 | // still need to collect inner items. | 110 | // still need to collect inner items. |
111 | ctx.lower_inner_items(e.syntax()) | 111 | ctx.lower_inner_items(e.syntax()) |
112 | }, | 112 | }, |
113 | ast::ExprStmt(stmt) => { | ||
114 | // Macros can expand to stmt. We return an empty item tree in this case, but | ||
115 | // still need to collect inner items. | ||
116 | ctx.lower_inner_items(stmt.syntax()) | ||
117 | }, | ||
118 | ast::Item(item) => { | ||
119 | // Macros can expand to stmt and other item, and we add it as top level item | ||
120 | ctx.lower_single_item(item) | ||
121 | }, | ||
122 | _ => { | 113 | _ => { |
123 | panic!("cannot create item tree from {:?} {}", syntax, syntax); | 114 | panic!("cannot create item tree from {:?} {}", syntax, syntax); |
124 | }, | 115 | }, |
@@ -156,6 +147,7 @@ impl ItemTree { | |||
156 | vis, | 147 | vis, |
157 | generics, | 148 | generics, |
158 | type_refs, | 149 | type_refs, |
150 | trait_refs, | ||
159 | inner_items, | 151 | inner_items, |
160 | } = &mut **data; | 152 | } = &mut **data; |
161 | 153 | ||
@@ -182,6 +174,7 @@ impl ItemTree { | |||
182 | generics.arena.shrink_to_fit(); | 174 | generics.arena.shrink_to_fit(); |
183 | type_refs.arena.shrink_to_fit(); | 175 | type_refs.arena.shrink_to_fit(); |
184 | type_refs.map.shrink_to_fit(); | 176 | type_refs.map.shrink_to_fit(); |
177 | trait_refs.map.shrink_to_fit(); | ||
185 | 178 | ||
186 | inner_items.shrink_to_fit(); | 179 | inner_items.shrink_to_fit(); |
187 | } | 180 | } |
@@ -304,6 +297,32 @@ impl TypeRefStorage { | |||
304 | } | 297 | } |
305 | } | 298 | } |
306 | 299 | ||
300 | /// `TraitRef` interner. | ||
301 | #[derive(Default, Debug, Eq, PartialEq)] | ||
302 | struct TraitRefStorage { | ||
303 | arena: Arena<Arc<TraitRef>>, | ||
304 | map: FxHashMap<Arc<TraitRef>, Idx<Arc<TraitRef>>>, | ||
305 | } | ||
306 | |||
307 | impl TraitRefStorage { | ||
308 | // Note: We lie about the `Idx<TraitRef>` to hide the interner details. | ||
309 | |||
310 | fn intern(&mut self, ty: TraitRef) -> Idx<TraitRef> { | ||
311 | if let Some(id) = self.map.get(&ty) { | ||
312 | return Idx::from_raw(id.into_raw()); | ||
313 | } | ||
314 | |||
315 | let ty = Arc::new(ty); | ||
316 | let idx = self.arena.alloc(ty.clone()); | ||
317 | self.map.insert(ty, idx); | ||
318 | Idx::from_raw(idx.into_raw()) | ||
319 | } | ||
320 | |||
321 | fn lookup(&self, id: Idx<TraitRef>) -> &TraitRef { | ||
322 | &self.arena[Idx::from_raw(id.into_raw())] | ||
323 | } | ||
324 | } | ||
325 | |||
307 | #[derive(Default, Debug, Eq, PartialEq)] | 326 | #[derive(Default, Debug, Eq, PartialEq)] |
308 | struct ItemTreeData { | 327 | struct ItemTreeData { |
309 | imports: Arena<Import>, | 328 | imports: Arena<Import>, |
@@ -328,6 +347,7 @@ struct ItemTreeData { | |||
328 | vis: ItemVisibilities, | 347 | vis: ItemVisibilities, |
329 | generics: GenericParamsStorage, | 348 | generics: GenericParamsStorage, |
330 | type_refs: TypeRefStorage, | 349 | type_refs: TypeRefStorage, |
350 | trait_refs: TraitRefStorage, | ||
331 | 351 | ||
332 | inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>, | 352 | inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>, |
333 | } | 353 | } |
@@ -565,6 +585,14 @@ impl Index<Idx<TypeRef>> for ItemTree { | |||
565 | } | 585 | } |
566 | } | 586 | } |
567 | 587 | ||
588 | impl Index<Idx<TraitRef>> for ItemTree { | ||
589 | type Output = TraitRef; | ||
590 | |||
591 | fn index(&self, id: Idx<TraitRef>) -> &Self::Output { | ||
592 | self.data().trait_refs.lookup(id) | ||
593 | } | ||
594 | } | ||
595 | |||
568 | impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { | 596 | impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { |
569 | type Output = N; | 597 | type Output = N; |
570 | fn index(&self, id: FileItemTreeId<N>) -> &N { | 598 | fn index(&self, id: FileItemTreeId<N>) -> &N { |
@@ -701,8 +729,8 @@ pub struct Trait { | |||
701 | #[derive(Debug, Clone, Eq, PartialEq)] | 729 | #[derive(Debug, Clone, Eq, PartialEq)] |
702 | pub struct Impl { | 730 | pub struct Impl { |
703 | pub generic_params: GenericParamsId, | 731 | pub generic_params: GenericParamsId, |
704 | pub target_trait: Option<Idx<TypeRef>>, | 732 | pub target_trait: Option<Idx<TraitRef>>, |
705 | pub target_type: Idx<TypeRef>, | 733 | pub self_ty: Idx<TypeRef>, |
706 | pub is_negative: bool, | 734 | pub is_negative: bool, |
707 | pub items: Box<[AssocItem]>, | 735 | pub items: Box<[AssocItem]>, |
708 | pub ast_id: FileAstId<ast::Impl>, | 736 | pub ast_id: FileAstId<ast::Impl>, |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index d3fe1ce1e..8d3862811 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -11,7 +11,7 @@ use syntax::{ | |||
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | generics::{GenericParams, TypeParamData, TypeParamProvenance}, | 13 | generics::{GenericParams, TypeParamData, TypeParamProvenance}, |
14 | type_ref::LifetimeRef, | 14 | type_ref::{LifetimeRef, TraitRef}, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | use super::*; | 17 | use super::*; |
@@ -87,14 +87,6 @@ impl Ctx { | |||
87 | self.tree | 87 | self.tree |
88 | } | 88 | } |
89 | 89 | ||
90 | pub(super) fn lower_single_item(mut self, item: ast::Item) -> ItemTree { | ||
91 | self.tree.top_level = self | ||
92 | .lower_mod_item(&item, false) | ||
93 | .map(|item| item.0) | ||
94 | .unwrap_or_else(|| Default::default()); | ||
95 | self.tree | ||
96 | } | ||
97 | |||
98 | pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree { | 90 | pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree { |
99 | self.collect_inner_items(within); | 91 | self.collect_inner_items(within); |
100 | self.tree | 92 | self.tree |
@@ -544,8 +536,11 @@ impl Ctx { | |||
544 | fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> { | 536 | fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> { |
545 | let generic_params = | 537 | let generic_params = |
546 | self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def); | 538 | self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def); |
547 | let target_trait = impl_def.trait_().map(|tr| self.lower_type_ref(&tr)); | 539 | // FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl |
548 | let target_type = self.lower_type_ref(&impl_def.self_ty()?); | 540 | // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only |
541 | // equals itself. | ||
542 | let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr)); | ||
543 | let self_ty = self.lower_type_ref(&impl_def.self_ty()?); | ||
549 | let is_negative = impl_def.excl_token().is_some(); | 544 | let is_negative = impl_def.excl_token().is_some(); |
550 | 545 | ||
551 | // We cannot use `assoc_items()` here as that does not include macro calls. | 546 | // We cannot use `assoc_items()` here as that does not include macro calls. |
@@ -562,7 +557,7 @@ impl Ctx { | |||
562 | }) | 557 | }) |
563 | .collect(); | 558 | .collect(); |
564 | let ast_id = self.source_ast_id_map.ast_id(impl_def); | 559 | let ast_id = self.source_ast_id_map.ast_id(impl_def); |
565 | let res = Impl { generic_params, target_trait, target_type, is_negative, items, ast_id }; | 560 | let res = Impl { generic_params, target_trait, self_ty, is_negative, items, ast_id }; |
566 | Some(id(self.data().impls.alloc(res))) | 561 | Some(id(self.data().impls.alloc(res))) |
567 | } | 562 | } |
568 | 563 | ||
@@ -748,10 +743,16 @@ impl Ctx { | |||
748 | self.data().vis.alloc(vis) | 743 | self.data().vis.alloc(vis) |
749 | } | 744 | } |
750 | 745 | ||
746 | fn lower_trait_ref(&mut self, trait_ref: &ast::Type) -> Option<Idx<TraitRef>> { | ||
747 | let trait_ref = TraitRef::from_ast(&self.body_ctx, trait_ref.clone())?; | ||
748 | Some(self.data().trait_refs.intern(trait_ref)) | ||
749 | } | ||
750 | |||
751 | fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Idx<TypeRef> { | 751 | fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Idx<TypeRef> { |
752 | let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone()); | 752 | let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone()); |
753 | self.data().type_refs.intern(tyref) | 753 | self.data().type_refs.intern(tyref) |
754 | } | 754 | } |
755 | |||
755 | fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Idx<TypeRef> { | 756 | fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Idx<TypeRef> { |
756 | match type_ref.map(|ty| self.lower_type_ref(&ty)) { | 757 | match type_ref.map(|ty| self.lower_type_ref(&ty)) { |
757 | Some(it) => it, | 758 | Some(it) => it, |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index d8fabe49b..d58135ec9 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -25,8 +25,8 @@ use crate::{ | |||
25 | derive_macro_as_call_id, | 25 | derive_macro_as_call_id, |
26 | item_scope::{ImportType, PerNsGlobImports}, | 26 | item_scope::{ImportType, PerNsGlobImports}, |
27 | item_tree::{ | 27 | item_tree::{ |
28 | self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroRules, Mod, ModItem, ModKind, | 28 | self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroDef, MacroRules, Mod, ModItem, |
29 | StructDefKind, | 29 | ModKind, StructDefKind, |
30 | }, | 30 | }, |
31 | macro_call_as_call_id, | 31 | macro_call_as_call_id, |
32 | nameres::{ | 32 | nameres::{ |
@@ -395,7 +395,7 @@ impl DefCollector<'_> { | |||
395 | /// macro_rules! foo { () => {} } | 395 | /// macro_rules! foo { () => {} } |
396 | /// use foo as bar; | 396 | /// use foo as bar; |
397 | /// ``` | 397 | /// ``` |
398 | fn define_macro( | 398 | fn define_macro_rules( |
399 | &mut self, | 399 | &mut self, |
400 | module_id: LocalModuleId, | 400 | module_id: LocalModuleId, |
401 | name: Name, | 401 | name: Name, |
@@ -430,6 +430,21 @@ impl DefCollector<'_> { | |||
430 | self.def_map.modules[module_id].scope.define_legacy_macro(name, mac); | 430 | self.def_map.modules[module_id].scope.define_legacy_macro(name, mac); |
431 | } | 431 | } |
432 | 432 | ||
433 | /// Define a macro 2.0 macro | ||
434 | /// | ||
435 | /// The scoped of macro 2.0 macro is equal to normal function | ||
436 | fn define_macro_def( | ||
437 | &mut self, | ||
438 | module_id: LocalModuleId, | ||
439 | name: Name, | ||
440 | macro_: MacroDefId, | ||
441 | vis: &RawVisibility, | ||
442 | ) { | ||
443 | let vis = | ||
444 | self.def_map.resolve_visibility(self.db, module_id, vis).unwrap_or(Visibility::Public); | ||
445 | self.update(module_id, &[(Some(name), PerNs::macros(macro_, vis))], vis, ImportType::Named); | ||
446 | } | ||
447 | |||
433 | /// Define a proc macro | 448 | /// Define a proc macro |
434 | /// | 449 | /// |
435 | /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped. | 450 | /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped. |
@@ -1067,40 +1082,7 @@ impl ModCollector<'_, '_> { | |||
1067 | } | 1082 | } |
1068 | ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]), | 1083 | ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]), |
1069 | ModItem::MacroRules(id) => self.collect_macro_rules(id), | 1084 | ModItem::MacroRules(id) => self.collect_macro_rules(id), |
1070 | ModItem::MacroDef(id) => { | 1085 | ModItem::MacroDef(id) => self.collect_macro_def(id), |
1071 | let mac = &self.item_tree[id]; | ||
1072 | let ast_id = InFile::new(self.file_id, mac.ast_id.upcast()); | ||
1073 | |||
1074 | // "Macro 2.0" is not currently supported by rust-analyzer, but libcore uses it | ||
1075 | // to define builtin macros, so we support at least that part. | ||
1076 | let attrs = self.item_tree.attrs( | ||
1077 | self.def_collector.db, | ||
1078 | krate, | ||
1079 | ModItem::from(id).into(), | ||
1080 | ); | ||
1081 | if attrs.by_key("rustc_builtin_macro").exists() { | ||
1082 | let krate = self.def_collector.def_map.krate; | ||
1083 | let macro_id = find_builtin_macro(&mac.name, krate, ast_id) | ||
1084 | .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)); | ||
1085 | if let Some(macro_id) = macro_id { | ||
1086 | let vis = self | ||
1087 | .def_collector | ||
1088 | .def_map | ||
1089 | .resolve_visibility( | ||
1090 | self.def_collector.db, | ||
1091 | self.module_id, | ||
1092 | &self.item_tree[mac.visibility], | ||
1093 | ) | ||
1094 | .unwrap_or(Visibility::Public); | ||
1095 | self.def_collector.update( | ||
1096 | self.module_id, | ||
1097 | &[(Some(mac.name.clone()), PerNs::macros(macro_id, vis))], | ||
1098 | vis, | ||
1099 | ImportType::Named, | ||
1100 | ); | ||
1101 | } | ||
1102 | } | ||
1103 | } | ||
1104 | ModItem::Impl(imp) => { | 1086 | ModItem::Impl(imp) => { |
1105 | let module = self.def_collector.def_map.module_id(self.module_id); | 1087 | let module = self.def_collector.def_map.module_id(self.module_id); |
1106 | let impl_id = | 1088 | let impl_id = |
@@ -1420,7 +1402,7 @@ impl ModCollector<'_, '_> { | |||
1420 | if attrs.by_key("rustc_builtin_macro").exists() { | 1402 | if attrs.by_key("rustc_builtin_macro").exists() { |
1421 | let krate = self.def_collector.def_map.krate; | 1403 | let krate = self.def_collector.def_map.krate; |
1422 | if let Some(macro_id) = find_builtin_macro(&mac.name, krate, ast_id) { | 1404 | if let Some(macro_id) = find_builtin_macro(&mac.name, krate, ast_id) { |
1423 | self.def_collector.define_macro( | 1405 | self.def_collector.define_macro_rules( |
1424 | self.module_id, | 1406 | self.module_id, |
1425 | mac.name.clone(), | 1407 | mac.name.clone(), |
1426 | macro_id, | 1408 | macro_id, |
@@ -1436,7 +1418,49 @@ impl ModCollector<'_, '_> { | |||
1436 | kind: MacroDefKind::Declarative(ast_id), | 1418 | kind: MacroDefKind::Declarative(ast_id), |
1437 | local_inner: is_local_inner, | 1419 | local_inner: is_local_inner, |
1438 | }; | 1420 | }; |
1439 | self.def_collector.define_macro(self.module_id, mac.name.clone(), macro_id, is_export); | 1421 | self.def_collector.define_macro_rules( |
1422 | self.module_id, | ||
1423 | mac.name.clone(), | ||
1424 | macro_id, | ||
1425 | is_export, | ||
1426 | ); | ||
1427 | } | ||
1428 | |||
1429 | fn collect_macro_def(&mut self, id: FileItemTreeId<MacroDef>) { | ||
1430 | let krate = self.def_collector.def_map.krate; | ||
1431 | let mac = &self.item_tree[id]; | ||
1432 | let ast_id = InFile::new(self.file_id, mac.ast_id.upcast()); | ||
1433 | |||
1434 | // Case 1: bulitin macros | ||
1435 | let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into()); | ||
1436 | if attrs.by_key("rustc_builtin_macro").exists() { | ||
1437 | let macro_id = find_builtin_macro(&mac.name, krate, ast_id) | ||
1438 | .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)); | ||
1439 | |||
1440 | if let Some(macro_id) = macro_id { | ||
1441 | self.def_collector.define_macro_def( | ||
1442 | self.module_id, | ||
1443 | mac.name.clone(), | ||
1444 | macro_id, | ||
1445 | &self.item_tree[mac.visibility], | ||
1446 | ); | ||
1447 | } | ||
1448 | return; | ||
1449 | } | ||
1450 | |||
1451 | // Case 2: normal `macro` | ||
1452 | let macro_id = MacroDefId { | ||
1453 | krate: self.def_collector.def_map.krate, | ||
1454 | kind: MacroDefKind::Declarative(ast_id), | ||
1455 | local_inner: false, | ||
1456 | }; | ||
1457 | |||
1458 | self.def_collector.define_macro_def( | ||
1459 | self.module_id, | ||
1460 | mac.name.clone(), | ||
1461 | macro_id, | ||
1462 | &self.item_tree[mac.visibility], | ||
1463 | ); | ||
1440 | } | 1464 | } |
1441 | 1465 | ||
1442 | fn collect_macro_call(&mut self, mac: &MacroCall) { | 1466 | fn collect_macro_call(&mut self, mac: &MacroCall) { |
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs index 6d3cb8d7a..c37f915ab 100644 --- a/crates/hir_def/src/nameres/tests/macros.rs +++ b/crates/hir_def/src/nameres/tests/macros.rs | |||
@@ -837,3 +837,21 @@ fn collects_derive_helpers() { | |||
837 | _ => unreachable!(), | 837 | _ => unreachable!(), |
838 | } | 838 | } |
839 | } | 839 | } |
840 | |||
841 | #[test] | ||
842 | fn resolve_macro_def() { | ||
843 | check( | ||
844 | r#" | ||
845 | //- /lib.rs | ||
846 | pub macro structs($($i:ident),*) { | ||
847 | $(struct $i { field: u32 } )* | ||
848 | } | ||
849 | structs!(Foo); | ||
850 | "#, | ||
851 | expect![[r#" | ||
852 | crate | ||
853 | Foo: t | ||
854 | structs: m | ||
855 | "#]], | ||
856 | ); | ||
857 | } | ||
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs index 505493a74..4de951fd3 100644 --- a/crates/hir_def/src/path/lower.rs +++ b/crates/hir_def/src/path/lower.rs | |||
@@ -74,6 +74,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
74 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo | 74 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo |
75 | Some(trait_ref) => { | 75 | Some(trait_ref) => { |
76 | let path = Path::from_src(trait_ref.path()?, hygiene)?; | 76 | let path = Path::from_src(trait_ref.path()?, hygiene)?; |
77 | let num_segments = path.mod_path.segments.len(); | ||
77 | kind = path.mod_path.kind; | 78 | kind = path.mod_path.kind; |
78 | 79 | ||
79 | let mut prefix_segments = path.mod_path.segments; | 80 | let mut prefix_segments = path.mod_path.segments; |
@@ -85,7 +86,8 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
85 | generic_args.extend(prefix_args); | 86 | generic_args.extend(prefix_args); |
86 | 87 | ||
87 | // Insert the type reference (T in the above example) as Self parameter for the trait | 88 | // Insert the type reference (T in the above example) as Self parameter for the trait |
88 | let last_segment = generic_args.last_mut()?; | 89 | let last_segment = |
90 | generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?; | ||
89 | if last_segment.is_none() { | 91 | if last_segment.is_none() { |
90 | *last_segment = Some(Arc::new(GenericArgs::empty())); | 92 | *last_segment = Some(Arc::new(GenericArgs::empty())); |
91 | }; | 93 | }; |
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs index 049b2e462..4c24aae94 100644 --- a/crates/hir_def/src/type_ref.rs +++ b/crates/hir_def/src/type_ref.rs | |||
@@ -51,6 +51,23 @@ impl Rawness { | |||
51 | } | 51 | } |
52 | } | 52 | } |
53 | 53 | ||
54 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||
55 | pub struct TraitRef { | ||
56 | pub path: Path, | ||
57 | } | ||
58 | |||
59 | impl TraitRef { | ||
60 | /// Converts an `ast::PathType` to a `hir::TraitRef`. | ||
61 | pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Option<Self> { | ||
62 | // FIXME: Use `Path::from_src` | ||
63 | match node { | ||
64 | ast::Type::PathType(path) => { | ||
65 | path.path().and_then(|it| ctx.lower_path(it)).map(|path| TraitRef { path }) | ||
66 | } | ||
67 | _ => None, | ||
68 | } | ||
69 | } | ||
70 | } | ||
54 | /// Compare ty::Ty | 71 | /// Compare ty::Ty |
55 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | 72 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] |
56 | pub enum TypeRef { | 73 | pub enum TypeRef { |
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index fc73e435b..c0ab70b60 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -3,9 +3,15 @@ | |||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use base_db::{salsa, SourceDatabase}; | 5 | use base_db::{salsa, SourceDatabase}; |
6 | use mbe::{ExpandError, ExpandResult, MacroRules}; | 6 | use mbe::{ExpandError, ExpandResult, MacroDef, MacroRules}; |
7 | use parser::FragmentKind; | 7 | use parser::FragmentKind; |
8 | use syntax::{algo::diff, ast::NameOwner, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; | 8 | use syntax::{ |
9 | algo::diff, | ||
10 | ast::{MacroStmts, NameOwner}, | ||
11 | AstNode, GreenNode, Parse, | ||
12 | SyntaxKind::*, | ||
13 | SyntaxNode, | ||
14 | }; | ||
9 | 15 | ||
10 | use crate::{ | 16 | use crate::{ |
11 | ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinDeriveExpander, BuiltinFnLikeExpander, | 17 | ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinDeriveExpander, BuiltinFnLikeExpander, |
@@ -22,6 +28,7 @@ const TOKEN_LIMIT: usize = 524288; | |||
22 | #[derive(Debug, Clone, Eq, PartialEq)] | 28 | #[derive(Debug, Clone, Eq, PartialEq)] |
23 | pub enum TokenExpander { | 29 | pub enum TokenExpander { |
24 | MacroRules(mbe::MacroRules), | 30 | MacroRules(mbe::MacroRules), |
31 | MacroDef(mbe::MacroDef), | ||
25 | Builtin(BuiltinFnLikeExpander), | 32 | Builtin(BuiltinFnLikeExpander), |
26 | BuiltinDerive(BuiltinDeriveExpander), | 33 | BuiltinDerive(BuiltinDeriveExpander), |
27 | ProcMacro(ProcMacroExpander), | 34 | ProcMacro(ProcMacroExpander), |
@@ -36,6 +43,7 @@ impl TokenExpander { | |||
36 | ) -> mbe::ExpandResult<tt::Subtree> { | 43 | ) -> mbe::ExpandResult<tt::Subtree> { |
37 | match self { | 44 | match self { |
38 | TokenExpander::MacroRules(it) => it.expand(tt), | 45 | TokenExpander::MacroRules(it) => it.expand(tt), |
46 | TokenExpander::MacroDef(it) => it.expand(tt), | ||
39 | TokenExpander::Builtin(it) => it.expand(db, id, tt), | 47 | TokenExpander::Builtin(it) => it.expand(db, id, tt), |
40 | // FIXME switch these to ExpandResult as well | 48 | // FIXME switch these to ExpandResult as well |
41 | TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(), | 49 | TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(), |
@@ -51,6 +59,7 @@ impl TokenExpander { | |||
51 | pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { | 59 | pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { |
52 | match self { | 60 | match self { |
53 | TokenExpander::MacroRules(it) => it.map_id_down(id), | 61 | TokenExpander::MacroRules(it) => it.map_id_down(id), |
62 | TokenExpander::MacroDef(it) => it.map_id_down(id), | ||
54 | TokenExpander::Builtin(..) => id, | 63 | TokenExpander::Builtin(..) => id, |
55 | TokenExpander::BuiltinDerive(..) => id, | 64 | TokenExpander::BuiltinDerive(..) => id, |
56 | TokenExpander::ProcMacro(..) => id, | 65 | TokenExpander::ProcMacro(..) => id, |
@@ -60,6 +69,7 @@ impl TokenExpander { | |||
60 | pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) { | 69 | pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) { |
61 | match self { | 70 | match self { |
62 | TokenExpander::MacroRules(it) => it.map_id_up(id), | 71 | TokenExpander::MacroRules(it) => it.map_id_up(id), |
72 | TokenExpander::MacroDef(it) => it.map_id_up(id), | ||
63 | TokenExpander::Builtin(..) => (id, mbe::Origin::Call), | 73 | TokenExpander::Builtin(..) => (id, mbe::Origin::Call), |
64 | TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call), | 74 | TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call), |
65 | TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call), | 75 | TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call), |
@@ -130,26 +140,40 @@ fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> { | |||
130 | 140 | ||
131 | fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { | 141 | fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { |
132 | match id.kind { | 142 | match id.kind { |
133 | MacroDefKind::Declarative(ast_id) => { | 143 | MacroDefKind::Declarative(ast_id) => match ast_id.to_node(db) { |
134 | let macro_rules = match ast_id.to_node(db) { | 144 | syntax::ast::Macro::MacroRules(macro_rules) => { |
135 | syntax::ast::Macro::MacroRules(mac) => mac, | 145 | let arg = macro_rules.token_tree()?; |
136 | syntax::ast::Macro::MacroDef(_) => return None, | 146 | let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { |
137 | }; | 147 | log::warn!("fail on macro_rules to token tree: {:#?}", arg); |
138 | let arg = macro_rules.token_tree()?; | 148 | None |
139 | let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { | 149 | })?; |
140 | log::warn!("fail on macro_def to token tree: {:#?}", arg); | 150 | let rules = match MacroRules::parse(&tt) { |
141 | None | 151 | Ok(it) => it, |
142 | })?; | 152 | Err(err) => { |
143 | let rules = match MacroRules::parse(&tt) { | 153 | let name = macro_rules.name().map(|n| n.to_string()).unwrap_or_default(); |
144 | Ok(it) => it, | 154 | log::warn!("fail on macro_def parse ({}): {:?} {:#?}", name, err, tt); |
145 | Err(err) => { | 155 | return None; |
146 | let name = macro_rules.name().map(|n| n.to_string()).unwrap_or_default(); | 156 | } |
147 | log::warn!("fail on macro_def parse ({}): {:?} {:#?}", name, err, tt); | 157 | }; |
148 | return None; | 158 | Some(Arc::new((TokenExpander::MacroRules(rules), tmap))) |
149 | } | 159 | } |
150 | }; | 160 | syntax::ast::Macro::MacroDef(macro_def) => { |
151 | Some(Arc::new((TokenExpander::MacroRules(rules), tmap))) | 161 | let arg = macro_def.body()?; |
152 | } | 162 | let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { |
163 | log::warn!("fail on macro_def to token tree: {:#?}", arg); | ||
164 | None | ||
165 | })?; | ||
166 | let rules = match MacroDef::parse(&tt) { | ||
167 | Ok(it) => it, | ||
168 | Err(err) => { | ||
169 | let name = macro_def.name().map(|n| n.to_string()).unwrap_or_default(); | ||
170 | log::warn!("fail on macro_def parse ({}): {:?} {:#?}", name, err, tt); | ||
171 | return None; | ||
172 | } | ||
173 | }; | ||
174 | Some(Arc::new((TokenExpander::MacroDef(rules), tmap))) | ||
175 | } | ||
176 | }, | ||
153 | MacroDefKind::BuiltIn(expander, _) => { | 177 | MacroDefKind::BuiltIn(expander, _) => { |
154 | Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default()))) | 178 | Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default()))) |
155 | } | 179 | } |
@@ -340,13 +364,19 @@ fn parse_macro_with_arg( | |||
340 | None => return ExpandResult { value: None, err: result.err }, | 364 | None => return ExpandResult { value: None, err: result.err }, |
341 | }; | 365 | }; |
342 | 366 | ||
343 | log::debug!("expanded = {}", tt.as_debug_string()); | ||
344 | |||
345 | let fragment_kind = to_fragment_kind(db, macro_call_id); | 367 | let fragment_kind = to_fragment_kind(db, macro_call_id); |
346 | 368 | ||
369 | log::debug!("expanded = {}", tt.as_debug_string()); | ||
370 | log::debug!("kind = {:?}", fragment_kind); | ||
371 | |||
347 | let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) { | 372 | let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) { |
348 | Ok(it) => it, | 373 | Ok(it) => it, |
349 | Err(err) => { | 374 | Err(err) => { |
375 | log::debug!( | ||
376 | "failed to parse expanstion to {:?} = {}", | ||
377 | fragment_kind, | ||
378 | tt.as_debug_string() | ||
379 | ); | ||
350 | return ExpandResult::only_err(err); | 380 | return ExpandResult::only_err(err); |
351 | } | 381 | } |
352 | }; | 382 | }; |
@@ -362,15 +392,34 @@ fn parse_macro_with_arg( | |||
362 | return ExpandResult::only_err(err); | 392 | return ExpandResult::only_err(err); |
363 | } | 393 | } |
364 | }; | 394 | }; |
365 | 395 | if is_self_replicating(&node, &call_node.value) { | |
366 | if !diff(&node, &call_node.value).is_empty() { | ||
367 | ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) } | ||
368 | } else { | ||
369 | return ExpandResult::only_err(err); | 396 | return ExpandResult::only_err(err); |
397 | } else { | ||
398 | ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) } | ||
399 | } | ||
400 | } | ||
401 | None => { | ||
402 | log::debug!("parse = {:?}", parse.syntax_node().kind()); | ||
403 | ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: None } | ||
404 | } | ||
405 | } | ||
406 | } | ||
407 | |||
408 | fn is_self_replicating(from: &SyntaxNode, to: &SyntaxNode) -> bool { | ||
409 | if diff(from, to).is_empty() { | ||
410 | return true; | ||
411 | } | ||
412 | if let Some(stmts) = MacroStmts::cast(from.clone()) { | ||
413 | if stmts.statements().any(|stmt| diff(stmt.syntax(), to).is_empty()) { | ||
414 | return true; | ||
415 | } | ||
416 | if let Some(expr) = stmts.expr() { | ||
417 | if diff(expr.syntax(), to).is_empty() { | ||
418 | return true; | ||
370 | } | 419 | } |
371 | } | 420 | } |
372 | None => ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: None }, | ||
373 | } | 421 | } |
422 | false | ||
374 | } | 423 | } |
375 | 424 | ||
376 | fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> { | 425 | fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> { |
@@ -390,21 +439,15 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind { | |||
390 | 439 | ||
391 | let parent = match syn.parent() { | 440 | let parent = match syn.parent() { |
392 | Some(it) => it, | 441 | Some(it) => it, |
393 | None => { | 442 | None => return FragmentKind::Statements, |
394 | // FIXME: | ||
395 | // If it is root, which means the parent HirFile | ||
396 | // MacroKindFile must be non-items | ||
397 | // return expr now. | ||
398 | return FragmentKind::Expr; | ||
399 | } | ||
400 | }; | 443 | }; |
401 | 444 | ||
402 | match parent.kind() { | 445 | match parent.kind() { |
403 | MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, | 446 | MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, |
404 | MACRO_STMTS => FragmentKind::Statement, | 447 | MACRO_STMTS => FragmentKind::Statements, |
405 | ITEM_LIST => FragmentKind::Items, | 448 | ITEM_LIST => FragmentKind::Items, |
406 | LET_STMT => { | 449 | LET_STMT => { |
407 | // FIXME: Handle Pattern | 450 | // FIXME: Handle LHS Pattern |
408 | FragmentKind::Expr | 451 | FragmentKind::Expr |
409 | } | 452 | } |
410 | EXPR_STMT => FragmentKind::Statements, | 453 | EXPR_STMT => FragmentKind::Statements, |
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs index 0e0f7214a..779725629 100644 --- a/crates/hir_expand/src/hygiene.rs +++ b/crates/hir_expand/src/hygiene.rs | |||
@@ -148,7 +148,7 @@ fn make_hygiene_info( | |||
148 | let def_offset = loc.def.ast_id().left().and_then(|id| { | 148 | let def_offset = loc.def.ast_id().left().and_then(|id| { |
149 | let def_tt = match id.to_node(db) { | 149 | let def_tt = match id.to_node(db) { |
150 | ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(), | 150 | ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(), |
151 | ast::Macro::MacroDef(_) => return None, | 151 | ast::Macro::MacroDef(mac) => mac.body()?.syntax().text_range().start(), |
152 | }; | 152 | }; |
153 | Some(InFile::new(id.file_id, def_tt)) | 153 | Some(InFile::new(id.file_id, def_tt)) |
154 | }); | 154 | }); |
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index b8045fda9..3e332ee47 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -151,7 +151,7 @@ impl HirFileId { | |||
151 | let def = loc.def.ast_id().left().and_then(|id| { | 151 | let def = loc.def.ast_id().left().and_then(|id| { |
152 | let def_tt = match id.to_node(db) { | 152 | let def_tt = match id.to_node(db) { |
153 | ast::Macro::MacroRules(mac) => mac.token_tree()?, | 153 | ast::Macro::MacroRules(mac) => mac.token_tree()?, |
154 | ast::Macro::MacroDef(_) => return None, | 154 | ast::Macro::MacroDef(mac) => mac.body()?, |
155 | }; | 155 | }; |
156 | Some(InFile::new(id.file_id, def_tt)) | 156 | Some(InFile::new(id.file_id, def_tt)) |
157 | }); | 157 | }); |
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs index 0aeea48d5..203ebbe85 100644 --- a/crates/hir_expand/src/name.rs +++ b/crates/hir_expand/src/name.rs | |||
@@ -55,6 +55,15 @@ impl Name { | |||
55 | } | 55 | } |
56 | } | 56 | } |
57 | 57 | ||
58 | /// A fake name for things missing in the source code. | ||
59 | /// | ||
60 | /// For example, `impl Foo for {}` should be treated as a trait impl for a | ||
61 | /// type with a missing name. Similarly, `struct S { : u32 }` should have a | ||
62 | /// single field with a missing name. | ||
63 | /// | ||
64 | /// Ideally, we want a `gensym` semantics for missing names -- each missing | ||
65 | /// name is equal only to itself. It's not clear how to implement this in | ||
66 | /// salsa though, so we punt on that bit for a moment. | ||
58 | pub fn missing() -> Name { | 67 | pub fn missing() -> Name { |
59 | Name::new_text("[missing name]".into()) | 68 | Name::new_text("[missing name]".into()) |
60 | } | 69 | } |
@@ -75,14 +84,14 @@ impl AsName for ast::NameRef { | |||
75 | fn as_name(&self) -> Name { | 84 | fn as_name(&self) -> Name { |
76 | match self.as_tuple_field() { | 85 | match self.as_tuple_field() { |
77 | Some(idx) => Name::new_tuple_field(idx), | 86 | Some(idx) => Name::new_tuple_field(idx), |
78 | None => Name::resolve(self.text()), | 87 | None => Name::resolve(&self.text()), |
79 | } | 88 | } |
80 | } | 89 | } |
81 | } | 90 | } |
82 | 91 | ||
83 | impl AsName for ast::Name { | 92 | impl AsName for ast::Name { |
84 | fn as_name(&self) -> Name { | 93 | fn as_name(&self) -> Name { |
85 | Name::resolve(self.text()) | 94 | Name::resolve(&self.text()) |
86 | } | 95 | } |
87 | } | 96 | } |
88 | 97 | ||
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs index 5a5cdcbf3..9cb472b51 100644 --- a/crates/hir_ty/src/diagnostics/match_check.rs +++ b/crates/hir_ty/src/diagnostics/match_check.rs | |||
@@ -539,7 +539,7 @@ impl Matrix { | |||
539 | if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) { | 539 | if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) { |
540 | // Or patterns are expanded here | 540 | // Or patterns are expanded here |
541 | for pat_id in pat_ids { | 541 | for pat_id in pat_ids { |
542 | self.0.push(PatStack::from_pattern(pat_id)); | 542 | self.0.push(row.replace_head_with([pat_id].iter())); |
543 | } | 543 | } |
544 | } else { | 544 | } else { |
545 | self.0.push(row); | 545 | self.0.push(row); |
@@ -1085,6 +1085,20 @@ fn main() { | |||
1085 | } | 1085 | } |
1086 | 1086 | ||
1087 | #[test] | 1087 | #[test] |
1088 | fn or_pattern_no_diagnostic() { | ||
1089 | check_diagnostics( | ||
1090 | r#" | ||
1091 | enum Either {A, B} | ||
1092 | |||
1093 | fn main() { | ||
1094 | match (Either::A, Either::B) { | ||
1095 | (Either::A | Either::B, _) => (), | ||
1096 | } | ||
1097 | }"#, | ||
1098 | ) | ||
1099 | } | ||
1100 | |||
1101 | #[test] | ||
1088 | fn mismatched_types() { | 1102 | fn mismatched_types() { |
1089 | // Match statements with arms that don't match the | 1103 | // Match statements with arms that don't match the |
1090 | // expression pattern do not fire this diagnostic. | 1104 | // expression pattern do not fire this diagnostic. |
@@ -1336,30 +1350,6 @@ fn bang(never: !) { | |||
1336 | } | 1350 | } |
1337 | 1351 | ||
1338 | #[test] | 1352 | #[test] |
1339 | fn or_pattern_panic() { | ||
1340 | check_diagnostics( | ||
1341 | r#" | ||
1342 | pub enum Category { Infinity, Zero } | ||
1343 | |||
1344 | fn panic(a: Category, b: Category) { | ||
1345 | match (a, b) { | ||
1346 | (Category::Zero | Category::Infinity, _) => (), | ||
1347 | (_, Category::Zero | Category::Infinity) => (), | ||
1348 | } | ||
1349 | |||
1350 | // FIXME: This is a false positive, but the code used to cause a panic in the match checker, | ||
1351 | // so this acts as a regression test for that. | ||
1352 | match (a, b) { | ||
1353 | //^^^^^^ Missing match arm | ||
1354 | (Category::Infinity, Category::Infinity) | (Category::Zero, Category::Zero) => (), | ||
1355 | (Category::Infinity | Category::Zero, _) => (), | ||
1356 | } | ||
1357 | } | ||
1358 | "#, | ||
1359 | ); | ||
1360 | } | ||
1361 | |||
1362 | #[test] | ||
1363 | fn unknown_type() { | 1353 | fn unknown_type() { |
1364 | check_diagnostics( | 1354 | check_diagnostics( |
1365 | r#" | 1355 | r#" |
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index 3f3187ea2..6279aa572 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs | |||
@@ -119,6 +119,8 @@ impl<'a> InferenceContext<'a> { | |||
119 | } | 119 | } |
120 | 120 | ||
121 | fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { | 121 | fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { |
122 | self.db.check_canceled(); | ||
123 | |||
122 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 124 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
123 | let ty = match &body[tgt_expr] { | 125 | let ty = match &body[tgt_expr] { |
124 | Expr::Missing => self.err_ty(), | 126 | Expr::Missing => self.err_ty(), |
@@ -767,6 +769,7 @@ impl<'a> InferenceContext<'a> { | |||
767 | None => self.table.new_float_var(), | 769 | None => self.table.new_float_var(), |
768 | }, | 770 | }, |
769 | }, | 771 | }, |
772 | Expr::MacroStmts { tail } => self.infer_expr(*tail, expected), | ||
770 | }; | 773 | }; |
771 | // use a new type variable if we got unknown here | 774 | // use a new type variable if we got unknown here |
772 | let ty = self.insert_type_vars_shallow(ty); | 775 | let ty = self.insert_type_vars_shallow(ty); |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index c87789d45..afbfa12d5 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -15,7 +15,7 @@ use hir_def::{ | |||
15 | generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget}, | 15 | generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget}, |
16 | path::{GenericArg, Path, PathSegment, PathSegments}, | 16 | path::{GenericArg, Path, PathSegment, PathSegments}, |
17 | resolver::{HasResolver, Resolver, TypeNs}, | 17 | resolver::{HasResolver, Resolver, TypeNs}, |
18 | type_ref::{TypeBound, TypeRef}, | 18 | type_ref::{TraitRef as HirTraitRef, TypeBound, TypeRef}, |
19 | AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, | 19 | AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, |
20 | GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, | 20 | GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, |
21 | TypeAliasId, TypeParamId, UnionId, VariantId, | 21 | TypeAliasId, TypeParamId, UnionId, VariantId, |
@@ -667,14 +667,10 @@ impl<'a> TyLoweringContext<'a> { | |||
667 | 667 | ||
668 | fn lower_trait_ref( | 668 | fn lower_trait_ref( |
669 | &self, | 669 | &self, |
670 | type_ref: &TypeRef, | 670 | trait_ref: &HirTraitRef, |
671 | explicit_self_ty: Option<Ty>, | 671 | explicit_self_ty: Option<Ty>, |
672 | ) -> Option<TraitRef> { | 672 | ) -> Option<TraitRef> { |
673 | let path = match type_ref { | 673 | self.lower_trait_ref_from_path(&trait_ref.path, explicit_self_ty) |
674 | TypeRef::Path(path) => path, | ||
675 | _ => return None, | ||
676 | }; | ||
677 | self.lower_trait_ref_from_path(path, explicit_self_ty) | ||
678 | } | 674 | } |
679 | 675 | ||
680 | fn trait_ref_substs_from_path( | 676 | fn trait_ref_substs_from_path( |
@@ -1253,7 +1249,7 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde | |||
1253 | let generics = generics(db.upcast(), impl_id.into()); | 1249 | let generics = generics(db.upcast(), impl_id.into()); |
1254 | let ctx = | 1250 | let ctx = |
1255 | TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); | 1251 | TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); |
1256 | Binders::new(generics.len(), ctx.lower_ty(&impl_data.target_type)) | 1252 | Binders::new(generics.len(), ctx.lower_ty(&impl_data.self_ty)) |
1257 | } | 1253 | } |
1258 | 1254 | ||
1259 | pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { | 1255 | pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { |
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index 7eda51866..3eb01dbd0 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs | |||
@@ -135,7 +135,88 @@ fn infer_path_qualified_macros_expanded() { | |||
135 | } | 135 | } |
136 | 136 | ||
137 | #[test] | 137 | #[test] |
138 | fn expr_macro_expanded_in_various_places() { | 138 | fn expr_macro_def_expanded_in_various_places() { |
139 | check_infer( | ||
140 | r#" | ||
141 | macro spam() { | ||
142 | 1isize | ||
143 | } | ||
144 | |||
145 | fn spam() { | ||
146 | spam!(); | ||
147 | (spam!()); | ||
148 | spam!().spam(spam!()); | ||
149 | for _ in spam!() {} | ||
150 | || spam!(); | ||
151 | while spam!() {} | ||
152 | break spam!(); | ||
153 | return spam!(); | ||
154 | match spam!() { | ||
155 | _ if spam!() => spam!(), | ||
156 | } | ||
157 | spam!()(spam!()); | ||
158 | Spam { spam: spam!() }; | ||
159 | spam!()[spam!()]; | ||
160 | await spam!(); | ||
161 | spam!() as usize; | ||
162 | &spam!(); | ||
163 | -spam!(); | ||
164 | spam!()..spam!(); | ||
165 | spam!() + spam!(); | ||
166 | } | ||
167 | "#, | ||
168 | expect![[r#" | ||
169 | !0..6 '1isize': isize | ||
170 | !0..6 '1isize': isize | ||
171 | !0..6 '1isize': isize | ||
172 | !0..6 '1isize': isize | ||
173 | !0..6 '1isize': isize | ||
174 | !0..6 '1isize': isize | ||
175 | !0..6 '1isize': isize | ||
176 | !0..6 '1isize': isize | ||
177 | !0..6 '1isize': isize | ||
178 | !0..6 '1isize': isize | ||
179 | !0..6 '1isize': isize | ||
180 | !0..6 '1isize': isize | ||
181 | !0..6 '1isize': isize | ||
182 | !0..6 '1isize': isize | ||
183 | !0..6 '1isize': isize | ||
184 | !0..6 '1isize': isize | ||
185 | !0..6 '1isize': isize | ||
186 | !0..6 '1isize': isize | ||
187 | !0..6 '1isize': isize | ||
188 | !0..6 '1isize': isize | ||
189 | !0..6 '1isize': isize | ||
190 | !0..6 '1isize': isize | ||
191 | !0..6 '1isize': isize | ||
192 | !0..6 '1isize': isize | ||
193 | !0..6 '1isize': isize | ||
194 | 39..442 '{ ...!(); }': () | ||
195 | 73..94 'spam!(...am!())': {unknown} | ||
196 | 100..119 'for _ ...!() {}': () | ||
197 | 104..105 '_': {unknown} | ||
198 | 117..119 '{}': () | ||
199 | 124..134 '|| spam!()': || -> isize | ||
200 | 140..156 'while ...!() {}': () | ||
201 | 154..156 '{}': () | ||
202 | 161..174 'break spam!()': ! | ||
203 | 180..194 'return spam!()': ! | ||
204 | 200..254 'match ... }': isize | ||
205 | 224..225 '_': isize | ||
206 | 259..275 'spam!(...am!())': {unknown} | ||
207 | 281..303 'Spam {...m!() }': {unknown} | ||
208 | 309..325 'spam!(...am!()]': {unknown} | ||
209 | 350..366 'spam!(... usize': usize | ||
210 | 372..380 '&spam!()': &isize | ||
211 | 386..394 '-spam!()': isize | ||
212 | 400..416 'spam!(...pam!()': {unknown} | ||
213 | 422..439 'spam!(...pam!()': isize | ||
214 | "#]], | ||
215 | ); | ||
216 | } | ||
217 | |||
218 | #[test] | ||
219 | fn expr_macro_rules_expanded_in_various_places() { | ||
139 | check_infer( | 220 | check_infer( |
140 | r#" | 221 | r#" |
141 | macro_rules! spam { | 222 | macro_rules! spam { |
@@ -226,12 +307,49 @@ fn expr_macro_expanded_in_stmts() { | |||
226 | "#, | 307 | "#, |
227 | expect![[r#" | 308 | expect![[r#" |
228 | !0..8 'leta=();': () | 309 | !0..8 'leta=();': () |
310 | !0..8 'leta=();': () | ||
311 | !3..4 'a': () | ||
312 | !5..7 '()': () | ||
229 | 57..84 '{ ...); } }': () | 313 | 57..84 '{ ...); } }': () |
230 | "#]], | 314 | "#]], |
231 | ); | 315 | ); |
232 | } | 316 | } |
233 | 317 | ||
234 | #[test] | 318 | #[test] |
319 | fn recurisve_macro_expanded_in_stmts() { | ||
320 | check_infer( | ||
321 | r#" | ||
322 | macro_rules! ng { | ||
323 | ([$($tts:tt)*]) => { | ||
324 | $($tts)*; | ||
325 | }; | ||
326 | ([$($tts:tt)*] $head:tt $($rest:tt)*) => { | ||
327 | ng! { | ||
328 | [$($tts)* $head] $($rest)* | ||
329 | } | ||
330 | }; | ||
331 | } | ||
332 | fn foo() { | ||
333 | ng!([] let a = 3); | ||
334 | let b = a; | ||
335 | } | ||
336 | "#, | ||
337 | expect![[r#" | ||
338 | !0..7 'leta=3;': {unknown} | ||
339 | !0..7 'leta=3;': {unknown} | ||
340 | !0..13 'ng!{[leta=3]}': {unknown} | ||
341 | !0..13 'ng!{[leta=]3}': {unknown} | ||
342 | !0..13 'ng!{[leta]=3}': {unknown} | ||
343 | !3..4 'a': i32 | ||
344 | !5..6 '3': i32 | ||
345 | 196..237 '{ ...= a; }': () | ||
346 | 229..230 'b': i32 | ||
347 | 233..234 'a': i32 | ||
348 | "#]], | ||
349 | ); | ||
350 | } | ||
351 | |||
352 | #[test] | ||
235 | fn recursive_inner_item_macro_rules() { | 353 | fn recursive_inner_item_macro_rules() { |
236 | check_infer( | 354 | check_infer( |
237 | r#" | 355 | r#" |
@@ -246,7 +364,8 @@ fn recursive_inner_item_macro_rules() { | |||
246 | "#, | 364 | "#, |
247 | expect![[r#" | 365 | expect![[r#" |
248 | !0..1 '1': i32 | 366 | !0..1 '1': i32 |
249 | !0..7 'mac!($)': {unknown} | 367 | !0..26 'macro_...>{1};}': {unknown} |
368 | !0..26 'macro_...>{1};}': {unknown} | ||
250 | 107..143 '{ ...!(); }': () | 369 | 107..143 '{ ...!(); }': () |
251 | 129..130 'a': i32 | 370 | 129..130 'a': i32 |
252 | "#]], | 371 | "#]], |
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index 2ba97f814..65b71fdfa 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs | |||
@@ -3370,3 +3370,46 @@ fn test() { | |||
3370 | "#]], | 3370 | "#]], |
3371 | ) | 3371 | ) |
3372 | } | 3372 | } |
3373 | |||
3374 | #[test] | ||
3375 | fn qualified_path_as_qualified_trait() { | ||
3376 | check_infer( | ||
3377 | r#" | ||
3378 | mod foo { | ||
3379 | |||
3380 | pub trait Foo { | ||
3381 | type Target; | ||
3382 | } | ||
3383 | pub trait Bar { | ||
3384 | type Output; | ||
3385 | fn boo() -> Self::Output { | ||
3386 | loop {} | ||
3387 | } | ||
3388 | } | ||
3389 | } | ||
3390 | |||
3391 | struct F; | ||
3392 | impl foo::Foo for F { | ||
3393 | type Target = (); | ||
3394 | } | ||
3395 | impl foo::Bar for F { | ||
3396 | type Output = <F as foo::Foo>::Target; | ||
3397 | } | ||
3398 | |||
3399 | fn foo() { | ||
3400 | use foo::Bar; | ||
3401 | let x = <F as Bar>::boo(); | ||
3402 | } | ||
3403 | |||
3404 | "#, | ||
3405 | expect![[r#" | ||
3406 | 132..163 '{ ... }': Bar::Output<Self> | ||
3407 | 146..153 'loop {}': ! | ||
3408 | 151..153 '{}': () | ||
3409 | 306..358 '{ ...o(); }': () | ||
3410 | 334..335 'x': () | ||
3411 | 338..353 '<F as Bar>::boo': fn boo<F>() -> <F as Bar>::Output | ||
3412 | 338..355 '<F as ...:boo()': () | ||
3413 | "#]], | ||
3414 | ); | ||
3415 | } | ||
diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index 64bc926f1..5ebe7fd0e 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs | |||
@@ -19,6 +19,8 @@ use crate::{ | |||
19 | // | 19 | // |
20 | // Provides user with annotations above items for looking up references or impl blocks | 20 | // Provides user with annotations above items for looking up references or impl blocks |
21 | // and running/debugging binaries. | 21 | // and running/debugging binaries. |
22 | // | ||
23 | // image::https://user-images.githubusercontent.com/48062697/113020672-b7c34f00-917a-11eb-8f6e-858735660a0e.png[] | ||
22 | #[derive(Debug)] | 24 | #[derive(Debug)] |
23 | pub struct Annotation { | 25 | pub struct Annotation { |
24 | pub range: TextRange, | 26 | pub range: TextRange, |
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 22697a537..dd42116a7 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -165,7 +165,6 @@ pub(crate) fn diagnostics( | |||
165 | sema.diagnostics_display_range(d.display_source()).range, | 165 | sema.diagnostics_display_range(d.display_source()).range, |
166 | d.message(), | 166 | d.message(), |
167 | ) | 167 | ) |
168 | .with_unused(true) | ||
169 | .with_fix(d.fix(&sema)) | 168 | .with_fix(d.fix(&sema)) |
170 | .with_code(Some(d.code())), | 169 | .with_code(Some(d.code())), |
171 | ); | 170 | ); |
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs index 2f840909c..5fb3e2d91 100644 --- a/crates/ide/src/diagnostics/fixes.rs +++ b/crates/ide/src/diagnostics/fixes.rs | |||
@@ -210,7 +210,7 @@ fn missing_record_expr_field_fix( | |||
210 | } | 210 | } |
211 | let new_field = make::record_field( | 211 | let new_field = make::record_field( |
212 | None, | 212 | None, |
213 | make::name(record_expr_field.field_name()?.text()), | 213 | make::name(&record_expr_field.field_name()?.text()), |
214 | make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?), | 214 | make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?), |
215 | ); | 215 | ); |
216 | 216 | ||
diff --git a/crates/ide/src/diagnostics/unlinked_file.rs b/crates/ide/src/diagnostics/unlinked_file.rs index 019b0b440..e174fb767 100644 --- a/crates/ide/src/diagnostics/unlinked_file.rs +++ b/crates/ide/src/diagnostics/unlinked_file.rs | |||
@@ -63,7 +63,7 @@ impl DiagnosticWithFix for UnlinkedFile { | |||
63 | // - `$dir.rs` in the parent folder, where `$dir` is the directory containing `self.file_id` | 63 | // - `$dir.rs` in the parent folder, where `$dir` is the directory containing `self.file_id` |
64 | let parent = our_path.parent()?; | 64 | let parent = our_path.parent()?; |
65 | let mut paths = | 65 | let mut paths = |
66 | vec![parent.join("mod.rs")?, parent.join("main.rs")?, parent.join("lib.rs")?]; | 66 | vec![parent.join("mod.rs")?, parent.join("lib.rs")?, parent.join("main.rs")?]; |
67 | 67 | ||
68 | // `submod/bla.rs` -> `submod.rs` | 68 | // `submod/bla.rs` -> `submod.rs` |
69 | if let Some(newmod) = (|| { | 69 | if let Some(newmod) = (|| { |
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 0cee741ac..67e2e5a1c 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -98,6 +98,29 @@ pub(crate) fn remove_links(markdown: &str) -> String { | |||
98 | out | 98 | out |
99 | } | 99 | } |
100 | 100 | ||
101 | /// Retrieve a link to documentation for the given symbol. | ||
102 | pub(crate) fn external_docs( | ||
103 | db: &RootDatabase, | ||
104 | position: &FilePosition, | ||
105 | ) -> Option<DocumentationLink> { | ||
106 | let sema = Semantics::new(db); | ||
107 | let file = sema.parse(position.file_id).syntax().clone(); | ||
108 | let token = pick_best(file.token_at_offset(position.offset))?; | ||
109 | let token = sema.descend_into_macros(token); | ||
110 | |||
111 | let node = token.parent()?; | ||
112 | let definition = match_ast! { | ||
113 | match node { | ||
114 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), | ||
115 | ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db)), | ||
116 | _ => None, | ||
117 | } | ||
118 | }; | ||
119 | |||
120 | get_doc_link(db, definition?) | ||
121 | } | ||
122 | |||
123 | /// Extracts all links from a given markdown text. | ||
101 | pub(crate) fn extract_definitions_from_markdown( | 124 | pub(crate) fn extract_definitions_from_markdown( |
102 | markdown: &str, | 125 | markdown: &str, |
103 | ) -> Vec<(Range<usize>, String, Option<hir::Namespace>)> { | 126 | ) -> Vec<(Range<usize>, String, Option<hir::Namespace>)> { |
@@ -161,7 +184,7 @@ pub(crate) fn doc_owner_to_def( | |||
161 | ast::Variant(it) => sema.to_def(&it)?.into(), | 184 | ast::Variant(it) => sema.to_def(&it)?.into(), |
162 | ast::Trait(it) => sema.to_def(&it)?.into(), | 185 | ast::Trait(it) => sema.to_def(&it)?.into(), |
163 | ast::Impl(it) => return sema.to_def(&it).map(Definition::SelfType), | 186 | ast::Impl(it) => return sema.to_def(&it).map(Definition::SelfType), |
164 | ast::MacroRules(it) => return sema.to_def(&it).map(Definition::Macro), | 187 | ast::Macro(it) => return sema.to_def(&it).map(Definition::Macro), |
165 | ast::TupleField(it) => return sema.to_def(&it).map(Definition::Field), | 188 | ast::TupleField(it) => return sema.to_def(&it).map(Definition::Field), |
166 | ast::RecordField(it) => return sema.to_def(&it).map(Definition::Field), | 189 | ast::RecordField(it) => return sema.to_def(&it).map(Definition::Field), |
167 | _ => return None, | 190 | _ => return None, |
@@ -178,15 +201,15 @@ pub(crate) fn resolve_doc_path_for_def( | |||
178 | ) -> Option<hir::ModuleDef> { | 201 | ) -> Option<hir::ModuleDef> { |
179 | match def { | 202 | match def { |
180 | Definition::ModuleDef(def) => match def { | 203 | Definition::ModuleDef(def) => match def { |
181 | ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns), | 204 | hir::ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns), |
182 | ModuleDef::Function(it) => it.resolve_doc_path(db, &link, ns), | 205 | hir::ModuleDef::Function(it) => it.resolve_doc_path(db, &link, ns), |
183 | ModuleDef::Adt(it) => it.resolve_doc_path(db, &link, ns), | 206 | hir::ModuleDef::Adt(it) => it.resolve_doc_path(db, &link, ns), |
184 | ModuleDef::Variant(it) => it.resolve_doc_path(db, &link, ns), | 207 | hir::ModuleDef::Variant(it) => it.resolve_doc_path(db, &link, ns), |
185 | ModuleDef::Const(it) => it.resolve_doc_path(db, &link, ns), | 208 | hir::ModuleDef::Const(it) => it.resolve_doc_path(db, &link, ns), |
186 | ModuleDef::Static(it) => it.resolve_doc_path(db, &link, ns), | 209 | hir::ModuleDef::Static(it) => it.resolve_doc_path(db, &link, ns), |
187 | ModuleDef::Trait(it) => it.resolve_doc_path(db, &link, ns), | 210 | hir::ModuleDef::Trait(it) => it.resolve_doc_path(db, &link, ns), |
188 | ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, &link, ns), | 211 | hir::ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, &link, ns), |
189 | ModuleDef::BuiltinType(_) => None, | 212 | hir::ModuleDef::BuiltinType(_) => None, |
190 | }, | 213 | }, |
191 | Definition::Macro(it) => it.resolve_doc_path(db, &link, ns), | 214 | Definition::Macro(it) => it.resolve_doc_path(db, &link, ns), |
192 | Definition::Field(it) => it.resolve_doc_path(db, &link, ns), | 215 | Definition::Field(it) => it.resolve_doc_path(db, &link, ns), |
@@ -214,7 +237,7 @@ fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> { | |||
214 | .and_then(|assoc| match assoc.container(db) { | 237 | .and_then(|assoc| match assoc.container(db) { |
215 | AssocItemContainer::Trait(t) => Some(t.into()), | 238 | AssocItemContainer::Trait(t) => Some(t.into()), |
216 | AssocItemContainer::Impl(impld) => { | 239 | AssocItemContainer::Impl(impld) => { |
217 | impld.target_ty(db).as_adt().map(|adt| adt.into()) | 240 | impld.self_ty(db).as_adt().map(|adt| adt.into()) |
218 | } | 241 | } |
219 | }) | 242 | }) |
220 | .unwrap_or_else(|| f.clone().into()), | 243 | .unwrap_or_else(|| f.clone().into()), |
@@ -328,28 +351,6 @@ fn rewrite_url_link(db: &RootDatabase, def: ModuleDef, target: &str) -> Option<S | |||
328 | .map(|url| url.into_string()) | 351 | .map(|url| url.into_string()) |
329 | } | 352 | } |
330 | 353 | ||
331 | /// Retrieve a link to documentation for the given symbol. | ||
332 | pub(crate) fn external_docs( | ||
333 | db: &RootDatabase, | ||
334 | position: &FilePosition, | ||
335 | ) -> Option<DocumentationLink> { | ||
336 | let sema = Semantics::new(db); | ||
337 | let file = sema.parse(position.file_id).syntax().clone(); | ||
338 | let token = pick_best(file.token_at_offset(position.offset))?; | ||
339 | let token = sema.descend_into_macros(token); | ||
340 | |||
341 | let node = token.parent()?; | ||
342 | let definition = match_ast! { | ||
343 | match node { | ||
344 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), | ||
345 | ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db)), | ||
346 | _ => None, | ||
347 | } | ||
348 | }; | ||
349 | |||
350 | get_doc_link(db, definition?) | ||
351 | } | ||
352 | |||
353 | /// Rewrites a markdown document, applying 'callback' to each link. | 354 | /// Rewrites a markdown document, applying 'callback' to each link. |
354 | fn map_links<'e>( | 355 | fn map_links<'e>( |
355 | events: impl Iterator<Item = Event<'e>>, | 356 | events: impl Iterator<Item = Event<'e>>, |
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index ffb3a6f7d..9eeabbeda 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs | |||
@@ -23,6 +23,8 @@ pub struct ExpandedMacro { | |||
23 | // | 23 | // |
24 | // | VS Code | **Rust Analyzer: Expand macro recursively** | 24 | // | VS Code | **Rust Analyzer: Expand macro recursively** |
25 | // |=== | 25 | // |=== |
26 | // | ||
27 | // image::https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif[] | ||
26 | pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> { | 28 | pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> { |
27 | let sema = Semantics::new(db); | 29 | let sema = Semantics::new(db); |
28 | let file = sema.parse(position.file_id); | 30 | let file = sema.parse(position.file_id); |
diff --git a/crates/ide/src/extend_selection.rs b/crates/ide/src/extend_selection.rs index 5201ce587..7032889ac 100644 --- a/crates/ide/src/extend_selection.rs +++ b/crates/ide/src/extend_selection.rs | |||
@@ -24,6 +24,8 @@ use crate::FileRange; | |||
24 | // | 24 | // |
25 | // | VS Code | kbd:[Alt+Shift+→], kbd:[Alt+Shift+←] | 25 | // | VS Code | kbd:[Alt+Shift+→], kbd:[Alt+Shift+←] |
26 | // |=== | 26 | // |=== |
27 | // | ||
28 | // image::https://user-images.githubusercontent.com/48062697/113020651-b42fc800-917a-11eb-8a4f-cf1a07859fac.gif[] | ||
27 | pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange { | 29 | pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange { |
28 | let sema = Semantics::new(db); | 30 | let sema = Semantics::new(db); |
29 | let src = sema.parse(frange.file_id); | 31 | let src = sema.parse(frange.file_id); |
diff --git a/crates/ide/src/file_structure.rs b/crates/ide/src/file_structure.rs index 9f879a66e..19071d6be 100644 --- a/crates/ide/src/file_structure.rs +++ b/crates/ide/src/file_structure.rs | |||
@@ -35,6 +35,9 @@ pub enum StructureNodeKind { | |||
35 | // | 35 | // |
36 | // | VS Code | kbd:[Ctrl+Shift+O] | 36 | // | VS Code | kbd:[Ctrl+Shift+O] |
37 | // |=== | 37 | // |=== |
38 | // | ||
39 | // image::https://user-images.githubusercontent.com/48062697/113020654-b42fc800-917a-11eb-8388-e7dc4d92b02e.gif[] | ||
40 | |||
38 | pub(crate) fn file_structure(file: &SourceFile) -> Vec<StructureNode> { | 41 | pub(crate) fn file_structure(file: &SourceFile) -> Vec<StructureNode> { |
39 | let mut res = Vec::new(); | 42 | let mut res = Vec::new(); |
40 | let mut stack = Vec::new(); | 43 | let mut stack = Vec::new(); |
@@ -172,7 +175,7 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> { | |||
172 | }; | 175 | }; |
173 | Some(node) | 176 | Some(node) |
174 | }, | 177 | }, |
175 | ast::MacroRules(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)), | 178 | ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)), |
176 | _ => None, | 179 | _ => None, |
177 | } | 180 | } |
178 | } | 181 | } |
diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs index 4b1b24562..153726ce8 100644 --- a/crates/ide/src/folding_ranges.rs +++ b/crates/ide/src/folding_ranges.rs | |||
@@ -17,6 +17,8 @@ pub enum FoldKind { | |||
17 | Block, | 17 | Block, |
18 | ArgList, | 18 | ArgList, |
19 | Region, | 19 | Region, |
20 | Consts, | ||
21 | Statics, | ||
20 | } | 22 | } |
21 | 23 | ||
22 | #[derive(Debug)] | 24 | #[derive(Debug)] |
@@ -30,6 +32,8 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> { | |||
30 | let mut visited_comments = FxHashSet::default(); | 32 | let mut visited_comments = FxHashSet::default(); |
31 | let mut visited_imports = FxHashSet::default(); | 33 | let mut visited_imports = FxHashSet::default(); |
32 | let mut visited_mods = FxHashSet::default(); | 34 | let mut visited_mods = FxHashSet::default(); |
35 | let mut visited_consts = FxHashSet::default(); | ||
36 | let mut visited_statics = FxHashSet::default(); | ||
33 | // regions can be nested, here is a LIFO buffer | 37 | // regions can be nested, here is a LIFO buffer |
34 | let mut regions_starts: Vec<TextSize> = vec![]; | 38 | let mut regions_starts: Vec<TextSize> = vec![]; |
35 | 39 | ||
@@ -91,6 +95,19 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> { | |||
91 | res.push(Fold { range, kind: FoldKind::Mods }) | 95 | res.push(Fold { range, kind: FoldKind::Mods }) |
92 | } | 96 | } |
93 | } | 97 | } |
98 | |||
99 | // Fold groups of consts | ||
100 | if node.kind() == CONST && !visited_consts.contains(&node) { | ||
101 | if let Some(range) = contiguous_range_for_group(&node, &mut visited_consts) { | ||
102 | res.push(Fold { range, kind: FoldKind::Consts }) | ||
103 | } | ||
104 | } | ||
105 | // Fold groups of consts | ||
106 | if node.kind() == STATIC && !visited_statics.contains(&node) { | ||
107 | if let Some(range) = contiguous_range_for_group(&node, &mut visited_statics) { | ||
108 | res.push(Fold { range, kind: FoldKind::Statics }) | ||
109 | } | ||
110 | } | ||
94 | } | 111 | } |
95 | } | 112 | } |
96 | } | 113 | } |
@@ -250,6 +267,8 @@ mod tests { | |||
250 | FoldKind::Block => "block", | 267 | FoldKind::Block => "block", |
251 | FoldKind::ArgList => "arglist", | 268 | FoldKind::ArgList => "arglist", |
252 | FoldKind::Region => "region", | 269 | FoldKind::Region => "region", |
270 | FoldKind::Consts => "consts", | ||
271 | FoldKind::Statics => "statics", | ||
253 | }; | 272 | }; |
254 | assert_eq!(kind, &attr.unwrap()); | 273 | assert_eq!(kind, &attr.unwrap()); |
255 | } | 274 | } |
@@ -457,4 +476,24 @@ calling_function(x,y); | |||
457 | "#, | 476 | "#, |
458 | ) | 477 | ) |
459 | } | 478 | } |
479 | |||
480 | #[test] | ||
481 | fn fold_consecutive_const() { | ||
482 | check( | ||
483 | r#" | ||
484 | <fold consts>const FIRST_CONST: &str = "first"; | ||
485 | const SECOND_CONST: &str = "second";</fold> | ||
486 | "#, | ||
487 | ) | ||
488 | } | ||
489 | |||
490 | #[test] | ||
491 | fn fold_consecutive_static() { | ||
492 | check( | ||
493 | r#" | ||
494 | <fold statics>static FIRST_STATIC: &str = "first"; | ||
495 | static SECOND_STATIC: &str = "second";</fold> | ||
496 | "#, | ||
497 | ) | ||
498 | } | ||
460 | } | 499 | } |
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index a2c97061f..8574d1e3f 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs | |||
@@ -21,6 +21,8 @@ use crate::{ | |||
21 | // | 21 | // |
22 | // | VS Code | kbd:[F12] | 22 | // | VS Code | kbd:[F12] |
23 | // |=== | 23 | // |=== |
24 | // | ||
25 | // image::https://user-images.githubusercontent.com/48062697/113065563-025fbe00-91b1-11eb-83e4-a5a703610b23.gif[] | ||
24 | pub(crate) fn goto_definition( | 26 | pub(crate) fn goto_definition( |
25 | db: &RootDatabase, | 27 | db: &RootDatabase, |
26 | position: FilePosition, | 28 | position: FilePosition, |
@@ -918,6 +920,21 @@ fn f() -> impl Iterator<Item$0 = u8> {} | |||
918 | } | 920 | } |
919 | 921 | ||
920 | #[test] | 922 | #[test] |
923 | #[should_panic = "unresolved reference"] | ||
924 | fn unknown_assoc_ty() { | ||
925 | check( | ||
926 | r#" | ||
927 | trait Iterator { | ||
928 | type Item; | ||
929 | //^^^^ | ||
930 | } | ||
931 | |||
932 | fn f() -> impl Iterator<Invalid$0 = u8> {} | ||
933 | "#, | ||
934 | ) | ||
935 | } | ||
936 | |||
937 | #[test] | ||
921 | fn goto_def_for_assoc_ty_in_path_multiple() { | 938 | fn goto_def_for_assoc_ty_in_path_multiple() { |
922 | check( | 939 | check( |
923 | r#" | 940 | r#" |
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index f4d7c14a6..05130a237 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs | |||
@@ -16,6 +16,8 @@ use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo}; | |||
16 | // | 16 | // |
17 | // | VS Code | kbd:[Ctrl+F12] | 17 | // | VS Code | kbd:[Ctrl+F12] |
18 | // |=== | 18 | // |=== |
19 | // | ||
20 | // image::https://user-images.githubusercontent.com/48062697/113065566-02f85480-91b1-11eb-9288-aaad8abd8841.gif[] | ||
19 | pub(crate) fn goto_implementation( | 21 | pub(crate) fn goto_implementation( |
20 | db: &RootDatabase, | 22 | db: &RootDatabase, |
21 | position: FilePosition, | 23 | position: FilePosition, |
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index 2d38cb112..9d34b109b 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs | |||
@@ -12,6 +12,8 @@ use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo}; | |||
12 | // | 12 | // |
13 | // | VS Code | **Go to Type Definition* | 13 | // | VS Code | **Go to Type Definition* |
14 | // |=== | 14 | // |=== |
15 | // | ||
16 | // image::https://user-images.githubusercontent.com/48062697/113020657-b560f500-917a-11eb-9007-0f809733a338.gif[] | ||
15 | pub(crate) fn goto_type_definition( | 17 | pub(crate) fn goto_type_definition( |
16 | db: &RootDatabase, | 18 | db: &RootDatabase, |
17 | position: FilePosition, | 19 | position: FilePosition, |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index c43089476..5f9edb476 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -82,6 +82,8 @@ pub struct HoverResult { | |||
82 | // | 82 | // |
83 | // Shows additional information, like type of an expression or documentation for definition when "focusing" code. | 83 | // Shows additional information, like type of an expression or documentation for definition when "focusing" code. |
84 | // Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. | 84 | // Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. |
85 | // | ||
86 | // image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[] | ||
85 | pub(crate) fn hover( | 87 | pub(crate) fn hover( |
86 | db: &RootDatabase, | 88 | db: &RootDatabase, |
87 | position: FilePosition, | 89 | position: FilePosition, |
@@ -195,7 +197,7 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov | |||
195 | let adt = match def { | 197 | let adt = match def { |
196 | Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), | 198 | Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), |
197 | Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), | 199 | Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), |
198 | Definition::SelfType(it) => it.target_ty(db).as_adt(), | 200 | Definition::SelfType(it) => it.self_ty(db).as_adt(), |
199 | _ => None, | 201 | _ => None, |
200 | }?; | 202 | }?; |
201 | adt.try_to_nav(db).map(to_action) | 203 | adt.try_to_nav(db).map(to_action) |
@@ -318,7 +320,7 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> | |||
318 | Definition::ModuleDef(md) => match md { | 320 | Definition::ModuleDef(md) => match md { |
319 | ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { | 321 | ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { |
320 | AssocItemContainer::Trait(t) => Some(t.name(db)), | 322 | AssocItemContainer::Trait(t) => Some(t.name(db)), |
321 | AssocItemContainer::Impl(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)), | 323 | AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)), |
322 | }, | 324 | }, |
323 | ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), | 325 | ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), |
324 | _ => None, | 326 | _ => None, |
@@ -376,7 +378,7 @@ fn hover_for_definition( | |||
376 | }, | 378 | }, |
377 | Definition::Local(it) => hover_for_local(it, db), | 379 | Definition::Local(it) => hover_for_local(it, db), |
378 | Definition::SelfType(impl_def) => { | 380 | Definition::SelfType(impl_def) => { |
379 | impl_def.target_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path)) | 381 | impl_def.self_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path)) |
380 | } | 382 | } |
381 | Definition::GenericParam(it) => from_hir_fmt(db, it, None), | 383 | Definition::GenericParam(it) => from_hir_fmt(db, it, None), |
382 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), | 384 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), |
@@ -470,6 +472,7 @@ fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module> | |||
470 | 472 | ||
471 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | 473 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { |
472 | return tokens.max_by_key(priority); | 474 | return tokens.max_by_key(priority); |
475 | |||
473 | fn priority(n: &SyntaxToken) -> usize { | 476 | fn priority(n: &SyntaxToken) -> usize { |
474 | match n.kind() { | 477 | match n.kind() { |
475 | IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3, | 478 | IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3, |
@@ -1235,6 +1238,37 @@ fn f() { fo$0o!(); } | |||
1235 | } | 1238 | } |
1236 | 1239 | ||
1237 | #[test] | 1240 | #[test] |
1241 | fn test_hover_macro2_invocation() { | ||
1242 | check( | ||
1243 | r#" | ||
1244 | /// foo bar | ||
1245 | /// | ||
1246 | /// foo bar baz | ||
1247 | macro foo() {} | ||
1248 | |||
1249 | fn f() { fo$0o!(); } | ||
1250 | "#, | ||
1251 | expect![[r#" | ||
1252 | *foo* | ||
1253 | |||
1254 | ```rust | ||
1255 | test | ||
1256 | ``` | ||
1257 | |||
1258 | ```rust | ||
1259 | macro foo | ||
1260 | ``` | ||
1261 | |||
1262 | --- | ||
1263 | |||
1264 | foo bar | ||
1265 | |||
1266 | foo bar baz | ||
1267 | "#]], | ||
1268 | ) | ||
1269 | } | ||
1270 | |||
1271 | #[test] | ||
1238 | fn test_hover_tuple_field() { | 1272 | fn test_hover_tuple_field() { |
1239 | check( | 1273 | check( |
1240 | r#"struct TS(String, i32$0);"#, | 1274 | r#"struct TS(String, i32$0);"#, |
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 16c04eeee..f73edf8b6 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs | |||
@@ -52,6 +52,8 @@ pub struct InlayHint { | |||
52 | // | 52 | // |
53 | // | VS Code | **Rust Analyzer: Toggle inlay hints* | 53 | // | VS Code | **Rust Analyzer: Toggle inlay hints* |
54 | // |=== | 54 | // |=== |
55 | // | ||
56 | // image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[] | ||
55 | pub(crate) fn inlay_hints( | 57 | pub(crate) fn inlay_hints( |
56 | db: &RootDatabase, | 58 | db: &RootDatabase, |
57 | file_id: FileId, | 59 | file_id: FileId, |
@@ -416,7 +418,7 @@ fn get_string_representation(expr: &ast::Expr) -> Option<String> { | |||
416 | match expr { | 418 | match expr { |
417 | ast::Expr::MethodCallExpr(method_call_expr) => { | 419 | ast::Expr::MethodCallExpr(method_call_expr) => { |
418 | let name_ref = method_call_expr.name_ref()?; | 420 | let name_ref = method_call_expr.name_ref()?; |
419 | match name_ref.text() { | 421 | match name_ref.text().as_str() { |
420 | "clone" => method_call_expr.receiver().map(|rec| rec.to_string()), | 422 | "clone" => method_call_expr.receiver().map(|rec| rec.to_string()), |
421 | name_ref => Some(name_ref.to_owned()), | 423 | name_ref => Some(name_ref.to_owned()), |
422 | } | 424 | } |
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index 4b25135cd..d584190f7 100644 --- a/crates/ide/src/join_lines.rs +++ b/crates/ide/src/join_lines.rs | |||
@@ -19,6 +19,8 @@ use text_edit::{TextEdit, TextEditBuilder}; | |||
19 | // | 19 | // |
20 | // | VS Code | **Rust Analyzer: Join lines** | 20 | // | VS Code | **Rust Analyzer: Join lines** |
21 | // |=== | 21 | // |=== |
22 | // | ||
23 | // image::https://user-images.githubusercontent.com/48062697/113020661-b6922200-917a-11eb-87c4-b75acc028f11.gif[] | ||
22 | pub(crate) fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit { | 24 | pub(crate) fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit { |
23 | let range = if range.is_empty() { | 25 | let range = if range.is_empty() { |
24 | let syntax = file.syntax(); | 26 | let syntax = file.syntax(); |
diff --git a/crates/ide/src/matching_brace.rs b/crates/ide/src/matching_brace.rs index 4241a6dac..261dcc255 100644 --- a/crates/ide/src/matching_brace.rs +++ b/crates/ide/src/matching_brace.rs | |||
@@ -14,6 +14,8 @@ use syntax::{ | |||
14 | // | 14 | // |
15 | // | VS Code | **Rust Analyzer: Find matching brace** | 15 | // | VS Code | **Rust Analyzer: Find matching brace** |
16 | // |=== | 16 | // |=== |
17 | // | ||
18 | // image::https://user-images.githubusercontent.com/48062697/113065573-04298180-91b1-11eb-8dec-d4e2a202f304.gif[] | ||
17 | pub(crate) fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<TextSize> { | 19 | pub(crate) fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<TextSize> { |
18 | const BRACES: &[SyntaxKind] = | 20 | const BRACES: &[SyntaxKind] = |
19 | &[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>], T![|], T![|]]; | 21 | &[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>], T![|], T![|]]; |
diff --git a/crates/ide/src/move_item.rs b/crates/ide/src/move_item.rs index 48690b073..8d37f4f92 100644 --- a/crates/ide/src/move_item.rs +++ b/crates/ide/src/move_item.rs | |||
@@ -4,10 +4,12 @@ use hir::Semantics; | |||
4 | use ide_db::{base_db::FileRange, RootDatabase}; | 4 | use ide_db::{base_db::FileRange, RootDatabase}; |
5 | use itertools::Itertools; | 5 | use itertools::Itertools; |
6 | use syntax::{ | 6 | use syntax::{ |
7 | algo, ast, match_ast, AstNode, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, | 7 | algo, ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, |
8 | TokenAtOffset, | ||
8 | }; | 9 | }; |
9 | use text_edit::{TextEdit, TextEditBuilder}; | 10 | use text_edit::{TextEdit, TextEditBuilder}; |
10 | 11 | ||
12 | #[derive(Copy, Clone, Debug)] | ||
11 | pub enum Direction { | 13 | pub enum Direction { |
12 | Up, | 14 | Up, |
13 | Down, | 15 | Down, |
@@ -23,6 +25,8 @@ pub enum Direction { | |||
23 | // | VS Code | **Rust Analyzer: Move item up** | 25 | // | VS Code | **Rust Analyzer: Move item up** |
24 | // | VS Code | **Rust Analyzer: Move item down** | 26 | // | VS Code | **Rust Analyzer: Move item down** |
25 | // |=== | 27 | // |=== |
28 | // | ||
29 | // image::https://user-images.githubusercontent.com/48062697/113065576-04298180-91b1-11eb-91ce-4505e99ed598.gif[] | ||
26 | pub(crate) fn move_item( | 30 | pub(crate) fn move_item( |
27 | db: &RootDatabase, | 31 | db: &RootDatabase, |
28 | range: FileRange, | 32 | range: FileRange, |
@@ -31,14 +35,19 @@ pub(crate) fn move_item( | |||
31 | let sema = Semantics::new(db); | 35 | let sema = Semantics::new(db); |
32 | let file = sema.parse(range.file_id); | 36 | let file = sema.parse(range.file_id); |
33 | 37 | ||
34 | let item = file.syntax().covering_element(range.range); | 38 | let item = if range.range.is_empty() { |
39 | SyntaxElement::Token(pick_best(file.syntax().token_at_offset(range.range.start()))?) | ||
40 | } else { | ||
41 | file.syntax().covering_element(range.range) | ||
42 | }; | ||
43 | |||
35 | find_ancestors(item, direction, range.range) | 44 | find_ancestors(item, direction, range.range) |
36 | } | 45 | } |
37 | 46 | ||
38 | fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -> Option<TextEdit> { | 47 | fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -> Option<TextEdit> { |
39 | let root = match item { | 48 | let root = match item { |
40 | NodeOrToken::Node(node) => node, | 49 | SyntaxElement::Node(node) => node, |
41 | NodeOrToken::Token(token) => token.parent()?, | 50 | SyntaxElement::Token(token) => token.parent()?, |
42 | }; | 51 | }; |
43 | 52 | ||
44 | let movable = [ | 53 | let movable = [ |
@@ -51,6 +60,11 @@ fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) - | |||
51 | SyntaxKind::PARAM, | 60 | SyntaxKind::PARAM, |
52 | SyntaxKind::LET_STMT, | 61 | SyntaxKind::LET_STMT, |
53 | SyntaxKind::EXPR_STMT, | 62 | SyntaxKind::EXPR_STMT, |
63 | SyntaxKind::IF_EXPR, | ||
64 | SyntaxKind::FOR_EXPR, | ||
65 | SyntaxKind::LOOP_EXPR, | ||
66 | SyntaxKind::WHILE_EXPR, | ||
67 | SyntaxKind::RETURN_EXPR, | ||
54 | SyntaxKind::MATCH_EXPR, | 68 | SyntaxKind::MATCH_EXPR, |
55 | SyntaxKind::MACRO_CALL, | 69 | SyntaxKind::MACRO_CALL, |
56 | SyntaxKind::TYPE_ALIAS, | 70 | SyntaxKind::TYPE_ALIAS, |
@@ -66,6 +80,7 @@ fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) - | |||
66 | SyntaxKind::STATIC, | 80 | SyntaxKind::STATIC, |
67 | SyntaxKind::CONST, | 81 | SyntaxKind::CONST, |
68 | SyntaxKind::MACRO_RULES, | 82 | SyntaxKind::MACRO_RULES, |
83 | SyntaxKind::MACRO_DEF, | ||
69 | ]; | 84 | ]; |
70 | 85 | ||
71 | let ancestor = once(root.clone()) | 86 | let ancestor = once(root.clone()) |
@@ -82,11 +97,11 @@ fn move_in_direction( | |||
82 | ) -> Option<TextEdit> { | 97 | ) -> Option<TextEdit> { |
83 | match_ast! { | 98 | match_ast! { |
84 | match node { | 99 | match node { |
85 | ast::ArgList(it) => swap_sibling_in_list(it.args(), range, direction), | 100 | ast::ArgList(it) => swap_sibling_in_list(node, it.args(), range, direction), |
86 | ast::GenericParamList(it) => swap_sibling_in_list(it.generic_params(), range, direction), | 101 | ast::GenericParamList(it) => swap_sibling_in_list(node, it.generic_params(), range, direction), |
87 | ast::GenericArgList(it) => swap_sibling_in_list(it.generic_args(), range, direction), | 102 | ast::GenericArgList(it) => swap_sibling_in_list(node, it.generic_args(), range, direction), |
88 | ast::VariantList(it) => swap_sibling_in_list(it.variants(), range, direction), | 103 | ast::VariantList(it) => swap_sibling_in_list(node, it.variants(), range, direction), |
89 | ast::TypeBoundList(it) => swap_sibling_in_list(it.bounds(), range, direction), | 104 | ast::TypeBoundList(it) => swap_sibling_in_list(node, it.bounds(), range, direction), |
90 | _ => Some(replace_nodes(node, &match direction { | 105 | _ => Some(replace_nodes(node, &match direction { |
91 | Direction::Up => node.prev_sibling(), | 106 | Direction::Up => node.prev_sibling(), |
92 | Direction::Down => node.next_sibling(), | 107 | Direction::Down => node.next_sibling(), |
@@ -96,19 +111,27 @@ fn move_in_direction( | |||
96 | } | 111 | } |
97 | 112 | ||
98 | fn swap_sibling_in_list<A: AstNode + Clone, I: Iterator<Item = A>>( | 113 | fn swap_sibling_in_list<A: AstNode + Clone, I: Iterator<Item = A>>( |
114 | node: &SyntaxNode, | ||
99 | list: I, | 115 | list: I, |
100 | range: TextRange, | 116 | range: TextRange, |
101 | direction: Direction, | 117 | direction: Direction, |
102 | ) -> Option<TextEdit> { | 118 | ) -> Option<TextEdit> { |
103 | let (l, r) = list | 119 | let list_lookup = list |
104 | .tuple_windows() | 120 | .tuple_windows() |
105 | .filter(|(l, r)| match direction { | 121 | .filter(|(l, r)| match direction { |
106 | Direction::Up => r.syntax().text_range().contains_range(range), | 122 | Direction::Up => r.syntax().text_range().contains_range(range), |
107 | Direction::Down => l.syntax().text_range().contains_range(range), | 123 | Direction::Down => l.syntax().text_range().contains_range(range), |
108 | }) | 124 | }) |
109 | .next()?; | 125 | .next(); |
110 | 126 | ||
111 | Some(replace_nodes(l.syntax(), r.syntax())) | 127 | if let Some((l, r)) = list_lookup { |
128 | Some(replace_nodes(l.syntax(), r.syntax())) | ||
129 | } else { | ||
130 | // Cursor is beyond any movable list item (for example, on curly brace in enum). | ||
131 | // It's not necessary, that parent of list is movable (arg list's parent is not, for example), | ||
132 | // and we have to continue tree traversal to find suitable node. | ||
133 | find_ancestors(SyntaxElement::Node(node.parent()?), direction, range) | ||
134 | } | ||
112 | } | 135 | } |
113 | 136 | ||
114 | fn replace_nodes(first: &SyntaxNode, second: &SyntaxNode) -> TextEdit { | 137 | fn replace_nodes(first: &SyntaxNode, second: &SyntaxNode) -> TextEdit { |
@@ -120,6 +143,18 @@ fn replace_nodes(first: &SyntaxNode, second: &SyntaxNode) -> TextEdit { | |||
120 | edit.finish() | 143 | edit.finish() |
121 | } | 144 | } |
122 | 145 | ||
146 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | ||
147 | return tokens.max_by_key(priority); | ||
148 | |||
149 | fn priority(n: &SyntaxToken) -> usize { | ||
150 | match n.kind() { | ||
151 | SyntaxKind::IDENT | SyntaxKind::LIFETIME_IDENT => 2, | ||
152 | kind if kind.is_trivia() => 0, | ||
153 | _ => 1, | ||
154 | } | ||
155 | } | ||
156 | } | ||
157 | |||
123 | #[cfg(test)] | 158 | #[cfg(test)] |
124 | mod tests { | 159 | mod tests { |
125 | use crate::fixture; | 160 | use crate::fixture; |
@@ -264,6 +299,107 @@ fn main() { | |||
264 | "#]], | 299 | "#]], |
265 | Direction::Up, | 300 | Direction::Up, |
266 | ); | 301 | ); |
302 | check( | ||
303 | r#" | ||
304 | fn main() { | ||
305 | println!("Hello, world"); | ||
306 | |||
307 | if true { | ||
308 | println!("Test"); | ||
309 | }$0$0 | ||
310 | } | ||
311 | "#, | ||
312 | expect![[r#" | ||
313 | fn main() { | ||
314 | if true { | ||
315 | println!("Test"); | ||
316 | } | ||
317 | |||
318 | println!("Hello, world"); | ||
319 | } | ||
320 | "#]], | ||
321 | Direction::Up, | ||
322 | ); | ||
323 | check( | ||
324 | r#" | ||
325 | fn main() { | ||
326 | println!("Hello, world"); | ||
327 | |||
328 | for i in 0..10 { | ||
329 | println!("Test"); | ||
330 | }$0$0 | ||
331 | } | ||
332 | "#, | ||
333 | expect![[r#" | ||
334 | fn main() { | ||
335 | for i in 0..10 { | ||
336 | println!("Test"); | ||
337 | } | ||
338 | |||
339 | println!("Hello, world"); | ||
340 | } | ||
341 | "#]], | ||
342 | Direction::Up, | ||
343 | ); | ||
344 | check( | ||
345 | r#" | ||
346 | fn main() { | ||
347 | println!("Hello, world"); | ||
348 | |||
349 | loop { | ||
350 | println!("Test"); | ||
351 | }$0$0 | ||
352 | } | ||
353 | "#, | ||
354 | expect![[r#" | ||
355 | fn main() { | ||
356 | loop { | ||
357 | println!("Test"); | ||
358 | } | ||
359 | |||
360 | println!("Hello, world"); | ||
361 | } | ||
362 | "#]], | ||
363 | Direction::Up, | ||
364 | ); | ||
365 | check( | ||
366 | r#" | ||
367 | fn main() { | ||
368 | println!("Hello, world"); | ||
369 | |||
370 | while true { | ||
371 | println!("Test"); | ||
372 | }$0$0 | ||
373 | } | ||
374 | "#, | ||
375 | expect![[r#" | ||
376 | fn main() { | ||
377 | while true { | ||
378 | println!("Test"); | ||
379 | } | ||
380 | |||
381 | println!("Hello, world"); | ||
382 | } | ||
383 | "#]], | ||
384 | Direction::Up, | ||
385 | ); | ||
386 | check( | ||
387 | r#" | ||
388 | fn main() { | ||
389 | println!("Hello, world"); | ||
390 | |||
391 | return 123;$0$0 | ||
392 | } | ||
393 | "#, | ||
394 | expect![[r#" | ||
395 | fn main() { | ||
396 | return 123; | ||
397 | |||
398 | println!("Hello, world"); | ||
399 | } | ||
400 | "#]], | ||
401 | Direction::Up, | ||
402 | ); | ||
267 | } | 403 | } |
268 | 404 | ||
269 | #[test] | 405 | #[test] |
@@ -614,6 +750,115 @@ fn test() { | |||
614 | } | 750 | } |
615 | 751 | ||
616 | #[test] | 752 | #[test] |
753 | fn test_cursor_at_item_start() { | ||
754 | check( | ||
755 | r#" | ||
756 | $0$0#[derive(Debug)] | ||
757 | enum FooBar { | ||
758 | Foo, | ||
759 | Bar, | ||
760 | } | ||
761 | |||
762 | fn main() {} | ||
763 | "#, | ||
764 | expect![[r#" | ||
765 | fn main() {} | ||
766 | |||
767 | #[derive(Debug)] | ||
768 | enum FooBar { | ||
769 | Foo, | ||
770 | Bar, | ||
771 | } | ||
772 | "#]], | ||
773 | Direction::Down, | ||
774 | ); | ||
775 | check( | ||
776 | r#" | ||
777 | $0$0enum FooBar { | ||
778 | Foo, | ||
779 | Bar, | ||
780 | } | ||
781 | |||
782 | fn main() {} | ||
783 | "#, | ||
784 | expect![[r#" | ||
785 | fn main() {} | ||
786 | |||
787 | enum FooBar { | ||
788 | Foo, | ||
789 | Bar, | ||
790 | } | ||
791 | "#]], | ||
792 | Direction::Down, | ||
793 | ); | ||
794 | check( | ||
795 | r#" | ||
796 | struct Test; | ||
797 | |||
798 | trait SomeTrait {} | ||
799 | |||
800 | $0$0impl SomeTrait for Test {} | ||
801 | |||
802 | fn main() {} | ||
803 | "#, | ||
804 | expect![[r#" | ||
805 | struct Test; | ||
806 | |||
807 | impl SomeTrait for Test {} | ||
808 | |||
809 | trait SomeTrait {} | ||
810 | |||
811 | fn main() {} | ||
812 | "#]], | ||
813 | Direction::Up, | ||
814 | ); | ||
815 | } | ||
816 | |||
817 | #[test] | ||
818 | fn test_cursor_at_item_end() { | ||
819 | check( | ||
820 | r#" | ||
821 | enum FooBar { | ||
822 | Foo, | ||
823 | Bar, | ||
824 | }$0$0 | ||
825 | |||
826 | fn main() {} | ||
827 | "#, | ||
828 | expect![[r#" | ||
829 | fn main() {} | ||
830 | |||
831 | enum FooBar { | ||
832 | Foo, | ||
833 | Bar, | ||
834 | } | ||
835 | "#]], | ||
836 | Direction::Down, | ||
837 | ); | ||
838 | check( | ||
839 | r#" | ||
840 | struct Test; | ||
841 | |||
842 | trait SomeTrait {} | ||
843 | |||
844 | impl SomeTrait for Test {}$0$0 | ||
845 | |||
846 | fn main() {} | ||
847 | "#, | ||
848 | expect![[r#" | ||
849 | struct Test; | ||
850 | |||
851 | impl SomeTrait for Test {} | ||
852 | |||
853 | trait SomeTrait {} | ||
854 | |||
855 | fn main() {} | ||
856 | "#]], | ||
857 | Direction::Up, | ||
858 | ); | ||
859 | } | ||
860 | |||
861 | #[test] | ||
617 | fn handles_empty_file() { | 862 | fn handles_empty_file() { |
618 | check(r#"$0$0"#, expect![[r#""#]], Direction::Up); | 863 | check(r#"$0$0"#, expect![[r#""#]], Direction::Up); |
619 | } | 864 | } |
diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs index 22b0d6ecb..99365c8a7 100644 --- a/crates/ide/src/parent_module.rs +++ b/crates/ide/src/parent_module.rs | |||
@@ -18,6 +18,8 @@ use crate::NavigationTarget; | |||
18 | // | 18 | // |
19 | // | VS Code | **Rust Analyzer: Locate parent module** | 19 | // | VS Code | **Rust Analyzer: Locate parent module** |
20 | // |=== | 20 | // |=== |
21 | // | ||
22 | // image::https://user-images.githubusercontent.com/48062697/113065580-04c21800-91b1-11eb-9a32-00086161c0bd.gif[] | ||
21 | 23 | ||
22 | /// This returns `Vec` because a module may be included from several places. | 24 | /// This returns `Vec` because a module may be included from several places. |
23 | pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> { | 25 | pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> { |
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 95ed8a045..11ca7ec6b 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -48,6 +48,8 @@ pub struct Declaration { | |||
48 | // | 48 | // |
49 | // | VS Code | kbd:[Shift+Alt+F12] | 49 | // | VS Code | kbd:[Shift+Alt+F12] |
50 | // |=== | 50 | // |=== |
51 | // | ||
52 | // image::https://user-images.githubusercontent.com/48062697/113020670-b7c34f00-917a-11eb-8003-370ac5f2b3cb.gif[] | ||
51 | pub(crate) fn find_all_refs( | 53 | pub(crate) fn find_all_refs( |
52 | sema: &Semantics<RootDatabase>, | 54 | sema: &Semantics<RootDatabase>, |
53 | position: FilePosition, | 55 | position: FilePosition, |
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs index 26d6dc9c9..2408a0181 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/references/rename.rs | |||
@@ -70,6 +70,8 @@ pub(crate) fn prepare_rename( | |||
70 | // | 70 | // |
71 | // | VS Code | kbd:[F2] | 71 | // | VS Code | kbd:[F2] |
72 | // |=== | 72 | // |=== |
73 | // | ||
74 | // image::https://user-images.githubusercontent.com/48062697/113065582-055aae80-91b1-11eb-8ade-2b58e6d81883.gif[] | ||
73 | pub(crate) fn rename( | 75 | pub(crate) fn rename( |
74 | db: &RootDatabase, | 76 | db: &RootDatabase, |
75 | position: FilePosition, | 77 | position: FilePosition, |
@@ -307,7 +309,7 @@ fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameRe | |||
307 | hir::AssocItemContainer::Impl(impl_) => impl_, | 309 | hir::AssocItemContainer::Impl(impl_) => impl_, |
308 | }; | 310 | }; |
309 | let first_param_ty = first_param.ty(); | 311 | let first_param_ty = first_param.ty(); |
310 | let impl_ty = impl_.target_ty(sema.db); | 312 | let impl_ty = impl_.self_ty(sema.db); |
311 | let (ty, self_param) = if impl_ty.remove_ref().is_some() { | 313 | let (ty, self_param) = if impl_ty.remove_ref().is_some() { |
312 | // if the impl is a ref to the type we can just match the `&T` with self directly | 314 | // if the impl is a ref to the type we can just match the `&T` with self directly |
313 | (first_param_ty.clone(), "self") | 315 | (first_param_ty.clone(), "self") |
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 7e4c5a078..3eb9e27ee 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -98,6 +98,7 @@ impl Runnable { | |||
98 | // | 98 | // |
99 | // | VS Code | **Rust Analyzer: Run** | 99 | // | VS Code | **Rust Analyzer: Run** |
100 | // |=== | 100 | // |=== |
101 | // image::https://user-images.githubusercontent.com/48062697/113065583-055aae80-91b1-11eb-958f-d67efcaf6a2f.gif[] | ||
101 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { | 102 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { |
102 | let sema = Semantics::new(db); | 103 | let sema = Semantics::new(db); |
103 | 104 | ||
@@ -298,7 +299,7 @@ fn module_def_doctest(sema: &Semantics<RootDatabase>, def: hir::ModuleDef) -> Op | |||
298 | // FIXME: this also looks very wrong | 299 | // FIXME: this also looks very wrong |
299 | if let Some(assoc_def) = assoc_def { | 300 | if let Some(assoc_def) = assoc_def { |
300 | if let hir::AssocItemContainer::Impl(imp) = assoc_def.container(sema.db) { | 301 | if let hir::AssocItemContainer::Impl(imp) = assoc_def.container(sema.db) { |
301 | let ty = imp.target_ty(sema.db); | 302 | let ty = imp.self_ty(sema.db); |
302 | if let Some(adt) = ty.as_adt() { | 303 | if let Some(adt) = ty.as_adt() { |
303 | let name = adt.name(sema.db); | 304 | let name = adt.name(sema.db); |
304 | let idx = path.rfind(':').map_or(0, |idx| idx + 1); | 305 | let idx = path.rfind(':').map_or(0, |idx| idx + 1); |
diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs index 137c38c0d..49fde1945 100644 --- a/crates/ide/src/status.rs +++ b/crates/ide/src/status.rs | |||
@@ -31,6 +31,7 @@ fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { | |||
31 | // | 31 | // |
32 | // | VS Code | **Rust Analyzer: Status** | 32 | // | VS Code | **Rust Analyzer: Status** |
33 | // |=== | 33 | // |=== |
34 | // image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[] | ||
34 | pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String { | 35 | pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String { |
35 | let mut buf = String::new(); | 36 | let mut buf = String::new(); |
36 | format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::<FilesStats>()); | 37 | format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::<FilesStats>()); |
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index e25b698e0..67a10766b 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -5,7 +5,7 @@ mod injector; | |||
5 | 5 | ||
6 | mod highlight; | 6 | mod highlight; |
7 | mod format; | 7 | mod format; |
8 | mod macro_rules; | 8 | mod macro_; |
9 | mod inject; | 9 | mod inject; |
10 | 10 | ||
11 | mod html; | 11 | mod html; |
@@ -24,8 +24,8 @@ use syntax::{ | |||
24 | 24 | ||
25 | use crate::{ | 25 | use crate::{ |
26 | syntax_highlighting::{ | 26 | syntax_highlighting::{ |
27 | format::highlight_format_string, highlights::Highlights, | 27 | format::highlight_format_string, highlights::Highlights, macro_::MacroHighlighter, |
28 | macro_rules::MacroRulesHighlighter, tags::Highlight, | 28 | tags::Highlight, |
29 | }, | 29 | }, |
30 | FileId, HlMod, HlTag, | 30 | FileId, HlMod, HlTag, |
31 | }; | 31 | }; |
@@ -93,8 +93,8 @@ fn traverse( | |||
93 | let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default(); | 93 | let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default(); |
94 | 94 | ||
95 | let mut current_macro_call: Option<ast::MacroCall> = None; | 95 | let mut current_macro_call: Option<ast::MacroCall> = None; |
96 | let mut current_macro_rules: Option<ast::MacroRules> = None; | 96 | let mut current_macro: Option<ast::Macro> = None; |
97 | let mut macro_rules_highlighter = MacroRulesHighlighter::default(); | 97 | let mut macro_highlighter = MacroHighlighter::default(); |
98 | let mut inside_attribute = false; | 98 | let mut inside_attribute = false; |
99 | 99 | ||
100 | // Walk all nodes, keeping track of whether we are inside a macro or not. | 100 | // Walk all nodes, keeping track of whether we are inside a macro or not. |
@@ -129,16 +129,16 @@ fn traverse( | |||
129 | _ => (), | 129 | _ => (), |
130 | } | 130 | } |
131 | 131 | ||
132 | match event.clone().map(|it| it.into_node().and_then(ast::MacroRules::cast)) { | 132 | match event.clone().map(|it| it.into_node().and_then(ast::Macro::cast)) { |
133 | WalkEvent::Enter(Some(mac)) => { | 133 | WalkEvent::Enter(Some(mac)) => { |
134 | macro_rules_highlighter.init(); | 134 | macro_highlighter.init(); |
135 | current_macro_rules = Some(mac); | 135 | current_macro = Some(mac); |
136 | continue; | 136 | continue; |
137 | } | 137 | } |
138 | WalkEvent::Leave(Some(mac)) => { | 138 | WalkEvent::Leave(Some(mac)) => { |
139 | assert_eq!(current_macro_rules, Some(mac)); | 139 | assert_eq!(current_macro, Some(mac)); |
140 | current_macro_rules = None; | 140 | current_macro = None; |
141 | macro_rules_highlighter = MacroRulesHighlighter::default(); | 141 | macro_highlighter = MacroHighlighter::default(); |
142 | } | 142 | } |
143 | _ => (), | 143 | _ => (), |
144 | } | 144 | } |
@@ -164,9 +164,9 @@ fn traverse( | |||
164 | 164 | ||
165 | let range = element.text_range(); | 165 | let range = element.text_range(); |
166 | 166 | ||
167 | if current_macro_rules.is_some() { | 167 | if current_macro.is_some() { |
168 | if let Some(tok) = element.as_token() { | 168 | if let Some(tok) = element.as_token() { |
169 | macro_rules_highlighter.advance(tok); | 169 | macro_highlighter.advance(tok); |
170 | } | 170 | } |
171 | } | 171 | } |
172 | 172 | ||
@@ -200,7 +200,7 @@ fn traverse( | |||
200 | } | 200 | } |
201 | } | 201 | } |
202 | 202 | ||
203 | if let Some(_) = macro_rules_highlighter.highlight(element_to_highlight.clone()) { | 203 | if let Some(_) = macro_highlighter.highlight(element_to_highlight.clone()) { |
204 | continue; | 204 | continue; |
205 | } | 205 | } |
206 | 206 | ||
diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs index e503abc93..5bbadb0f4 100644 --- a/crates/ide/src/syntax_highlighting/format.rs +++ b/crates/ide/src/syntax_highlighting/format.rs | |||
@@ -31,7 +31,7 @@ fn is_format_string(string: &ast::String) -> Option<()> { | |||
31 | let parent = string.syntax().parent()?; | 31 | let parent = string.syntax().parent()?; |
32 | 32 | ||
33 | let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?; | 33 | let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?; |
34 | if !matches!(name.text(), "format_args" | "format_args_nl") { | 34 | if !matches!(name.text().as_str(), "format_args" | "format_args_nl") { |
35 | return None; | 35 | return None; |
36 | } | 36 | } |
37 | 37 | ||
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index b0cfdd8b7..5ccb84714 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! Computes color for a single element. | 1 | //! Computes color for a single element. |
2 | 2 | ||
3 | use hir::{AsAssocItem, Semantics, VariantDef}; | 3 | use hir::{AsAssocItem, AssocItemContainer, Semantics, VariantDef}; |
4 | use ide_db::{ | 4 | use ide_db::{ |
5 | defs::{Definition, NameClass, NameRefClass}, | 5 | defs::{Definition, NameClass, NameRefClass}, |
6 | RootDatabase, SymbolKind, | 6 | RootDatabase, SymbolKind, |
@@ -275,12 +275,24 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
275 | hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module), | 275 | hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module), |
276 | hir::ModuleDef::Function(func) => { | 276 | hir::ModuleDef::Function(func) => { |
277 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function)); | 277 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function)); |
278 | if func.as_assoc_item(db).is_some() { | 278 | if let Some(item) = func.as_assoc_item(db) { |
279 | h |= HlMod::Associated; | 279 | h |= HlMod::Associated; |
280 | if func.self_param(db).is_none() { | 280 | if func.self_param(db).is_none() { |
281 | h |= HlMod::Static | 281 | h |= HlMod::Static |
282 | } | 282 | } |
283 | |||
284 | match item.container(db) { | ||
285 | AssocItemContainer::Impl(i) => { | ||
286 | if i.trait_(db).is_some() { | ||
287 | h |= HlMod::Trait; | ||
288 | } | ||
289 | } | ||
290 | AssocItemContainer::Trait(_t) => { | ||
291 | h |= HlMod::Trait; | ||
292 | } | ||
293 | } | ||
283 | } | 294 | } |
295 | |||
284 | if func.is_unsafe(db) { | 296 | if func.is_unsafe(db) { |
285 | h |= HlMod::Unsafe; | 297 | h |= HlMod::Unsafe; |
286 | } | 298 | } |
@@ -292,9 +304,20 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
292 | hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant), | 304 | hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant), |
293 | hir::ModuleDef::Const(konst) => { | 305 | hir::ModuleDef::Const(konst) => { |
294 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const)); | 306 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const)); |
295 | if konst.as_assoc_item(db).is_some() { | 307 | if let Some(item) = konst.as_assoc_item(db) { |
296 | h |= HlMod::Associated | 308 | h |= HlMod::Associated; |
309 | match item.container(db) { | ||
310 | AssocItemContainer::Impl(i) => { | ||
311 | if i.trait_(db).is_some() { | ||
312 | h |= HlMod::Trait; | ||
313 | } | ||
314 | } | ||
315 | AssocItemContainer::Trait(_t) => { | ||
316 | h |= HlMod::Trait; | ||
317 | } | ||
318 | } | ||
297 | } | 319 | } |
320 | |||
298 | return h; | 321 | return h; |
299 | } | 322 | } |
300 | hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait), | 323 | hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait), |
@@ -362,6 +385,10 @@ fn highlight_method_call( | |||
362 | if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { | 385 | if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { |
363 | h |= HlMod::Unsafe; | 386 | h |= HlMod::Unsafe; |
364 | } | 387 | } |
388 | if func.as_assoc_item(sema.db).and_then(|it| it.containing_trait(sema.db)).is_some() { | ||
389 | h |= HlMod::Trait | ||
390 | } | ||
391 | |||
365 | if let Some(self_param) = func.self_param(sema.db) { | 392 | if let Some(self_param) = func.self_param(sema.db) { |
366 | match self_param.access(sema.db) { | 393 | match self_param.access(sema.db) { |
367 | hir::Access::Shared => (), | 394 | hir::Access::Shared => (), |
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs index 38bf49348..b62d43256 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs | |||
@@ -11,7 +11,8 @@ use syntax::{ | |||
11 | }; | 11 | }; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | doc_links::extract_definitions_from_markdown, Analysis, HlMod, HlRange, HlTag, RootDatabase, | 14 | doc_links::{extract_definitions_from_markdown, resolve_doc_path_for_def}, |
15 | Analysis, HlMod, HlRange, HlTag, RootDatabase, | ||
15 | }; | 16 | }; |
16 | 17 | ||
17 | use super::{highlights::Highlights, injector::Injector}; | 18 | use super::{highlights::Highlights, injector::Injector}; |
@@ -109,8 +110,7 @@ fn doc_attributes<'node>( | |||
109 | ast::Impl(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))), | 110 | ast::Impl(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))), |
110 | ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), | 111 | ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), |
111 | ast::TupleField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), | 112 | ast::TupleField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), |
112 | ast::MacroRules(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))), | 113 | ast::Macro(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))), |
113 | // ast::MacroDef(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
114 | // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | 114 | // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), |
115 | _ => return None | 115 | _ => return None |
116 | } | 116 | } |
@@ -191,7 +191,7 @@ pub(super) fn doc_comment( | |||
191 | extract_definitions_from_markdown(line) | 191 | extract_definitions_from_markdown(line) |
192 | .into_iter() | 192 | .into_iter() |
193 | .filter_map(|(range, link, ns)| { | 193 | .filter_map(|(range, link, ns)| { |
194 | Some(range).zip(validate_intra_doc_link(sema.db, &def, &link, ns)) | 194 | Some(range).zip(resolve_doc_path_for_def(sema.db, def, &link, ns)) |
195 | }) | 195 | }) |
196 | .map(|(Range { start, end }, def)| { | 196 | .map(|(Range { start, end }, def)| { |
197 | ( | 197 | ( |
@@ -284,33 +284,6 @@ fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option<ast::Stri | |||
284 | } | 284 | } |
285 | } | 285 | } |
286 | 286 | ||
287 | fn validate_intra_doc_link( | ||
288 | db: &RootDatabase, | ||
289 | def: &Definition, | ||
290 | link: &str, | ||
291 | ns: Option<hir::Namespace>, | ||
292 | ) -> Option<hir::ModuleDef> { | ||
293 | match def { | ||
294 | Definition::ModuleDef(def) => match def { | ||
295 | hir::ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns), | ||
296 | hir::ModuleDef::Function(it) => it.resolve_doc_path(db, &link, ns), | ||
297 | hir::ModuleDef::Adt(it) => it.resolve_doc_path(db, &link, ns), | ||
298 | hir::ModuleDef::Variant(it) => it.resolve_doc_path(db, &link, ns), | ||
299 | hir::ModuleDef::Const(it) => it.resolve_doc_path(db, &link, ns), | ||
300 | hir::ModuleDef::Static(it) => it.resolve_doc_path(db, &link, ns), | ||
301 | hir::ModuleDef::Trait(it) => it.resolve_doc_path(db, &link, ns), | ||
302 | hir::ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, &link, ns), | ||
303 | hir::ModuleDef::BuiltinType(_) => None, | ||
304 | }, | ||
305 | Definition::Macro(it) => it.resolve_doc_path(db, &link, ns), | ||
306 | Definition::Field(it) => it.resolve_doc_path(db, &link, ns), | ||
307 | Definition::SelfType(_) | ||
308 | | Definition::Local(_) | ||
309 | | Definition::GenericParam(_) | ||
310 | | Definition::Label(_) => None, | ||
311 | } | ||
312 | } | ||
313 | |||
314 | fn module_def_to_hl_tag(def: hir::ModuleDef) -> HlTag { | 287 | fn module_def_to_hl_tag(def: hir::ModuleDef) -> HlTag { |
315 | let symbol = match def { | 288 | let symbol = match def { |
316 | hir::ModuleDef::Module(_) => SymbolKind::Module, | 289 | hir::ModuleDef::Module(_) => SymbolKind::Module, |
diff --git a/crates/ide/src/syntax_highlighting/macro_rules.rs b/crates/ide/src/syntax_highlighting/macro_.rs index 44620e912..819704294 100644 --- a/crates/ide/src/syntax_highlighting/macro_rules.rs +++ b/crates/ide/src/syntax_highlighting/macro_.rs | |||
@@ -4,18 +4,18 @@ use syntax::{SyntaxElement, SyntaxKind, SyntaxToken, TextRange, T}; | |||
4 | use crate::{HlRange, HlTag}; | 4 | use crate::{HlRange, HlTag}; |
5 | 5 | ||
6 | #[derive(Default)] | 6 | #[derive(Default)] |
7 | pub(super) struct MacroRulesHighlighter { | 7 | pub(super) struct MacroHighlighter { |
8 | state: Option<MacroMatcherParseState>, | 8 | state: Option<MacroMatcherParseState>, |
9 | } | 9 | } |
10 | 10 | ||
11 | impl MacroRulesHighlighter { | 11 | impl MacroHighlighter { |
12 | pub(super) fn init(&mut self) { | 12 | pub(super) fn init(&mut self) { |
13 | self.state = Some(MacroMatcherParseState::default()); | 13 | self.state = Some(MacroMatcherParseState::default()); |
14 | } | 14 | } |
15 | 15 | ||
16 | pub(super) fn advance(&mut self, token: &SyntaxToken) { | 16 | pub(super) fn advance(&mut self, token: &SyntaxToken) { |
17 | if let Some(state) = self.state.as_mut() { | 17 | if let Some(state) = self.state.as_mut() { |
18 | update_macro_rules_state(state, token); | 18 | update_macro_state(state, token); |
19 | } | 19 | } |
20 | } | 20 | } |
21 | 21 | ||
@@ -74,9 +74,9 @@ impl RuleState { | |||
74 | } | 74 | } |
75 | } | 75 | } |
76 | 76 | ||
77 | fn update_macro_rules_state(state: &mut MacroMatcherParseState, tok: &SyntaxToken) { | 77 | fn update_macro_state(state: &mut MacroMatcherParseState, tok: &SyntaxToken) { |
78 | if !state.in_invoc_body { | 78 | if !state.in_invoc_body { |
79 | if tok.kind() == T!['{'] { | 79 | if tok.kind() == T!['{'] || tok.kind() == T!['('] { |
80 | state.in_invoc_body = true; | 80 | state.in_invoc_body = true; |
81 | } | 81 | } |
82 | return; | 82 | return; |
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index 93db79b89..1cec991aa 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs | |||
@@ -58,6 +58,8 @@ pub enum HlMod { | |||
58 | Associated, | 58 | Associated, |
59 | /// Used for intra doc links in doc injection. | 59 | /// Used for intra doc links in doc injection. |
60 | IntraDocLink, | 60 | IntraDocLink, |
61 | /// Used for items in traits and trait impls. | ||
62 | Trait, | ||
61 | 63 | ||
62 | /// Keep this last! | 64 | /// Keep this last! |
63 | Unsafe, | 65 | Unsafe, |
@@ -158,6 +160,7 @@ impl HlMod { | |||
158 | HlMod::Callable, | 160 | HlMod::Callable, |
159 | HlMod::Static, | 161 | HlMod::Static, |
160 | HlMod::Associated, | 162 | HlMod::Associated, |
163 | HlMod::Trait, | ||
161 | HlMod::Unsafe, | 164 | HlMod::Unsafe, |
162 | ]; | 165 | ]; |
163 | 166 | ||
@@ -174,6 +177,7 @@ impl HlMod { | |||
174 | HlMod::IntraDocLink => "intra_doc_link", | 177 | HlMod::IntraDocLink => "intra_doc_link", |
175 | HlMod::Mutable => "mutable", | 178 | HlMod::Mutable => "mutable", |
176 | HlMod::Static => "static", | 179 | HlMod::Static => "static", |
180 | HlMod::Trait => "trait", | ||
177 | HlMod::Unsafe => "unsafe", | 181 | HlMod::Unsafe => "unsafe", |
178 | } | 182 | } |
179 | } | 183 | } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html index 4635ea927..8cde3906c 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html | |||
@@ -47,12 +47,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
47 | <span class="brace">}</span> | 47 | <span class="brace">}</span> |
48 | 48 | ||
49 | <span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span> | 49 | <span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span> |
50 | <span class="keyword">fn</span> <span class="function declaration static associated">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | 50 | <span class="keyword">fn</span> <span class="function declaration static associated trait">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
51 | <span class="keyword">fn</span> <span class="function declaration associated">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | 51 | <span class="keyword">fn</span> <span class="function declaration associated trait">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
52 | <span class="brace">}</span> | 52 | <span class="brace">}</span> |
53 | 53 | ||
54 | <span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span> | 54 | <span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span> |
55 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | 55 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated trait">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
56 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | 56 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated trait">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
57 | <span class="brace">}</span> | 57 | <span class="brace">}</span> |
58 | </code></pre> \ No newline at end of file | 58 | </code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html index 9215ddd9e..7c6694a27 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html | |||
@@ -42,7 +42,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
42 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> | 42 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
43 | <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span> | 43 | <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span> |
44 | <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="brace">{</span> | 44 | <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="brace">{</span> |
45 | <span class="keyword">fn</span> <span class="function declaration static associated">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> | 45 | <span class="keyword">fn</span> <span class="function declaration static associated trait">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
46 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span> | 46 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
47 | <span class="brace">}</span> | 47 | <span class="brace">}</span> |
48 | <span class="brace">}</span><span class="string_literal">"#</span> | 48 | <span class="brace">}</span><span class="string_literal">"#</span> |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html index 6a6555208..72910421d 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html | |||
@@ -62,11 +62,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
62 | <span class="brace">}</span> | 62 | <span class="brace">}</span> |
63 | 63 | ||
64 | <span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span> | 64 | <span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span> |
65 | <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span> | 65 | <span class="keyword">fn</span> <span class="function declaration associated trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
66 | <span class="brace">}</span> | 66 | <span class="brace">}</span> |
67 | 67 | ||
68 | <span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span> | 68 | <span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span> |
69 | <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | 69 | <span class="keyword">fn</span> <span class="function declaration associated trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
70 | <span class="brace">}</span> | 70 | <span class="brace">}</span> |
71 | 71 | ||
72 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> | 72 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
@@ -96,6 +96,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
96 | <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span> | 96 | <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span> |
97 | 97 | ||
98 | <span class="comment">// unsafe auto ref of packed field</span> | 98 | <span class="comment">// unsafe auto ref of packed field</span> |
99 | <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> | 99 | <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated trait unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
100 | <span class="brace">}</span> | 100 | <span class="brace">}</span> |
101 | <span class="brace">}</span></code></pre> \ No newline at end of file | 101 | <span class="brace">}</span></code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index 8b2dd3b70..973173254 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html | |||
@@ -41,7 +41,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
41 | <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span> | 41 | <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span> |
42 | 42 | ||
43 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> | 43 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> |
44 | <span class="keyword">macro</span> <span class="unresolved_reference declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span> | 44 | <span class="keyword">macro</span> <span class="macro declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span> |
45 | 45 | ||
46 | <span class="comment">// Needed for function consuming vs normal</span> | 46 | <span class="comment">// Needed for function consuming vs normal</span> |
47 | <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="brace">{</span> | 47 | <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="brace">{</span> |
@@ -67,11 +67,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
67 | <span class="brace">}</span> | 67 | <span class="brace">}</span> |
68 | 68 | ||
69 | <span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span> | 69 | <span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span> |
70 | <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span><span class="semicolon">;</span> | 70 | <span class="keyword">fn</span> <span class="function declaration associated trait">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span><span class="semicolon">;</span> |
71 | <span class="brace">}</span> | 71 | <span class="brace">}</span> |
72 | 72 | ||
73 | <span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span> | 73 | <span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span> |
74 | <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="brace">{</span> | 74 | <span class="keyword">fn</span> <span class="function declaration associated trait">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="brace">{</span> |
75 | <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> | 75 | <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> |
76 | <span class="brace">}</span> | 76 | <span class="brace">}</span> |
77 | <span class="brace">}</span> | 77 | <span class="brace">}</span> |
@@ -158,6 +158,16 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
158 | <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="colon">:</span>ty<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="parenthesis">)</span> | 158 | <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="colon">:</span>ty<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="parenthesis">)</span> |
159 | <span class="brace">}</span> | 159 | <span class="brace">}</span> |
160 | 160 | ||
161 | <span class="keyword">macro</span> <span class="macro declaration">with_args</span><span class="parenthesis">(</span><span class="punctuation">$</span>i<span class="colon">:</span>ident<span class="parenthesis">)</span> <span class="brace">{</span> | ||
162 | <span class="punctuation">$</span>i | ||
163 | <span class="brace">}</span> | ||
164 | |||
165 | <span class="keyword">macro</span> <span class="macro declaration">without_args</span> <span class="brace">{</span> | ||
166 | <span class="parenthesis">(</span><span class="punctuation">$</span>i<span class="colon">:</span>ident<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> | ||
167 | <span class="punctuation">$</span>i | ||
168 | <span class="brace">}</span> | ||
169 | <span class="brace">}</span> | ||
170 | |||
161 | <span class="comment">// comment</span> | 171 | <span class="comment">// comment</span> |
162 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> | 172 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
163 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello, {}!"</span><span class="comma">,</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span> | 173 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello, {}!"</span><span class="comma">,</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 7b2922b0d..369ae0972 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -129,6 +129,16 @@ macro_rules! keyword_frag { | |||
129 | ($type:ty) => ($type) | 129 | ($type:ty) => ($type) |
130 | } | 130 | } |
131 | 131 | ||
132 | macro with_args($i:ident) { | ||
133 | $i | ||
134 | } | ||
135 | |||
136 | macro without_args { | ||
137 | ($i:ident) => { | ||
138 | $i | ||
139 | } | ||
140 | } | ||
141 | |||
132 | // comment | 142 | // comment |
133 | fn main() { | 143 | fn main() { |
134 | println!("Hello, {}!", 92); | 144 | println!("Hello, {}!", 92); |
diff --git a/crates/ide/src/syntax_tree.rs b/crates/ide/src/syntax_tree.rs index 8979de528..633878d1c 100644 --- a/crates/ide/src/syntax_tree.rs +++ b/crates/ide/src/syntax_tree.rs | |||
@@ -14,6 +14,7 @@ use syntax::{ | |||
14 | // | 14 | // |
15 | // | VS Code | **Rust Analyzer: Show Syntax Tree** | 15 | // | VS Code | **Rust Analyzer: Show Syntax Tree** |
16 | // |=== | 16 | // |=== |
17 | // image::https://user-images.githubusercontent.com/48062697/113065586-068bdb80-91b1-11eb-9507-fee67f9f45a0.gif[] | ||
17 | pub(crate) fn syntax_tree( | 18 | pub(crate) fn syntax_tree( |
18 | db: &RootDatabase, | 19 | db: &RootDatabase, |
19 | file_id: FileId, | 20 | file_id: FileId, |
diff --git a/crates/ide/src/typing/on_enter.rs b/crates/ide/src/typing/on_enter.rs index 978c479de..9144681bf 100644 --- a/crates/ide/src/typing/on_enter.rs +++ b/crates/ide/src/typing/on_enter.rs | |||
@@ -32,6 +32,8 @@ use text_edit::TextEdit; | |||
32 | // "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust" | 32 | // "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust" |
33 | // } | 33 | // } |
34 | // ---- | 34 | // ---- |
35 | // | ||
36 | // image::https://user-images.githubusercontent.com/48062697/113065578-04c21800-91b1-11eb-82b8-22b8c481e645.gif[] | ||
35 | pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> { | 37 | pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> { |
36 | let parse = db.parse(position.file_id); | 38 | let parse = db.parse(position.file_id); |
37 | let file = parse.tree(); | 39 | let file = parse.tree(); |
diff --git a/crates/ide/src/view_hir.rs b/crates/ide/src/view_hir.rs index f8f3fae3d..7312afe53 100644 --- a/crates/ide/src/view_hir.rs +++ b/crates/ide/src/view_hir.rs | |||
@@ -10,6 +10,7 @@ use syntax::{algo::find_node_at_offset, ast, AstNode}; | |||
10 | // | 10 | // |
11 | // | VS Code | **Rust Analyzer: View Hir** | 11 | // | VS Code | **Rust Analyzer: View Hir** |
12 | // |=== | 12 | // |=== |
13 | // image::https://user-images.githubusercontent.com/48062697/113065588-068bdb80-91b1-11eb-9a78-0b4ef1e972fb.gif[] | ||
13 | pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String { | 14 | pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String { |
14 | body_hir(db, position).unwrap_or_else(|| "Not inside a function body".to_string()) | 15 | body_hir(db, position).unwrap_or_else(|| "Not inside a function body".to_string()) |
15 | } | 16 | } |
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs index 7019039b9..5ccd7f7a2 100644 --- a/crates/ide_assists/src/handlers/auto_import.rs +++ b/crates/ide_assists/src/handlers/auto_import.rs | |||
@@ -61,6 +61,8 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; | |||
61 | // - `plain`: This setting does not impose any restrictions in imports. | 61 | // - `plain`: This setting does not impose any restrictions in imports. |
62 | // | 62 | // |
63 | // In `VS Code` the configuration for this is `rust-analyzer.assist.importPrefix`. | 63 | // In `VS Code` the configuration for this is `rust-analyzer.assist.importPrefix`. |
64 | // | ||
65 | // image::https://user-images.githubusercontent.com/48062697/113020673-b85be580-917a-11eb-9022-59585f35d4f8.gif[] | ||
64 | 66 | ||
65 | // Assist: auto_import | 67 | // Assist: auto_import |
66 | // | 68 | // |
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs index 596c536a7..a8d6355bd 100644 --- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -195,7 +195,7 @@ fn extract_struct_def( | |||
195 | 195 | ||
196 | fn update_variant(rewriter: &mut SyntaxRewriter, variant: &ast::Variant) -> Option<()> { | 196 | fn update_variant(rewriter: &mut SyntaxRewriter, variant: &ast::Variant) -> Option<()> { |
197 | let name = variant.name()?; | 197 | let name = variant.name()?; |
198 | let tuple_field = make::tuple_field(None, make::ty(name.text())); | 198 | let tuple_field = make::tuple_field(None, make::ty(&name.text())); |
199 | let replacement = make::variant( | 199 | let replacement = make::variant( |
200 | name, | 200 | name, |
201 | Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))), | 201 | Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))), |
diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs index 81c54ba3e..dc14552d6 100644 --- a/crates/ide_assists/src/handlers/generate_default_from_new.rs +++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs | |||
@@ -92,7 +92,7 @@ fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool { | |||
92 | None => return false, | 92 | None => return false, |
93 | }; | 93 | }; |
94 | 94 | ||
95 | let ty = impl_def.target_ty(db); | 95 | let ty = impl_def.self_ty(db); |
96 | let krate = impl_def.module(db).krate(); | 96 | let krate = impl_def.module(db).krate(); |
97 | let default = FamousDefs(&ctx.sema, Some(krate)).core_default_Default(); | 97 | let default = FamousDefs(&ctx.sema, Some(krate)).core_default_Default(); |
98 | let default_trait = match default { | 98 | let default_trait = match default { |
diff --git a/crates/ide_assists/src/handlers/generate_enum_is_method.rs b/crates/ide_assists/src/handlers/generate_enum_is_method.rs index 7e181a480..a9f71a703 100644 --- a/crates/ide_assists/src/handlers/generate_enum_is_method.rs +++ b/crates/ide_assists/src/handlers/generate_enum_is_method.rs | |||
@@ -44,7 +44,7 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext) -> | |||
44 | }; | 44 | }; |
45 | 45 | ||
46 | let enum_lowercase_name = to_lower_snake_case(&parent_enum.name()?.to_string()); | 46 | let enum_lowercase_name = to_lower_snake_case(&parent_enum.name()?.to_string()); |
47 | let fn_name = format!("is_{}", &to_lower_snake_case(variant_name.text())); | 47 | let fn_name = format!("is_{}", &to_lower_snake_case(&variant_name.text())); |
48 | 48 | ||
49 | // Return early if we've found an existing new fn | 49 | // Return early if we've found an existing new fn |
50 | let impl_def = find_struct_impl(&ctx, &parent_enum, &fn_name)?; | 50 | let impl_def = find_struct_impl(&ctx, &parent_enum, &fn_name)?; |
diff --git a/crates/ide_assists/src/handlers/generate_enum_projection_method.rs b/crates/ide_assists/src/handlers/generate_enum_projection_method.rs index 871bcab50..e2f572ba3 100644 --- a/crates/ide_assists/src/handlers/generate_enum_projection_method.rs +++ b/crates/ide_assists/src/handlers/generate_enum_projection_method.rs | |||
@@ -132,7 +132,8 @@ fn generate_enum_projection_method( | |||
132 | ast::StructKind::Unit => return None, | 132 | ast::StructKind::Unit => return None, |
133 | }; | 133 | }; |
134 | 134 | ||
135 | let fn_name = format!("{}_{}", props.fn_name_prefix, &to_lower_snake_case(variant_name.text())); | 135 | let fn_name = |
136 | format!("{}_{}", props.fn_name_prefix, &to_lower_snake_case(&variant_name.text())); | ||
136 | 137 | ||
137 | // Return early if we've found an existing new fn | 138 | // Return early if we've found an existing new fn |
138 | let impl_def = find_struct_impl(&ctx, &parent_enum, &fn_name)?; | 139 | let impl_def = find_struct_impl(&ctx, &parent_enum, &fn_name)?; |
diff --git a/crates/ide_assists/src/handlers/generate_impl.rs b/crates/ide_assists/src/handlers/generate_impl.rs index a8e3c4fc2..fd2e250bc 100644 --- a/crates/ide_assists/src/handlers/generate_impl.rs +++ b/crates/ide_assists/src/handlers/generate_impl.rs | |||
@@ -72,6 +72,17 @@ mod tests { | |||
72 | check_assist( | 72 | check_assist( |
73 | generate_impl, | 73 | generate_impl, |
74 | r#" | 74 | r#" |
75 | struct MyOwnArray<T, const S: usize> {}$0"#, | ||
76 | r#" | ||
77 | struct MyOwnArray<T, const S: usize> {} | ||
78 | |||
79 | impl<T, const S: usize> MyOwnArray<T, S> { | ||
80 | $0 | ||
81 | }"#, | ||
82 | ); | ||
83 | check_assist( | ||
84 | generate_impl, | ||
85 | r#" | ||
75 | #[cfg(feature = "foo")] | 86 | #[cfg(feature = "foo")] |
76 | struct Foo<'a, T: Foo<'a>> {$0}"#, | 87 | struct Foo<'a, T: Foo<'a>> {$0}"#, |
77 | r#" | 88 | r#" |
@@ -114,11 +125,11 @@ mod tests { | |||
114 | check_assist( | 125 | check_assist( |
115 | generate_impl, | 126 | generate_impl, |
116 | r#" | 127 | r#" |
117 | struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String> {}$0"#, | 128 | struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}$0"#, |
118 | r#" | 129 | r#" |
119 | struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String> {} | 130 | struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {} |
120 | 131 | ||
121 | impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b> Defaulted<'a, 'b, T> { | 132 | impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> Defaulted<'a, 'b, T, S> { |
122 | $0 | 133 | $0 |
123 | }"#, | 134 | }"#, |
124 | ); | 135 | ); |
diff --git a/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs index b8834d283..910010a04 100644 --- a/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs +++ b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs | |||
@@ -91,7 +91,7 @@ fn get_impl_method( | |||
91 | 91 | ||
92 | let scope = ctx.sema.scope(impl_.syntax()); | 92 | let scope = ctx.sema.scope(impl_.syntax()); |
93 | let krate = impl_def.module(db).krate(); | 93 | let krate = impl_def.module(db).krate(); |
94 | let ty = impl_def.target_ty(db); | 94 | let ty = impl_def.self_ty(db); |
95 | let traits_in_scope = scope.traits_in_scope(); | 95 | let traits_in_scope = scope.traits_in_scope(); |
96 | ty.iterate_method_candidates(db, krate, &traits_in_scope, Some(fn_name), |_, func| Some(func)) | 96 | ty.iterate_method_candidates(db, krate, &traits_in_scope, Some(fn_name), |_, func| Some(func)) |
97 | } | 97 | } |
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 4f0ef52ca..f872d20c8 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 | |||
@@ -165,7 +165,7 @@ fn impl_def_from_trait( | |||
165 | } | 165 | } |
166 | let impl_def = make::impl_trait( | 166 | let impl_def = make::impl_trait( |
167 | trait_path.clone(), | 167 | trait_path.clone(), |
168 | make::path_unqualified(make::path_segment(make::name_ref(annotated_name.text()))), | 168 | make::path_unqualified(make::path_segment(make::name_ref(&annotated_name.text()))), |
169 | ); | 169 | ); |
170 | let (impl_def, first_assoc_item) = | 170 | let (impl_def, first_assoc_item) = |
171 | add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope); | 171 | add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope); |
@@ -178,12 +178,13 @@ fn update_attribute( | |||
178 | trait_name: &ast::NameRef, | 178 | trait_name: &ast::NameRef, |
179 | attr: &ast::Attr, | 179 | attr: &ast::Attr, |
180 | ) { | 180 | ) { |
181 | let trait_name = trait_name.text(); | ||
181 | let new_attr_input = input | 182 | let new_attr_input = input |
182 | .syntax() | 183 | .syntax() |
183 | .descendants_with_tokens() | 184 | .descendants_with_tokens() |
184 | .filter(|t| t.kind() == IDENT) | 185 | .filter(|t| t.kind() == IDENT) |
185 | .filter_map(|t| t.into_token().map(|t| t.text().to_string())) | 186 | .filter_map(|t| t.into_token().map(|t| t.text().to_string())) |
186 | .filter(|t| t != trait_name.text()) | 187 | .filter(|t| t != &trait_name) |
187 | .collect::<Vec<_>>(); | 188 | .collect::<Vec<_>>(); |
188 | let has_more_derives = !new_attr_input.is_empty(); | 189 | let has_more_derives = !new_attr_input.is_empty(); |
189 | 190 | ||
diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs index 62f959082..d67524937 100644 --- a/crates/ide_assists/src/utils.rs +++ b/crates/ide_assists/src/utils.rs | |||
@@ -246,7 +246,7 @@ fn invert_special_case(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Opti | |||
246 | let method = mce.name_ref()?; | 246 | let method = mce.name_ref()?; |
247 | let arg_list = mce.arg_list()?; | 247 | let arg_list = mce.arg_list()?; |
248 | 248 | ||
249 | let method = match method.text() { | 249 | let method = match method.text().as_str() { |
250 | "is_some" => "is_none", | 250 | "is_some" => "is_none", |
251 | "is_none" => "is_some", | 251 | "is_none" => "is_some", |
252 | "is_ok" => "is_err", | 252 | "is_ok" => "is_err", |
@@ -338,11 +338,11 @@ pub(crate) fn find_struct_impl( | |||
338 | // (we currently use the wrong type parameter) | 338 | // (we currently use the wrong type parameter) |
339 | // also we wouldn't want to use e.g. `impl S<u32>` | 339 | // also we wouldn't want to use e.g. `impl S<u32>` |
340 | 340 | ||
341 | let same_ty = match blk.target_ty(db).as_adt() { | 341 | let same_ty = match blk.self_ty(db).as_adt() { |
342 | Some(def) => def == struct_def, | 342 | Some(def) => def == struct_def, |
343 | None => false, | 343 | None => false, |
344 | }; | 344 | }; |
345 | let not_trait_impl = blk.target_trait(db).is_none(); | 345 | let not_trait_impl = blk.trait_(db).is_none(); |
346 | 346 | ||
347 | if !(same_ty && not_trait_impl) { | 347 | if !(same_ty && not_trait_impl) { |
348 | None | 348 | None |
@@ -434,7 +434,8 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str | |||
434 | } | 434 | } |
435 | buf | 435 | buf |
436 | }); | 436 | }); |
437 | let generics = lifetimes.chain(type_params).format(", "); | 437 | let const_params = generic_params.const_params().map(|t| t.syntax().to_string()); |
438 | let generics = lifetimes.chain(type_params).chain(const_params).format(", "); | ||
438 | format_to!(buf, "<{}>", generics); | 439 | format_to!(buf, "<{}>", generics); |
439 | } | 440 | } |
440 | buf.push(' '); | 441 | buf.push(' '); |
@@ -442,7 +443,7 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str | |||
442 | buf.push_str(trait_text); | 443 | buf.push_str(trait_text); |
443 | buf.push_str(" for "); | 444 | buf.push_str(" for "); |
444 | } | 445 | } |
445 | buf.push_str(adt.name().unwrap().text()); | 446 | buf.push_str(&adt.name().unwrap().text()); |
446 | if let Some(generic_params) = generic_params { | 447 | if let Some(generic_params) = generic_params { |
447 | let lifetime_params = generic_params | 448 | let lifetime_params = generic_params |
448 | .lifetime_params() | 449 | .lifetime_params() |
@@ -452,7 +453,11 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str | |||
452 | .type_params() | 453 | .type_params() |
453 | .filter_map(|it| it.name()) | 454 | .filter_map(|it| it.name()) |
454 | .map(|it| SmolStr::from(it.text())); | 455 | .map(|it| SmolStr::from(it.text())); |
455 | format_to!(buf, "<{}>", lifetime_params.chain(type_params).format(", ")) | 456 | let const_params = generic_params |
457 | .const_params() | ||
458 | .filter_map(|it| it.name()) | ||
459 | .map(|it| SmolStr::from(it.text())); | ||
460 | format_to!(buf, "<{}>", lifetime_params.chain(type_params).chain(const_params).format(", ")) | ||
456 | } | 461 | } |
457 | 462 | ||
458 | match adt.where_clause() { | 463 | match adt.where_clause() { |
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index 6d572a836..e2994eed4 100644 --- a/crates/ide_completion/src/completions.rs +++ b/crates/ide_completion/src/completions.rs | |||
@@ -220,7 +220,7 @@ fn complete_enum_variants( | |||
220 | }; | 220 | }; |
221 | 221 | ||
222 | if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { | 222 | if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { |
223 | if impl_.target_ty(ctx.db) == *ty { | 223 | if impl_.self_ty(ctx.db) == *ty { |
224 | for &variant in &variants { | 224 | for &variant in &variants { |
225 | let self_path = hir::ModPath::from_segments( | 225 | let self_path = hir::ModPath::from_segments( |
226 | hir::PathKind::Plain, | 226 | hir::PathKind::Plain, |
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs index b06498e6d..808d7ff7e 100644 --- a/crates/ide_completion/src/completions/pattern.rs +++ b/crates/ide_completion/src/completions/pattern.rs | |||
@@ -40,7 +40,7 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
40 | _ => false, | 40 | _ => false, |
41 | }, | 41 | }, |
42 | hir::ScopeDef::MacroDef(_) => true, | 42 | hir::ScopeDef::MacroDef(_) => true, |
43 | hir::ScopeDef::ImplSelfType(impl_) => match impl_.target_ty(ctx.db).as_adt() { | 43 | hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() { |
44 | Some(hir::Adt::Struct(strukt)) => { | 44 | Some(hir::Adt::Struct(strukt)) => { |
45 | acc.add_struct_pat(ctx, strukt, Some(name.clone())); | 45 | acc.add_struct_pat(ctx, strukt, Some(name.clone())); |
46 | true | 46 | true |
diff --git a/crates/ide_completion/src/completions/postfix/format_like.rs b/crates/ide_completion/src/completions/postfix/format_like.rs index 3f1c6730b..e86ffa8f8 100644 --- a/crates/ide_completion/src/completions/postfix/format_like.rs +++ b/crates/ide_completion/src/completions/postfix/format_like.rs | |||
@@ -13,6 +13,8 @@ | |||
13 | // + `logi` -> `log::info!(...)` | 13 | // + `logi` -> `log::info!(...)` |
14 | // + `logw` -> `log::warn!(...)` | 14 | // + `logw` -> `log::warn!(...)` |
15 | // + `loge` -> `log::error!(...)` | 15 | // + `loge` -> `log::error!(...)` |
16 | // | ||
17 | // image::https://user-images.githubusercontent.com/48062697/113020656-b560f500-917a-11eb-87de-02991f61beb8.gif[] | ||
16 | 18 | ||
17 | use ide_db::helpers::SnippetCap; | 19 | use ide_db::helpers::SnippetCap; |
18 | use syntax::ast::{self, AstToken}; | 20 | use syntax::ast::{self, AstToken}; |
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index 105ff6013..1891eb5b3 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs | |||
@@ -117,7 +117,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
117 | if let Some(krate) = ctx.krate { | 117 | if let Some(krate) = ctx.krate { |
118 | let ty = match resolution { | 118 | let ty = match resolution { |
119 | PathResolution::TypeParam(param) => param.ty(ctx.db), | 119 | PathResolution::TypeParam(param) => param.ty(ctx.db), |
120 | PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db), | 120 | PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db), |
121 | _ => return, | 121 | _ => return, |
122 | }; | 122 | }; |
123 | 123 | ||
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index 5ac1cb48d..831d543bb 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs | |||
@@ -81,6 +81,8 @@ pub use crate::{ | |||
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 agains the completion imput. |
84 | // | ||
85 | // image::https://user-images.githubusercontent.com/48062697/113020667-b72ab880-917a-11eb-8778-716cf26a0eb3.gif[] | ||
84 | 86 | ||
85 | /// Main entry point for completion. We run completion as a two-phase process. | 87 | /// Main entry point for completion. We run completion as a two-phase process. |
86 | /// | 88 | /// |
diff --git a/crates/ide_db/src/apply_change.rs b/crates/ide_db/src/apply_change.rs index 047a9b6bc..111e9325a 100644 --- a/crates/ide_db/src/apply_change.rs +++ b/crates/ide_db/src/apply_change.rs | |||
@@ -101,6 +101,7 @@ impl RootDatabase { | |||
101 | // | 101 | // |
102 | // | VS Code | **Rust Analyzer: Memory Usage (Clears Database)** | 102 | // | VS Code | **Rust Analyzer: Memory Usage (Clears Database)** |
103 | // |=== | 103 | // |=== |
104 | // image::https://user-images.githubusercontent.com/48062697/113065592-08559f00-91b1-11eb-8c96-64b88068ec02.gif[] | ||
104 | pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> { | 105 | pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> { |
105 | let mut acc: Vec<(String, Bytes)> = vec![]; | 106 | let mut acc: Vec<(String, Bytes)> = vec![]; |
106 | let sweep = SweepStrategy::default().discard_values().sweep_all_revisions(); | 107 | let sweep = SweepStrategy::default().discard_values().sweep_all_revisions(); |
diff --git a/crates/ide_db/src/call_info/tests.rs b/crates/ide_db/src/call_info/tests.rs index 75ab3eb6e..281a081a3 100644 --- a/crates/ide_db/src/call_info/tests.rs +++ b/crates/ide_db/src/call_info/tests.rs | |||
@@ -1,8 +1,9 @@ | |||
1 | use crate::RootDatabase; | ||
2 | use base_db::{fixture::ChangeFixture, FilePosition}; | 1 | use base_db::{fixture::ChangeFixture, FilePosition}; |
3 | use expect_test::{expect, Expect}; | 2 | use expect_test::{expect, Expect}; |
4 | use test_utils::RangeOrOffset; | 3 | use test_utils::RangeOrOffset; |
5 | 4 | ||
5 | use crate::RootDatabase; | ||
6 | |||
6 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. | 7 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. |
7 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { | 8 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { |
8 | let change_fixture = ChangeFixture::parse(ra_fixture); | 9 | let change_fixture = ChangeFixture::parse(ra_fixture); |
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs index 75167ff39..de0dc2a40 100644 --- a/crates/ide_db/src/defs.rs +++ b/crates/ide_db/src/defs.rs | |||
@@ -227,7 +227,7 @@ impl NameClass { | |||
227 | let def: hir::TypeAlias = sema.to_def(&it)?; | 227 | let def: hir::TypeAlias = sema.to_def(&it)?; |
228 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) | 228 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) |
229 | }, | 229 | }, |
230 | ast::MacroRules(it) => { | 230 | ast::Macro(it) => { |
231 | let def = sema.to_def(&it)?; | 231 | let def = sema.to_def(&it)?; |
232 | Some(NameClass::Definition(Definition::Macro(def))) | 232 | Some(NameClass::Definition(Definition::Macro(def))) |
233 | }, | 233 | }, |
@@ -330,25 +330,30 @@ impl NameRefClass { | |||
330 | } | 330 | } |
331 | } | 331 | } |
332 | 332 | ||
333 | if ast::AssocTypeArg::cast(parent.clone()).is_some() { | 333 | if let Some(assoc_type_arg) = ast::AssocTypeArg::cast(parent.clone()) { |
334 | // `Trait<Assoc = Ty>` | 334 | if assoc_type_arg.name_ref().as_ref() == Some(name_ref) { |
335 | // ^^^^^ | 335 | // `Trait<Assoc = Ty>` |
336 | let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; | 336 | // ^^^^^ |
337 | let resolved = sema.resolve_path(&path)?; | 337 | let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; |
338 | if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved { | 338 | let resolved = sema.resolve_path(&path)?; |
339 | if let Some(ty) = tr | 339 | if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved { |
340 | .items(sema.db) | 340 | // FIXME: resolve in supertraits |
341 | .iter() | 341 | if let Some(ty) = tr |
342 | .filter_map(|assoc| match assoc { | 342 | .items(sema.db) |
343 | hir::AssocItem::TypeAlias(it) => Some(*it), | 343 | .iter() |
344 | _ => None, | 344 | .filter_map(|assoc| match assoc { |
345 | }) | 345 | hir::AssocItem::TypeAlias(it) => Some(*it), |
346 | .find(|alias| &alias.name(sema.db).to_string() == name_ref.text()) | 346 | _ => None, |
347 | { | 347 | }) |
348 | return Some(NameRefClass::Definition(Definition::ModuleDef( | 348 | .find(|alias| &alias.name(sema.db).to_string() == &name_ref.text()) |
349 | ModuleDef::TypeAlias(ty), | 349 | { |
350 | ))); | 350 | return Some(NameRefClass::Definition(Definition::ModuleDef( |
351 | ModuleDef::TypeAlias(ty), | ||
352 | ))); | ||
353 | } | ||
351 | } | 354 | } |
355 | |||
356 | return None; | ||
352 | } | 357 | } |
353 | } | 358 | } |
354 | 359 | ||
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs index 1881c746f..8ce648367 100644 --- a/crates/ide_db/src/helpers/import_assets.rs +++ b/crates/ide_db/src/helpers/import_assets.rs | |||
@@ -288,7 +288,7 @@ fn path_applicable_imports( | |||
288 | import_for_item( | 288 | import_for_item( |
289 | sema.db, | 289 | sema.db, |
290 | mod_path, | 290 | mod_path, |
291 | unresolved_first_segment, | 291 | &unresolved_first_segment, |
292 | &unresolved_qualifier, | 292 | &unresolved_qualifier, |
293 | item, | 293 | item, |
294 | ) | 294 | ) |
@@ -361,7 +361,7 @@ fn item_for_path_search(db: &RootDatabase, item: ItemInNs) -> Option<ItemInNs> { | |||
361 | Some(assoc_item) => match assoc_item.container(db) { | 361 | Some(assoc_item) => match assoc_item.container(db) { |
362 | AssocItemContainer::Trait(trait_) => ItemInNs::from(ModuleDef::from(trait_)), | 362 | AssocItemContainer::Trait(trait_) => ItemInNs::from(ModuleDef::from(trait_)), |
363 | AssocItemContainer::Impl(impl_) => { | 363 | AssocItemContainer::Impl(impl_) => { |
364 | ItemInNs::from(ModuleDef::from(impl_.target_ty(db).as_adt()?)) | 364 | ItemInNs::from(ModuleDef::from(impl_.self_ty(db).as_adt()?)) |
365 | } | 365 | } |
366 | }, | 366 | }, |
367 | None => item, | 367 | None => item, |
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs index 20c195f82..be3a22725 100644 --- a/crates/ide_db/src/helpers/insert_use.rs +++ b/crates/ide_db/src/helpers/insert_use.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | //! Handle syntactic aspects of inserting a new `use`. | 1 | //! Handle syntactic aspects of inserting a new `use`. |
2 | use std::{cmp::Ordering, iter::successors}; | 2 | use std::{cmp::Ordering, iter::successors}; |
3 | 3 | ||
4 | use crate::RootDatabase; | ||
5 | use hir::Semantics; | 4 | use hir::Semantics; |
6 | use itertools::{EitherOrBoth, Itertools}; | 5 | use itertools::{EitherOrBoth, Itertools}; |
7 | use syntax::{ | 6 | use syntax::{ |
@@ -14,6 +13,8 @@ use syntax::{ | |||
14 | AstToken, InsertPosition, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken, | 13 | AstToken, InsertPosition, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken, |
15 | }; | 14 | }; |
16 | 15 | ||
16 | use crate::RootDatabase; | ||
17 | |||
17 | pub use hir::PrefixKind; | 18 | pub use hir::PrefixKind; |
18 | 19 | ||
19 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | 20 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
@@ -509,7 +510,7 @@ impl ImportGroup { | |||
509 | PathSegmentKind::SelfKw => ImportGroup::ThisModule, | 510 | PathSegmentKind::SelfKw => ImportGroup::ThisModule, |
510 | PathSegmentKind::SuperKw => ImportGroup::SuperModule, | 511 | PathSegmentKind::SuperKw => ImportGroup::SuperModule, |
511 | PathSegmentKind::CrateKw => ImportGroup::ThisCrate, | 512 | PathSegmentKind::CrateKw => ImportGroup::ThisCrate, |
512 | PathSegmentKind::Name(name) => match name.text() { | 513 | PathSegmentKind::Name(name) => match name.text().as_str() { |
513 | "std" => ImportGroup::Std, | 514 | "std" => ImportGroup::Std, |
514 | "core" => ImportGroup::Std, | 515 | "core" => ImportGroup::Std, |
515 | _ => ImportGroup::ExternCrate, | 516 | _ => ImportGroup::ExternCrate, |
diff --git a/crates/ide_db/src/label.rs b/crates/ide_db/src/label.rs index c0e89e72f..1f1e715c9 100644 --- a/crates/ide_db/src/label.rs +++ b/crates/ide_db/src/label.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | //! See `Label` | 1 | //! See [`Label`] |
2 | use std::fmt; | 2 | use std::fmt; |
3 | 3 | ||
4 | /// A type to specify UI label, like an entry in the list of assists. Enforces | 4 | /// A type to specify UI label, like an entry in the list of assists. Enforces |
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs index 3634b2b26..b55e3851e 100644 --- a/crates/ide_db/src/search.rs +++ b/crates/ide_db/src/search.rs | |||
@@ -12,9 +12,8 @@ use once_cell::unsync::Lazy; | |||
12 | use rustc_hash::FxHashMap; | 12 | use rustc_hash::FxHashMap; |
13 | use syntax::{ast, match_ast, AstNode, TextRange, TextSize}; | 13 | use syntax::{ast, match_ast, AstNode, TextRange, TextSize}; |
14 | 14 | ||
15 | use crate::defs::NameClass; | ||
16 | use crate::{ | 15 | use crate::{ |
17 | defs::{Definition, NameRefClass}, | 16 | defs::{Definition, NameClass, NameRefClass}, |
18 | RootDatabase, | 17 | RootDatabase, |
19 | }; | 18 | }; |
20 | 19 | ||
diff --git a/crates/ide_db/src/source_change.rs b/crates/ide_db/src/source_change.rs index b36455d49..846530f78 100644 --- a/crates/ide_db/src/source_change.rs +++ b/crates/ide_db/src/source_change.rs | |||
@@ -37,6 +37,8 @@ impl SourceChange { | |||
37 | } | 37 | } |
38 | } | 38 | } |
39 | 39 | ||
40 | /// Inserts a [`TextEdit`] for the given [`FileId`]. This properly handles merging existing | ||
41 | /// edits for a file if some already exist. | ||
40 | pub fn insert_source_edit(&mut self, file_id: FileId, edit: TextEdit) { | 42 | pub fn insert_source_edit(&mut self, file_id: FileId, edit: TextEdit) { |
41 | match self.source_file_edits.entry(file_id) { | 43 | match self.source_file_edits.entry(file_id) { |
42 | Entry::Occupied(mut entry) => { | 44 | Entry::Occupied(mut entry) => { |
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs index 35e382b5c..da427d686 100644 --- a/crates/ide_db/src/symbol_index.rs +++ b/crates/ide_db/src/symbol_index.rs | |||
@@ -438,7 +438,7 @@ fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> { | |||
438 | ast::TypeAlias(it) => decl(it), | 438 | ast::TypeAlias(it) => decl(it), |
439 | ast::Const(it) => decl(it), | 439 | ast::Const(it) => decl(it), |
440 | ast::Static(it) => decl(it), | 440 | ast::Static(it) => decl(it), |
441 | ast::MacroRules(it) => decl(it), | 441 | ast::Macro(it) => decl(it), |
442 | ast::Union(it) => decl(it), | 442 | ast::Union(it) => decl(it), |
443 | _ => None, | 443 | _ => None, |
444 | } | 444 | } |
@@ -458,6 +458,7 @@ fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option<FileSymbol> { | |||
458 | CONST => FileSymbolKind::Const, | 458 | CONST => FileSymbolKind::Const, |
459 | STATIC => FileSymbolKind::Static, | 459 | STATIC => FileSymbolKind::Static, |
460 | MACRO_RULES => FileSymbolKind::Macro, | 460 | MACRO_RULES => FileSymbolKind::Macro, |
461 | MACRO_DEF => FileSymbolKind::Macro, | ||
461 | UNION => FileSymbolKind::Union, | 462 | UNION => FileSymbolKind::Union, |
462 | kind => unreachable!("{:?}", kind), | 463 | kind => unreachable!("{:?}", kind), |
463 | }, | 464 | }, |
diff --git a/crates/ide_db/src/traits.rs b/crates/ide_db/src/traits.rs index 78a43f587..66ae81c73 100644 --- a/crates/ide_db/src/traits.rs +++ b/crates/ide_db/src/traits.rs | |||
@@ -61,7 +61,7 @@ pub fn get_missing_assoc_items( | |||
61 | resolve_target_trait(sema, impl_def).map_or(vec![], |target_trait| { | 61 | resolve_target_trait(sema, impl_def).map_or(vec![], |target_trait| { |
62 | target_trait | 62 | target_trait |
63 | .items(sema.db) | 63 | .items(sema.db) |
64 | .iter() | 64 | .into_iter() |
65 | .filter(|i| match i { | 65 | .filter(|i| match i { |
66 | hir::AssocItem::Function(f) => { | 66 | hir::AssocItem::Function(f) => { |
67 | !impl_fns_consts.contains(&f.name(sema.db).to_string()) | 67 | !impl_fns_consts.contains(&f.name(sema.db).to_string()) |
@@ -72,7 +72,6 @@ pub fn get_missing_assoc_items( | |||
72 | .map(|n| !impl_fns_consts.contains(&n.to_string())) | 72 | .map(|n| !impl_fns_consts.contains(&n.to_string())) |
73 | .unwrap_or_default(), | 73 | .unwrap_or_default(), |
74 | }) | 74 | }) |
75 | .cloned() | ||
76 | .collect() | 75 | .collect() |
77 | }) | 76 | }) |
78 | } | 77 | } |
diff --git a/crates/ide_db/src/traits/tests.rs b/crates/ide_db/src/traits/tests.rs index 84bb25505..2a5482024 100644 --- a/crates/ide_db/src/traits/tests.rs +++ b/crates/ide_db/src/traits/tests.rs | |||
@@ -1,10 +1,11 @@ | |||
1 | use crate::RootDatabase; | ||
2 | use base_db::{fixture::ChangeFixture, FilePosition}; | 1 | use base_db::{fixture::ChangeFixture, FilePosition}; |
3 | use expect_test::{expect, Expect}; | 2 | use expect_test::{expect, Expect}; |
4 | use hir::Semantics; | 3 | use hir::Semantics; |
5 | use syntax::ast::{self, AstNode}; | 4 | use syntax::ast::{self, AstNode}; |
6 | use test_utils::RangeOrOffset; | 5 | use test_utils::RangeOrOffset; |
7 | 6 | ||
7 | use crate::RootDatabase; | ||
8 | |||
8 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. | 9 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. |
9 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { | 10 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { |
10 | let change_fixture = ChangeFixture::parse(ra_fixture); | 11 | let change_fixture = ChangeFixture::parse(ra_fixture); |
diff --git a/crates/ide_db/src/ty_filter.rs b/crates/ide_db/src/ty_filter.rs index f8406851b..988ecd060 100644 --- a/crates/ide_db/src/ty_filter.rs +++ b/crates/ide_db/src/ty_filter.rs | |||
@@ -2,11 +2,13 @@ | |||
2 | //! Use case for structures in this module is, for example, situation when you need to process | 2 | //! Use case for structures in this module is, for example, situation when you need to process |
3 | //! only certain `Enum`s. | 3 | //! only certain `Enum`s. |
4 | 4 | ||
5 | use crate::RootDatabase; | ||
6 | use hir::{Adt, Semantics, Type}; | ||
7 | use std::iter; | 5 | use std::iter; |
6 | |||
7 | use hir::{Adt, Semantics, Type}; | ||
8 | use syntax::ast::{self, make}; | 8 | use syntax::ast::{self, make}; |
9 | 9 | ||
10 | use crate::RootDatabase; | ||
11 | |||
10 | /// Enum types that implement `std::ops::Try` trait. | 12 | /// Enum types that implement `std::ops::Try` trait. |
11 | #[derive(Clone, Copy)] | 13 | #[derive(Clone, Copy)] |
12 | pub enum TryEnum { | 14 | pub enum TryEnum { |
diff --git a/crates/ide_ssr/src/resolving.rs b/crates/ide_ssr/src/resolving.rs index dc7835473..541da4122 100644 --- a/crates/ide_ssr/src/resolving.rs +++ b/crates/ide_ssr/src/resolving.rs | |||
@@ -150,7 +150,7 @@ impl Resolver<'_, '_> { | |||
150 | fn path_contains_placeholder(&self, path: &ast::Path) -> bool { | 150 | fn path_contains_placeholder(&self, path: &ast::Path) -> bool { |
151 | if let Some(segment) = path.segment() { | 151 | if let Some(segment) = path.segment() { |
152 | if let Some(name_ref) = segment.name_ref() { | 152 | if let Some(name_ref) = segment.name_ref() { |
153 | if self.placeholders_by_stand_in.contains_key(name_ref.text()) { | 153 | if self.placeholders_by_stand_in.contains_key(name_ref.text().as_str()) { |
154 | return true; | 154 | return true; |
155 | } | 155 | } |
156 | } | 156 | } |
diff --git a/crates/proc_macro_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/rustc_server.rs index c147484c0..5d765f6e2 100644 --- a/crates/proc_macro_srv/src/rustc_server.rs +++ b/crates/proc_macro_srv/src/rustc_server.rs | |||
@@ -534,8 +534,12 @@ impl server::Literal for Rustc { | |||
534 | } | 534 | } |
535 | 535 | ||
536 | fn integer(&mut self, n: &str) -> Self::Literal { | 536 | fn integer(&mut self, n: &str) -> Self::Literal { |
537 | let n: i128 = n.parse().unwrap(); | 537 | let n = if let Ok(n) = n.parse::<i128>() { |
538 | Literal { text: n.to_string().into(), id: tt::TokenId::unspecified() } | 538 | n.to_string() |
539 | } else { | ||
540 | n.parse::<u128>().unwrap().to_string() | ||
541 | }; | ||
542 | return Literal { text: n.into(), id: tt::TokenId::unspecified() }; | ||
539 | } | 543 | } |
540 | 544 | ||
541 | fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal { | 545 | fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal { |
@@ -757,6 +761,17 @@ mod tests { | |||
757 | assert_eq!(srv.string("hello_world").text, "\"hello_world\""); | 761 | assert_eq!(srv.string("hello_world").text, "\"hello_world\""); |
758 | assert_eq!(srv.character('c').text, "'c'"); | 762 | assert_eq!(srv.character('c').text, "'c'"); |
759 | assert_eq!(srv.byte_string(b"1234586\x88").text, "b\"1234586\\x88\""); | 763 | assert_eq!(srv.byte_string(b"1234586\x88").text, "b\"1234586\\x88\""); |
764 | |||
765 | // u128::max | ||
766 | assert_eq!( | ||
767 | srv.integer("340282366920938463463374607431768211455").text, | ||
768 | "340282366920938463463374607431768211455" | ||
769 | ); | ||
770 | // i128::min | ||
771 | assert_eq!( | ||
772 | srv.integer("-170141183460469231731687303715884105728").text, | ||
773 | "-170141183460469231731687303715884105728" | ||
774 | ); | ||
760 | } | 775 | } |
761 | 776 | ||
762 | #[test] | 777 | #[test] |
diff --git a/crates/profile/src/google_cpu_profiler.rs b/crates/profile/src/google_cpu_profiler.rs index db865c65b..cae6caeaa 100644 --- a/crates/profile/src/google_cpu_profiler.rs +++ b/crates/profile/src/google_cpu_profiler.rs | |||
@@ -14,26 +14,31 @@ extern "C" { | |||
14 | fn ProfilerStop(); | 14 | fn ProfilerStop(); |
15 | } | 15 | } |
16 | 16 | ||
17 | static PROFILER_STATE: AtomicUsize = AtomicUsize::new(OFF); | ||
18 | const OFF: usize = 0; | 17 | const OFF: usize = 0; |
19 | const ON: usize = 1; | 18 | const ON: usize = 1; |
20 | const PENDING: usize = 2; | 19 | const PENDING: usize = 2; |
21 | 20 | ||
22 | pub fn start(path: &Path) { | 21 | fn transition(current: usize, new: usize) -> bool { |
23 | if PROFILER_STATE.compare_and_swap(OFF, PENDING, Ordering::SeqCst) != OFF { | 22 | static STATE: AtomicUsize = AtomicUsize::new(OFF); |
23 | |||
24 | STATE.compare_exchange(current, new, Ordering::SeqCst, Ordering::SeqCst).is_ok() | ||
25 | } | ||
26 | |||
27 | pub(crate) fn start(path: &Path) { | ||
28 | if !transition(OFF, PENDING) { | ||
24 | panic!("profiler already started"); | 29 | panic!("profiler already started"); |
25 | } | 30 | } |
26 | let path = CString::new(path.display().to_string()).unwrap(); | 31 | let path = CString::new(path.display().to_string()).unwrap(); |
27 | if unsafe { ProfilerStart(path.as_ptr()) } == 0 { | 32 | if unsafe { ProfilerStart(path.as_ptr()) } == 0 { |
28 | panic!("profiler failed to start") | 33 | panic!("profiler failed to start") |
29 | } | 34 | } |
30 | assert!(PROFILER_STATE.compare_and_swap(PENDING, ON, Ordering::SeqCst) == PENDING); | 35 | assert!(transition(PENDING, ON)); |
31 | } | 36 | } |
32 | 37 | ||
33 | pub fn stop() { | 38 | pub(crate) fn stop() { |
34 | if PROFILER_STATE.compare_and_swap(ON, PENDING, Ordering::SeqCst) != ON { | 39 | if !transition(ON, PENDING) { |
35 | panic!("profiler is not started") | 40 | panic!("profiler is not started") |
36 | } | 41 | } |
37 | unsafe { ProfilerStop() }; | 42 | unsafe { ProfilerStop() }; |
38 | assert!(PROFILER_STATE.compare_and_swap(PENDING, OFF, Ordering::SeqCst) == PENDING); | 43 | assert!(transition(PENDING, OFF)); |
39 | } | 44 | } |
diff --git a/crates/profile/src/hprof.rs b/crates/profile/src/hprof.rs index 29d2ed518..5fdb37206 100644 --- a/crates/profile/src/hprof.rs +++ b/crates/profile/src/hprof.rs | |||
@@ -1,5 +1,4 @@ | |||
1 | //! Simple hierarchical profiler | 1 | //! Simple hierarchical profiler |
2 | use once_cell::sync::Lazy; | ||
3 | use std::{ | 2 | use std::{ |
4 | cell::RefCell, | 3 | cell::RefCell, |
5 | collections::{BTreeMap, HashSet}, | 4 | collections::{BTreeMap, HashSet}, |
@@ -12,6 +11,8 @@ use std::{ | |||
12 | time::{Duration, Instant}, | 11 | time::{Duration, Instant}, |
13 | }; | 12 | }; |
14 | 13 | ||
14 | use once_cell::sync::Lazy; | ||
15 | |||
15 | use crate::tree::{Idx, Tree}; | 16 | use crate::tree::{Idx, Tree}; |
16 | 17 | ||
17 | /// Filtering syntax | 18 | /// Filtering syntax |
@@ -56,18 +57,32 @@ type Label = &'static str; | |||
56 | /// 0ms - profile | 57 | /// 0ms - profile |
57 | /// 0ms - profile2 | 58 | /// 0ms - profile2 |
58 | /// ``` | 59 | /// ``` |
60 | #[inline] | ||
59 | pub fn span(label: Label) -> ProfileSpan { | 61 | pub fn span(label: Label) -> ProfileSpan { |
60 | assert!(!label.is_empty()); | 62 | debug_assert!(!label.is_empty()); |
61 | 63 | ||
62 | if PROFILING_ENABLED.load(Ordering::Relaxed) | 64 | let enabled = PROFILING_ENABLED.load(Ordering::Relaxed); |
63 | && PROFILE_STACK.with(|stack| stack.borrow_mut().push(label)) | 65 | if enabled && with_profile_stack(|stack| stack.push(label)) { |
64 | { | ||
65 | ProfileSpan(Some(ProfilerImpl { label, detail: None })) | 66 | ProfileSpan(Some(ProfilerImpl { label, detail: None })) |
66 | } else { | 67 | } else { |
67 | ProfileSpan(None) | 68 | ProfileSpan(None) |
68 | } | 69 | } |
69 | } | 70 | } |
70 | 71 | ||
72 | #[inline] | ||
73 | pub fn heartbeat_span() -> HeartbeatSpan { | ||
74 | let enabled = PROFILING_ENABLED.load(Ordering::Relaxed); | ||
75 | HeartbeatSpan::new(enabled) | ||
76 | } | ||
77 | |||
78 | #[inline] | ||
79 | pub fn heartbeat() { | ||
80 | let enabled = PROFILING_ENABLED.load(Ordering::Relaxed); | ||
81 | if enabled { | ||
82 | with_profile_stack(|it| it.heartbeat(1)); | ||
83 | } | ||
84 | } | ||
85 | |||
71 | pub struct ProfileSpan(Option<ProfilerImpl>); | 86 | pub struct ProfileSpan(Option<ProfilerImpl>); |
72 | 87 | ||
73 | struct ProfilerImpl { | 88 | struct ProfilerImpl { |
@@ -85,20 +100,48 @@ impl ProfileSpan { | |||
85 | } | 100 | } |
86 | 101 | ||
87 | impl Drop for ProfilerImpl { | 102 | impl Drop for ProfilerImpl { |
103 | #[inline] | ||
104 | fn drop(&mut self) { | ||
105 | with_profile_stack(|it| it.pop(self.label, self.detail.take())); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | pub struct HeartbeatSpan { | ||
110 | enabled: bool, | ||
111 | } | ||
112 | |||
113 | impl HeartbeatSpan { | ||
114 | #[inline] | ||
115 | pub fn new(enabled: bool) -> Self { | ||
116 | if enabled { | ||
117 | with_profile_stack(|it| it.heartbeats(true)) | ||
118 | } | ||
119 | Self { enabled } | ||
120 | } | ||
121 | } | ||
122 | |||
123 | impl Drop for HeartbeatSpan { | ||
88 | fn drop(&mut self) { | 124 | fn drop(&mut self) { |
89 | PROFILE_STACK.with(|it| it.borrow_mut().pop(self.label, self.detail.take())); | 125 | if self.enabled { |
126 | with_profile_stack(|it| it.heartbeats(false)) | ||
127 | } | ||
90 | } | 128 | } |
91 | } | 129 | } |
92 | 130 | ||
93 | static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false); | 131 | static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false); |
94 | static FILTER: Lazy<RwLock<Filter>> = Lazy::new(Default::default); | 132 | static FILTER: Lazy<RwLock<Filter>> = Lazy::new(Default::default); |
95 | thread_local!(static PROFILE_STACK: RefCell<ProfileStack> = RefCell::new(ProfileStack::new())); | 133 | |
134 | fn with_profile_stack<T>(f: impl FnOnce(&mut ProfileStack) -> T) -> T { | ||
135 | thread_local!(static STACK: RefCell<ProfileStack> = RefCell::new(ProfileStack::new())); | ||
136 | STACK.with(|it| f(&mut *it.borrow_mut())) | ||
137 | } | ||
96 | 138 | ||
97 | #[derive(Default, Clone, Debug)] | 139 | #[derive(Default, Clone, Debug)] |
98 | struct Filter { | 140 | struct Filter { |
99 | depth: usize, | 141 | depth: usize, |
100 | allowed: HashSet<String>, | 142 | allowed: HashSet<String>, |
101 | longer_than: Duration, | 143 | longer_than: Duration, |
144 | heartbeat_longer_than: Duration, | ||
102 | version: usize, | 145 | version: usize, |
103 | } | 146 | } |
104 | 147 | ||
@@ -115,6 +158,7 @@ impl Filter { | |||
115 | } else { | 158 | } else { |
116 | Duration::new(0, 0) | 159 | Duration::new(0, 0) |
117 | }; | 160 | }; |
161 | let heartbeat_longer_than = longer_than; | ||
118 | 162 | ||
119 | let depth = if let Some(idx) = spec.rfind('@') { | 163 | let depth = if let Some(idx) = spec.rfind('@') { |
120 | let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth"); | 164 | let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth"); |
@@ -125,7 +169,7 @@ impl Filter { | |||
125 | }; | 169 | }; |
126 | let allowed = | 170 | let allowed = |
127 | if spec == "*" { HashSet::new() } else { spec.split('|').map(String::from).collect() }; | 171 | if spec == "*" { HashSet::new() } else { spec.split('|').map(String::from).collect() }; |
128 | Filter { depth, allowed, longer_than, version: 0 } | 172 | Filter { depth, allowed, longer_than, heartbeat_longer_than, version: 0 } |
129 | } | 173 | } |
130 | 174 | ||
131 | fn install(mut self) { | 175 | fn install(mut self) { |
@@ -137,9 +181,15 @@ impl Filter { | |||
137 | } | 181 | } |
138 | 182 | ||
139 | struct ProfileStack { | 183 | struct ProfileStack { |
140 | starts: Vec<Instant>, | 184 | frames: Vec<Frame>, |
141 | filter: Filter, | 185 | filter: Filter, |
142 | messages: Tree<Message>, | 186 | messages: Tree<Message>, |
187 | heartbeats: bool, | ||
188 | } | ||
189 | |||
190 | struct Frame { | ||
191 | t: Instant, | ||
192 | heartbeats: u32, | ||
143 | } | 193 | } |
144 | 194 | ||
145 | #[derive(Default)] | 195 | #[derive(Default)] |
@@ -151,35 +201,49 @@ struct Message { | |||
151 | 201 | ||
152 | impl ProfileStack { | 202 | impl ProfileStack { |
153 | fn new() -> ProfileStack { | 203 | fn new() -> ProfileStack { |
154 | ProfileStack { starts: Vec::new(), messages: Tree::default(), filter: Default::default() } | 204 | ProfileStack { |
205 | frames: Vec::new(), | ||
206 | messages: Tree::default(), | ||
207 | filter: Default::default(), | ||
208 | heartbeats: false, | ||
209 | } | ||
155 | } | 210 | } |
156 | 211 | ||
157 | fn push(&mut self, label: Label) -> bool { | 212 | fn push(&mut self, label: Label) -> bool { |
158 | if self.starts.is_empty() { | 213 | if self.frames.is_empty() { |
159 | if let Ok(f) = FILTER.try_read() { | 214 | if let Ok(f) = FILTER.try_read() { |
160 | if f.version > self.filter.version { | 215 | if f.version > self.filter.version { |
161 | self.filter = f.clone(); | 216 | self.filter = f.clone(); |
162 | } | 217 | } |
163 | }; | 218 | }; |
164 | } | 219 | } |
165 | if self.starts.len() > self.filter.depth { | 220 | if self.frames.len() > self.filter.depth { |
166 | return false; | 221 | return false; |
167 | } | 222 | } |
168 | let allowed = &self.filter.allowed; | 223 | let allowed = &self.filter.allowed; |
169 | if self.starts.is_empty() && !allowed.is_empty() && !allowed.contains(label) { | 224 | if self.frames.is_empty() && !allowed.is_empty() && !allowed.contains(label) { |
170 | return false; | 225 | return false; |
171 | } | 226 | } |
172 | 227 | ||
173 | self.starts.push(Instant::now()); | 228 | self.frames.push(Frame { t: Instant::now(), heartbeats: 0 }); |
174 | self.messages.start(); | 229 | self.messages.start(); |
175 | true | 230 | true |
176 | } | 231 | } |
177 | 232 | ||
178 | fn pop(&mut self, label: Label, detail: Option<String>) { | 233 | fn pop(&mut self, label: Label, detail: Option<String>) { |
179 | let start = self.starts.pop().unwrap(); | 234 | let frame = self.frames.pop().unwrap(); |
180 | let duration = start.elapsed(); | 235 | let duration = frame.t.elapsed(); |
236 | |||
237 | if self.heartbeats { | ||
238 | self.heartbeat(frame.heartbeats); | ||
239 | let avg_span = duration / (frame.heartbeats + 1); | ||
240 | if avg_span > self.filter.heartbeat_longer_than { | ||
241 | eprintln!("Too few heartbeats {} ({}/{:?})?", label, frame.heartbeats, duration) | ||
242 | } | ||
243 | } | ||
244 | |||
181 | self.messages.finish(Message { duration, label, detail }); | 245 | self.messages.finish(Message { duration, label, detail }); |
182 | if self.starts.is_empty() { | 246 | if self.frames.is_empty() { |
183 | let longer_than = self.filter.longer_than; | 247 | let longer_than = self.filter.longer_than; |
184 | // Convert to millis for comparison to avoid problems with rounding | 248 | // Convert to millis for comparison to avoid problems with rounding |
185 | // (otherwise we could print `0ms` despite user's `>0` filter when | 249 | // (otherwise we could print `0ms` despite user's `>0` filter when |
@@ -192,6 +256,15 @@ impl ProfileStack { | |||
192 | self.messages.clear(); | 256 | self.messages.clear(); |
193 | } | 257 | } |
194 | } | 258 | } |
259 | |||
260 | fn heartbeats(&mut self, yes: bool) { | ||
261 | self.heartbeats = yes; | ||
262 | } | ||
263 | fn heartbeat(&mut self, n: u32) { | ||
264 | if let Some(frame) = self.frames.last_mut() { | ||
265 | frame.heartbeats += n; | ||
266 | } | ||
267 | } | ||
195 | } | 268 | } |
196 | 269 | ||
197 | fn print( | 270 | fn print( |
diff --git a/crates/profile/src/lib.rs b/crates/profile/src/lib.rs index 79dba47d5..a31fb8f43 100644 --- a/crates/profile/src/lib.rs +++ b/crates/profile/src/lib.rs | |||
@@ -10,7 +10,7 @@ mod tree; | |||
10 | use std::cell::RefCell; | 10 | use std::cell::RefCell; |
11 | 11 | ||
12 | pub use crate::{ | 12 | pub use crate::{ |
13 | hprof::{init, init_from, span}, | 13 | hprof::{heartbeat, heartbeat_span, init, init_from, span}, |
14 | memory_usage::{Bytes, MemoryUsage}, | 14 | memory_usage::{Bytes, MemoryUsage}, |
15 | stop_watch::{StopWatch, StopWatchSpan}, | 15 | stop_watch::{StopWatch, StopWatchSpan}, |
16 | }; | 16 | }; |
@@ -52,7 +52,7 @@ impl Drop for Scope { | |||
52 | /// Usage: | 52 | /// Usage: |
53 | /// 1. Install gpref_tools (https://github.com/gperftools/gperftools), probably packaged with your Linux distro. | 53 | /// 1. Install gpref_tools (https://github.com/gperftools/gperftools), probably packaged with your Linux distro. |
54 | /// 2. Build with `cpu_profiler` feature. | 54 | /// 2. Build with `cpu_profiler` feature. |
55 | /// 3. Tun the code, the *raw* output would be in the `./out.profile` file. | 55 | /// 3. Run the code, the *raw* output would be in the `./out.profile` file. |
56 | /// 4. Install pprof for visualization (https://github.com/google/pprof). | 56 | /// 4. Install pprof for visualization (https://github.com/google/pprof). |
57 | /// 5. Bump sampling frequency to once per ms: `export CPUPROFILE_FREQUENCY=1000` | 57 | /// 5. Bump sampling frequency to once per ms: `export CPUPROFILE_FREQUENCY=1000` |
58 | /// 6. Use something like `pprof -svg target/release/rust-analyzer ./out.profile` to see the results. | 58 | /// 6. Use something like `pprof -svg target/release/rust-analyzer ./out.profile` to see the results. |
@@ -60,8 +60,17 @@ impl Drop for Scope { | |||
60 | /// For example, here's how I run profiling on NixOS: | 60 | /// For example, here's how I run profiling on NixOS: |
61 | /// | 61 | /// |
62 | /// ```bash | 62 | /// ```bash |
63 | /// $ nix-shell -p gperftools --run \ | 63 | /// $ bat -p shell.nix |
64 | /// 'cargo run --release -p rust-analyzer -- parse < ~/projects/rustbench/parser.rs > /dev/null' | 64 | /// with import <nixpkgs> {}; |
65 | /// mkShell { | ||
66 | /// buildInputs = [ gperftools ]; | ||
67 | /// shellHook = '' | ||
68 | /// export LD_LIBRARY_PATH="${gperftools}/lib:" | ||
69 | /// ''; | ||
70 | /// } | ||
71 | /// $ set -x CPUPROFILE_FREQUENCY 1000 | ||
72 | /// $ nix-shell --run 'cargo test --release --package rust-analyzer --lib -- benchmarks::benchmark_integrated_highlighting --exact --nocapture' | ||
73 | /// $ pprof -svg target/release/deps/rust_analyzer-8739592dc93d63cb crates/rust-analyzer/out.profile > profile.svg | ||
65 | /// ``` | 74 | /// ``` |
66 | /// | 75 | /// |
67 | /// See this diff for how to profile completions: | 76 | /// See this diff for how to profile completions: |
@@ -81,7 +90,9 @@ pub fn cpu_span() -> CpuSpan { | |||
81 | 90 | ||
82 | #[cfg(not(feature = "cpu_profiler"))] | 91 | #[cfg(not(feature = "cpu_profiler"))] |
83 | { | 92 | { |
84 | eprintln!("cpu_profiler feature is disabled") | 93 | eprintln!( |
94 | r#"cpu profiling is disabled, uncomment `default = [ "cpu_profiler" ]` in Cargo.toml to enable."# | ||
95 | ) | ||
85 | } | 96 | } |
86 | 97 | ||
87 | CpuSpan { _private: () } | 98 | CpuSpan { _private: () } |
@@ -91,7 +102,23 @@ impl Drop for CpuSpan { | |||
91 | fn drop(&mut self) { | 102 | fn drop(&mut self) { |
92 | #[cfg(feature = "cpu_profiler")] | 103 | #[cfg(feature = "cpu_profiler")] |
93 | { | 104 | { |
94 | google_cpu_profiler::stop() | 105 | google_cpu_profiler::stop(); |
106 | let profile_data = std::env::current_dir().unwrap().join("out.profile"); | ||
107 | eprintln!("Profile data saved to:\n\n {}\n", profile_data.display()); | ||
108 | let mut cmd = std::process::Command::new("pprof"); | ||
109 | cmd.arg("-svg").arg(std::env::current_exe().unwrap()).arg(&profile_data); | ||
110 | let out = cmd.output(); | ||
111 | |||
112 | match out { | ||
113 | Ok(out) if out.status.success() => { | ||
114 | let svg = profile_data.with_extension("svg"); | ||
115 | std::fs::write(&svg, &out.stdout).unwrap(); | ||
116 | eprintln!("Profile rendered to:\n\n {}\n", svg.display()); | ||
117 | } | ||
118 | _ => { | ||
119 | eprintln!("Failed to run:\n\n {:?}\n", cmd); | ||
120 | } | ||
121 | } | ||
95 | } | 122 | } |
96 | } | 123 | } |
97 | } | 124 | } |
diff --git a/crates/rust-analyzer/src/benchmarks.rs b/crates/rust-analyzer/src/benchmarks.rs new file mode 100644 index 000000000..bf569b40b --- /dev/null +++ b/crates/rust-analyzer/src/benchmarks.rs | |||
@@ -0,0 +1,71 @@ | |||
1 | //! Fully integrated benchmarks for rust-analyzer, which load real cargo | ||
2 | //! projects. | ||
3 | //! | ||
4 | //! The benchmark here is used to debug specific performance regressions. If you | ||
5 | //! notice that, eg, completion is slow in some specific case, you can modify | ||
6 | //! code here exercise this specific completion, and thus have a fast | ||
7 | //! edit/compile/test cycle. | ||
8 | //! | ||
9 | //! Note that "Rust Analyzer: Run" action does not allow running a single test | ||
10 | //! in release mode in VS Code. There's however "Rust Analyzer: Copy Run Command Line" | ||
11 | //! which you can use to paste the command in terminal and add `--release` manually. | ||
12 | |||
13 | use std::sync::Arc; | ||
14 | |||
15 | use ide::Change; | ||
16 | use test_utils::project_root; | ||
17 | use vfs::{AbsPathBuf, VfsPath}; | ||
18 | |||
19 | use crate::cli::load_cargo::{load_workspace_at, LoadCargoConfig}; | ||
20 | |||
21 | #[test] | ||
22 | fn benchmark_integrated_highlighting() { | ||
23 | // Don't run slow benchmark by default | ||
24 | if true { | ||
25 | return; | ||
26 | } | ||
27 | |||
28 | // Load rust-analyzer itself. | ||
29 | let workspace_to_load = project_root(); | ||
30 | let file = "./crates/ide_db/src/apply_change.rs"; | ||
31 | |||
32 | let cargo_config = Default::default(); | ||
33 | let load_cargo_config = | ||
34 | LoadCargoConfig { load_out_dirs_from_check: true, with_proc_macro: false }; | ||
35 | |||
36 | let (mut host, vfs, _proc_macro) = { | ||
37 | let _it = stdx::timeit("workspace loading"); | ||
38 | load_workspace_at(&workspace_to_load, &cargo_config, &load_cargo_config, &|_| {}).unwrap() | ||
39 | }; | ||
40 | |||
41 | let file_id = { | ||
42 | let file = workspace_to_load.join(file); | ||
43 | let path = VfsPath::from(AbsPathBuf::assert(file)); | ||
44 | vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {}", path)) | ||
45 | }; | ||
46 | |||
47 | { | ||
48 | let _it = stdx::timeit("initial"); | ||
49 | let analysis = host.analysis(); | ||
50 | analysis.highlight_as_html(file_id, false).unwrap(); | ||
51 | } | ||
52 | |||
53 | profile::init_from("*>100"); | ||
54 | // let _s = profile::heartbeat_span(); | ||
55 | |||
56 | { | ||
57 | let _it = stdx::timeit("change"); | ||
58 | let mut text = host.analysis().file_text(file_id).unwrap().to_string(); | ||
59 | text.push_str("\npub fn _dummy() {}\n"); | ||
60 | let mut change = Change::new(); | ||
61 | change.change_file(file_id, Some(Arc::new(text))); | ||
62 | host.apply_change(change); | ||
63 | } | ||
64 | |||
65 | { | ||
66 | let _it = stdx::timeit("after change"); | ||
67 | let _span = profile::cpu_span(); | ||
68 | let analysis = host.analysis(); | ||
69 | analysis.highlight_as_html(file_id, false).unwrap(); | ||
70 | } | ||
71 | } | ||
diff --git a/crates/rust-analyzer/src/bin/flags.rs b/crates/rust-analyzer/src/bin/flags.rs index d8987633d..b05fc00b9 100644 --- a/crates/rust-analyzer/src/bin/flags.rs +++ b/crates/rust-analyzer/src/bin/flags.rs | |||
@@ -1,10 +1,9 @@ | |||
1 | //! Grammar for the command-line arguments. | 1 | //! Grammar for the command-line arguments. |
2 | #![allow(unreachable_pub)] | 2 | #![allow(unreachable_pub)] |
3 | use std::{env, path::PathBuf}; | 3 | use std::path::PathBuf; |
4 | 4 | ||
5 | use ide_ssr::{SsrPattern, SsrRule}; | 5 | use ide_ssr::{SsrPattern, SsrRule}; |
6 | use rust_analyzer::cli::{BenchWhat, Position, Verbosity}; | 6 | use rust_analyzer::cli::Verbosity; |
7 | use vfs::AbsPathBuf; | ||
8 | 7 | ||
9 | xflags::xflags! { | 8 | xflags::xflags! { |
10 | src "./src/bin/flags.rs" | 9 | src "./src/bin/flags.rs" |
@@ -74,27 +73,6 @@ xflags::xflags! { | |||
74 | optional --with-proc-macro | 73 | optional --with-proc-macro |
75 | } | 74 | } |
76 | 75 | ||
77 | /// Benchmark specific analysis operation | ||
78 | cmd analysis-bench | ||
79 | /// Directory with Cargo.toml. | ||
80 | required path: PathBuf | ||
81 | { | ||
82 | /// Collect memory usage statistics. | ||
83 | optional --memory-usage | ||
84 | |||
85 | /// Compute syntax highlighting for this file | ||
86 | optional --highlight path: PathBuf | ||
87 | /// Compute completions at file:line:column location. | ||
88 | optional --complete location: Position | ||
89 | /// Compute goto definition at file:line:column location. | ||
90 | optional --goto-def location: Position | ||
91 | |||
92 | /// Load OUT_DIR values by running `cargo check` before analysis. | ||
93 | optional --load-output-dirs | ||
94 | /// Use proc-macro-srv for proc-macro expanding. | ||
95 | optional --with-proc-macro | ||
96 | } | ||
97 | |||
98 | cmd diagnostics | 76 | cmd diagnostics |
99 | /// Directory with Cargo.toml. | 77 | /// Directory with Cargo.toml. |
100 | required path: PathBuf | 78 | required path: PathBuf |
@@ -142,7 +120,6 @@ pub enum RustAnalyzerCmd { | |||
142 | Symbols(Symbols), | 120 | Symbols(Symbols), |
143 | Highlight(Highlight), | 121 | Highlight(Highlight), |
144 | AnalysisStats(AnalysisStats), | 122 | AnalysisStats(AnalysisStats), |
145 | AnalysisBench(AnalysisBench), | ||
146 | Diagnostics(Diagnostics), | 123 | Diagnostics(Diagnostics), |
147 | Ssr(Ssr), | 124 | Ssr(Ssr), |
148 | Search(Search), | 125 | Search(Search), |
@@ -184,18 +161,6 @@ pub struct AnalysisStats { | |||
184 | } | 161 | } |
185 | 162 | ||
186 | #[derive(Debug)] | 163 | #[derive(Debug)] |
187 | pub struct AnalysisBench { | ||
188 | pub path: PathBuf, | ||
189 | |||
190 | pub memory_usage: bool, | ||
191 | pub highlight: Option<PathBuf>, | ||
192 | pub complete: Option<Position>, | ||
193 | pub goto_def: Option<Position>, | ||
194 | pub load_output_dirs: bool, | ||
195 | pub with_proc_macro: bool, | ||
196 | } | ||
197 | |||
198 | #[derive(Debug)] | ||
199 | pub struct Diagnostics { | 164 | pub struct Diagnostics { |
200 | pub path: PathBuf, | 165 | pub path: PathBuf, |
201 | 166 | ||
@@ -239,17 +204,3 @@ impl RustAnalyzer { | |||
239 | } | 204 | } |
240 | } | 205 | } |
241 | } | 206 | } |
242 | |||
243 | impl AnalysisBench { | ||
244 | pub(crate) fn what(&self) -> BenchWhat { | ||
245 | match (&self.highlight, &self.complete, &self.goto_def) { | ||
246 | (Some(path), None, None) => { | ||
247 | let path = env::current_dir().unwrap().join(path); | ||
248 | BenchWhat::Highlight { path: AbsPathBuf::assert(path) } | ||
249 | } | ||
250 | (None, Some(position), None) => BenchWhat::Complete(position.clone()), | ||
251 | (None, None, Some(position)) => BenchWhat::GotoDef(position.clone()), | ||
252 | _ => panic!("exactly one of `--highlight`, `--complete` or `--goto-def` must be set"), | ||
253 | } | ||
254 | } | ||
255 | } | ||
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index a0b611bff..ae99eefe3 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs | |||
@@ -9,7 +9,7 @@ use std::{convert::TryFrom, env, fs, path::Path, process}; | |||
9 | use lsp_server::Connection; | 9 | use lsp_server::Connection; |
10 | use project_model::ProjectManifest; | 10 | use project_model::ProjectManifest; |
11 | use rust_analyzer::{ | 11 | use rust_analyzer::{ |
12 | cli::{self, AnalysisStatsCmd, BenchCmd}, | 12 | cli::{self, AnalysisStatsCmd}, |
13 | config::Config, | 13 | config::Config, |
14 | from_json, | 14 | from_json, |
15 | lsp_ext::supports_utf8, | 15 | lsp_ext::supports_utf8, |
@@ -80,17 +80,6 @@ fn try_main() -> Result<()> { | |||
80 | with_proc_macro: cmd.with_proc_macro, | 80 | with_proc_macro: cmd.with_proc_macro, |
81 | } | 81 | } |
82 | .run(verbosity)?, | 82 | .run(verbosity)?, |
83 | flags::RustAnalyzerCmd::AnalysisBench(cmd) => { | ||
84 | let what = cmd.what(); | ||
85 | BenchCmd { | ||
86 | memory_usage: cmd.memory_usage, | ||
87 | path: cmd.path, | ||
88 | load_output_dirs: cmd.load_output_dirs, | ||
89 | with_proc_macro: cmd.with_proc_macro, | ||
90 | what, | ||
91 | } | ||
92 | .run(verbosity)? | ||
93 | } | ||
94 | 83 | ||
95 | flags::RustAnalyzerCmd::Diagnostics(cmd) => { | 84 | flags::RustAnalyzerCmd::Diagnostics(cmd) => { |
96 | cli::diagnostics(&cmd.path, cmd.load_output_dirs, cmd.with_proc_macro)? | 85 | cli::diagnostics(&cmd.path, cmd.load_output_dirs, cmd.with_proc_macro)? |
diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs index ed732eb38..76b666dc2 100644 --- a/crates/rust-analyzer/src/cli.rs +++ b/crates/rust-analyzer/src/cli.rs | |||
@@ -1,8 +1,7 @@ | |||
1 | //! Various batch processing tasks, intended primarily for debugging. | 1 | //! Various batch processing tasks, intended primarily for debugging. |
2 | 2 | ||
3 | mod load_cargo; | 3 | pub(crate) mod load_cargo; |
4 | mod analysis_stats; | 4 | mod analysis_stats; |
5 | mod analysis_bench; | ||
6 | mod diagnostics; | 5 | mod diagnostics; |
7 | mod progress_report; | 6 | mod progress_report; |
8 | mod ssr; | 7 | mod ssr; |
@@ -15,7 +14,6 @@ use syntax::{AstNode, SourceFile}; | |||
15 | use vfs::Vfs; | 14 | use vfs::Vfs; |
16 | 15 | ||
17 | pub use self::{ | 16 | pub use self::{ |
18 | analysis_bench::{BenchCmd, BenchWhat, Position}, | ||
19 | analysis_stats::AnalysisStatsCmd, | 17 | analysis_stats::AnalysisStatsCmd, |
20 | diagnostics::diagnostics, | 18 | diagnostics::diagnostics, |
21 | load_cargo::{load_workspace, load_workspace_at, LoadCargoConfig}, | 19 | load_cargo::{load_workspace, load_workspace_at, LoadCargoConfig}, |
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs deleted file mode 100644 index 49994824f..000000000 --- a/crates/rust-analyzer/src/cli/analysis_bench.rs +++ /dev/null | |||
@@ -1,196 +0,0 @@ | |||
1 | //! Benchmark operations like highlighting or goto definition. | ||
2 | |||
3 | use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant}; | ||
4 | |||
5 | use anyhow::{bail, format_err, Result}; | ||
6 | use hir::PrefixKind; | ||
7 | use ide::{ | ||
8 | Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol, | ||
9 | }; | ||
10 | use ide_db::{ | ||
11 | base_db::{ | ||
12 | salsa::{Database, Durability}, | ||
13 | FileId, | ||
14 | }, | ||
15 | helpers::{insert_use::InsertUseConfig, SnippetCap}, | ||
16 | }; | ||
17 | use vfs::AbsPathBuf; | ||
18 | |||
19 | use crate::cli::{ | ||
20 | load_cargo::{load_workspace_at, LoadCargoConfig}, | ||
21 | print_memory_usage, Verbosity, | ||
22 | }; | ||
23 | |||
24 | pub struct BenchCmd { | ||
25 | pub path: PathBuf, | ||
26 | pub what: BenchWhat, | ||
27 | pub memory_usage: bool, | ||
28 | pub load_output_dirs: bool, | ||
29 | pub with_proc_macro: bool, | ||
30 | } | ||
31 | |||
32 | pub enum BenchWhat { | ||
33 | Highlight { path: AbsPathBuf }, | ||
34 | Complete(Position), | ||
35 | GotoDef(Position), | ||
36 | } | ||
37 | |||
38 | #[derive(Debug, Clone)] | ||
39 | pub struct Position { | ||
40 | pub path: AbsPathBuf, | ||
41 | pub line: u32, | ||
42 | pub column: u32, | ||
43 | } | ||
44 | |||
45 | impl FromStr for Position { | ||
46 | type Err = anyhow::Error; | ||
47 | fn from_str(s: &str) -> Result<Self> { | ||
48 | let mut split = s.rsplitn(3, ':'); | ||
49 | match (split.next(), split.next(), split.next()) { | ||
50 | (Some(column), Some(line), Some(path)) => { | ||
51 | let path = env::current_dir().unwrap().join(path); | ||
52 | let path = AbsPathBuf::assert(path); | ||
53 | Ok(Position { path, line: line.parse()?, column: column.parse()? }) | ||
54 | } | ||
55 | _ => bail!("position should be in file:line:column format: {:?}", s), | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | |||
60 | impl BenchCmd { | ||
61 | pub fn run(self, verbosity: Verbosity) -> Result<()> { | ||
62 | profile::init(); | ||
63 | |||
64 | let start = Instant::now(); | ||
65 | eprint!("loading: "); | ||
66 | |||
67 | let cargo_config = Default::default(); | ||
68 | let load_cargo_config = LoadCargoConfig { | ||
69 | load_out_dirs_from_check: self.load_output_dirs, | ||
70 | with_proc_macro: self.with_proc_macro, | ||
71 | }; | ||
72 | let (mut host, vfs, _proc_macro) = | ||
73 | load_workspace_at(&self.path, &cargo_config, &load_cargo_config, &|_| {})?; | ||
74 | eprintln!("{:?}\n", start.elapsed()); | ||
75 | |||
76 | let file_id = { | ||
77 | let path = match &self.what { | ||
78 | BenchWhat::Highlight { path } => path, | ||
79 | BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => &pos.path, | ||
80 | }; | ||
81 | let path = path.clone().into(); | ||
82 | vfs.file_id(&path).ok_or_else(|| format_err!("Can't find {}", path))? | ||
83 | }; | ||
84 | |||
85 | match &self.what { | ||
86 | BenchWhat::Highlight { .. } => { | ||
87 | let res = do_work(&mut host, file_id, |analysis| { | ||
88 | analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap(); | ||
89 | analysis.highlight_as_html(file_id, false).unwrap() | ||
90 | }); | ||
91 | if verbosity.is_verbose() { | ||
92 | println!("\n{}", res); | ||
93 | } | ||
94 | } | ||
95 | BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => { | ||
96 | let is_completion = matches!(self.what, BenchWhat::Complete(..)); | ||
97 | |||
98 | let offset = host | ||
99 | .analysis() | ||
100 | .file_line_index(file_id)? | ||
101 | .offset(LineCol { line: pos.line - 1, col: pos.column }); | ||
102 | let file_position = FilePosition { file_id, offset }; | ||
103 | |||
104 | if is_completion { | ||
105 | let options = CompletionConfig { | ||
106 | enable_postfix_completions: true, | ||
107 | enable_imports_on_the_fly: true, | ||
108 | add_call_parenthesis: true, | ||
109 | add_call_argument_snippets: true, | ||
110 | snippet_cap: SnippetCap::new(true), | ||
111 | insert_use: InsertUseConfig { | ||
112 | merge: None, | ||
113 | prefix_kind: PrefixKind::Plain, | ||
114 | group: true, | ||
115 | }, | ||
116 | }; | ||
117 | let res = do_work(&mut host, file_id, |analysis| { | ||
118 | analysis.completions(&options, file_position) | ||
119 | }); | ||
120 | if verbosity.is_verbose() { | ||
121 | println!("\n{:#?}", res); | ||
122 | } | ||
123 | } else { | ||
124 | let res = do_work(&mut host, file_id, |analysis| { | ||
125 | analysis.goto_definition(file_position) | ||
126 | }); | ||
127 | if verbosity.is_verbose() { | ||
128 | println!("\n{:#?}", res); | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
134 | if self.memory_usage { | ||
135 | print_memory_usage(host, vfs); | ||
136 | } | ||
137 | |||
138 | Ok(()) | ||
139 | } | ||
140 | } | ||
141 | |||
142 | fn do_work<F: Fn(&Analysis) -> T, T>(host: &mut AnalysisHost, file_id: FileId, work: F) -> T { | ||
143 | { | ||
144 | let start = Instant::now(); | ||
145 | eprint!("from scratch: "); | ||
146 | work(&host.analysis()); | ||
147 | eprintln!("{:?}", start.elapsed()); | ||
148 | } | ||
149 | { | ||
150 | let start = Instant::now(); | ||
151 | eprint!("no change: "); | ||
152 | work(&host.analysis()); | ||
153 | eprintln!("{:?}", start.elapsed()); | ||
154 | } | ||
155 | { | ||
156 | let start = Instant::now(); | ||
157 | eprint!("trivial change: "); | ||
158 | host.raw_database_mut().salsa_runtime_mut().synthetic_write(Durability::LOW); | ||
159 | work(&host.analysis()); | ||
160 | eprintln!("{:?}", start.elapsed()); | ||
161 | } | ||
162 | { | ||
163 | let start = Instant::now(); | ||
164 | eprint!("comment change: "); | ||
165 | { | ||
166 | let mut text = host.analysis().file_text(file_id).unwrap().to_string(); | ||
167 | text.push_str("\n/* Hello world */\n"); | ||
168 | let mut change = Change::new(); | ||
169 | change.change_file(file_id, Some(Arc::new(text))); | ||
170 | host.apply_change(change); | ||
171 | } | ||
172 | work(&host.analysis()); | ||
173 | eprintln!("{:?}", start.elapsed()); | ||
174 | } | ||
175 | { | ||
176 | let start = Instant::now(); | ||
177 | eprint!("item change: "); | ||
178 | { | ||
179 | let mut text = host.analysis().file_text(file_id).unwrap().to_string(); | ||
180 | text.push_str("\npub fn _dummy() {}\n"); | ||
181 | let mut change = Change::new(); | ||
182 | change.change_file(file_id, Some(Arc::new(text))); | ||
183 | host.apply_change(change); | ||
184 | } | ||
185 | work(&host.analysis()); | ||
186 | eprintln!("{:?}", start.elapsed()); | ||
187 | } | ||
188 | { | ||
189 | let start = Instant::now(); | ||
190 | eprint!("const change: "); | ||
191 | host.raw_database_mut().salsa_runtime_mut().synthetic_write(Durability::HIGH); | ||
192 | let res = work(&host.analysis()); | ||
193 | eprintln!("{:?}", start.elapsed()); | ||
194 | res | ||
195 | } | ||
196 | } | ||
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index 8b874239c..d9a5030a0 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs | |||
@@ -39,6 +39,9 @@ mod op_queue; | |||
39 | pub mod lsp_ext; | 39 | pub mod lsp_ext; |
40 | pub mod config; | 40 | pub mod config; |
41 | 41 | ||
42 | #[cfg(test)] | ||
43 | mod benchmarks; | ||
44 | |||
42 | use serde::de::DeserializeOwned; | 45 | use serde::de::DeserializeOwned; |
43 | use std::fmt; | 46 | use std::fmt; |
44 | 47 | ||
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index a3c5e9ccf..2dc8a42f1 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs | |||
@@ -88,6 +88,7 @@ define_semantic_token_modifiers![ | |||
88 | (CONSUMING, "consuming"), | 88 | (CONSUMING, "consuming"), |
89 | (UNSAFE, "unsafe"), | 89 | (UNSAFE, "unsafe"), |
90 | (ATTRIBUTE_MODIFIER, "attribute"), | 90 | (ATTRIBUTE_MODIFIER, "attribute"), |
91 | (TRAIT_MODIFIER, "trait"), | ||
91 | (CALLABLE, "callable"), | 92 | (CALLABLE, "callable"), |
92 | (INTRA_DOC_LINK, "intraDocLink"), | 93 | (INTRA_DOC_LINK, "intraDocLink"), |
93 | ]; | 94 | ]; |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 530c8a5a4..c3820944b 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -474,6 +474,7 @@ fn semantic_token_type_and_modifiers( | |||
474 | HlMod::Callable => semantic_tokens::CALLABLE, | 474 | HlMod::Callable => semantic_tokens::CALLABLE, |
475 | HlMod::Static => lsp_types::SemanticTokenModifier::STATIC, | 475 | HlMod::Static => lsp_types::SemanticTokenModifier::STATIC, |
476 | HlMod::IntraDocLink => semantic_tokens::INTRA_DOC_LINK, | 476 | HlMod::IntraDocLink => semantic_tokens::INTRA_DOC_LINK, |
477 | HlMod::Trait => semantic_tokens::TRAIT_MODIFIER, | ||
477 | HlMod::Associated => continue, | 478 | HlMod::Associated => continue, |
478 | }; | 479 | }; |
479 | mods |= modifier; | 480 | mods |= modifier; |
@@ -492,7 +493,11 @@ pub(crate) fn folding_range( | |||
492 | FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment), | 493 | FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment), |
493 | FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports), | 494 | FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports), |
494 | FoldKind::Region => Some(lsp_types::FoldingRangeKind::Region), | 495 | FoldKind::Region => Some(lsp_types::FoldingRangeKind::Region), |
495 | FoldKind::Mods | FoldKind::Block | FoldKind::ArgList => None, | 496 | FoldKind::Mods |
497 | | FoldKind::Block | ||
498 | | FoldKind::ArgList | ||
499 | | FoldKind::Consts | ||
500 | | FoldKind::Statics => None, | ||
496 | }; | 501 | }; |
497 | 502 | ||
498 | let range = range(line_index, fold.range); | 503 | let range = range(line_index, fold.range); |
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index c08f2c14f..c6a7b99b7 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs | |||
@@ -268,14 +268,14 @@ pub fn arg_list(args: impl IntoIterator<Item = ast::Expr>) -> ast::ArgList { | |||
268 | } | 268 | } |
269 | 269 | ||
270 | pub fn ident_pat(name: ast::Name) -> ast::IdentPat { | 270 | pub fn ident_pat(name: ast::Name) -> ast::IdentPat { |
271 | return from_text(name.text()); | 271 | return from_text(&name.text()); |
272 | 272 | ||
273 | fn from_text(text: &str) -> ast::IdentPat { | 273 | fn from_text(text: &str) -> ast::IdentPat { |
274 | ast_from_text(&format!("fn f({}: ())", text)) | 274 | ast_from_text(&format!("fn f({}: ())", text)) |
275 | } | 275 | } |
276 | } | 276 | } |
277 | pub fn ident_mut_pat(name: ast::Name) -> ast::IdentPat { | 277 | pub fn ident_mut_pat(name: ast::Name) -> ast::IdentPat { |
278 | return from_text(name.text()); | 278 | return from_text(&name.text()); |
279 | 279 | ||
280 | fn from_text(text: &str) -> ast::IdentPat { | 280 | fn from_text(text: &str) -> ast::IdentPat { |
281 | ast_from_text(&format!("fn f(mut {}: ())", text)) | 281 | ast_from_text(&format!("fn f(mut {}: ())", text)) |
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index bdf907a21..ae98dbd26 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs | |||
@@ -8,23 +8,23 @@ use parser::SyntaxKind; | |||
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | ast::{self, support, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode}, | 10 | ast::{self, support, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode}, |
11 | SmolStr, SyntaxElement, SyntaxToken, T, | 11 | SmolStr, SyntaxElement, SyntaxToken, TokenText, T, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | impl ast::Lifetime { | 14 | impl ast::Lifetime { |
15 | pub fn text(&self) -> &str { | 15 | pub fn text(&self) -> TokenText { |
16 | text_of_first_token(self.syntax()) | 16 | text_of_first_token(self.syntax()) |
17 | } | 17 | } |
18 | } | 18 | } |
19 | 19 | ||
20 | impl ast::Name { | 20 | impl ast::Name { |
21 | pub fn text(&self) -> &str { | 21 | pub fn text(&self) -> TokenText { |
22 | text_of_first_token(self.syntax()) | 22 | text_of_first_token(self.syntax()) |
23 | } | 23 | } |
24 | } | 24 | } |
25 | 25 | ||
26 | impl ast::NameRef { | 26 | impl ast::NameRef { |
27 | pub fn text(&self) -> &str { | 27 | pub fn text(&self) -> TokenText { |
28 | text_of_first_token(self.syntax()) | 28 | text_of_first_token(self.syntax()) |
29 | } | 29 | } |
30 | 30 | ||
@@ -33,12 +33,14 @@ impl ast::NameRef { | |||
33 | } | 33 | } |
34 | } | 34 | } |
35 | 35 | ||
36 | fn text_of_first_token(node: &SyntaxNode) -> &str { | 36 | fn text_of_first_token(node: &SyntaxNode) -> TokenText { |
37 | let t = | 37 | let first_token = |
38 | node.green().children().next().and_then(|it| it.into_token()).unwrap().text().to_string(); | 38 | node.green().children().next().and_then(|it| it.into_token()).unwrap().to_owned(); |
39 | Box::leak(Box::new(t)) | 39 | |
40 | TokenText(first_token) | ||
40 | } | 41 | } |
41 | 42 | ||
43 | #[derive(Debug, PartialEq, Eq, Clone)] | ||
42 | pub enum Macro { | 44 | pub enum Macro { |
43 | MacroRules(ast::MacroRules), | 45 | MacroRules(ast::MacroRules), |
44 | MacroDef(ast::MacroDef), | 46 | MacroDef(ast::MacroDef), |
@@ -378,7 +380,7 @@ impl fmt::Display for NameOrNameRef { | |||
378 | } | 380 | } |
379 | 381 | ||
380 | impl NameOrNameRef { | 382 | impl NameOrNameRef { |
381 | pub fn text(&self) -> &str { | 383 | pub fn text(&self) -> TokenText { |
382 | match self { | 384 | match self { |
383 | NameOrNameRef::Name(name) => name.text(), | 385 | NameOrNameRef::Name(name) => name.text(), |
384 | NameOrNameRef::NameRef(name_ref) => name_ref.text(), | 386 | NameOrNameRef::NameRef(name_ref) => name_ref.text(), |
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index 2a5c61171..90de6bef6 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs | |||
@@ -29,6 +29,7 @@ mod syntax_error; | |||
29 | mod parsing; | 29 | mod parsing; |
30 | mod validation; | 30 | mod validation; |
31 | mod ptr; | 31 | mod ptr; |
32 | mod token_text; | ||
32 | #[cfg(test)] | 33 | #[cfg(test)] |
33 | mod tests; | 34 | mod tests; |
34 | 35 | ||
@@ -55,6 +56,7 @@ pub use crate::{ | |||
55 | SyntaxElement, SyntaxElementChildren, SyntaxNode, SyntaxNodeChildren, SyntaxToken, | 56 | SyntaxElement, SyntaxElementChildren, SyntaxNode, SyntaxNodeChildren, SyntaxToken, |
56 | SyntaxTreeBuilder, | 57 | SyntaxTreeBuilder, |
57 | }, | 58 | }, |
59 | token_text::TokenText, | ||
58 | }; | 60 | }; |
59 | pub use parser::{SyntaxKind, T}; | 61 | pub use parser::{SyntaxKind, T}; |
60 | pub use rowan::{ | 62 | pub use rowan::{ |
diff --git a/crates/syntax/src/parsing/text_tree_sink.rs b/crates/syntax/src/parsing/text_tree_sink.rs index bb10f20c9..1934204ea 100644 --- a/crates/syntax/src/parsing/text_tree_sink.rs +++ b/crates/syntax/src/parsing/text_tree_sink.rs | |||
@@ -147,8 +147,8 @@ fn n_attached_trivias<'a>( | |||
147 | trivias: impl Iterator<Item = (SyntaxKind, &'a str)>, | 147 | trivias: impl Iterator<Item = (SyntaxKind, &'a str)>, |
148 | ) -> usize { | 148 | ) -> usize { |
149 | match kind { | 149 | match kind { |
150 | MACRO_CALL | MACRO_RULES | CONST | TYPE_ALIAS | STRUCT | UNION | ENUM | VARIANT | FN | 150 | MACRO_CALL | MACRO_RULES | MACRO_DEF | CONST | TYPE_ALIAS | STRUCT | UNION | ENUM |
151 | | TRAIT | MODULE | RECORD_FIELD | STATIC | USE => { | 151 | | VARIANT | FN | TRAIT | MODULE | RECORD_FIELD | STATIC | USE => { |
152 | let mut res = 0; | 152 | let mut res = 0; |
153 | let mut trivias = trivias.enumerate().peekable(); | 153 | let mut trivias = trivias.enumerate().peekable(); |
154 | 154 | ||
diff --git a/crates/syntax/src/token_text.rs b/crates/syntax/src/token_text.rs new file mode 100644 index 000000000..d2ed0a12a --- /dev/null +++ b/crates/syntax/src/token_text.rs | |||
@@ -0,0 +1,77 @@ | |||
1 | //! Yet another version of owned string, backed by a syntax tree token. | ||
2 | |||
3 | use std::{cmp::Ordering, fmt, ops}; | ||
4 | |||
5 | pub struct TokenText(pub(crate) rowan::GreenToken); | ||
6 | |||
7 | impl TokenText { | ||
8 | pub fn as_str(&self) -> &str { | ||
9 | self.0.text() | ||
10 | } | ||
11 | } | ||
12 | |||
13 | impl ops::Deref for TokenText { | ||
14 | type Target = str; | ||
15 | |||
16 | fn deref(&self) -> &str { | ||
17 | self.as_str() | ||
18 | } | ||
19 | } | ||
20 | impl AsRef<str> for TokenText { | ||
21 | fn as_ref(&self) -> &str { | ||
22 | self.as_str() | ||
23 | } | ||
24 | } | ||
25 | |||
26 | impl From<TokenText> for String { | ||
27 | fn from(token_text: TokenText) -> Self { | ||
28 | token_text.as_str().into() | ||
29 | } | ||
30 | } | ||
31 | |||
32 | impl PartialEq<&'_ str> for TokenText { | ||
33 | fn eq(&self, other: &&str) -> bool { | ||
34 | self.as_str() == *other | ||
35 | } | ||
36 | } | ||
37 | impl PartialEq<TokenText> for &'_ str { | ||
38 | fn eq(&self, other: &TokenText) -> bool { | ||
39 | other == self | ||
40 | } | ||
41 | } | ||
42 | impl PartialEq<String> for TokenText { | ||
43 | fn eq(&self, other: &String) -> bool { | ||
44 | self.as_str() == other.as_str() | ||
45 | } | ||
46 | } | ||
47 | impl PartialEq<TokenText> for String { | ||
48 | fn eq(&self, other: &TokenText) -> bool { | ||
49 | other == self | ||
50 | } | ||
51 | } | ||
52 | impl PartialEq for TokenText { | ||
53 | fn eq(&self, other: &TokenText) -> bool { | ||
54 | self.as_str() == other.as_str() | ||
55 | } | ||
56 | } | ||
57 | impl Eq for TokenText {} | ||
58 | impl Ord for TokenText { | ||
59 | fn cmp(&self, other: &Self) -> Ordering { | ||
60 | self.as_str().cmp(other.as_str()) | ||
61 | } | ||
62 | } | ||
63 | impl PartialOrd for TokenText { | ||
64 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||
65 | Some(self.cmp(other)) | ||
66 | } | ||
67 | } | ||
68 | impl fmt::Display for TokenText { | ||
69 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
70 | fmt::Display::fmt(self.as_str(), f) | ||
71 | } | ||
72 | } | ||
73 | impl fmt::Debug for TokenText { | ||
74 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
75 | fmt::Debug::fmt(self.as_str(), f) | ||
76 | } | ||
77 | } | ||