diff options
28 files changed, 258 insertions, 180 deletions
diff --git a/Cargo.toml b/Cargo.toml index 46c64d35c..d34251fc0 100644 --- a/Cargo.toml +++ b/Cargo.toml | |||
@@ -27,3 +27,5 @@ debug = 0 # Set this to 1 or 2 to get more useful backtraces in debugger. | |||
27 | # chalk-recursive = { path = "../chalk/chalk-recursive" } | 27 | # chalk-recursive = { path = "../chalk/chalk-recursive" } |
28 | 28 | ||
29 | # ungrammar = { path = "../ungrammar" } | 29 | # ungrammar = { path = "../ungrammar" } |
30 | |||
31 | # salsa = { path = "../salsa" } | ||
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index 4a11622fc..e8fa3c56e 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs | |||
@@ -112,7 +112,7 @@ fn resolve_doc_path( | |||
112 | AttrDefId::MacroDefId(_) => return None, | 112 | AttrDefId::MacroDefId(_) => return None, |
113 | }; | 113 | }; |
114 | let path = ast::Path::parse(link).ok()?; | 114 | let path = ast::Path::parse(link).ok()?; |
115 | let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap(); | 115 | let modpath = ModPath::from_src(db.upcast(), path, &Hygiene::new_unhygienic()).unwrap(); |
116 | let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath); | 116 | let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath); |
117 | if resolved == PerNs::none() { | 117 | if resolved == PerNs::none() { |
118 | if let Some(trait_id) = resolver.resolve_module_path_in_trait_items(db.upcast(), &modpath) { | 118 | if let Some(trait_id) = resolver.resolve_module_path_in_trait_items(db.upcast(), &modpath) { |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 6fcc58f61..f876339de 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -1666,7 +1666,7 @@ impl Impl { | |||
1666 | .value | 1666 | .value |
1667 | .attrs() | 1667 | .attrs() |
1668 | .filter_map(|it| { | 1668 | .filter_map(|it| { |
1669 | let path = ModPath::from_src(it.path()?, &hygenic)?; | 1669 | let path = ModPath::from_src(db.upcast(), it.path()?, &hygenic)?; |
1670 | if path.as_ident()?.to_string() == "derive" { | 1670 | if path.as_ident()?.to_string() == "derive" { |
1671 | Some(it) | 1671 | Some(it) |
1672 | } else { | 1672 | } else { |
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 0895bd6f1..b5c65808e 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs | |||
@@ -283,7 +283,7 @@ impl SourceAnalyzer { | |||
283 | 283 | ||
284 | // This must be a normal source file rather than macro file. | 284 | // This must be a normal source file rather than macro file. |
285 | let hygiene = Hygiene::new(db.upcast(), self.file_id); | 285 | let hygiene = Hygiene::new(db.upcast(), self.file_id); |
286 | let ctx = body::LowerCtx::with_hygiene(&hygiene); | 286 | let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene); |
287 | let hir_path = Path::from_src(path.clone(), &ctx)?; | 287 | let hir_path = Path::from_src(path.clone(), &ctx)?; |
288 | 288 | ||
289 | // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we | 289 | // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we |
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 0171d8a92..a2479016e 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -95,13 +95,17 @@ impl ops::Deref for AttrsWithOwner { | |||
95 | impl RawAttrs { | 95 | impl RawAttrs { |
96 | pub(crate) const EMPTY: Self = Self { entries: None }; | 96 | pub(crate) const EMPTY: Self = Self { entries: None }; |
97 | 97 | ||
98 | pub(crate) fn new(owner: &dyn ast::AttrsOwner, hygiene: &Hygiene) -> Self { | 98 | pub(crate) fn new( |
99 | db: &dyn DefDatabase, | ||
100 | owner: &dyn ast::AttrsOwner, | ||
101 | hygiene: &Hygiene, | ||
102 | ) -> Self { | ||
99 | let entries = collect_attrs(owner) | 103 | let entries = collect_attrs(owner) |
100 | .enumerate() | 104 | .enumerate() |
101 | .flat_map(|(i, attr)| { | 105 | .flat_map(|(i, attr)| { |
102 | let index = AttrId(i as u32); | 106 | let index = AttrId(i as u32); |
103 | match attr { | 107 | match attr { |
104 | Either::Left(attr) => Attr::from_src(attr, hygiene, index), | 108 | Either::Left(attr) => Attr::from_src(db, attr, hygiene, index), |
105 | Either::Right(comment) => comment.doc_comment().map(|doc| Attr { | 109 | Either::Right(comment) => comment.doc_comment().map(|doc| Attr { |
106 | id: index, | 110 | id: index, |
107 | input: Some(AttrInput::Literal(SmolStr::new(doc))), | 111 | input: Some(AttrInput::Literal(SmolStr::new(doc))), |
@@ -116,7 +120,7 @@ impl RawAttrs { | |||
116 | 120 | ||
117 | fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn ast::AttrsOwner>) -> Self { | 121 | fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn ast::AttrsOwner>) -> Self { |
118 | let hygiene = Hygiene::new(db.upcast(), owner.file_id); | 122 | let hygiene = Hygiene::new(db.upcast(), owner.file_id); |
119 | Self::new(owner.value, &hygiene) | 123 | Self::new(db, owner.value, &hygiene) |
120 | } | 124 | } |
121 | 125 | ||
122 | pub(crate) fn merge(&self, other: Self) -> Self { | 126 | pub(crate) fn merge(&self, other: Self) -> Self { |
@@ -170,7 +174,7 @@ impl RawAttrs { | |||
170 | let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; | 174 | let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; |
171 | // FIXME hygiene | 175 | // FIXME hygiene |
172 | let hygiene = Hygiene::new_unhygienic(); | 176 | let hygiene = Hygiene::new_unhygienic(); |
173 | Attr::from_src(attr, &hygiene, index) | 177 | Attr::from_src(db, attr, &hygiene, index) |
174 | }); | 178 | }); |
175 | 179 | ||
176 | let cfg_options = &crate_graph[krate].cfg_options; | 180 | let cfg_options = &crate_graph[krate].cfg_options; |
@@ -627,8 +631,13 @@ pub enum AttrInput { | |||
627 | } | 631 | } |
628 | 632 | ||
629 | impl Attr { | 633 | impl Attr { |
630 | fn from_src(ast: ast::Attr, hygiene: &Hygiene, id: AttrId) -> Option<Attr> { | 634 | fn from_src( |
631 | let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?); | 635 | db: &dyn DefDatabase, |
636 | ast: ast::Attr, | ||
637 | hygiene: &Hygiene, | ||
638 | id: AttrId, | ||
639 | ) -> Option<Attr> { | ||
640 | let path = Interned::new(ModPath::from_src(db, ast.path()?, hygiene)?); | ||
632 | let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { | 641 | let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { |
633 | let value = match lit.kind() { | 642 | let value = match lit.kind() { |
634 | ast::LiteralKind::String(string) => string.value()?.into(), | 643 | ast::LiteralKind::String(string) => string.value()?.into(), |
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index 131f424cc..8360426f1 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs | |||
@@ -72,7 +72,7 @@ impl CfgExpander { | |||
72 | } | 72 | } |
73 | 73 | ||
74 | pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> Attrs { | 74 | pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> Attrs { |
75 | RawAttrs::new(owner, &self.hygiene).filter(db, self.krate) | 75 | RawAttrs::new(db, owner, &self.hygiene).filter(db, self.krate) |
76 | } | 76 | } |
77 | 77 | ||
78 | pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> bool { | 78 | pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> bool { |
@@ -192,8 +192,8 @@ impl Expander { | |||
192 | self.current_file_id | 192 | self.current_file_id |
193 | } | 193 | } |
194 | 194 | ||
195 | fn parse_path(&mut self, path: ast::Path) -> Option<Path> { | 195 | fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> { |
196 | let ctx = LowerCtx::with_hygiene(&self.cfg_expander.hygiene); | 196 | let ctx = LowerCtx::with_hygiene(db, &self.cfg_expander.hygiene); |
197 | Path::from_src(path, &ctx) | 197 | Path::from_src(path, &ctx) |
198 | } | 198 | } |
199 | 199 | ||
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index c11da30d2..75dc19c11 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs | |||
@@ -40,23 +40,25 @@ use crate::{ | |||
40 | 40 | ||
41 | use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; | 41 | use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; |
42 | 42 | ||
43 | pub struct LowerCtx { | 43 | pub struct LowerCtx<'a> { |
44 | pub db: &'a dyn DefDatabase, | ||
44 | hygiene: Hygiene, | 45 | hygiene: Hygiene, |
45 | file_id: Option<HirFileId>, | 46 | file_id: Option<HirFileId>, |
46 | source_ast_id_map: Option<Arc<AstIdMap>>, | 47 | source_ast_id_map: Option<Arc<AstIdMap>>, |
47 | } | 48 | } |
48 | 49 | ||
49 | impl LowerCtx { | 50 | impl<'a> LowerCtx<'a> { |
50 | pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { | 51 | pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self { |
51 | LowerCtx { | 52 | LowerCtx { |
53 | db, | ||
52 | hygiene: Hygiene::new(db.upcast(), file_id), | 54 | hygiene: Hygiene::new(db.upcast(), file_id), |
53 | file_id: Some(file_id), | 55 | file_id: Some(file_id), |
54 | source_ast_id_map: Some(db.ast_id_map(file_id)), | 56 | source_ast_id_map: Some(db.ast_id_map(file_id)), |
55 | } | 57 | } |
56 | } | 58 | } |
57 | 59 | ||
58 | pub fn with_hygiene(hygiene: &Hygiene) -> Self { | 60 | pub fn with_hygiene(db: &'a dyn DefDatabase, hygiene: &Hygiene) -> Self { |
59 | LowerCtx { hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None } | 61 | LowerCtx { db, hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None } |
60 | } | 62 | } |
61 | 63 | ||
62 | pub(crate) fn hygiene(&self) -> &Hygiene { | 64 | pub(crate) fn hygiene(&self) -> &Hygiene { |
@@ -145,7 +147,7 @@ impl ExprCollector<'_> { | |||
145 | (self.body, self.source_map) | 147 | (self.body, self.source_map) |
146 | } | 148 | } |
147 | 149 | ||
148 | fn ctx(&self) -> LowerCtx { | 150 | fn ctx(&self) -> LowerCtx<'_> { |
149 | LowerCtx::new(self.db, self.expander.current_file_id) | 151 | LowerCtx::new(self.db, self.expander.current_file_id) |
150 | } | 152 | } |
151 | 153 | ||
@@ -376,7 +378,7 @@ impl ExprCollector<'_> { | |||
376 | ast::Expr::PathExpr(e) => { | 378 | ast::Expr::PathExpr(e) => { |
377 | let path = e | 379 | let path = e |
378 | .path() | 380 | .path() |
379 | .and_then(|path| self.expander.parse_path(path)) | 381 | .and_then(|path| self.expander.parse_path(self.db, path)) |
380 | .map(Expr::Path) | 382 | .map(Expr::Path) |
381 | .unwrap_or(Expr::Missing); | 383 | .unwrap_or(Expr::Missing); |
382 | self.alloc_expr(path, syntax_ptr) | 384 | self.alloc_expr(path, syntax_ptr) |
@@ -408,7 +410,8 @@ impl ExprCollector<'_> { | |||
408 | self.alloc_expr(Expr::Yield { expr }, syntax_ptr) | 410 | self.alloc_expr(Expr::Yield { expr }, syntax_ptr) |
409 | } | 411 | } |
410 | ast::Expr::RecordExpr(e) => { | 412 | ast::Expr::RecordExpr(e) => { |
411 | let path = e.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); | 413 | let path = |
414 | e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); | ||
412 | let record_lit = if let Some(nfl) = e.record_expr_field_list() { | 415 | let record_lit = if let Some(nfl) = e.record_expr_field_list() { |
413 | let fields = nfl | 416 | let fields = nfl |
414 | .fields() | 417 | .fields() |
@@ -791,7 +794,8 @@ impl ExprCollector<'_> { | |||
791 | } | 794 | } |
792 | } | 795 | } |
793 | ast::Pat::TupleStructPat(p) => { | 796 | ast::Pat::TupleStructPat(p) => { |
794 | let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); | 797 | let path = |
798 | p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); | ||
795 | let (args, ellipsis) = self.collect_tuple_pat(p.fields()); | 799 | let (args, ellipsis) = self.collect_tuple_pat(p.fields()); |
796 | Pat::TupleStruct { path, args, ellipsis } | 800 | Pat::TupleStruct { path, args, ellipsis } |
797 | } | 801 | } |
@@ -801,7 +805,8 @@ impl ExprCollector<'_> { | |||
801 | Pat::Ref { pat, mutability } | 805 | Pat::Ref { pat, mutability } |
802 | } | 806 | } |
803 | ast::Pat::PathPat(p) => { | 807 | ast::Pat::PathPat(p) => { |
804 | let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); | 808 | let path = |
809 | p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); | ||
805 | path.map(Pat::Path).unwrap_or(Pat::Missing) | 810 | path.map(Pat::Path).unwrap_or(Pat::Missing) |
806 | } | 811 | } |
807 | ast::Pat::OrPat(p) => { | 812 | ast::Pat::OrPat(p) => { |
@@ -815,7 +820,8 @@ impl ExprCollector<'_> { | |||
815 | } | 820 | } |
816 | ast::Pat::WildcardPat(_) => Pat::Wild, | 821 | ast::Pat::WildcardPat(_) => Pat::Wild, |
817 | ast::Pat::RecordPat(p) => { | 822 | ast::Pat::RecordPat(p) => { |
818 | let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); | 823 | let path = |
824 | p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); | ||
819 | let args: Vec<_> = p | 825 | let args: Vec<_> = p |
820 | .record_pat_field_list() | 826 | .record_pat_field_list() |
821 | .expect("every struct should have a field list") | 827 | .expect("every struct should have a field list") |
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs index c06a37294..858e88038 100644 --- a/crates/hir_def/src/find_path.rs +++ b/crates/hir_def/src/find_path.rs | |||
@@ -386,7 +386,7 @@ mod tests { | |||
386 | let parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path)); | 386 | let parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path)); |
387 | let ast_path = | 387 | let ast_path = |
388 | parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap(); | 388 | parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap(); |
389 | let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap(); | 389 | let mod_path = ModPath::from_src(&db, ast_path, &Hygiene::new_unhygienic()).unwrap(); |
390 | 390 | ||
391 | let def_map = module.def_map(&db); | 391 | let def_map = module.def_map(&db); |
392 | let resolved = def_map | 392 | let resolved = def_map |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index eaeca01bd..8d13c7e04 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -88,7 +88,7 @@ impl ItemTree { | |||
88 | let mut item_tree = match_ast! { | 88 | let mut item_tree = match_ast! { |
89 | match syntax { | 89 | match syntax { |
90 | ast::SourceFile(file) => { | 90 | ast::SourceFile(file) => { |
91 | top_attrs = Some(RawAttrs::new(&file, &hygiene)); | 91 | top_attrs = Some(RawAttrs::new(db, &file, &hygiene)); |
92 | ctx.lower_module_items(&file) | 92 | ctx.lower_module_items(&file) |
93 | }, | 93 | }, |
94 | ast::MacroItems(items) => { | 94 | ast::MacroItems(items) => { |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 45b099cf3..5743b3386 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -31,18 +31,20 @@ where | |||
31 | } | 31 | } |
32 | } | 32 | } |
33 | 33 | ||
34 | pub(super) struct Ctx { | 34 | pub(super) struct Ctx<'a> { |
35 | db: &'a dyn DefDatabase, | ||
35 | tree: ItemTree, | 36 | tree: ItemTree, |
36 | hygiene: Hygiene, | 37 | hygiene: Hygiene, |
37 | file: HirFileId, | 38 | file: HirFileId, |
38 | source_ast_id_map: Arc<AstIdMap>, | 39 | source_ast_id_map: Arc<AstIdMap>, |
39 | body_ctx: crate::body::LowerCtx, | 40 | body_ctx: crate::body::LowerCtx<'a>, |
40 | forced_visibility: Option<RawVisibilityId>, | 41 | forced_visibility: Option<RawVisibilityId>, |
41 | } | 42 | } |
42 | 43 | ||
43 | impl Ctx { | 44 | impl<'a> Ctx<'a> { |
44 | pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self { | 45 | pub(super) fn new(db: &'a dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self { |
45 | Self { | 46 | Self { |
47 | db, | ||
46 | tree: ItemTree::default(), | 48 | tree: ItemTree::default(), |
47 | hygiene, | 49 | hygiene, |
48 | file, | 50 | file, |
@@ -126,7 +128,7 @@ impl Ctx { | |||
126 | | ast::Item::MacroDef(_) => {} | 128 | | ast::Item::MacroDef(_) => {} |
127 | }; | 129 | }; |
128 | 130 | ||
129 | let attrs = RawAttrs::new(item, &self.hygiene); | 131 | let attrs = RawAttrs::new(self.db, item, &self.hygiene); |
130 | let items = match item { | 132 | let items = match item { |
131 | ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into), | 133 | ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into), |
132 | ast::Item::Union(ast) => self.lower_union(ast).map(Into::into), | 134 | ast::Item::Union(ast) => self.lower_union(ast).map(Into::into), |
@@ -256,7 +258,7 @@ impl Ctx { | |||
256 | for field in fields.fields() { | 258 | for field in fields.fields() { |
257 | if let Some(data) = self.lower_record_field(&field) { | 259 | if let Some(data) = self.lower_record_field(&field) { |
258 | let idx = self.data().fields.alloc(data); | 260 | let idx = self.data().fields.alloc(data); |
259 | self.add_attrs(idx.into(), RawAttrs::new(&field, &self.hygiene)); | 261 | self.add_attrs(idx.into(), RawAttrs::new(self.db, &field, &self.hygiene)); |
260 | } | 262 | } |
261 | } | 263 | } |
262 | let end = self.next_field_idx(); | 264 | let end = self.next_field_idx(); |
@@ -276,7 +278,7 @@ impl Ctx { | |||
276 | for (i, field) in fields.fields().enumerate() { | 278 | for (i, field) in fields.fields().enumerate() { |
277 | let data = self.lower_tuple_field(i, &field); | 279 | let data = self.lower_tuple_field(i, &field); |
278 | let idx = self.data().fields.alloc(data); | 280 | let idx = self.data().fields.alloc(data); |
279 | self.add_attrs(idx.into(), RawAttrs::new(&field, &self.hygiene)); | 281 | self.add_attrs(idx.into(), RawAttrs::new(self.db, &field, &self.hygiene)); |
280 | } | 282 | } |
281 | let end = self.next_field_idx(); | 283 | let end = self.next_field_idx(); |
282 | IdRange::new(start..end) | 284 | IdRange::new(start..end) |
@@ -321,7 +323,7 @@ impl Ctx { | |||
321 | for variant in variants.variants() { | 323 | for variant in variants.variants() { |
322 | if let Some(data) = self.lower_variant(&variant) { | 324 | if let Some(data) = self.lower_variant(&variant) { |
323 | let idx = self.data().variants.alloc(data); | 325 | let idx = self.data().variants.alloc(data); |
324 | self.add_attrs(idx.into(), RawAttrs::new(&variant, &self.hygiene)); | 326 | self.add_attrs(idx.into(), RawAttrs::new(self.db, &variant, &self.hygiene)); |
325 | } | 327 | } |
326 | } | 328 | } |
327 | let end = self.next_variant_idx(); | 329 | let end = self.next_variant_idx(); |
@@ -364,7 +366,7 @@ impl Ctx { | |||
364 | }; | 366 | }; |
365 | let ty = Interned::new(self_type); | 367 | let ty = Interned::new(self_type); |
366 | let idx = self.data().params.alloc(Param::Normal(ty)); | 368 | let idx = self.data().params.alloc(Param::Normal(ty)); |
367 | self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene)); | 369 | self.add_attrs(idx.into(), RawAttrs::new(self.db, &self_param, &self.hygiene)); |
368 | has_self_param = true; | 370 | has_self_param = true; |
369 | } | 371 | } |
370 | for param in param_list.params() { | 372 | for param in param_list.params() { |
@@ -376,7 +378,7 @@ impl Ctx { | |||
376 | self.data().params.alloc(Param::Normal(ty)) | 378 | self.data().params.alloc(Param::Normal(ty)) |
377 | } | 379 | } |
378 | }; | 380 | }; |
379 | self.add_attrs(idx.into(), RawAttrs::new(¶m, &self.hygiene)); | 381 | self.add_attrs(idx.into(), RawAttrs::new(self.db, ¶m, &self.hygiene)); |
380 | } | 382 | } |
381 | } | 383 | } |
382 | let end_param = self.next_param_idx(); | 384 | let end_param = self.next_param_idx(); |
@@ -522,10 +524,11 @@ impl Ctx { | |||
522 | let is_unsafe = trait_def.unsafe_token().is_some(); | 524 | let is_unsafe = trait_def.unsafe_token().is_some(); |
523 | let bounds = self.lower_type_bounds(trait_def); | 525 | let bounds = self.lower_type_bounds(trait_def); |
524 | let items = trait_def.assoc_item_list().map(|list| { | 526 | let items = trait_def.assoc_item_list().map(|list| { |
527 | let db = self.db; | ||
525 | self.with_inherited_visibility(visibility, |this| { | 528 | self.with_inherited_visibility(visibility, |this| { |
526 | list.assoc_items() | 529 | list.assoc_items() |
527 | .filter_map(|item| { | 530 | .filter_map(|item| { |
528 | let attrs = RawAttrs::new(&item, &this.hygiene); | 531 | let attrs = RawAttrs::new(db, &item, &this.hygiene); |
529 | this.collect_inner_items(item.syntax()); | 532 | this.collect_inner_items(item.syntax()); |
530 | this.lower_assoc_item(&item).map(|item| { | 533 | this.lower_assoc_item(&item).map(|item| { |
531 | this.add_attrs(ModItem::from(item).into(), attrs); | 534 | this.add_attrs(ModItem::from(item).into(), attrs); |
@@ -567,7 +570,7 @@ impl Ctx { | |||
567 | .filter_map(|item| { | 570 | .filter_map(|item| { |
568 | self.collect_inner_items(item.syntax()); | 571 | self.collect_inner_items(item.syntax()); |
569 | let assoc = self.lower_assoc_item(&item)?; | 572 | let assoc = self.lower_assoc_item(&item)?; |
570 | let attrs = RawAttrs::new(&item, &self.hygiene); | 573 | let attrs = RawAttrs::new(self.db, &item, &self.hygiene); |
571 | self.add_attrs(ModItem::from(assoc).into(), attrs); | 574 | self.add_attrs(ModItem::from(assoc).into(), attrs); |
572 | Some(assoc) | 575 | Some(assoc) |
573 | }) | 576 | }) |
@@ -585,6 +588,7 @@ impl Ctx { | |||
585 | let mut imports = Vec::new(); | 588 | let mut imports = Vec::new(); |
586 | let tree = self.tree.data_mut(); | 589 | let tree = self.tree.data_mut(); |
587 | ModPath::expand_use_item( | 590 | ModPath::expand_use_item( |
591 | self.db, | ||
588 | InFile::new(self.file, use_item.clone()), | 592 | InFile::new(self.file, use_item.clone()), |
589 | &self.hygiene, | 593 | &self.hygiene, |
590 | |path, _use_tree, is_glob, alias| { | 594 | |path, _use_tree, is_glob, alias| { |
@@ -618,7 +622,7 @@ impl Ctx { | |||
618 | } | 622 | } |
619 | 623 | ||
620 | fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> { | 624 | fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> { |
621 | let path = Interned::new(ModPath::from_src(m.path()?, &self.hygiene)?); | 625 | let path = Interned::new(ModPath::from_src(self.db, m.path()?, &self.hygiene)?); |
622 | let ast_id = self.source_ast_id_map.ast_id(m); | 626 | let ast_id = self.source_ast_id_map.ast_id(m); |
623 | let res = MacroCall { path, ast_id }; | 627 | let res = MacroCall { path, ast_id }; |
624 | Some(id(self.data().macro_calls.alloc(res))) | 628 | Some(id(self.data().macro_calls.alloc(res))) |
@@ -647,7 +651,7 @@ impl Ctx { | |||
647 | list.extern_items() | 651 | list.extern_items() |
648 | .filter_map(|item| { | 652 | .filter_map(|item| { |
649 | self.collect_inner_items(item.syntax()); | 653 | self.collect_inner_items(item.syntax()); |
650 | let attrs = RawAttrs::new(&item, &self.hygiene); | 654 | let attrs = RawAttrs::new(self.db, &item, &self.hygiene); |
651 | let id: ModItem = match item { | 655 | let id: ModItem = match item { |
652 | ast::ExternItem::Fn(ast) => { | 656 | ast::ExternItem::Fn(ast) => { |
653 | let func_id = self.lower_function(&ast)?; | 657 | let func_id = self.lower_function(&ast)?; |
@@ -755,7 +759,7 @@ impl Ctx { | |||
755 | fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId { | 759 | fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId { |
756 | let vis = match self.forced_visibility { | 760 | let vis = match self.forced_visibility { |
757 | Some(vis) => return vis, | 761 | Some(vis) => return vis, |
758 | None => RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene), | 762 | None => RawVisibility::from_ast_with_hygiene(self.db, item.visibility(), &self.hygiene), |
759 | }; | 763 | }; |
760 | 764 | ||
761 | self.data().vis.alloc(vis) | 765 | self.data().vis.alloc(vis) |
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index 25694f037..da46f16f7 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -654,7 +654,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> { | |||
654 | ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> { | 654 | ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> { |
655 | let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); | 655 | let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); |
656 | let h = Hygiene::new(db.upcast(), self.file_id); | 656 | let h = Hygiene::new(db.upcast(), self.file_id); |
657 | let path = self.value.path().and_then(|path| path::ModPath::from_src(path, &h)); | 657 | let path = self.value.path().and_then(|path| path::ModPath::from_src(db, path, &h)); |
658 | 658 | ||
659 | let path = match error_sink | 659 | let path = match error_sink |
660 | .option(path, || mbe::ExpandError::Other("malformed macro invocation".into())) | 660 | .option(path, || mbe::ExpandError::Other("malformed macro invocation".into())) |
@@ -712,7 +712,7 @@ fn macro_call_as_call_id( | |||
712 | krate, | 712 | krate, |
713 | macro_call, | 713 | macro_call, |
714 | def, | 714 | def, |
715 | &|path: ast::Path| resolver(path::ModPath::from_src(path, &hygiene)?), | 715 | &|path: ast::Path| resolver(path::ModPath::from_src(db, path, &hygiene)?), |
716 | error_sink, | 716 | error_sink, |
717 | ) | 717 | ) |
718 | .map(MacroCallId::from) | 718 | .map(MacroCallId::from) |
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index ba027c44a..1bc72ec1f 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -599,6 +599,7 @@ mod diagnostics { | |||
599 | let mut cur = 0; | 599 | let mut cur = 0; |
600 | let mut tree = None; | 600 | let mut tree = None; |
601 | ModPath::expand_use_item( | 601 | ModPath::expand_use_item( |
602 | db, | ||
602 | InFile::new(ast.file_id, use_item), | 603 | InFile::new(ast.file_id, use_item), |
603 | &hygiene, | 604 | &hygiene, |
604 | |_mod_path, use_tree, _is_glob, _alias| { | 605 | |_mod_path, use_tree, _is_glob, _alias| { |
diff --git a/crates/hir_def/src/nameres/tests/incremental.rs b/crates/hir_def/src/nameres/tests/incremental.rs index 509e1bbbc..227ecd162 100644 --- a/crates/hir_def/src/nameres/tests/incremental.rs +++ b/crates/hir_def/src/nameres/tests/incremental.rs | |||
@@ -105,3 +105,55 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() { | |||
105 | assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) | 105 | assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) |
106 | } | 106 | } |
107 | } | 107 | } |
108 | |||
109 | #[test] | ||
110 | fn typing_inside_a_function_should_not_invalidate_expansions() { | ||
111 | let (mut db, pos) = TestDB::with_position( | ||
112 | r#" | ||
113 | //- /lib.rs | ||
114 | macro_rules! m { | ||
115 | ($ident:ident) => { | ||
116 | fn $ident() { }; | ||
117 | } | ||
118 | } | ||
119 | mod foo; | ||
120 | |||
121 | //- /foo/mod.rs | ||
122 | pub mod bar; | ||
123 | |||
124 | //- /foo/bar.rs | ||
125 | m!(X); | ||
126 | fn quux() { 1$0 } | ||
127 | m!(Y); | ||
128 | m!(Z); | ||
129 | "#, | ||
130 | ); | ||
131 | let krate = db.test_crate(); | ||
132 | { | ||
133 | let events = db.log_executed(|| { | ||
134 | let crate_def_map = db.crate_def_map(krate); | ||
135 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | ||
136 | assert_eq!(module_data.scope.resolutions().count(), 4); | ||
137 | }); | ||
138 | let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); | ||
139 | assert_eq!(n_recalculated_item_trees, 6); | ||
140 | } | ||
141 | |||
142 | let new_text = r#" | ||
143 | m!(X); | ||
144 | fn quux() { 92 } | ||
145 | m!(Y); | ||
146 | m!(Z); | ||
147 | "#; | ||
148 | db.set_file_text(pos.file_id, Arc::new(new_text.to_string())); | ||
149 | |||
150 | { | ||
151 | let events = db.log_executed(|| { | ||
152 | let crate_def_map = db.crate_def_map(krate); | ||
153 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | ||
154 | assert_eq!(module_data.scope.resolutions().count(), 4); | ||
155 | }); | ||
156 | let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); | ||
157 | assert_eq!(n_recalculated_item_trees, 1); | ||
158 | } | ||
159 | } | ||
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs index 509f77850..a43441b1c 100644 --- a/crates/hir_def/src/path.rs +++ b/crates/hir_def/src/path.rs | |||
@@ -7,7 +7,7 @@ use std::{ | |||
7 | sync::Arc, | 7 | sync::Arc, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | use crate::{body::LowerCtx, intern::Interned, type_ref::LifetimeRef}; | 10 | use crate::{body::LowerCtx, db::DefDatabase, intern::Interned, type_ref::LifetimeRef}; |
11 | use base_db::CrateId; | 11 | use base_db::CrateId; |
12 | use hir_expand::{ | 12 | use hir_expand::{ |
13 | hygiene::Hygiene, | 13 | hygiene::Hygiene, |
@@ -47,8 +47,8 @@ pub enum ImportAlias { | |||
47 | } | 47 | } |
48 | 48 | ||
49 | impl ModPath { | 49 | impl ModPath { |
50 | pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { | 50 | pub fn from_src(db: &dyn DefDatabase, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { |
51 | let ctx = LowerCtx::with_hygiene(hygiene); | 51 | let ctx = LowerCtx::with_hygiene(db, hygiene); |
52 | lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone()) | 52 | lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone()) |
53 | } | 53 | } |
54 | 54 | ||
@@ -64,12 +64,13 @@ impl ModPath { | |||
64 | 64 | ||
65 | /// Calls `cb` with all paths, represented by this use item. | 65 | /// Calls `cb` with all paths, represented by this use item. |
66 | pub(crate) fn expand_use_item( | 66 | pub(crate) fn expand_use_item( |
67 | db: &dyn DefDatabase, | ||
67 | item_src: InFile<ast::Use>, | 68 | item_src: InFile<ast::Use>, |
68 | hygiene: &Hygiene, | 69 | hygiene: &Hygiene, |
69 | mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>), | 70 | mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>), |
70 | ) { | 71 | ) { |
71 | if let Some(tree) = item_src.value.use_tree() { | 72 | if let Some(tree) = item_src.value.use_tree() { |
72 | lower::lower_use_tree(None, tree, hygiene, &mut cb); | 73 | lower::lower_use_tree(db, None, tree, hygiene, &mut cb); |
73 | } | 74 | } |
74 | } | 75 | } |
75 | 76 | ||
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs index 1df6db525..a873325b2 100644 --- a/crates/hir_def/src/path/lower.rs +++ b/crates/hir_def/src/path/lower.rs | |||
@@ -36,7 +36,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> { | |||
36 | match segment.kind()? { | 36 | match segment.kind()? { |
37 | ast::PathSegmentKind::Name(name_ref) => { | 37 | ast::PathSegmentKind::Name(name_ref) => { |
38 | // FIXME: this should just return name | 38 | // FIXME: this should just return name |
39 | match hygiene.name_ref_to_name(name_ref) { | 39 | match hygiene.name_ref_to_name(ctx.db.upcast(), name_ref) { |
40 | Either::Left(name) => { | 40 | Either::Left(name) => { |
41 | let args = segment | 41 | let args = segment |
42 | .generic_arg_list() | 42 | .generic_arg_list() |
@@ -133,7 +133,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> { | |||
133 | // We follow what it did anyway :) | 133 | // We follow what it did anyway :) |
134 | if segments.len() == 1 && kind == PathKind::Plain { | 134 | if segments.len() == 1 && kind == PathKind::Plain { |
135 | if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { | 135 | if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { |
136 | if let Some(crate_id) = hygiene.local_inner_macros(path) { | 136 | if let Some(crate_id) = hygiene.local_inner_macros(ctx.db.upcast(), path) { |
137 | kind = PathKind::DollarCrate(crate_id); | 137 | kind = PathKind::DollarCrate(crate_id); |
138 | } | 138 | } |
139 | } | 139 | } |
diff --git a/crates/hir_def/src/path/lower/lower_use.rs b/crates/hir_def/src/path/lower/lower_use.rs index e2965b033..ee80e3df3 100644 --- a/crates/hir_def/src/path/lower/lower_use.rs +++ b/crates/hir_def/src/path/lower/lower_use.rs | |||
@@ -7,9 +7,13 @@ use either::Either; | |||
7 | use hir_expand::{hygiene::Hygiene, name::AsName}; | 7 | use hir_expand::{hygiene::Hygiene, name::AsName}; |
8 | use syntax::ast::{self, NameOwner}; | 8 | use syntax::ast::{self, NameOwner}; |
9 | 9 | ||
10 | use crate::path::{ImportAlias, ModPath, PathKind}; | 10 | use crate::{ |
11 | db::DefDatabase, | ||
12 | path::{ImportAlias, ModPath, PathKind}, | ||
13 | }; | ||
11 | 14 | ||
12 | pub(crate) fn lower_use_tree( | 15 | pub(crate) fn lower_use_tree( |
16 | db: &dyn DefDatabase, | ||
13 | prefix: Option<ModPath>, | 17 | prefix: Option<ModPath>, |
14 | tree: ast::UseTree, | 18 | tree: ast::UseTree, |
15 | hygiene: &Hygiene, | 19 | hygiene: &Hygiene, |
@@ -21,13 +25,13 @@ pub(crate) fn lower_use_tree( | |||
21 | None => prefix, | 25 | None => prefix, |
22 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) | 26 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) |
23 | // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) | 27 | // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) |
24 | Some(path) => match convert_path(prefix, path, hygiene) { | 28 | Some(path) => match convert_path(db, prefix, path, hygiene) { |
25 | Some(it) => Some(it), | 29 | Some(it) => Some(it), |
26 | None => return, // FIXME: report errors somewhere | 30 | None => return, // FIXME: report errors somewhere |
27 | }, | 31 | }, |
28 | }; | 32 | }; |
29 | for child_tree in use_tree_list.use_trees() { | 33 | for child_tree in use_tree_list.use_trees() { |
30 | lower_use_tree(prefix.clone(), child_tree, hygiene, cb); | 34 | lower_use_tree(db, prefix.clone(), child_tree, hygiene, cb); |
31 | } | 35 | } |
32 | } else { | 36 | } else { |
33 | let alias = tree.rename().map(|a| { | 37 | let alias = tree.rename().map(|a| { |
@@ -47,7 +51,7 @@ pub(crate) fn lower_use_tree( | |||
47 | } | 51 | } |
48 | } | 52 | } |
49 | } | 53 | } |
50 | if let Some(path) = convert_path(prefix, ast_path, hygiene) { | 54 | if let Some(path) = convert_path(db, prefix, ast_path, hygiene) { |
51 | cb(path, &tree, is_glob, alias) | 55 | cb(path, &tree, is_glob, alias) |
52 | } | 56 | } |
53 | // FIXME: report errors somewhere | 57 | // FIXME: report errors somewhere |
@@ -61,9 +65,14 @@ pub(crate) fn lower_use_tree( | |||
61 | } | 65 | } |
62 | } | 66 | } |
63 | 67 | ||
64 | fn convert_path(prefix: Option<ModPath>, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { | 68 | fn convert_path( |
69 | db: &dyn DefDatabase, | ||
70 | prefix: Option<ModPath>, | ||
71 | path: ast::Path, | ||
72 | hygiene: &Hygiene, | ||
73 | ) -> Option<ModPath> { | ||
65 | let prefix = if let Some(qual) = path.qualifier() { | 74 | let prefix = if let Some(qual) = path.qualifier() { |
66 | Some(convert_path(prefix, qual, hygiene)?) | 75 | Some(convert_path(db, prefix, qual, hygiene)?) |
67 | } else { | 76 | } else { |
68 | prefix | 77 | prefix |
69 | }; | 78 | }; |
@@ -71,7 +80,7 @@ fn convert_path(prefix: Option<ModPath>, path: ast::Path, hygiene: &Hygiene) -> | |||
71 | let segment = path.segment()?; | 80 | let segment = path.segment()?; |
72 | let res = match segment.kind()? { | 81 | let res = match segment.kind()? { |
73 | ast::PathSegmentKind::Name(name_ref) => { | 82 | ast::PathSegmentKind::Name(name_ref) => { |
74 | match hygiene.name_ref_to_name(name_ref) { | 83 | match hygiene.name_ref_to_name(db.upcast(), name_ref) { |
75 | Either::Left(name) => { | 84 | Either::Left(name) => { |
76 | // no type args in use | 85 | // no type args in use |
77 | let mut res = prefix.unwrap_or_else(|| { | 86 | let mut res = prefix.unwrap_or_else(|| { |
diff --git a/crates/hir_def/src/visibility.rs b/crates/hir_def/src/visibility.rs index d4b7c9970..83500f54e 100644 --- a/crates/hir_def/src/visibility.rs +++ b/crates/hir_def/src/visibility.rs | |||
@@ -33,17 +33,19 @@ impl RawVisibility { | |||
33 | db: &dyn DefDatabase, | 33 | db: &dyn DefDatabase, |
34 | node: InFile<Option<ast::Visibility>>, | 34 | node: InFile<Option<ast::Visibility>>, |
35 | ) -> RawVisibility { | 35 | ) -> RawVisibility { |
36 | Self::from_ast_with_hygiene(node.value, &Hygiene::new(db.upcast(), node.file_id)) | 36 | Self::from_ast_with_hygiene(db, node.value, &Hygiene::new(db.upcast(), node.file_id)) |
37 | } | 37 | } |
38 | 38 | ||
39 | pub(crate) fn from_ast_with_hygiene( | 39 | pub(crate) fn from_ast_with_hygiene( |
40 | db: &dyn DefDatabase, | ||
40 | node: Option<ast::Visibility>, | 41 | node: Option<ast::Visibility>, |
41 | hygiene: &Hygiene, | 42 | hygiene: &Hygiene, |
42 | ) -> RawVisibility { | 43 | ) -> RawVisibility { |
43 | Self::from_ast_with_hygiene_and_default(node, RawVisibility::private(), hygiene) | 44 | Self::from_ast_with_hygiene_and_default(db, node, RawVisibility::private(), hygiene) |
44 | } | 45 | } |
45 | 46 | ||
46 | pub(crate) fn from_ast_with_hygiene_and_default( | 47 | pub(crate) fn from_ast_with_hygiene_and_default( |
48 | db: &dyn DefDatabase, | ||
47 | node: Option<ast::Visibility>, | 49 | node: Option<ast::Visibility>, |
48 | default: RawVisibility, | 50 | default: RawVisibility, |
49 | hygiene: &Hygiene, | 51 | hygiene: &Hygiene, |
@@ -54,7 +56,7 @@ impl RawVisibility { | |||
54 | }; | 56 | }; |
55 | match node.kind() { | 57 | match node.kind() { |
56 | ast::VisibilityKind::In(path) => { | 58 | ast::VisibilityKind::In(path) => { |
57 | let path = ModPath::from_src(path, hygiene); | 59 | let path = ModPath::from_src(db, path, hygiene); |
58 | let path = match path { | 60 | let path = match path { |
59 | None => return RawVisibility::private(), | 61 | None => return RawVisibility::private(), |
60 | Some(path) => path, | 62 | Some(path) => path, |
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs index ed61ebca3..aca69e35a 100644 --- a/crates/hir_expand/src/hygiene.rs +++ b/crates/hir_expand/src/hygiene.rs | |||
@@ -32,10 +32,14 @@ impl Hygiene { | |||
32 | } | 32 | } |
33 | 33 | ||
34 | // FIXME: this should just return name | 34 | // FIXME: this should just return name |
35 | pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> { | 35 | pub fn name_ref_to_name( |
36 | &self, | ||
37 | db: &dyn AstDatabase, | ||
38 | name_ref: ast::NameRef, | ||
39 | ) -> Either<Name, CrateId> { | ||
36 | if let Some(frames) = &self.frames { | 40 | if let Some(frames) = &self.frames { |
37 | if name_ref.text() == "$crate" { | 41 | if name_ref.text() == "$crate" { |
38 | if let Some(krate) = frames.root_crate(name_ref.syntax()) { | 42 | if let Some(krate) = frames.root_crate(db, name_ref.syntax()) { |
39 | return Either::Right(krate); | 43 | return Either::Right(krate); |
40 | } | 44 | } |
41 | } | 45 | } |
@@ -44,15 +48,19 @@ impl Hygiene { | |||
44 | Either::Left(name_ref.as_name()) | 48 | Either::Left(name_ref.as_name()) |
45 | } | 49 | } |
46 | 50 | ||
47 | pub fn local_inner_macros(&self, path: ast::Path) -> Option<CrateId> { | 51 | pub fn local_inner_macros(&self, db: &dyn AstDatabase, path: ast::Path) -> Option<CrateId> { |
48 | let mut token = path.syntax().first_token()?.text_range(); | 52 | let mut token = path.syntax().first_token()?.text_range(); |
49 | let frames = self.frames.as_ref()?; | 53 | let frames = self.frames.as_ref()?; |
50 | let mut current = frames.0.clone(); | 54 | let mut current = frames.0.clone(); |
51 | 55 | ||
52 | loop { | 56 | loop { |
53 | let (mapped, origin) = current.expansion.as_ref()?.map_ident_up(token)?; | 57 | let (mapped, origin) = current.expansion.as_ref()?.map_ident_up(db, token)?; |
54 | if origin == Origin::Def { | 58 | if origin == Origin::Def { |
55 | return if current.local_inner { frames.root_crate(path.syntax()) } else { None }; | 59 | return if current.local_inner { |
60 | frames.root_crate(db, path.syntax()) | ||
61 | } else { | ||
62 | None | ||
63 | }; | ||
56 | } | 64 | } |
57 | current = current.call_site.as_ref()?.clone(); | 65 | current = current.call_site.as_ref()?.clone(); |
58 | token = mapped.value; | 66 | token = mapped.value; |
@@ -82,13 +90,13 @@ impl HygieneFrames { | |||
82 | HygieneFrames(Arc::new(HygieneFrame::new(db, file_id))) | 90 | HygieneFrames(Arc::new(HygieneFrame::new(db, file_id))) |
83 | } | 91 | } |
84 | 92 | ||
85 | fn root_crate(&self, node: &SyntaxNode) -> Option<CrateId> { | 93 | fn root_crate(&self, db: &dyn AstDatabase, node: &SyntaxNode) -> Option<CrateId> { |
86 | let mut token = node.first_token()?.text_range(); | 94 | let mut token = node.first_token()?.text_range(); |
87 | let mut result = self.0.krate; | 95 | let mut result = self.0.krate; |
88 | let mut current = self.0.clone(); | 96 | let mut current = self.0.clone(); |
89 | 97 | ||
90 | while let Some((mapped, origin)) = | 98 | while let Some((mapped, origin)) = |
91 | current.expansion.as_ref().and_then(|it| it.map_ident_up(token)) | 99 | current.expansion.as_ref().and_then(|it| it.map_ident_up(db, token)) |
92 | { | 100 | { |
93 | result = current.krate; | 101 | result = current.krate; |
94 | 102 | ||
@@ -112,7 +120,7 @@ impl HygieneFrames { | |||
112 | 120 | ||
113 | #[derive(Debug, Clone, PartialEq, Eq)] | 121 | #[derive(Debug, Clone, PartialEq, Eq)] |
114 | struct HygieneInfo { | 122 | struct HygieneInfo { |
115 | arg_start: InFile<TextSize>, | 123 | file: MacroFile, |
116 | /// The `macro_rules!` arguments. | 124 | /// The `macro_rules!` arguments. |
117 | def_start: Option<InFile<TextSize>>, | 125 | def_start: Option<InFile<TextSize>>, |
118 | 126 | ||
@@ -122,12 +130,24 @@ struct HygieneInfo { | |||
122 | } | 130 | } |
123 | 131 | ||
124 | impl HygieneInfo { | 132 | impl HygieneInfo { |
125 | fn map_ident_up(&self, token: TextRange) -> Option<(InFile<TextRange>, Origin)> { | 133 | fn map_ident_up( |
134 | &self, | ||
135 | db: &dyn AstDatabase, | ||
136 | token: TextRange, | ||
137 | ) -> Option<(InFile<TextRange>, Origin)> { | ||
126 | let token_id = self.exp_map.token_by_range(token)?; | 138 | let token_id = self.exp_map.token_by_range(token)?; |
127 | 139 | ||
128 | let (token_id, origin) = self.macro_def.map_id_up(token_id); | 140 | let (token_id, origin) = self.macro_def.map_id_up(token_id); |
129 | let (token_map, tt) = match origin { | 141 | let (token_map, tt) = match origin { |
130 | mbe::Origin::Call => (&self.macro_arg.1, self.arg_start), | 142 | mbe::Origin::Call => { |
143 | let call_id = match self.file.macro_call_id { | ||
144 | MacroCallId::LazyMacro(lazy) => lazy, | ||
145 | MacroCallId::EagerMacro(_) => unreachable!(), | ||
146 | }; | ||
147 | let loc: MacroCallLoc = db.lookup_intern_macro(call_id); | ||
148 | let arg_start = loc.kind.arg(db)?.text_range().start(); | ||
149 | (&self.macro_arg.1, InFile::new(loc.kind.file_id(), arg_start)) | ||
150 | } | ||
131 | mbe::Origin::Def => match (&*self.macro_def, self.def_start) { | 151 | mbe::Origin::Def => match (&*self.macro_def, self.def_start) { |
132 | (TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt)) | 152 | (TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt)) |
133 | | (TokenExpander::MacroRules { def_site_token_map, .. }, Some(tt)) => { | 153 | | (TokenExpander::MacroRules { def_site_token_map, .. }, Some(tt)) => { |
@@ -147,8 +167,6 @@ fn make_hygiene_info( | |||
147 | macro_file: MacroFile, | 167 | macro_file: MacroFile, |
148 | loc: &MacroCallLoc, | 168 | loc: &MacroCallLoc, |
149 | ) -> Option<HygieneInfo> { | 169 | ) -> Option<HygieneInfo> { |
150 | let arg_tt = loc.kind.arg(db)?; | ||
151 | |||
152 | let def_offset = loc.def.ast_id().left().and_then(|id| { | 170 | let def_offset = loc.def.ast_id().left().and_then(|id| { |
153 | let def_tt = match id.to_node(db) { | 171 | let def_tt = match id.to_node(db) { |
154 | ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(), | 172 | ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(), |
@@ -161,13 +179,7 @@ fn make_hygiene_info( | |||
161 | let (_, exp_map) = db.parse_macro_expansion(macro_file).value?; | 179 | let (_, exp_map) = db.parse_macro_expansion(macro_file).value?; |
162 | let macro_arg = db.macro_arg(macro_file.macro_call_id)?; | 180 | let macro_arg = db.macro_arg(macro_file.macro_call_id)?; |
163 | 181 | ||
164 | Some(HygieneInfo { | 182 | Some(HygieneInfo { file: macro_file, def_start: def_offset, macro_arg, macro_def, exp_map }) |
165 | arg_start: InFile::new(loc.kind.file_id(), arg_tt.text_range().start()), | ||
166 | def_start: def_offset, | ||
167 | macro_arg, | ||
168 | macro_def, | ||
169 | exp_map, | ||
170 | }) | ||
171 | } | 183 | } |
172 | 184 | ||
173 | impl HygieneFrame { | 185 | impl HygieneFrame { |
@@ -178,7 +190,8 @@ impl HygieneFrame { | |||
178 | MacroCallId::EagerMacro(_id) => (None, None, false), | 190 | MacroCallId::EagerMacro(_id) => (None, None, false), |
179 | MacroCallId::LazyMacro(id) => { | 191 | MacroCallId::LazyMacro(id) => { |
180 | let loc = db.lookup_intern_macro(id); | 192 | let loc = db.lookup_intern_macro(id); |
181 | let info = make_hygiene_info(db, macro_file, &loc); | 193 | let info = make_hygiene_info(db, macro_file, &loc) |
194 | .map(|info| (loc.kind.file_id(), info)); | ||
182 | match loc.def.kind { | 195 | match loc.def.kind { |
183 | MacroDefKind::Declarative(_) => { | 196 | MacroDefKind::Declarative(_) => { |
184 | (info, Some(loc.def.krate), loc.def.local_inner) | 197 | (info, Some(loc.def.krate), loc.def.local_inner) |
@@ -192,7 +205,7 @@ impl HygieneFrame { | |||
192 | }, | 205 | }, |
193 | }; | 206 | }; |
194 | 207 | ||
195 | let info = match info { | 208 | let (calling_file, info) = match info { |
196 | None => { | 209 | None => { |
197 | return HygieneFrame { | 210 | return HygieneFrame { |
198 | expansion: None, | 211 | expansion: None, |
@@ -206,7 +219,7 @@ impl HygieneFrame { | |||
206 | }; | 219 | }; |
207 | 220 | ||
208 | let def_site = info.def_start.map(|it| db.hygiene_frame(it.file_id)); | 221 | let def_site = info.def_start.map(|it| db.hygiene_frame(it.file_id)); |
209 | let call_site = Some(db.hygiene_frame(info.arg_start.file_id)); | 222 | let call_site = Some(db.hygiene_frame(calling_file)); |
210 | 223 | ||
211 | HygieneFrame { expansion: Some(info), local_inner, krate, call_site, def_site } | 224 | HygieneFrame { expansion: Some(info), local_inner, krate, call_site, def_site } |
212 | } | 225 | } |
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index 4fb7d9cf2..1f6edf7a2 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs | |||
@@ -1000,7 +1000,7 @@ impl HirDisplay for TypeRef { | |||
1000 | } | 1000 | } |
1001 | TypeRef::Macro(macro_call) => { | 1001 | TypeRef::Macro(macro_call) => { |
1002 | let macro_call = macro_call.to_node(f.db.upcast()); | 1002 | let macro_call = macro_call.to_node(f.db.upcast()); |
1003 | let ctx = body::LowerCtx::with_hygiene(&Hygiene::new_unhygienic()); | 1003 | let ctx = body::LowerCtx::with_hygiene(f.db.upcast(), &Hygiene::new_unhygienic()); |
1004 | match macro_call.path() { | 1004 | match macro_call.path() { |
1005 | Some(path) => match Path::from_src(path, &ctx) { | 1005 | Some(path) => match Path::from_src(path, &ctx) { |
1006 | Some(path) => path.hir_fmt(f)?, | 1006 | Some(path) => path.hir_fmt(f)?, |
diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs index a26fe7c6c..968c0254d 100644 --- a/crates/ide_completion/src/completions/trait_impl.rs +++ b/crates/ide_completion/src/completions/trait_impl.rs | |||
@@ -36,7 +36,7 @@ use ide_db::{traits::get_missing_assoc_items, SymbolKind}; | |||
36 | use syntax::{ | 36 | use syntax::{ |
37 | ast::{self, edit, Impl}, | 37 | ast::{self, edit, Impl}, |
38 | display::function_declaration, | 38 | display::function_declaration, |
39 | AstNode, SyntaxKind, SyntaxNode, TextRange, T, | 39 | AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, T, |
40 | }; | 40 | }; |
41 | use text_edit::TextEdit; | 41 | use text_edit::TextEdit; |
42 | 42 | ||
@@ -154,8 +154,7 @@ fn add_function_impl( | |||
154 | } else { | 154 | } else { |
155 | CompletionItemKind::SymbolKind(SymbolKind::Function) | 155 | CompletionItemKind::SymbolKind(SymbolKind::Function) |
156 | }; | 156 | }; |
157 | let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); | 157 | let range = replacement_range(ctx, fn_def_node); |
158 | |||
159 | if let Some(src) = func.source(ctx.db) { | 158 | if let Some(src) = func.source(ctx.db) { |
160 | let function_decl = function_declaration(&src.value); | 159 | let function_decl = function_declaration(&src.value); |
161 | match ctx.config.snippet_cap { | 160 | match ctx.config.snippet_cap { |
@@ -183,8 +182,7 @@ fn add_type_alias_impl( | |||
183 | 182 | ||
184 | let snippet = format!("type {} = ", alias_name); | 183 | let snippet = format!("type {} = ", alias_name); |
185 | 184 | ||
186 | let range = TextRange::new(type_def_node.text_range().start(), ctx.source_range().end()); | 185 | let range = replacement_range(ctx, type_def_node); |
187 | |||
188 | let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()); | 186 | let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()); |
189 | item.text_edit(TextEdit::replace(range, snippet)) | 187 | item.text_edit(TextEdit::replace(range, snippet)) |
190 | .lookup_by(alias_name) | 188 | .lookup_by(alias_name) |
@@ -205,9 +203,7 @@ fn add_const_impl( | |||
205 | if let Some(source) = const_.source(ctx.db) { | 203 | if let Some(source) = const_.source(ctx.db) { |
206 | let snippet = make_const_compl_syntax(&source.value); | 204 | let snippet = make_const_compl_syntax(&source.value); |
207 | 205 | ||
208 | let range = | 206 | let range = replacement_range(ctx, const_def_node); |
209 | TextRange::new(const_def_node.text_range().start(), ctx.source_range().end()); | ||
210 | |||
211 | let mut item = | 207 | let mut item = |
212 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()); | 208 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()); |
213 | item.text_edit(TextEdit::replace(range, snippet)) | 209 | item.text_edit(TextEdit::replace(range, snippet)) |
@@ -242,6 +238,17 @@ fn make_const_compl_syntax(const_: &ast::Const) -> String { | |||
242 | format!("{} = ", syntax.trim_end()) | 238 | format!("{} = ", syntax.trim_end()) |
243 | } | 239 | } |
244 | 240 | ||
241 | fn replacement_range(ctx: &CompletionContext, item: &SyntaxNode) -> TextRange { | ||
242 | let first_child = item | ||
243 | .children_with_tokens() | ||
244 | .find(|child| { | ||
245 | !matches!(child.kind(), SyntaxKind::COMMENT | SyntaxKind::WHITESPACE | SyntaxKind::ATTR) | ||
246 | }) | ||
247 | .unwrap_or_else(|| SyntaxElement::Node(item.clone())); | ||
248 | |||
249 | TextRange::new(first_child.text_range().start(), ctx.source_range().end()) | ||
250 | } | ||
251 | |||
245 | #[cfg(test)] | 252 | #[cfg(test)] |
246 | mod tests { | 253 | mod tests { |
247 | use expect_test::{expect, Expect}; | 254 | use expect_test::{expect, Expect}; |
@@ -734,4 +741,50 @@ impl Test for T {{ | |||
734 | test("CONST", "const $0", "const CONST: u16 = ", next_sibling); | 741 | test("CONST", "const $0", "const CONST: u16 = ", next_sibling); |
735 | } | 742 | } |
736 | } | 743 | } |
744 | |||
745 | #[test] | ||
746 | fn snippet_does_not_overwrite_comment_or_attr() { | ||
747 | let test = |completion: &str, hint: &str, completed: &str| { | ||
748 | check_edit( | ||
749 | completion, | ||
750 | &format!( | ||
751 | r#" | ||
752 | trait Foo {{ | ||
753 | type Type; | ||
754 | fn function(); | ||
755 | const CONST: i32 = 0; | ||
756 | }} | ||
757 | struct T; | ||
758 | |||
759 | impl Foo for T {{ | ||
760 | // Comment | ||
761 | #[bar] | ||
762 | {} | ||
763 | }} | ||
764 | "#, | ||
765 | hint | ||
766 | ), | ||
767 | &format!( | ||
768 | r#" | ||
769 | trait Foo {{ | ||
770 | type Type; | ||
771 | fn function(); | ||
772 | const CONST: i32 = 0; | ||
773 | }} | ||
774 | struct T; | ||
775 | |||
776 | impl Foo for T {{ | ||
777 | // Comment | ||
778 | #[bar] | ||
779 | {} | ||
780 | }} | ||
781 | "#, | ||
782 | completed | ||
783 | ), | ||
784 | ) | ||
785 | }; | ||
786 | test("function", "fn f$0", "fn function() {\n $0\n}"); | ||
787 | test("Type", "type T$0", "type Type = "); | ||
788 | test("CONST", "const C$0", "const CONST: i32 = "); | ||
789 | } | ||
737 | } | 790 | } |
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index f3fcb712c..62ef40818 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -381,7 +381,7 @@ impl<'a> CompletionContext<'a> { | |||
381 | let def = self.sema.to_def(&it); | 381 | let def = self.sema.to_def(&it); |
382 | (def.map(|def| def.ret_type(self.db)), None) | 382 | (def.map(|def| def.ret_type(self.db)), None) |
383 | }, | 383 | }, |
384 | ast::Stmt(it) => (None, None), | 384 | ast::Stmt(_it) => (None, None), |
385 | _ => { | 385 | _ => { |
386 | match node.parent() { | 386 | match node.parent() { |
387 | Some(n) => { | 387 | Some(n) => { |
diff --git a/crates/ide_db/src/line_index.rs b/crates/ide_db/src/line_index.rs index 8e9d8cca2..816edfe6a 100644 --- a/crates/ide_db/src/line_index.rs +++ b/crates/ide_db/src/line_index.rs | |||
@@ -3,7 +3,6 @@ | |||
3 | use std::iter; | 3 | use std::iter; |
4 | 4 | ||
5 | use rustc_hash::FxHashMap; | 5 | use rustc_hash::FxHashMap; |
6 | use stdx::partition_point; | ||
7 | use syntax::{TextRange, TextSize}; | 6 | use syntax::{TextRange, TextSize}; |
8 | 7 | ||
9 | #[derive(Clone, Debug, PartialEq, Eq)] | 8 | #[derive(Clone, Debug, PartialEq, Eq)] |
@@ -97,7 +96,7 @@ impl LineIndex { | |||
97 | } | 96 | } |
98 | 97 | ||
99 | pub fn line_col(&self, offset: TextSize) -> LineCol { | 98 | pub fn line_col(&self, offset: TextSize) -> LineCol { |
100 | let line = partition_point(&self.newlines, |&it| it <= offset) - 1; | 99 | let line = self.newlines.partition_point(|&it| it <= offset) - 1; |
101 | let line_start_offset = self.newlines[line]; | 100 | let line_start_offset = self.newlines[line]; |
102 | let col = offset - line_start_offset; | 101 | let col = offset - line_start_offset; |
103 | LineCol { line: line as u32, col: col.into() } | 102 | LineCol { line: line as u32, col: col.into() } |
@@ -118,8 +117,8 @@ impl LineIndex { | |||
118 | } | 117 | } |
119 | 118 | ||
120 | pub fn lines(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ { | 119 | pub fn lines(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ { |
121 | let lo = partition_point(&self.newlines, |&it| it < range.start()); | 120 | let lo = self.newlines.partition_point(|&it| it < range.start()); |
122 | let hi = partition_point(&self.newlines, |&it| it <= range.end()); | 121 | let hi = self.newlines.partition_point(|&it| it <= range.end()); |
123 | let all = iter::once(range.start()) | 122 | let all = iter::once(range.start()) |
124 | .chain(self.newlines[lo..hi].iter().copied()) | 123 | .chain(self.newlines[lo..hi].iter().copied()) |
125 | .chain(iter::once(range.end())); | 124 | .chain(iter::once(range.end())); |
diff --git a/crates/project_model/src/cfg_flag.rs b/crates/project_model/src/cfg_flag.rs index e92962cf6..bfdfd458f 100644 --- a/crates/project_model/src/cfg_flag.rs +++ b/crates/project_model/src/cfg_flag.rs | |||
@@ -4,7 +4,6 @@ | |||
4 | use std::str::FromStr; | 4 | use std::str::FromStr; |
5 | 5 | ||
6 | use cfg::CfgOptions; | 6 | use cfg::CfgOptions; |
7 | use stdx::split_once; | ||
8 | 7 | ||
9 | #[derive(Clone, Eq, PartialEq, Debug)] | 8 | #[derive(Clone, Eq, PartialEq, Debug)] |
10 | pub enum CfgFlag { | 9 | pub enum CfgFlag { |
@@ -15,7 +14,7 @@ pub enum CfgFlag { | |||
15 | impl FromStr for CfgFlag { | 14 | impl FromStr for CfgFlag { |
16 | type Err = String; | 15 | type Err = String; |
17 | fn from_str(s: &str) -> Result<Self, Self::Err> { | 16 | fn from_str(s: &str) -> Result<Self, Self::Err> { |
18 | let res = match split_once(s, '=') { | 17 | let res = match s.split_once('=') { |
19 | Some((key, value)) => { | 18 | Some((key, value)) => { |
20 | if !(value.starts_with('"') && value.ends_with('"')) { | 19 | if !(value.starts_with('"') && value.ends_with('"')) { |
21 | return Err(format!("Invalid cfg ({:?}), value should be in quotes", s)); | 20 | return Err(format!("Invalid cfg ({:?}), value should be in quotes", s)); |
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 1b6211044..340fcacfa 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs | |||
@@ -65,20 +65,6 @@ pub fn replace(buf: &mut String, from: char, to: &str) { | |||
65 | *buf = buf.replace(from, to) | 65 | *buf = buf.replace(from, to) |
66 | } | 66 | } |
67 | 67 | ||
68 | // https://github.com/rust-lang/rust/issues/74773 | ||
69 | pub fn split_once(haystack: &str, delim: char) -> Option<(&str, &str)> { | ||
70 | let mut split = haystack.splitn(2, delim); | ||
71 | let prefix = split.next()?; | ||
72 | let suffix = split.next()?; | ||
73 | Some((prefix, suffix)) | ||
74 | } | ||
75 | pub fn rsplit_once(haystack: &str, delim: char) -> Option<(&str, &str)> { | ||
76 | let mut split = haystack.rsplitn(2, delim); | ||
77 | let suffix = split.next()?; | ||
78 | let prefix = split.next()?; | ||
79 | Some((prefix, suffix)) | ||
80 | } | ||
81 | |||
82 | pub fn trim_indent(mut text: &str) -> String { | 68 | pub fn trim_indent(mut text: &str) -> String { |
83 | if text.starts_with('\n') { | 69 | if text.starts_with('\n') { |
84 | text = &text[1..]; | 70 | text = &text[1..]; |
@@ -89,7 +75,7 @@ pub fn trim_indent(mut text: &str) -> String { | |||
89 | .map(|it| it.len() - it.trim_start().len()) | 75 | .map(|it| it.len() - it.trim_start().len()) |
90 | .min() | 76 | .min() |
91 | .unwrap_or(0); | 77 | .unwrap_or(0); |
92 | lines_with_ends(text) | 78 | text.split_inclusive('\n') |
93 | .map( | 79 | .map( |
94 | |line| { | 80 | |line| { |
95 | if line.len() <= indent { | 81 | if line.len() <= indent { |
@@ -102,70 +88,12 @@ pub fn trim_indent(mut text: &str) -> String { | |||
102 | .collect() | 88 | .collect() |
103 | } | 89 | } |
104 | 90 | ||
105 | pub fn lines_with_ends(text: &str) -> LinesWithEnds { | ||
106 | LinesWithEnds { text } | ||
107 | } | ||
108 | |||
109 | pub struct LinesWithEnds<'a> { | ||
110 | text: &'a str, | ||
111 | } | ||
112 | |||
113 | impl<'a> Iterator for LinesWithEnds<'a> { | ||
114 | type Item = &'a str; | ||
115 | fn next(&mut self) -> Option<&'a str> { | ||
116 | if self.text.is_empty() { | ||
117 | return None; | ||
118 | } | ||
119 | let idx = self.text.find('\n').map_or(self.text.len(), |it| it + 1); | ||
120 | let (res, next) = self.text.split_at(idx); | ||
121 | self.text = next; | ||
122 | Some(res) | ||
123 | } | ||
124 | } | ||
125 | |||
126 | /// Returns `idx` such that: | ||
127 | /// | ||
128 | /// ```text | ||
129 | /// ∀ x in slice[..idx]: pred(x) | ||
130 | /// && ∀ x in slice[idx..]: !pred(x) | ||
131 | /// ``` | ||
132 | /// | ||
133 | /// https://github.com/rust-lang/rust/issues/73831 | ||
134 | pub fn partition_point<T, P>(slice: &[T], mut pred: P) -> usize | ||
135 | where | ||
136 | P: FnMut(&T) -> bool, | ||
137 | { | ||
138 | let mut left = 0; | ||
139 | let mut right = slice.len(); | ||
140 | |||
141 | while left != right { | ||
142 | let mid = left + (right - left) / 2; | ||
143 | // SAFETY: | ||
144 | // When left < right, left <= mid < right. | ||
145 | // Therefore left always increases and right always decreases, | ||
146 | // and either of them is selected. | ||
147 | // In both cases left <= right is satisfied. | ||
148 | // Therefore if left < right in a step, | ||
149 | // left <= right is satisfied in the next step. | ||
150 | // Therefore as long as left != right, 0 <= left < right <= len is satisfied | ||
151 | // and if this case 0 <= mid < len is satisfied too. | ||
152 | let value = unsafe { slice.get_unchecked(mid) }; | ||
153 | if pred(value) { | ||
154 | left = mid + 1; | ||
155 | } else { | ||
156 | right = mid; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | left | ||
161 | } | ||
162 | |||
163 | pub fn equal_range_by<T, F>(slice: &[T], mut key: F) -> ops::Range<usize> | 91 | pub fn equal_range_by<T, F>(slice: &[T], mut key: F) -> ops::Range<usize> |
164 | where | 92 | where |
165 | F: FnMut(&T) -> Ordering, | 93 | F: FnMut(&T) -> Ordering, |
166 | { | 94 | { |
167 | let start = partition_point(slice, |it| key(it) == Ordering::Less); | 95 | let start = slice.partition_point(|it| key(it) == Ordering::Less); |
168 | let len = partition_point(&slice[start..], |it| key(it) == Ordering::Equal); | 96 | let len = slice[start..].partition_point(|it| key(it) == Ordering::Equal); |
169 | start..start + len | 97 | start..start + len |
170 | } | 98 | } |
171 | 99 | ||
diff --git a/crates/test_utils/src/fixture.rs b/crates/test_utils/src/fixture.rs index 099baeca2..d0bddf7d8 100644 --- a/crates/test_utils/src/fixture.rs +++ b/crates/test_utils/src/fixture.rs | |||
@@ -62,7 +62,7 @@ | |||
62 | //! ``` | 62 | //! ``` |
63 | 63 | ||
64 | use rustc_hash::FxHashMap; | 64 | use rustc_hash::FxHashMap; |
65 | use stdx::{lines_with_ends, split_once, trim_indent}; | 65 | use stdx::trim_indent; |
66 | 66 | ||
67 | #[derive(Debug, Eq, PartialEq)] | 67 | #[derive(Debug, Eq, PartialEq)] |
68 | pub struct Fixture { | 68 | pub struct Fixture { |
@@ -93,7 +93,7 @@ impl Fixture { | |||
93 | 93 | ||
94 | let default = if ra_fixture.contains("//-") { None } else { Some("//- /main.rs") }; | 94 | let default = if ra_fixture.contains("//-") { None } else { Some("//- /main.rs") }; |
95 | 95 | ||
96 | for (ix, line) in default.into_iter().chain(lines_with_ends(&fixture)).enumerate() { | 96 | for (ix, line) in default.into_iter().chain(fixture.split_inclusive('\n')).enumerate() { |
97 | if line.contains("//-") { | 97 | if line.contains("//-") { |
98 | assert!( | 98 | assert!( |
99 | line.starts_with("//-"), | 99 | line.starts_with("//-"), |
@@ -133,14 +133,14 @@ impl Fixture { | |||
133 | let mut env = FxHashMap::default(); | 133 | let mut env = FxHashMap::default(); |
134 | let mut introduce_new_source_root = false; | 134 | let mut introduce_new_source_root = false; |
135 | for component in components[1..].iter() { | 135 | for component in components[1..].iter() { |
136 | let (key, value) = split_once(component, ':').unwrap(); | 136 | let (key, value) = component.split_once(':').unwrap(); |
137 | match key { | 137 | match key { |
138 | "crate" => krate = Some(value.to_string()), | 138 | "crate" => krate = Some(value.to_string()), |
139 | "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), | 139 | "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), |
140 | "edition" => edition = Some(value.to_string()), | 140 | "edition" => edition = Some(value.to_string()), |
141 | "cfg" => { | 141 | "cfg" => { |
142 | for entry in value.split(',') { | 142 | for entry in value.split(',') { |
143 | match split_once(entry, '=') { | 143 | match entry.split_once('=') { |
144 | Some((k, v)) => cfg_key_values.push((k.to_string(), v.to_string())), | 144 | Some((k, v)) => cfg_key_values.push((k.to_string(), v.to_string())), |
145 | None => cfg_atoms.push(entry.to_string()), | 145 | None => cfg_atoms.push(entry.to_string()), |
146 | } | 146 | } |
@@ -148,7 +148,7 @@ impl Fixture { | |||
148 | } | 148 | } |
149 | "env" => { | 149 | "env" => { |
150 | for key in value.split(',') { | 150 | for key in value.split(',') { |
151 | if let Some((k, v)) = split_once(key, '=') { | 151 | if let Some((k, v)) = key.split_once('=') { |
152 | env.insert(k.into(), v.into()); | 152 | env.insert(k.into(), v.into()); |
153 | } | 153 | } |
154 | } | 154 | } |
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index 72466c957..fce4fd6bf 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -17,7 +17,7 @@ use std::{ | |||
17 | }; | 17 | }; |
18 | 18 | ||
19 | use profile::StopWatch; | 19 | use profile::StopWatch; |
20 | use stdx::{is_ci, lines_with_ends}; | 20 | use stdx::is_ci; |
21 | use text_size::{TextRange, TextSize}; | 21 | use text_size::{TextRange, TextSize}; |
22 | 22 | ||
23 | pub use dissimilar::diff as __diff; | 23 | pub use dissimilar::diff as __diff; |
@@ -181,7 +181,7 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { | |||
181 | let mut prev_line_start: Option<TextSize> = None; | 181 | let mut prev_line_start: Option<TextSize> = None; |
182 | let mut line_start: TextSize = 0.into(); | 182 | let mut line_start: TextSize = 0.into(); |
183 | let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new(); | 183 | let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new(); |
184 | for line in lines_with_ends(text) { | 184 | for line in text.split_inclusive('\n') { |
185 | let mut this_line_annotations = Vec::new(); | 185 | let mut this_line_annotations = Vec::new(); |
186 | if let Some(idx) = line.find("//") { | 186 | if let Some(idx) = line.find("//") { |
187 | let annotation_offset = TextSize::of(&line[..idx + "//".len()]); | 187 | let annotation_offset = TextSize::of(&line[..idx + "//".len()]); |
diff --git a/docs/dev/style.md b/docs/dev/style.md index 00de7a711..d24a5952e 100644 --- a/docs/dev/style.md +++ b/docs/dev/style.md | |||
@@ -947,4 +947,4 @@ match p.current() { | |||
947 | For `.md` and `.adoc` files, prefer a sentence-per-line format, don't wrap lines. | 947 | For `.md` and `.adoc` files, prefer a sentence-per-line format, don't wrap lines. |
948 | If the line is too long, you want to split the sentence in two :-) | 948 | If the line is too long, you want to split the sentence in two :-) |
949 | 949 | ||
950 | **Rationale:** much easier to edit the text and read the diff. | 950 | **Rationale:** much easier to edit the text and read the diff, see [this link](https://asciidoctor.org/docs/asciidoc-recommended-practices/#one-sentence-per-line). |
diff --git a/xtask/src/install.rs b/xtask/src/install.rs index 91d6a2853..7e2dccdfe 100644 --- a/xtask/src/install.rs +++ b/xtask/src/install.rs | |||
@@ -8,7 +8,7 @@ use xshell::{cmd, pushd}; | |||
8 | use crate::flags; | 8 | use crate::flags; |
9 | 9 | ||
10 | // Latest stable, feel free to send a PR if this lags behind. | 10 | // Latest stable, feel free to send a PR if this lags behind. |
11 | const REQUIRED_RUST_VERSION: u32 = 51; | 11 | const REQUIRED_RUST_VERSION: u32 = 52; |
12 | 12 | ||
13 | impl flags::Install { | 13 | impl flags::Install { |
14 | pub(crate) fn run(self) -> Result<()> { | 14 | pub(crate) fn run(self) -> Result<()> { |