diff options
-rw-r--r-- | crates/ra_assists/src/assists/auto_import.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/expr/lower.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir/src/generics.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/ids.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir/src/impl_block.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/marks.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/raw.rs | 41 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/macros.rs | 105 | ||||
-rw-r--r-- | crates/ra_hir/src/path.rs | 64 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 33 | ||||
-rw-r--r-- | crates/ra_hir/src/type_ref.rs | 2 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_expander/transcriber.rs | 2 |
14 files changed, 268 insertions, 37 deletions
diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/assists/auto_import.rs index 5aae98546..43c14ad23 100644 --- a/crates/ra_assists/src/assists/auto_import.rs +++ b/crates/ra_assists/src/assists/auto_import.rs | |||
@@ -512,7 +512,7 @@ pub fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> { | |||
512 | hir::PathKind::Plain => {} | 512 | hir::PathKind::Plain => {} |
513 | hir::PathKind::Self_ => ps.push("self".into()), | 513 | hir::PathKind::Self_ => ps.push("self".into()), |
514 | hir::PathKind::Super => ps.push("super".into()), | 514 | hir::PathKind::Super => ps.push("super".into()), |
515 | hir::PathKind::Type(_) => return None, | 515 | hir::PathKind::Type(_) | hir::PathKind::DollarCrate(_) => return None, |
516 | } | 516 | } |
517 | for s in path.segments.iter() { | 517 | for s in path.segments.iter() { |
518 | ps.push(s.name.to_string().into()); | 518 | ps.push(s.name.to_string().into()); |
diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs index 61535d24f..6d6f60506 100644 --- a/crates/ra_hir/src/expr/lower.rs +++ b/crates/ra_hir/src/expr/lower.rs | |||
@@ -272,8 +272,11 @@ where | |||
272 | self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr) | 272 | self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr) |
273 | } | 273 | } |
274 | ast::Expr::PathExpr(e) => { | 274 | ast::Expr::PathExpr(e) => { |
275 | let path = | 275 | let path = e |
276 | e.path().and_then(Path::from_ast).map(Expr::Path).unwrap_or(Expr::Missing); | 276 | .path() |
277 | .and_then(|path| self.parse_path(path)) | ||
278 | .map(Expr::Path) | ||
279 | .unwrap_or(Expr::Missing); | ||
277 | self.alloc_expr(path, syntax_ptr) | 280 | self.alloc_expr(path, syntax_ptr) |
278 | } | 281 | } |
279 | ast::Expr::ContinueExpr(_e) => { | 282 | ast::Expr::ContinueExpr(_e) => { |
@@ -295,7 +298,7 @@ where | |||
295 | self.alloc_expr(Expr::Return { expr }, syntax_ptr) | 298 | self.alloc_expr(Expr::Return { expr }, syntax_ptr) |
296 | } | 299 | } |
297 | ast::Expr::RecordLit(e) => { | 300 | ast::Expr::RecordLit(e) => { |
298 | let path = e.path().and_then(Path::from_ast); | 301 | let path = e.path().and_then(|path| self.parse_path(path)); |
299 | let mut field_ptrs = Vec::new(); | 302 | let mut field_ptrs = Vec::new(); |
300 | let record_lit = if let Some(nfl) = e.record_field_list() { | 303 | let record_lit = if let Some(nfl) = e.record_field_list() { |
301 | let fields = nfl | 304 | let fields = nfl |
@@ -459,7 +462,7 @@ where | |||
459 | .ast_id(&e) | 462 | .ast_id(&e) |
460 | .with_file_id(self.current_file_id); | 463 | .with_file_id(self.current_file_id); |
461 | 464 | ||
462 | if let Some(path) = e.path().and_then(Path::from_ast) { | 465 | if let Some(path) = e.path().and_then(|path| self.parse_path(path)) { |
463 | if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) { | 466 | if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) { |
464 | let call_id = MacroCallLoc { def: def.id, ast_id }.id(self.db); | 467 | let call_id = MacroCallLoc { def: def.id, ast_id }.id(self.db); |
465 | let file_id = call_id.as_file(MacroFileKind::Expr); | 468 | let file_id = call_id.as_file(MacroFileKind::Expr); |
@@ -529,7 +532,7 @@ where | |||
529 | Pat::Bind { name, mode: annotation, subpat } | 532 | Pat::Bind { name, mode: annotation, subpat } |
530 | } | 533 | } |
531 | ast::Pat::TupleStructPat(p) => { | 534 | ast::Pat::TupleStructPat(p) => { |
532 | let path = p.path().and_then(Path::from_ast); | 535 | let path = p.path().and_then(|path| self.parse_path(path)); |
533 | let args = p.args().map(|p| self.collect_pat(p)).collect(); | 536 | let args = p.args().map(|p| self.collect_pat(p)).collect(); |
534 | Pat::TupleStruct { path, args } | 537 | Pat::TupleStruct { path, args } |
535 | } | 538 | } |
@@ -539,7 +542,7 @@ where | |||
539 | Pat::Ref { pat, mutability } | 542 | Pat::Ref { pat, mutability } |
540 | } | 543 | } |
541 | ast::Pat::PathPat(p) => { | 544 | ast::Pat::PathPat(p) => { |
542 | let path = p.path().and_then(Path::from_ast); | 545 | let path = p.path().and_then(|path| self.parse_path(path)); |
543 | path.map(Pat::Path).unwrap_or(Pat::Missing) | 546 | path.map(Pat::Path).unwrap_or(Pat::Missing) |
544 | } | 547 | } |
545 | ast::Pat::TuplePat(p) => { | 548 | ast::Pat::TuplePat(p) => { |
@@ -548,7 +551,7 @@ where | |||
548 | } | 551 | } |
549 | ast::Pat::PlaceholderPat(_) => Pat::Wild, | 552 | ast::Pat::PlaceholderPat(_) => Pat::Wild, |
550 | ast::Pat::RecordPat(p) => { | 553 | ast::Pat::RecordPat(p) => { |
551 | let path = p.path().and_then(Path::from_ast); | 554 | let path = p.path().and_then(|path| self.parse_path(path)); |
552 | let record_field_pat_list = | 555 | let record_field_pat_list = |
553 | p.record_field_pat_list().expect("every struct should have a field list"); | 556 | p.record_field_pat_list().expect("every struct should have a field list"); |
554 | let mut fields: Vec<_> = record_field_pat_list | 557 | let mut fields: Vec<_> = record_field_pat_list |
@@ -589,6 +592,10 @@ where | |||
589 | self.missing_pat() | 592 | self.missing_pat() |
590 | } | 593 | } |
591 | } | 594 | } |
595 | |||
596 | fn parse_path(&mut self, path: ast::Path) -> Option<Path> { | ||
597 | Path::from_src(Source { ast: path, file_id: self.current_file_id }, self.db) | ||
598 | } | ||
592 | } | 599 | } |
593 | 600 | ||
594 | impl From<ast::BinOp> for BinaryOp { | 601 | impl From<ast::BinOp> for BinaryOp { |
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index 6865d34ba..4ce7551c3 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs | |||
@@ -132,6 +132,7 @@ impl GenericParams { | |||
132 | fn fill_params(&mut self, params: ast::TypeParamList, start: u32) { | 132 | fn fill_params(&mut self, params: ast::TypeParamList, start: u32) { |
133 | for (idx, type_param) in params.type_params().enumerate() { | 133 | for (idx, type_param) in params.type_params().enumerate() { |
134 | let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); | 134 | let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); |
135 | // FIXME: Use `Path::from_src` | ||
135 | let default = type_param.default_type().and_then(|t| t.path()).and_then(Path::from_ast); | 136 | let default = type_param.default_type().and_then(|t| t.path()).and_then(Path::from_ast); |
136 | 137 | ||
137 | let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default }; | 138 | let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default }; |
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index 246377100..bcbcd3dd7 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs | |||
@@ -58,6 +58,17 @@ impl HirFileId { | |||
58 | } | 58 | } |
59 | } | 59 | } |
60 | 60 | ||
61 | /// Get the crate which the macro lives in, if it is a macro file. | ||
62 | pub(crate) fn macro_crate(self, db: &impl AstDatabase) -> Option<Crate> { | ||
63 | match self.0 { | ||
64 | HirFileIdRepr::File(_) => None, | ||
65 | HirFileIdRepr::Macro(macro_file) => { | ||
66 | let loc = macro_file.macro_call_id.loc(db); | ||
67 | Some(loc.def.krate) | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | |||
61 | pub(crate) fn parse_or_expand_query( | 72 | pub(crate) fn parse_or_expand_query( |
62 | db: &impl AstDatabase, | 73 | db: &impl AstDatabase, |
63 | file_id: HirFileId, | 74 | file_id: HirFileId, |
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index d830202bd..c66a1c6a6 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs | |||
@@ -218,7 +218,10 @@ impl ModuleImplBlocks { | |||
218 | ast::ItemOrMacro::Macro(macro_call) => { | 218 | ast::ItemOrMacro::Macro(macro_call) => { |
219 | //FIXME: we should really cut down on the boilerplate required to process a macro | 219 | //FIXME: we should really cut down on the boilerplate required to process a macro |
220 | let ast_id = db.ast_id_map(file_id).ast_id(¯o_call).with_file_id(file_id); | 220 | let ast_id = db.ast_id_map(file_id).ast_id(¯o_call).with_file_id(file_id); |
221 | if let Some(path) = macro_call.path().and_then(Path::from_ast) { | 221 | if let Some(path) = macro_call |
222 | .path() | ||
223 | .and_then(|path| Path::from_src(Source { ast: path, file_id }, db)) | ||
224 | { | ||
222 | if let Some(def) = self.module.resolver(db).resolve_path_as_macro(db, &path) | 225 | if let Some(def) = self.module.resolver(db).resolve_path_as_macro(db, &path) |
223 | { | 226 | { |
224 | let call_id = MacroCallLoc { def: def.id, ast_id }.id(db); | 227 | let call_id = MacroCallLoc { def: def.id, ast_id }.id(db); |
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index b2111be05..72f76bb79 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs | |||
@@ -14,4 +14,6 @@ test_utils::marks!( | |||
14 | macro_rules_from_other_crates_are_visible_with_macro_use | 14 | macro_rules_from_other_crates_are_visible_with_macro_use |
15 | prelude_is_macro_use | 15 | prelude_is_macro_use |
16 | coerce_merge_fail_fallback | 16 | coerce_merge_fail_fallback |
17 | macro_dollar_crate_self | ||
18 | macro_dollar_crate_other | ||
17 | ); | 19 | ); |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index b808a0c36..15b5b4ee6 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -332,6 +332,20 @@ impl CrateDefMap { | |||
332 | ) -> ResolvePathResult { | 332 | ) -> ResolvePathResult { |
333 | let mut segments = path.segments.iter().enumerate(); | 333 | let mut segments = path.segments.iter().enumerate(); |
334 | let mut curr_per_ns: PerNs = match path.kind { | 334 | let mut curr_per_ns: PerNs = match path.kind { |
335 | PathKind::DollarCrate(krate) => { | ||
336 | if krate == self.krate { | ||
337 | tested_by!(macro_dollar_crate_self); | ||
338 | PerNs::types(Module { krate: self.krate, module_id: self.root }.into()) | ||
339 | } else { | ||
340 | match krate.root_module(db) { | ||
341 | Some(module) => { | ||
342 | tested_by!(macro_dollar_crate_other); | ||
343 | PerNs::types(module.into()) | ||
344 | } | ||
345 | None => return ResolvePathResult::empty(ReachedFixedPoint::No), | ||
346 | } | ||
347 | } | ||
348 | } | ||
335 | PathKind::Crate => { | 349 | PathKind::Crate => { |
336 | PerNs::types(Module { krate: self.krate, module_id: self.root }.into()) | 350 | PerNs::types(Module { krate: self.krate, module_id: self.root }.into()) |
337 | } | 351 | } |
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs index 29aaddbf1..c607b8a11 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs | |||
@@ -9,7 +9,7 @@ use test_utils::tested_by; | |||
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | db::{AstDatabase, DefDatabase}, | 11 | db::{AstDatabase, DefDatabase}, |
12 | AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, | 12 | AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, Source, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | /// `RawItems` is a set of top-level items in a file (except for impls). | 15 | /// `RawItems` is a set of top-level items in a file (except for impls). |
@@ -71,6 +71,8 @@ impl RawItems { | |||
71 | raw_items: RawItems::default(), | 71 | raw_items: RawItems::default(), |
72 | source_ast_id_map: db.ast_id_map(file_id), | 72 | source_ast_id_map: db.ast_id_map(file_id), |
73 | source_map: ImportSourceMap::default(), | 73 | source_map: ImportSourceMap::default(), |
74 | file_id, | ||
75 | db, | ||
74 | }; | 76 | }; |
75 | if let Some(node) = db.parse_or_expand(file_id) { | 77 | if let Some(node) = db.parse_or_expand(file_id) { |
76 | if let Some(source_file) = ast::SourceFile::cast(node.clone()) { | 78 | if let Some(source_file) = ast::SourceFile::cast(node.clone()) { |
@@ -192,13 +194,15 @@ pub(super) struct MacroData { | |||
192 | pub(super) export: bool, | 194 | pub(super) export: bool, |
193 | } | 195 | } |
194 | 196 | ||
195 | struct RawItemsCollector { | 197 | struct RawItemsCollector<DB> { |
196 | raw_items: RawItems, | 198 | raw_items: RawItems, |
197 | source_ast_id_map: Arc<AstIdMap>, | 199 | source_ast_id_map: Arc<AstIdMap>, |
198 | source_map: ImportSourceMap, | 200 | source_map: ImportSourceMap, |
201 | file_id: HirFileId, | ||
202 | db: DB, | ||
199 | } | 203 | } |
200 | 204 | ||
201 | impl RawItemsCollector { | 205 | impl<DB: AstDatabase> RawItemsCollector<&'_ DB> { |
202 | fn process_module(&mut self, current_module: Option<Module>, body: impl ast::ModuleItemOwner) { | 206 | fn process_module(&mut self, current_module: Option<Module>, body: impl ast::ModuleItemOwner) { |
203 | for item_or_macro in body.items_with_macros() { | 207 | for item_or_macro in body.items_with_macros() { |
204 | match item_or_macro { | 208 | match item_or_macro { |
@@ -300,17 +304,21 @@ impl RawItemsCollector { | |||
300 | fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) { | 304 | fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) { |
301 | let is_prelude = use_item.has_atom_attr("prelude_import"); | 305 | let is_prelude = use_item.has_atom_attr("prelude_import"); |
302 | 306 | ||
303 | Path::expand_use_item(&use_item, |path, use_tree, is_glob, alias| { | 307 | Path::expand_use_item( |
304 | let import_data = ImportData { | 308 | Source { ast: use_item, file_id: self.file_id }, |
305 | path, | 309 | self.db, |
306 | alias, | 310 | |path, use_tree, is_glob, alias| { |
307 | is_glob, | 311 | let import_data = ImportData { |
308 | is_prelude, | 312 | path, |
309 | is_extern_crate: false, | 313 | alias, |
310 | is_macro_use: false, | 314 | is_glob, |
311 | }; | 315 | is_prelude, |
312 | self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree))); | 316 | is_extern_crate: false, |
313 | }) | 317 | is_macro_use: false, |
318 | }; | ||
319 | self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree))); | ||
320 | }, | ||
321 | ) | ||
314 | } | 322 | } |
315 | 323 | ||
316 | fn add_extern_crate_item( | 324 | fn add_extern_crate_item( |
@@ -335,7 +343,10 @@ impl RawItemsCollector { | |||
335 | } | 343 | } |
336 | 344 | ||
337 | fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { | 345 | fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { |
338 | let path = match m.path().and_then(Path::from_ast) { | 346 | let path = match m |
347 | .path() | ||
348 | .and_then(|path| Path::from_src(Source { ast: path, file_id: self.file_id }, self.db)) | ||
349 | { | ||
339 | Some(it) => it, | 350 | Some(it) => it, |
340 | _ => return, | 351 | _ => return, |
341 | }; | 352 | }; |
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs index bd60f4258..e4b408394 100644 --- a/crates/ra_hir/src/nameres/tests/macros.rs +++ b/crates/ra_hir/src/nameres/tests/macros.rs | |||
@@ -515,3 +515,108 @@ fn path_qualified_macros() { | |||
515 | â‹®not_found: _ | 515 | â‹®not_found: _ |
516 | "###); | 516 | "###); |
517 | } | 517 | } |
518 | |||
519 | #[test] | ||
520 | fn macro_dollar_crate_is_correct_in_item() { | ||
521 | covers!(macro_dollar_crate_self); | ||
522 | covers!(macro_dollar_crate_other); | ||
523 | let map = def_map_with_crate_graph( | ||
524 | " | ||
525 | //- /main.rs | ||
526 | #[macro_use] | ||
527 | extern crate foo; | ||
528 | |||
529 | #[macro_use] | ||
530 | mod m { | ||
531 | macro_rules! current { | ||
532 | () => { | ||
533 | use $crate::Foo as FooSelf; | ||
534 | } | ||
535 | } | ||
536 | } | ||
537 | |||
538 | struct Foo; | ||
539 | |||
540 | current!(); | ||
541 | not_current1!(); | ||
542 | foo::not_current2!(); | ||
543 | |||
544 | //- /lib.rs | ||
545 | mod m { | ||
546 | #[macro_export] | ||
547 | macro_rules! not_current1 { | ||
548 | () => { | ||
549 | use $crate::Bar; | ||
550 | } | ||
551 | } | ||
552 | } | ||
553 | |||
554 | #[macro_export] | ||
555 | macro_rules! not_current2 { | ||
556 | () => { | ||
557 | use $crate::Baz; | ||
558 | } | ||
559 | } | ||
560 | |||
561 | struct Bar; | ||
562 | struct Baz; | ||
563 | ", | ||
564 | crate_graph! { | ||
565 | "main": ("/main.rs", ["foo"]), | ||
566 | "foo": ("/lib.rs", []), | ||
567 | }, | ||
568 | ); | ||
569 | assert_snapshot!(map, @r###" | ||
570 | â‹®crate | ||
571 | â‹®Bar: t v | ||
572 | â‹®Baz: t v | ||
573 | â‹®Foo: t v | ||
574 | â‹®FooSelf: t v | ||
575 | â‹®foo: t | ||
576 | â‹®m: t | ||
577 | â‹® | ||
578 | â‹®crate::m | ||
579 | "###); | ||
580 | } | ||
581 | |||
582 | #[test] | ||
583 | fn macro_dollar_crate_is_correct_in_indirect_deps() { | ||
584 | covers!(macro_dollar_crate_other); | ||
585 | // From std | ||
586 | let map = def_map_with_crate_graph( | ||
587 | r#" | ||
588 | //- /main.rs | ||
589 | foo!(); | ||
590 | |||
591 | //- /std.rs | ||
592 | #[prelude_import] | ||
593 | use self::prelude::*; | ||
594 | |||
595 | pub use core::foo; | ||
596 | |||
597 | mod prelude {} | ||
598 | |||
599 | #[macro_use] | ||
600 | mod std_macros; | ||
601 | |||
602 | //- /core.rs | ||
603 | #[macro_export] | ||
604 | macro_rules! foo { | ||
605 | () => { | ||
606 | use $crate::bar; | ||
607 | } | ||
608 | } | ||
609 | |||
610 | pub struct bar; | ||
611 | "#, | ||
612 | crate_graph! { | ||
613 | "main": ("/main.rs", ["std"]), | ||
614 | "std": ("/std.rs", ["core"]), | ||
615 | "core": ("/core.rs", []), | ||
616 | }, | ||
617 | ); | ||
618 | assert_snapshot!(map, @r###" | ||
619 | â‹®crate | ||
620 | â‹®bar: t v | ||
621 | "###); | ||
622 | } | ||
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 39d1b7e46..158c853d4 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -5,7 +5,7 @@ use ra_syntax::{ | |||
5 | AstNode, | 5 | AstNode, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::{name, type_ref::TypeRef, AsName, Name}; | 8 | use crate::{db::AstDatabase, name, type_ref::TypeRef, AsName, Crate, Name, Source}; |
9 | 9 | ||
10 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 10 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
11 | pub struct Path { | 11 | pub struct Path { |
@@ -52,16 +52,19 @@ pub enum PathKind { | |||
52 | Abs, | 52 | Abs, |
53 | // Type based path like `<T>::foo` | 53 | // Type based path like `<T>::foo` |
54 | Type(Box<TypeRef>), | 54 | Type(Box<TypeRef>), |
55 | // `$crate` from macro expansion | ||
56 | DollarCrate(Crate), | ||
55 | } | 57 | } |
56 | 58 | ||
57 | impl Path { | 59 | impl Path { |
58 | /// Calls `cb` with all paths, represented by this use item. | 60 | /// Calls `cb` with all paths, represented by this use item. |
59 | pub fn expand_use_item( | 61 | pub fn expand_use_item( |
60 | item: &ast::UseItem, | 62 | item_src: Source<ast::UseItem>, |
63 | db: &impl AstDatabase, | ||
61 | mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>), | 64 | mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>), |
62 | ) { | 65 | ) { |
63 | if let Some(tree) = item.use_tree() { | 66 | if let Some(tree) = item_src.ast.use_tree() { |
64 | expand_use_tree(None, tree, &mut cb); | 67 | expand_use_tree(None, tree, &|| item_src.file_id.macro_crate(db), &mut cb); |
65 | } | 68 | } |
66 | } | 69 | } |
67 | 70 | ||
@@ -76,7 +79,19 @@ impl Path { | |||
76 | } | 79 | } |
77 | 80 | ||
78 | /// Converts an `ast::Path` to `Path`. Works with use trees. | 81 | /// Converts an `ast::Path` to `Path`. Works with use trees. |
79 | pub fn from_ast(mut path: ast::Path) -> Option<Path> { | 82 | /// DEPRECATED: It does not handle `$crate` from macro call. |
83 | pub fn from_ast(path: ast::Path) -> Option<Path> { | ||
84 | Path::parse(path, &|| None) | ||
85 | } | ||
86 | |||
87 | /// Converts an `ast::Path` to `Path`. Works with use trees. | ||
88 | /// It correctly handles `$crate` based path from macro call. | ||
89 | pub fn from_src(source: Source<ast::Path>, db: &impl AstDatabase) -> Option<Path> { | ||
90 | let file_id = source.file_id; | ||
91 | Path::parse(source.ast, &|| file_id.macro_crate(db)) | ||
92 | } | ||
93 | |||
94 | fn parse(mut path: ast::Path, macro_crate: &impl Fn() -> Option<Crate>) -> Option<Path> { | ||
80 | let mut kind = PathKind::Plain; | 95 | let mut kind = PathKind::Plain; |
81 | let mut segments = Vec::new(); | 96 | let mut segments = Vec::new(); |
82 | loop { | 97 | loop { |
@@ -88,6 +103,13 @@ impl Path { | |||
88 | 103 | ||
89 | match segment.kind()? { | 104 | match segment.kind()? { |
90 | ast::PathSegmentKind::Name(name) => { | 105 | ast::PathSegmentKind::Name(name) => { |
106 | if name.text() == "$crate" { | ||
107 | if let Some(macro_crate) = macro_crate() { | ||
108 | kind = PathKind::DollarCrate(macro_crate); | ||
109 | break; | ||
110 | } | ||
111 | } | ||
112 | |||
91 | let args = segment | 113 | let args = segment |
92 | .type_arg_list() | 114 | .type_arg_list() |
93 | .and_then(GenericArgs::from_ast) | 115 | .and_then(GenericArgs::from_ast) |
@@ -113,7 +135,7 @@ impl Path { | |||
113 | } | 135 | } |
114 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo | 136 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo |
115 | Some(trait_ref) => { | 137 | Some(trait_ref) => { |
116 | let path = Path::from_ast(trait_ref.path()?)?; | 138 | let path = Path::parse(trait_ref.path()?, macro_crate)?; |
117 | kind = path.kind; | 139 | kind = path.kind; |
118 | let mut prefix_segments = path.segments; | 140 | let mut prefix_segments = path.segments; |
119 | prefix_segments.reverse(); | 141 | prefix_segments.reverse(); |
@@ -264,6 +286,7 @@ impl From<Name> for Path { | |||
264 | fn expand_use_tree( | 286 | fn expand_use_tree( |
265 | prefix: Option<Path>, | 287 | prefix: Option<Path>, |
266 | tree: ast::UseTree, | 288 | tree: ast::UseTree, |
289 | macro_crate: &impl Fn() -> Option<Crate>, | ||
267 | cb: &mut impl FnMut(Path, &ast::UseTree, bool, Option<Name>), | 290 | cb: &mut impl FnMut(Path, &ast::UseTree, bool, Option<Name>), |
268 | ) { | 291 | ) { |
269 | if let Some(use_tree_list) = tree.use_tree_list() { | 292 | if let Some(use_tree_list) = tree.use_tree_list() { |
@@ -272,13 +295,13 @@ fn expand_use_tree( | |||
272 | None => prefix, | 295 | None => prefix, |
273 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) | 296 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) |
274 | // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) | 297 | // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) |
275 | Some(path) => match convert_path(prefix, path) { | 298 | Some(path) => match convert_path(prefix, path, macro_crate) { |
276 | Some(it) => Some(it), | 299 | Some(it) => Some(it), |
277 | None => return, // FIXME: report errors somewhere | 300 | None => return, // FIXME: report errors somewhere |
278 | }, | 301 | }, |
279 | }; | 302 | }; |
280 | for child_tree in use_tree_list.use_trees() { | 303 | for child_tree in use_tree_list.use_trees() { |
281 | expand_use_tree(prefix.clone(), child_tree, cb); | 304 | expand_use_tree(prefix.clone(), child_tree, macro_crate, cb); |
282 | } | 305 | } |
283 | } else { | 306 | } else { |
284 | let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name()); | 307 | let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name()); |
@@ -295,7 +318,7 @@ fn expand_use_tree( | |||
295 | } | 318 | } |
296 | } | 319 | } |
297 | } | 320 | } |
298 | if let Some(path) = convert_path(prefix, ast_path) { | 321 | if let Some(path) = convert_path(prefix, ast_path, macro_crate) { |
299 | let is_glob = tree.has_star(); | 322 | let is_glob = tree.has_star(); |
300 | cb(path, &tree, is_glob, alias) | 323 | cb(path, &tree, is_glob, alias) |
301 | } | 324 | } |
@@ -305,12 +328,29 @@ fn expand_use_tree( | |||
305 | } | 328 | } |
306 | } | 329 | } |
307 | 330 | ||
308 | fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> { | 331 | fn convert_path( |
309 | let prefix = | 332 | prefix: Option<Path>, |
310 | if let Some(qual) = path.qualifier() { Some(convert_path(prefix, qual)?) } else { prefix }; | 333 | path: ast::Path, |
334 | macro_crate: &impl Fn() -> Option<Crate>, | ||
335 | ) -> Option<Path> { | ||
336 | let prefix = if let Some(qual) = path.qualifier() { | ||
337 | Some(convert_path(prefix, qual, macro_crate)?) | ||
338 | } else { | ||
339 | prefix | ||
340 | }; | ||
341 | |||
311 | let segment = path.segment()?; | 342 | let segment = path.segment()?; |
312 | let res = match segment.kind()? { | 343 | let res = match segment.kind()? { |
313 | ast::PathSegmentKind::Name(name) => { | 344 | ast::PathSegmentKind::Name(name) => { |
345 | if name.text() == "$crate" { | ||
346 | if let Some(krate) = macro_crate() { | ||
347 | return Some(Path::from_simple_segments( | ||
348 | PathKind::DollarCrate(krate), | ||
349 | iter::empty(), | ||
350 | )); | ||
351 | } | ||
352 | } | ||
353 | |||
314 | // no type args in use | 354 | // no type args in use |
315 | let mut res = prefix | 355 | let mut res = prefix |
316 | .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) }); | 356 | .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) }); |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index bd4be8430..6e89bfc76 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -203,6 +203,7 @@ impl SourceAnalyzer { | |||
203 | db: &impl HirDatabase, | 203 | db: &impl HirDatabase, |
204 | macro_call: &ast::MacroCall, | 204 | macro_call: &ast::MacroCall, |
205 | ) -> Option<MacroDef> { | 205 | ) -> Option<MacroDef> { |
206 | // This must be a normal source file rather than macro file. | ||
206 | let path = macro_call.path().and_then(Path::from_ast)?; | 207 | let path = macro_call.path().and_then(Path::from_ast)?; |
207 | self.resolver.resolve_path_as_macro(db, &path) | 208 | self.resolver.resolve_path_as_macro(db, &path) |
208 | } | 209 | } |
@@ -261,6 +262,7 @@ impl SourceAnalyzer { | |||
261 | return Some(PathResolution::AssocItem(assoc)); | 262 | return Some(PathResolution::AssocItem(assoc)); |
262 | } | 263 | } |
263 | } | 264 | } |
265 | // This must be a normal source file rather than macro file. | ||
264 | let hir_path = crate::Path::from_ast(path.clone())?; | 266 | let hir_path = crate::Path::from_ast(path.clone())?; |
265 | self.resolve_hir_path(db, &hir_path) | 267 | self.resolve_hir_path(db, &hir_path) |
266 | } | 268 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 4362bb27a..bd2b07755 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -3130,6 +3130,39 @@ fn test() { S.foo()<|>; } | |||
3130 | assert_eq!(t, "u128"); | 3130 | assert_eq!(t, "u128"); |
3131 | } | 3131 | } |
3132 | 3132 | ||
3133 | #[test] | ||
3134 | fn infer_macro_with_dollar_crate_is_correct_in_expr() { | ||
3135 | covers!(macro_dollar_crate_other); | ||
3136 | let (mut db, pos) = MockDatabase::with_position( | ||
3137 | r#" | ||
3138 | //- /main.rs | ||
3139 | fn test() { | ||
3140 | let x = (foo::foo!(1), foo::foo!(2)); | ||
3141 | x<|>; | ||
3142 | } | ||
3143 | |||
3144 | //- /lib.rs | ||
3145 | #[macro_export] | ||
3146 | macro_rules! foo { | ||
3147 | (1) => { $crate::bar!() }; | ||
3148 | (2) => { 1 + $crate::baz() }; | ||
3149 | } | ||
3150 | |||
3151 | #[macro_export] | ||
3152 | macro_rules! bar { | ||
3153 | () => { 42 } | ||
3154 | } | ||
3155 | |||
3156 | pub fn baz() -> usize { 31usize } | ||
3157 | "#, | ||
3158 | ); | ||
3159 | db.set_crate_graph_from_fixture(crate_graph! { | ||
3160 | "main": ("/main.rs", ["foo"]), | ||
3161 | "foo": ("/lib.rs", []), | ||
3162 | }); | ||
3163 | assert_eq!("(i32, usize)", type_at_pos(&db, pos)); | ||
3164 | } | ||
3165 | |||
3133 | #[ignore] | 3166 | #[ignore] |
3134 | #[test] | 3167 | #[test] |
3135 | fn method_resolution_trait_before_autoref() { | 3168 | fn method_resolution_trait_before_autoref() { |
diff --git a/crates/ra_hir/src/type_ref.rs b/crates/ra_hir/src/type_ref.rs index bc8acc7ee..2cf06b250 100644 --- a/crates/ra_hir/src/type_ref.rs +++ b/crates/ra_hir/src/type_ref.rs | |||
@@ -72,6 +72,7 @@ impl TypeRef { | |||
72 | } | 72 | } |
73 | ast::TypeRef::NeverType(..) => TypeRef::Never, | 73 | ast::TypeRef::NeverType(..) => TypeRef::Never, |
74 | ast::TypeRef::PathType(inner) => { | 74 | ast::TypeRef::PathType(inner) => { |
75 | // FIXME: Use `Path::from_src` | ||
75 | inner.path().and_then(Path::from_ast).map(TypeRef::Path).unwrap_or(TypeRef::Error) | 76 | inner.path().and_then(Path::from_ast).map(TypeRef::Path).unwrap_or(TypeRef::Error) |
76 | } | 77 | } |
77 | ast::TypeRef::PointerType(inner) => { | 78 | ast::TypeRef::PointerType(inner) => { |
@@ -141,6 +142,7 @@ impl TypeBound { | |||
141 | Some(p) => p, | 142 | Some(p) => p, |
142 | None => return TypeBound::Error, | 143 | None => return TypeBound::Error, |
143 | }; | 144 | }; |
145 | // FIXME: Use `Path::from_src` | ||
144 | let path = match Path::from_ast(path) { | 146 | let path = match Path::from_ast(path) { |
145 | Some(p) => p, | 147 | Some(p) => p, |
146 | None => return TypeBound::Error, | 148 | None => return TypeBound::Error, |
diff --git a/crates/ra_mbe/src/mbe_expander/transcriber.rs b/crates/ra_mbe/src/mbe_expander/transcriber.rs index c22680b93..ed094d5bb 100644 --- a/crates/ra_mbe/src/mbe_expander/transcriber.rs +++ b/crates/ra_mbe/src/mbe_expander/transcriber.rs | |||
@@ -86,7 +86,7 @@ fn expand_subtree(ctx: &mut ExpandCtx, template: &tt::Subtree) -> Result<tt::Sub | |||
86 | 86 | ||
87 | fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> Result<Fragment, ExpandError> { | 87 | fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> Result<Fragment, ExpandError> { |
88 | let res = if v == "crate" { | 88 | let res = if v == "crate" { |
89 | // FIXME: Properly handle $crate token | 89 | // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path. |
90 | let tt = | 90 | let tt = |
91 | tt::Leaf::from(tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() }) | 91 | tt::Leaf::from(tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() }) |
92 | .into(); | 92 | .into(); |