aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-05-27 08:38:21 +0100
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-05-27 08:38:21 +0100
commitbdd779aa44455d86a9975800ab6cd70057fab4a3 (patch)
tree6c39bd0ad6ce7ab52cfcf19ad6b5c8f34c68420f
parentce694ae11854a806031db98c51c068253f927519 (diff)
parent6d68d60d32222af9fda1a6a89911a2c25f4fe402 (diff)
Merge #1277
1277: Improve macro item resolution r=matklad a=edwin0cheng ~This PR add a new namespace `Macros` in `per_ns.rs` to allow following use case:~ This PR improve macro item resolution to allow following use case: ```rust //- /main.rs use foo::bar; bar!(); //- /lib.rs (crate foo) #[macro_export] macro_rules! bar{ () => { struct Foo { field: u32 } } ``` Co-authored-by: Edwin Cheng <[email protected]>
-rw-r--r--Cargo.lock1
-rw-r--r--crates/ra_hir/Cargo.toml1
-rw-r--r--crates/ra_hir/src/code_model.rs6
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/nameres.rs115
-rw-r--r--crates/ra_hir/src/nameres/collector.rs187
-rw-r--r--crates/ra_hir/src/nameres/tests.rs17
-rw-r--r--crates/ra_hir/src/nameres/tests/macros.rs40
8 files changed, 273 insertions, 96 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a61aec4e1..79e632907 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1117,6 +1117,7 @@ dependencies = [
1117 "chalk-ir 0.1.0 (git+https://github.com/flodiebold/chalk.git?branch=fuel)", 1117 "chalk-ir 0.1.0 (git+https://github.com/flodiebold/chalk.git?branch=fuel)",
1118 "chalk-rust-ir 0.1.0 (git+https://github.com/flodiebold/chalk.git?branch=fuel)", 1118 "chalk-rust-ir 0.1.0 (git+https://github.com/flodiebold/chalk.git?branch=fuel)",
1119 "chalk-solve 0.1.0 (git+https://github.com/flodiebold/chalk.git?branch=fuel)", 1119 "chalk-solve 0.1.0 (git+https://github.com/flodiebold/chalk.git?branch=fuel)",
1120 "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
1120 "ena 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 1121 "ena 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
1121 "flexi_logger 0.11.5 (registry+https://github.com/rust-lang/crates.io-index)", 1122 "flexi_logger 0.11.5 (registry+https://github.com/rust-lang/crates.io-index)",
1122 "insta 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 1123 "insta 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml
index 294d047d8..18ecb7957 100644
--- a/crates/ra_hir/Cargo.toml
+++ b/crates/ra_hir/Cargo.toml
@@ -12,6 +12,7 @@ rustc-hash = "1.0"
12parking_lot = "0.7.0" 12parking_lot = "0.7.0"
13ena = "0.11" 13ena = "0.11"
14join_to_string = "0.1.3" 14join_to_string = "0.1.3"
15either = "1.5.2"
15 16
16ra_syntax = { path = "../ra_syntax" } 17ra_syntax = { path = "../ra_syntax" }
17ra_arena = { path = "../ra_arena" } 18ra_arena = { path = "../ra_arena" }
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 49030ce67..a9ffc8782 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -13,7 +13,7 @@ use crate::{
13 adt::{EnumVariantId, StructFieldId, VariantDef}, 13 adt::{EnumVariantId, StructFieldId, VariantDef},
14 generics::HasGenericParams, 14 generics::HasGenericParams,
15 docs::{Documentation, Docs, docs_from_ast}, 15 docs::{Documentation, Docs, docs_from_ast},
16 ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeAliasId}, 16 ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeAliasId, MacroDefId},
17 impl_block::ImplBlock, 17 impl_block::ImplBlock,
18 resolve::Resolver, 18 resolve::Resolver,
19 diagnostics::{DiagnosticSink}, 19 diagnostics::{DiagnosticSink},
@@ -937,6 +937,10 @@ impl Docs for TypeAlias {
937 docs_from_ast(&*self.source(db).1) 937 docs_from_ast(&*self.source(db).1)
938 } 938 }
939} 939}
940#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
941pub struct MacroDef {
942 pub(crate) id: MacroDefId,
943}
940 944
941pub enum Container { 945pub enum Container {
942 Trait(Trait), 946 Trait(Trait),
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index fe2d4adee..cb09c60f8 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -80,5 +80,5 @@ pub use self::code_model::{
80 Function, FnSignature, 80 Function, FnSignature,
81 StructField, FieldSource, 81 StructField, FieldSource,
82 Static, Const, ConstSignature, 82 Static, Const, ConstSignature,
83 Trait, TypeAlias, Container 83 Trait, TypeAlias, MacroDef, Container
84}; 84};
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 0290b3474..9b9212bfc 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -56,6 +56,7 @@ mod tests;
56use std::sync::Arc; 56use std::sync::Arc;
57 57
58use rustc_hash::{FxHashMap, FxHashSet}; 58use rustc_hash::{FxHashMap, FxHashSet};
59use either::Either;
59use ra_arena::{Arena, RawId, impl_arena_id}; 60use ra_arena::{Arena, RawId, impl_arena_id};
60use ra_db::{FileId, Edition}; 61use ra_db::{FileId, Edition};
61use test_utils::tested_by; 62use test_utils::tested_by;
@@ -63,7 +64,7 @@ use ra_syntax::ast;
63use ra_prof::profile; 64use ra_prof::profile;
64 65
65use crate::{ 66use crate::{
66 ModuleDef, Name, Crate, Module, 67 ModuleDef, Name, Crate, Module, MacroDef,
67 DefDatabase, Path, PathKind, HirFileId, Trait, 68 DefDatabase, Path, PathKind, HirFileId, Trait,
68 ids::MacroDefId, 69 ids::MacroDefId,
69 diagnostics::DiagnosticSink, 70 diagnostics::DiagnosticSink,
@@ -136,6 +137,7 @@ pub(crate) struct ModuleData {
136#[derive(Debug, Default, PartialEq, Eq, Clone)] 137#[derive(Debug, Default, PartialEq, Eq, Clone)]
137pub struct ModuleScope { 138pub struct ModuleScope {
138 items: FxHashMap<Name, Resolution>, 139 items: FxHashMap<Name, Resolution>,
140 macros: FxHashMap<Name, MacroDef>,
139} 141}
140 142
141impl ModuleScope { 143impl ModuleScope {
@@ -151,8 +153,17 @@ impl ModuleScope {
151 _ => None, 153 _ => None,
152 }) 154 })
153 } 155 }
156 fn get_item_or_macro(&self, name: &Name) -> Option<ItemOrMacro> {
157 match (self.items.get(name), self.macros.get(name)) {
158 (Some(item), _) if !item.def.is_none() => Some(Either::Left(item.def)),
159 (_, Some(macro_)) => Some(Either::Right(*macro_)),
160 _ => None,
161 }
162 }
154} 163}
155 164
165type ItemOrMacro = Either<PerNs<ModuleDef>, MacroDef>;
166
156#[derive(Debug, Clone, PartialEq, Eq, Default)] 167#[derive(Debug, Clone, PartialEq, Eq, Default)]
157pub struct Resolution { 168pub struct Resolution {
158 /// None for unresolved 169 /// None for unresolved
@@ -163,18 +174,18 @@ pub struct Resolution {
163 174
164#[derive(Debug, Clone)] 175#[derive(Debug, Clone)]
165struct ResolvePathResult { 176struct ResolvePathResult {
166 resolved_def: PerNs<ModuleDef>, 177 resolved_def: ItemOrMacro,
167 segment_index: Option<usize>, 178 segment_index: Option<usize>,
168 reached_fixedpoint: ReachedFixedPoint, 179 reached_fixedpoint: ReachedFixedPoint,
169} 180}
170 181
171impl ResolvePathResult { 182impl ResolvePathResult {
172 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { 183 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
173 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None) 184 ResolvePathResult::with(Either::Left(PerNs::none()), reached_fixedpoint, None)
174 } 185 }
175 186
176 fn with( 187 fn with(
177 resolved_def: PerNs<ModuleDef>, 188 resolved_def: ItemOrMacro,
178 reached_fixedpoint: ReachedFixedPoint, 189 reached_fixedpoint: ReachedFixedPoint,
179 segment_index: Option<usize>, 190 segment_index: Option<usize>,
180 ) -> ResolvePathResult { 191 ) -> ResolvePathResult {
@@ -194,6 +205,21 @@ enum ReachedFixedPoint {
194 No, 205 No,
195} 206}
196 207
208/// helper function for select item or macro to use
209fn or(left: ItemOrMacro, right: ItemOrMacro) -> ItemOrMacro {
210 match (left, right) {
211 (Either::Left(s), Either::Left(o)) => Either::Left(s.or(o)),
212 (Either::Right(s), _) => Either::Right(s),
213 (Either::Left(s), Either::Right(o)) => {
214 if !s.is_none() {
215 Either::Left(s)
216 } else {
217 Either::Right(o)
218 }
219 }
220 }
221}
222
197impl CrateDefMap { 223impl CrateDefMap {
198 pub(crate) fn crate_def_map_query(db: &impl DefDatabase, krate: Crate) -> Arc<CrateDefMap> { 224 pub(crate) fn crate_def_map_query(db: &impl DefDatabase, krate: Crate) -> Arc<CrateDefMap> {
199 let _p = profile("crate_def_map_query"); 225 let _p = profile("crate_def_map_query");
@@ -268,7 +294,17 @@ impl CrateDefMap {
268 original_module: CrateModuleId, 294 original_module: CrateModuleId,
269 path: &Path, 295 path: &Path,
270 ) -> (PerNs<ModuleDef>, Option<usize>) { 296 ) -> (PerNs<ModuleDef>, Option<usize>) {
271 let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path); 297 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
298 (res.resolved_def.left().unwrap_or_else(PerNs::none), res.segment_index)
299 }
300
301 fn resolve_path_with_macro(
302 &self,
303 db: &impl DefDatabase,
304 original_module: CrateModuleId,
305 path: &Path,
306 ) -> (ItemOrMacro, Option<usize>) {
307 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
272 (res.resolved_def, res.segment_index) 308 (res.resolved_def, res.segment_index)
273 } 309 }
274 310
@@ -278,7 +314,7 @@ impl CrateDefMap {
278 314
279 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change 315 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
280 // the result. 316 // the result.
281 fn resolve_path_fp( 317 fn resolve_path_fp_with_macro(
282 &self, 318 &self,
283 db: &impl DefDatabase, 319 db: &impl DefDatabase,
284 mode: ResolveMode, 320 mode: ResolveMode,
@@ -286,13 +322,13 @@ impl CrateDefMap {
286 path: &Path, 322 path: &Path,
287 ) -> ResolvePathResult { 323 ) -> ResolvePathResult {
288 let mut segments = path.segments.iter().enumerate(); 324 let mut segments = path.segments.iter().enumerate();
289 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { 325 let mut curr_per_ns: ItemOrMacro = match path.kind {
290 PathKind::Crate => { 326 PathKind::Crate => Either::Left(PerNs::types(
291 PerNs::types(Module { krate: self.krate, module_id: self.root }.into()) 327 Module { krate: self.krate, module_id: self.root }.into(),
292 } 328 )),
293 PathKind::Self_ => { 329 PathKind::Self_ => Either::Left(PerNs::types(
294 PerNs::types(Module { krate: self.krate, module_id: original_module }.into()) 330 Module { krate: self.krate, module_id: original_module }.into(),
295 } 331 )),
296 // plain import or absolute path in 2015: crate-relative with 332 // plain import or absolute path in 2015: crate-relative with
297 // fallback to extern prelude (with the simplification in 333 // fallback to extern prelude (with the simplification in
298 // rust-lang/rust#57745) 334 // rust-lang/rust#57745)
@@ -314,11 +350,11 @@ impl CrateDefMap {
314 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 350 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
315 }; 351 };
316 log::debug!("resolving {:?} in module", segment); 352 log::debug!("resolving {:?} in module", segment);
317 self.resolve_name_in_module(db, original_module, &segment.name) 353 self.resolve_name_in_module_with_macro(db, original_module, &segment.name)
318 } 354 }
319 PathKind::Super => { 355 PathKind::Super => {
320 if let Some(p) = self.modules[original_module].parent { 356 if let Some(p) = self.modules[original_module].parent {
321 PerNs::types(Module { krate: self.krate, module_id: p }.into()) 357 Either::Left(PerNs::types(Module { krate: self.krate, module_id: p }.into()))
322 } else { 358 } else {
323 log::debug!("super path in root module"); 359 log::debug!("super path in root module");
324 return ResolvePathResult::empty(ReachedFixedPoint::Yes); 360 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
@@ -332,7 +368,7 @@ impl CrateDefMap {
332 }; 368 };
333 if let Some(def) = self.extern_prelude.get(&segment.name) { 369 if let Some(def) = self.extern_prelude.get(&segment.name) {
334 log::debug!("absolute path {:?} resolved to crate {:?}", path, def); 370 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
335 PerNs::types(*def) 371 Either::Left(PerNs::types(*def))
336 } else { 372 } else {
337 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude 373 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
338 } 374 }
@@ -340,7 +376,7 @@ impl CrateDefMap {
340 }; 376 };
341 377
342 for (i, segment) in segments { 378 for (i, segment) in segments {
343 let curr = match curr_per_ns.as_ref().take_types() { 379 let curr = match curr_per_ns.as_ref().left().map_or(None, |m| m.as_ref().take_types()) {
344 Some(r) => r, 380 Some(r) => r,
345 None => { 381 None => {
346 // we still have path segments left, but the path so far 382 // we still have path segments left, but the path so far
@@ -362,7 +398,8 @@ impl CrateDefMap {
362 }; 398 };
363 log::debug!("resolving {:?} in other crate", path); 399 log::debug!("resolving {:?} in other crate", path);
364 let defp_map = db.crate_def_map(module.krate); 400 let defp_map = db.crate_def_map(module.krate);
365 let (def, s) = defp_map.resolve_path(db, module.module_id, &path); 401 let (def, s) =
402 defp_map.resolve_path_with_macro(db, module.module_id, &path);
366 return ResolvePathResult::with( 403 return ResolvePathResult::with(
367 def, 404 def,
368 ReachedFixedPoint::Yes, 405 ReachedFixedPoint::Yes,
@@ -370,8 +407,8 @@ impl CrateDefMap {
370 ); 407 );
371 } 408 }
372 409
373 match self[module.module_id].scope.items.get(&segment.name) { 410 match self[module.module_id].scope.get_item_or_macro(&segment.name) {
374 Some(res) if !res.def.is_none() => res.def, 411 Some(res) => res,
375 _ => { 412 _ => {
376 log::debug!("path segment {:?} not found", segment.name); 413 log::debug!("path segment {:?} not found", segment.name);
377 return ResolvePathResult::empty(ReachedFixedPoint::No); 414 return ResolvePathResult::empty(ReachedFixedPoint::No);
@@ -382,10 +419,10 @@ impl CrateDefMap {
382 // enum variant 419 // enum variant
383 tested_by!(can_import_enum_variant); 420 tested_by!(can_import_enum_variant);
384 match e.variant(db, &segment.name) { 421 match e.variant(db, &segment.name) {
385 Some(variant) => PerNs::both(variant.into(), variant.into()), 422 Some(variant) => Either::Left(PerNs::both(variant.into(), variant.into())),
386 None => { 423 None => {
387 return ResolvePathResult::with( 424 return ResolvePathResult::with(
388 PerNs::types((*e).into()), 425 Either::Left(PerNs::types((*e).into())),
389 ReachedFixedPoint::Yes, 426 ReachedFixedPoint::Yes,
390 Some(i), 427 Some(i),
391 ); 428 );
@@ -402,7 +439,7 @@ impl CrateDefMap {
402 ); 439 );
403 440
404 return ResolvePathResult::with( 441 return ResolvePathResult::with(
405 PerNs::types((*s).into()), 442 Either::Left(PerNs::types((*s).into())),
406 ReachedFixedPoint::Yes, 443 ReachedFixedPoint::Yes,
407 Some(i), 444 Some(i),
408 ); 445 );
@@ -412,12 +449,12 @@ impl CrateDefMap {
412 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) 449 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
413 } 450 }
414 451
415 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { 452 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> ItemOrMacro {
416 let from_crate_root = 453 let from_crate_root =
417 self[self.root].scope.items.get(name).map_or(PerNs::none(), |it| it.def); 454 self[self.root].scope.get_item_or_macro(name).unwrap_or(Either::Left(PerNs::none()));
418 let from_extern_prelude = self.resolve_name_in_extern_prelude(name); 455 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
419 456
420 from_crate_root.or(from_extern_prelude) 457 or(from_crate_root, Either::Left(from_extern_prelude))
421 } 458 }
422 459
423 pub(crate) fn resolve_name_in_module( 460 pub(crate) fn resolve_name_in_module(
@@ -426,32 +463,42 @@ impl CrateDefMap {
426 module: CrateModuleId, 463 module: CrateModuleId,
427 name: &Name, 464 name: &Name,
428 ) -> PerNs<ModuleDef> { 465 ) -> PerNs<ModuleDef> {
466 self.resolve_name_in_module_with_macro(db, module, name).left().unwrap_or_else(PerNs::none)
467 }
468
469 fn resolve_name_in_module_with_macro(
470 &self,
471 db: &impl DefDatabase,
472 module: CrateModuleId,
473 name: &Name,
474 ) -> ItemOrMacro {
429 // Resolve in: 475 // Resolve in:
430 // - current module / scope 476 // - current module / scope
431 // - extern prelude 477 // - extern prelude
432 // - std prelude 478 // - std prelude
433 let from_scope = self[module].scope.items.get(name).map_or(PerNs::none(), |it| it.def); 479 let from_scope =
480 self[module].scope.get_item_or_macro(name).unwrap_or(Either::Left(PerNs::none()));;
434 let from_extern_prelude = 481 let from_extern_prelude =
435 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); 482 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
436 let from_prelude = self.resolve_in_prelude(db, name); 483 let from_prelude = self.resolve_in_prelude(db, name);
437 484
438 from_scope.or(from_extern_prelude).or(from_prelude) 485 or(from_scope, or(Either::Left(from_extern_prelude), from_prelude))
439 } 486 }
440 487
441 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { 488 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
442 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) 489 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
443 } 490 }
444 491
445 fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs<ModuleDef> { 492 fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> ItemOrMacro {
446 if let Some(prelude) = self.prelude { 493 if let Some(prelude) = self.prelude {
447 let resolution = if prelude.krate == self.krate { 494 let resolution = if prelude.krate == self.krate {
448 self[prelude.module_id].scope.items.get(name).cloned() 495 self[prelude.module_id].scope.get_item_or_macro(name)
449 } else { 496 } else {
450 db.crate_def_map(prelude.krate)[prelude.module_id].scope.items.get(name).cloned() 497 db.crate_def_map(prelude.krate)[prelude.module_id].scope.get_item_or_macro(name)
451 }; 498 };
452 resolution.map(|r| r.def).unwrap_or_else(PerNs::none) 499 resolution.unwrap_or(Either::Left(PerNs::none()))
453 } else { 500 } else {
454 PerNs::none() 501 Either::Left(PerNs::none())
455 } 502 }
456 } 503 }
457} 504}
@@ -463,7 +510,7 @@ mod diagnostics {
463 use crate::{ 510 use crate::{
464 AstId, DefDatabase, 511 AstId, DefDatabase,
465 nameres::CrateModuleId, 512 nameres::CrateModuleId,
466 diagnostics::{DiagnosticSink, UnresolvedModule}, 513 diagnostics::{DiagnosticSink, UnresolvedModule}
467}; 514};
468 515
469 #[derive(Debug, PartialEq, Eq)] 516 #[derive(Debug, PartialEq, Eq)]
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index 621236551..ba7ea0017 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -1,17 +1,18 @@
1use arrayvec::ArrayVec; 1use arrayvec::ArrayVec;
2use rustc_hash::FxHashMap; 2use rustc_hash::FxHashMap;
3use either::Either;
3use relative_path::RelativePathBuf; 4use relative_path::RelativePathBuf;
4use test_utils::tested_by; 5use test_utils::tested_by;
5use ra_db::FileId; 6use ra_db::FileId;
6use ra_syntax::ast; 7use ra_syntax::ast;
7 8
8use crate::{ 9use crate::{
9 Function, Module, Struct, Union, Enum, Const, Static, Trait, TypeAlias, 10 Function, Module, Struct, Union, Enum, Const, Static, Trait, TypeAlias, MacroDef,
10 DefDatabase, HirFileId, Name, Path, 11 DefDatabase, HirFileId, Name, Path,
11 KnownName, 12 KnownName,
12 nameres::{ 13 nameres::{
13 Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, 14 Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode,
14 CrateDefMap, CrateModuleId, ModuleData, 15 CrateDefMap, CrateModuleId, ModuleData, ItemOrMacro,
15 diagnostics::DefDiagnostic, 16 diagnostics::DefDiagnostic,
16 raw, 17 raw,
17 }, 18 },
@@ -124,13 +125,21 @@ where
124 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); 125 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
125 // show unresolved imports in completion, etc 126 // show unresolved imports in completion, etc
126 for (module_id, import, import_data) in unresolved_imports { 127 for (module_id, import, import_data) in unresolved_imports {
127 self.record_resolved_import(module_id, PerNs::none(), import, &import_data) 128 self.record_resolved_import(
129 module_id,
130 Either::Left(PerNs::none()),
131 import,
132 &import_data,
133 )
128 } 134 }
129 } 135 }
130 136
131 fn define_macro(&mut self, name: Name, macro_id: MacroDefId, export: bool) { 137 fn define_macro(&mut self, name: Name, macro_id: MacroDefId, export: bool) {
132 if export { 138 if export {
133 self.def_map.public_macros.insert(name.clone(), macro_id); 139 self.def_map.public_macros.insert(name.clone(), macro_id);
140
141 let def = Either::Right(MacroDef { id: macro_id });
142 self.update(self.def_map.root, None, &[(name.clone(), def)]);
134 } else { 143 } else {
135 self.def_map.local_macros.insert(name.clone(), macro_id); 144 self.def_map.local_macros.insert(name.clone(), macro_id);
136 } 145 }
@@ -161,7 +170,7 @@ where
161 &self, 170 &self,
162 module_id: CrateModuleId, 171 module_id: CrateModuleId,
163 import: &raw::ImportData, 172 import: &raw::ImportData,
164 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { 173 ) -> (ItemOrMacro, ReachedFixedPoint) {
165 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); 174 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
166 if import.is_extern_crate { 175 if import.is_extern_crate {
167 let res = self.def_map.resolve_name_in_extern_prelude( 176 let res = self.def_map.resolve_name_in_extern_prelude(
@@ -170,10 +179,14 @@ where
170 .as_ident() 179 .as_ident()
171 .expect("extern crate should have been desugared to one-element path"), 180 .expect("extern crate should have been desugared to one-element path"),
172 ); 181 );
173 (res, ReachedFixedPoint::Yes) 182 (Either::Left(res), ReachedFixedPoint::Yes)
174 } else { 183 } else {
175 let res = 184 let res = self.def_map.resolve_path_fp_with_macro(
176 self.def_map.resolve_path_fp(self.db, ResolveMode::Import, module_id, &import.path); 185 self.db,
186 ResolveMode::Import,
187 module_id,
188 &import.path,
189 );
177 190
178 (res.resolved_def, res.reached_fixedpoint) 191 (res.resolved_def, res.reached_fixedpoint)
179 } 192 }
@@ -182,13 +195,13 @@ where
182 fn record_resolved_import( 195 fn record_resolved_import(
183 &mut self, 196 &mut self,
184 module_id: CrateModuleId, 197 module_id: CrateModuleId,
185 def: PerNs<ModuleDef>, 198 def: ItemOrMacro,
186 import_id: raw::ImportId, 199 import_id: raw::ImportId,
187 import: &raw::ImportData, 200 import: &raw::ImportData,
188 ) { 201 ) {
189 if import.is_glob { 202 if import.is_glob {
190 log::debug!("glob import: {:?}", import); 203 log::debug!("glob import: {:?}", import);
191 match def.take_types() { 204 match def.left().and_then(|item| item.take_types()) {
192 Some(ModuleDef::Module(m)) => { 205 Some(ModuleDef::Module(m)) => {
193 if import.is_prelude { 206 if import.is_prelude {
194 tested_by!(std_prelude); 207 tested_by!(std_prelude);
@@ -201,9 +214,14 @@ where
201 let items = scope 214 let items = scope
202 .items 215 .items
203 .iter() 216 .iter()
204 .map(|(name, res)| (name.clone(), res.clone())) 217 .map(|(name, res)| (name.clone(), Either::Left(res.clone())));
205 .collect::<Vec<_>>(); 218 let macros = scope
206 self.update(module_id, Some(import_id), &items); 219 .macros
220 .iter()
221 .map(|(name, res)| (name.clone(), Either::Right(res.clone())));
222
223 let all = items.chain(macros).collect::<Vec<_>>();
224 self.update(module_id, Some(import_id), &all);
207 } else { 225 } else {
208 // glob import from same crate => we do an initial 226 // glob import from same crate => we do an initial
209 // import, and then need to propagate any further 227 // import, and then need to propagate any further
@@ -212,9 +230,15 @@ where
212 let items = scope 230 let items = scope
213 .items 231 .items
214 .iter() 232 .iter()
215 .map(|(name, res)| (name.clone(), res.clone())) 233 .map(|(name, res)| (name.clone(), Either::Left(res.clone())));
216 .collect::<Vec<_>>(); 234 let macros = scope
217 self.update(module_id, Some(import_id), &items); 235 .macros
236 .iter()
237 .map(|(name, res)| (name.clone(), Either::Right(res.clone())));
238
239 let all = items.chain(macros).collect::<Vec<_>>();
240
241 self.update(module_id, Some(import_id), &all);
218 // record the glob import in case we add further items 242 // record the glob import in case we add further items
219 self.glob_imports 243 self.glob_imports
220 .entry(m.module_id) 244 .entry(m.module_id)
@@ -234,7 +258,7 @@ where
234 import: Some(import_id), 258 import: Some(import_id),
235 }; 259 };
236 let name = variant.name(self.db)?; 260 let name = variant.name(self.db)?;
237 Some((name, res)) 261 Some((name, Either::Left(res)))
238 }) 262 })
239 .collect::<Vec<_>>(); 263 .collect::<Vec<_>>();
240 self.update(module_id, Some(import_id), &resolutions); 264 self.update(module_id, Some(import_id), &resolutions);
@@ -254,11 +278,18 @@ where
254 278
255 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 279 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
256 if import.is_extern_crate && module_id == self.def_map.root { 280 if import.is_extern_crate && module_id == self.def_map.root {
257 if let Some(def) = def.take_types() { 281 if let Some(def) = def.left().and_then(|item| item.take_types()) {
258 self.def_map.extern_prelude.insert(name.clone(), def); 282 self.def_map.extern_prelude.insert(name.clone(), def);
259 } 283 }
260 } 284 }
261 let resolution = Resolution { def, import: Some(import_id) }; 285
286 let resolution = match def {
287 Either::Left(item) => {
288 Either::Left(Resolution { def: item, import: Some(import_id) })
289 }
290 Either::Right(macro_) => Either::Right(macro_),
291 };
292
262 self.update(module_id, Some(import_id), &[(name, resolution)]); 293 self.update(module_id, Some(import_id), &[(name, resolution)]);
263 } 294 }
264 None => tested_by!(bogus_paths), 295 None => tested_by!(bogus_paths),
@@ -270,7 +301,7 @@ where
270 &mut self, 301 &mut self,
271 module_id: CrateModuleId, 302 module_id: CrateModuleId,
272 import: Option<raw::ImportId>, 303 import: Option<raw::ImportId>,
273 resolutions: &[(Name, Resolution)], 304 resolutions: &[(Name, Either<Resolution, MacroDef>)],
274 ) { 305 ) {
275 self.update_recursive(module_id, import, resolutions, 0) 306 self.update_recursive(module_id, import, resolutions, 0)
276 } 307 }
@@ -279,7 +310,7 @@ where
279 &mut self, 310 &mut self,
280 module_id: CrateModuleId, 311 module_id: CrateModuleId,
281 import: Option<raw::ImportId>, 312 import: Option<raw::ImportId>,
282 resolutions: &[(Name, Resolution)], 313 resolutions: &[(Name, Either<Resolution, MacroDef>)],
283 depth: usize, 314 depth: usize,
284 ) { 315 ) {
285 if depth > 100 { 316 if depth > 100 {
@@ -289,25 +320,38 @@ where
289 let module_items = &mut self.def_map.modules[module_id].scope; 320 let module_items = &mut self.def_map.modules[module_id].scope;
290 let mut changed = false; 321 let mut changed = false;
291 for (name, res) in resolutions { 322 for (name, res) in resolutions {
292 let existing = module_items.items.entry(name.clone()).or_default(); 323 match res {
293 if existing.def.types.is_none() && res.def.types.is_some() { 324 // item
294 existing.def.types = res.def.types; 325 Either::Left(res) => {
295 existing.import = import.or(res.import); 326 let existing = module_items.items.entry(name.clone()).or_default();
296 changed = true; 327
297 } 328 if existing.def.types.is_none() && res.def.types.is_some() {
298 if existing.def.values.is_none() && res.def.values.is_some() { 329 existing.def.types = res.def.types;
299 existing.def.values = res.def.values; 330 existing.import = import.or(res.import);
300 existing.import = import.or(res.import); 331 changed = true;
301 changed = true; 332 }
302 } 333 if existing.def.values.is_none() && res.def.values.is_some() {
303 if existing.def.is_none() 334 existing.def.values = res.def.values;
304 && res.def.is_none() 335 existing.import = import.or(res.import);
305 && existing.import.is_none() 336 changed = true;
306 && res.import.is_some() 337 }
307 { 338
308 existing.import = res.import; 339 if existing.def.is_none()
340 && res.def.is_none()
341 && existing.import.is_none()
342 && res.import.is_some()
343 {
344 existing.import = res.import;
345 }
346 }
347 // macro
348 Either::Right(res) => {
349 // Always shadowing
350 module_items.macros.insert(name.clone(), *res);
351 }
309 } 352 }
310 } 353 }
354
311 if !changed { 355 if !changed {
312 return; 356 return;
313 } 357 }
@@ -324,37 +368,64 @@ where
324 } 368 }
325 } 369 }
326 370
327 // XXX: this is just a pile of hacks now, because `PerNs` does not handle
328 // macro namespace.
329 fn resolve_macros(&mut self) -> ReachedFixedPoint { 371 fn resolve_macros(&mut self) -> ReachedFixedPoint {
330 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); 372 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
331 let mut resolved = Vec::new(); 373 let mut resolved = Vec::new();
332 let mut res = ReachedFixedPoint::Yes; 374 let mut res = ReachedFixedPoint::Yes;
333 macros.retain(|(module_id, ast_id, path)| { 375 macros.retain(|(module_id, ast_id, path)| {
334 if path.segments.len() != 2 { 376 let resolved_res = self.def_map.resolve_path_fp_with_macro(
335 return true; 377 self.db,
378 ResolveMode::Other,
379 *module_id,
380 path,
381 );
382
383 if let Some(def) = resolved_res.resolved_def.right() {
384 let call_id = MacroCallLoc { def: def.id, ast_id: *ast_id }.id(self.db);
385 resolved.push((*module_id, call_id, def.id));
386 res = ReachedFixedPoint::No;
387 return false;
336 } 388 }
337 let crate_name = &path.segments[0].name; 389
338 let krate = match self.def_map.resolve_name_in_extern_prelude(crate_name).take_types() { 390 if resolved_res.reached_fixedpoint != ReachedFixedPoint::Yes {
339 Some(ModuleDef::Module(m)) => m.krate(self.db), 391 let crate_name = &path.segments[0].name;
340 _ => return true, 392
341 }; 393 // FIXME:
342 let krate = match krate { 394 // $crate are not handled in resolver right now
343 Some(it) => it, 395 if crate_name.to_string() == "$crate" {
344 _ => return true, 396 return true;
345 }; 397 }
346 res = ReachedFixedPoint::No; 398
347 let def_map = self.db.crate_def_map(krate); 399 // FIXME:
348 if let Some(macro_id) = def_map.public_macros.get(&path.segments[1].name).cloned() { 400 // Currently `#[cfg(test)]` are ignored and cargo-metadata do not insert
349 let call_id = MacroCallLoc { def: macro_id, ast_id: *ast_id }.id(self.db); 401 // dev-dependencies of dependencies. For example,
350 resolved.push((*module_id, call_id, macro_id)); 402 // if we depend on parking lot, and parking lot has a dev-dependency on lazy_static.
403 // Then `lazy_static` wil not included in `CrateGraph`
404 // We can fix that by proper handling `cfg(test)`.
405 //
406 // So right now we set the fixpoint to No only if its crate is in CrateGraph
407 // See issue #1282 for details
408 let krate =
409 match self.def_map.resolve_name_in_extern_prelude(crate_name).take_types() {
410 Some(ModuleDef::Module(m)) => m.krate(self.db),
411 _ => return true,
412 };
413 if krate.is_none() {
414 return true;
415 }
416
417 res = resolved_res.reached_fixedpoint;
351 } 418 }
352 false 419
420 true
353 }); 421 });
354 422
423 self.unexpanded_macros = macros;
424
355 for (module_id, macro_call_id, macro_def_id) in resolved { 425 for (module_id, macro_call_id, macro_def_id) in resolved {
356 self.collect_macro_expansion(module_id, macro_call_id, macro_def_id); 426 self.collect_macro_expansion(module_id, macro_call_id, macro_def_id);
357 } 427 }
428
358 res 429 res
359 } 430 }
360 431
@@ -475,7 +546,7 @@ where
475 ), 546 ),
476 import: None, 547 import: None,
477 }; 548 };
478 self.def_collector.update(self.module_id, None, &[(name, resolution)]); 549 self.def_collector.update(self.module_id, None, &[(name, Either::Left(resolution))]);
479 res 550 res
480 } 551 }
481 552
@@ -506,7 +577,7 @@ where
506 raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)), 577 raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)),
507 }; 578 };
508 let resolution = Resolution { def, import: None }; 579 let resolution = Resolution { def, import: None };
509 self.def_collector.update(self.module_id, None, &[(name, resolution)]) 580 self.def_collector.update(self.module_id, None, &[(name, Either::Left(resolution))])
510 } 581 }
511 582
512 fn collect_macro(&mut self, mac: &raw::MacroData) { 583 fn collect_macro(&mut self, mac: &raw::MacroData) {
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 14c8ee50b..ffb627c02 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -7,6 +7,7 @@ use std::sync::Arc;
7use ra_db::SourceDatabase; 7use ra_db::SourceDatabase;
8use test_utils::covers; 8use test_utils::covers;
9use insta::assert_snapshot_matches; 9use insta::assert_snapshot_matches;
10use either::Either;
10 11
11use crate::{ 12use crate::{
12 Crate, 13 Crate,
@@ -35,10 +36,22 @@ fn render_crate_def_map(map: &CrateDefMap) -> String {
35 *buf += path; 36 *buf += path;
36 *buf += "\n"; 37 *buf += "\n";
37 38
38 let mut entries = map.modules[module].scope.items.iter().collect::<Vec<_>>(); 39 let items =
40 map.modules[module].scope.items.iter().map(|(name, it)| (name, Either::Left(it)));
41 let macros =
42 map.modules[module].scope.macros.iter().map(|(name, m)| (name, Either::Right(m)));
43 let mut entries = items.chain(macros).collect::<Vec<_>>();
44
39 entries.sort_by_key(|(name, _)| *name); 45 entries.sort_by_key(|(name, _)| *name);
40 for (name, res) in entries { 46 for (name, res) in entries {
41 *buf += &format!("{}: {}\n", name, dump_resolution(res)) 47 match res {
48 Either::Left(it) => {
49 *buf += &format!("{}: {}\n", name, dump_resolution(it));
50 }
51 Either::Right(_) => {
52 *buf += &format!("{}: m\n", name);
53 }
54 }
42 } 55 }
43 for (name, child) in map.modules[module].children.iter() { 56 for (name, child) in map.modules[module].children.iter() {
44 let path = path.to_string() + &format!("::{}", name); 57 let path = path.to_string() + &format!("::{}", name);
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs
index f7ca380ad..42241aeff 100644
--- a/crates/ra_hir/src/nameres/tests/macros.rs
+++ b/crates/ra_hir/src/nameres/tests/macros.rs
@@ -92,3 +92,43 @@ fn macro_rules_from_other_crates_are_visible() {
92 ⋮bar: t 92 ⋮bar: t
93 "###); 93 "###);
94} 94}
95
96#[test]
97fn unexpanded_macro_should_expand_by_fixedpoint_loop() {
98 let map = def_map_with_crate_graph(
99 "
100 //- /main.rs
101 macro_rules! baz {
102 () => {
103 use foo::bar;
104 }
105 }
106
107 foo!();
108 bar!();
109 baz!();
110
111 //- /lib.rs
112 #[macro_export]
113 macro_rules! foo {
114 () => {
115 struct Foo { field: u32 }
116 }
117 }
118 #[macro_export]
119 macro_rules! bar {
120 () => {
121 use foo::foo;
122 }
123 }
124 ",
125 crate_graph! {
126 "main": ("/main.rs", ["foo"]),
127 "foo": ("/lib.rs", []),
128 },
129 );
130 assert_snapshot_matches!(map, @r###"crate
131Foo: t v
132bar: m
133foo: m"###);
134}