aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--crates/ra_hir/src/adt.rs2
-rw-r--r--crates/ra_hir/src/code_model.rs12
-rw-r--r--crates/ra_hir/src/code_model/src.rs4
-rw-r--r--crates/ra_hir/src/expr/scope.rs5
-rw-r--r--crates/ra_hir/src/from_source.rs10
-rw-r--r--crates/ra_hir/src/ty/lower.rs4
-rw-r--r--crates/ra_hir_def/src/adt.rs16
-rw-r--r--crates/ra_hir_def/src/db.rs12
-rw-r--r--crates/ra_hir_def/src/lib.rs28
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs11
-rw-r--r--crates/ra_hir_expand/Cargo.toml1
-rw-r--r--crates/ra_hir_expand/src/db.rs46
-rw-r--r--crates/ra_hir_expand/src/lib.rs59
-rw-r--r--crates/ra_ide_api/src/display/navigation_target.rs120
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs77
-rw-r--r--crates/ra_ide_api/src/status.rs4
-rw-r--r--crates/ra_mbe/src/lib.rs7
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs75
-rw-r--r--crates/ra_mbe/src/tests.rs102
20 files changed, 406 insertions, 190 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b67637fe8..37ff1ce76 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1060,6 +1060,7 @@ dependencies = [
1060 "ra_arena 0.1.0", 1060 "ra_arena 0.1.0",
1061 "ra_db 0.1.0", 1061 "ra_db 0.1.0",
1062 "ra_mbe 0.1.0", 1062 "ra_mbe 0.1.0",
1063 "ra_parser 0.1.0",
1063 "ra_prof 0.1.0", 1064 "ra_prof 0.1.0",
1064 "ra_syntax 0.1.0", 1065 "ra_syntax 0.1.0",
1065 "ra_tt 0.1.0", 1066 "ra_tt 0.1.0",
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs
index 0436d20b7..945f236c2 100644
--- a/crates/ra_hir/src/adt.rs
+++ b/crates/ra_hir/src/adt.rs
@@ -12,7 +12,7 @@ use crate::{
12 12
13impl Struct { 13impl Struct {
14 pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> { 14 pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
15 db.struct_data(self.id).variant_data.clone() 15 db.struct_data(self.id.into()).variant_data.clone()
16 } 16 }
17} 17}
18 18
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 9d0db8024..e5bfad3ca 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -288,7 +288,7 @@ pub struct Struct {
288 288
289impl Struct { 289impl Struct {
290 pub fn module(self, db: &impl DefDatabase) -> Module { 290 pub fn module(self, db: &impl DefDatabase) -> Module {
291 Module { id: self.id.module(db) } 291 Module { id: self.id.0.module(db) }
292 } 292 }
293 293
294 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { 294 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
@@ -296,11 +296,11 @@ impl Struct {
296 } 296 }
297 297
298 pub fn name(self, db: &impl DefDatabase) -> Option<Name> { 298 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
299 db.struct_data(self.id).name.clone() 299 db.struct_data(self.id.into()).name.clone()
300 } 300 }
301 301
302 pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> { 302 pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> {
303 db.struct_data(self.id) 303 db.struct_data(self.id.into())
304 .variant_data 304 .variant_data
305 .fields() 305 .fields()
306 .into_iter() 306 .into_iter()
@@ -310,7 +310,7 @@ impl Struct {
310 } 310 }
311 311
312 pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> { 312 pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
313 db.struct_data(self.id) 313 db.struct_data(self.id.into())
314 .variant_data 314 .variant_data
315 .fields() 315 .fields()
316 .into_iter() 316 .into_iter()
@@ -346,11 +346,11 @@ pub struct Union {
346 346
347impl Union { 347impl Union {
348 pub fn name(self, db: &impl DefDatabase) -> Option<Name> { 348 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
349 db.union_data(self.id).name.clone() 349 db.struct_data(self.id.into()).name.clone()
350 } 350 }
351 351
352 pub fn module(self, db: &impl HirDatabase) -> Module { 352 pub fn module(self, db: &impl HirDatabase) -> Module {
353 Module { id: self.id.module(db) } 353 Module { id: self.id.0.module(db) }
354 } 354 }
355 355
356 pub fn ty(self, db: &impl HirDatabase) -> Ty { 356 pub fn ty(self, db: &impl HirDatabase) -> Ty {
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs
index 6d116ee75..247ae3e55 100644
--- a/crates/ra_hir/src/code_model/src.rs
+++ b/crates/ra_hir/src/code_model/src.rs
@@ -78,13 +78,13 @@ impl HasSource for StructField {
78impl HasSource for Struct { 78impl HasSource for Struct {
79 type Ast = ast::StructDef; 79 type Ast = ast::StructDef;
80 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StructDef> { 80 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StructDef> {
81 self.id.source(db) 81 self.id.0.source(db)
82 } 82 }
83} 83}
84impl HasSource for Union { 84impl HasSource for Union {
85 type Ast = ast::StructDef; 85 type Ast = ast::StructDef;
86 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StructDef> { 86 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StructDef> {
87 self.id.source(db) 87 self.id.0.source(db)
88 } 88 }
89} 89}
90impl HasSource for Enum { 90impl HasSource for Enum {
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs
index c14c2ab66..5a1eade2c 100644
--- a/crates/ra_hir/src/expr/scope.rs
+++ b/crates/ra_hir/src/expr/scope.rs
@@ -67,10 +67,7 @@ impl ExprScopes {
67 &self.scopes[scope].entries 67 &self.scopes[scope].entries
68 } 68 }
69 69
70 pub(crate) fn scope_chain<'a>( 70 pub(crate) fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ {
71 &'a self,
72 scope: Option<ScopeId>,
73 ) -> impl Iterator<Item = ScopeId> + 'a {
74 std::iter::successors(scope, move |&scope| self.scopes[scope].parent) 71 std::iter::successors(scope, move |&scope| self.scopes[scope].parent)
75 } 72 }
76 73
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index 9899bdbbc..c95d2cdd0 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -1,5 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir_def::{StructId, StructOrUnionId, UnionId};
3use hir_expand::name::AsName; 4use hir_expand::name::AsName;
4use ra_syntax::ast::{self, AstNode, NameOwner}; 5use ra_syntax::ast::{self, AstNode, NameOwner};
5 6
@@ -15,18 +16,19 @@ pub trait FromSource: Sized {
15 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self>; 16 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self>;
16} 17}
17 18
19// FIXIME: these two impls are wrong, `ast::StructDef` might produce either a struct or a union
18impl FromSource for Struct { 20impl FromSource for Struct {
19 type Ast = ast::StructDef; 21 type Ast = ast::StructDef;
20 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 22 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
21 let id = from_source(db, src)?; 23 let id: StructOrUnionId = from_source(db, src)?;
22 Some(Struct { id }) 24 Some(Struct { id: StructId(id) })
23 } 25 }
24} 26}
25impl FromSource for Union { 27impl FromSource for Union {
26 type Ast = ast::StructDef; 28 type Ast = ast::StructDef;
27 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 29 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
28 let id = from_source(db, src)?; 30 let id: StructOrUnionId = from_source(db, src)?;
29 Some(Union { id }) 31 Some(Union { id: UnionId(id) })
30 } 32 }
31} 33}
32impl FromSource for Enum { 34impl FromSource for Enum {
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index d26b16cb2..1fed5025e 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -665,7 +665,7 @@ fn type_for_builtin(def: BuiltinType) -> Ty {
665} 665}
666 666
667fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig { 667fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig {
668 let struct_data = db.struct_data(def.id); 668 let struct_data = db.struct_data(def.id.into());
669 let fields = match struct_data.variant_data.fields() { 669 let fields = match struct_data.variant_data.fields() {
670 Some(fields) => fields, 670 Some(fields) => fields,
671 None => panic!("fn_sig_for_struct_constructor called on unit struct"), 671 None => panic!("fn_sig_for_struct_constructor called on unit struct"),
@@ -681,7 +681,7 @@ fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig {
681 681
682/// Build the type of a tuple struct constructor. 682/// Build the type of a tuple struct constructor.
683fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty { 683fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
684 let struct_data = db.struct_data(def.id); 684 let struct_data = db.struct_data(def.id.into());
685 if struct_data.variant_data.fields().is_none() { 685 if struct_data.variant_data.fields().is_none() {
686 return type_for_adt(db, def); // Unit struct 686 return type_for_adt(db, def); // Unit struct
687 } 687 }
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index 8f41e55d2..a29c4d41e 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -8,7 +8,7 @@ use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
8 8
9use crate::{ 9use crate::{
10 db::DefDatabase2, type_ref::TypeRef, AstItemDef, EnumId, LocalEnumVariantId, 10 db::DefDatabase2, type_ref::TypeRef, AstItemDef, EnumId, LocalEnumVariantId,
11 LocalStructFieldId, StructId, UnionId, 11 LocalStructFieldId, StructOrUnionId,
12}; 12};
13 13
14/// Note that we use `StructData` for unions as well! 14/// Note that we use `StructData` for unions as well!
@@ -49,15 +49,11 @@ pub struct StructFieldData {
49} 49}
50 50
51impl StructData { 51impl StructData {
52 pub(crate) fn struct_data_query(db: &impl DefDatabase2, struct_: StructId) -> Arc<StructData> { 52 pub(crate) fn struct_data_query(
53 let src = struct_.source(db); 53 db: &impl DefDatabase2,
54 let name = src.ast.name().map(|n| n.as_name()); 54 id: StructOrUnionId,
55 let variant_data = VariantData::new(src.ast.kind()); 55 ) -> Arc<StructData> {
56 let variant_data = Arc::new(variant_data); 56 let src = id.source(db);
57 Arc::new(StructData { name, variant_data })
58 }
59 pub(crate) fn union_data_query(db: &impl DefDatabase2, struct_: UnionId) -> Arc<StructData> {
60 let src = struct_.source(db);
61 let name = src.ast.name().map(|n| n.as_name()); 57 let name = src.ast.name().map(|n| n.as_name());
62 let variant_data = VariantData::new(src.ast.kind()); 58 let variant_data = VariantData::new(src.ast.kind());
63 let variant_data = Arc::new(variant_data); 59 let variant_data = Arc::new(variant_data);
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index a42348101..29cf71a59 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -11,7 +11,7 @@ use crate::{
11 raw::{ImportSourceMap, RawItems}, 11 raw::{ImportSourceMap, RawItems},
12 CrateDefMap, 12 CrateDefMap,
13 }, 13 },
14 EnumId, StructId, UnionId, 14 EnumId, StructOrUnionId,
15}; 15};
16 16
17#[salsa::query_group(InternDatabaseStorage)] 17#[salsa::query_group(InternDatabaseStorage)]
@@ -19,9 +19,8 @@ pub trait InternDatabase: SourceDatabase {
19 #[salsa::interned] 19 #[salsa::interned]
20 fn intern_function(&self, loc: crate::ItemLoc<ast::FnDef>) -> crate::FunctionId; 20 fn intern_function(&self, loc: crate::ItemLoc<ast::FnDef>) -> crate::FunctionId;
21 #[salsa::interned] 21 #[salsa::interned]
22 fn intern_struct(&self, loc: crate::ItemLoc<ast::StructDef>) -> crate::StructId; 22 fn intern_struct_or_union(&self, loc: crate::ItemLoc<ast::StructDef>)
23 #[salsa::interned] 23 -> crate::StructOrUnionId;
24 fn intern_union(&self, loc: crate::ItemLoc<ast::StructDef>) -> crate::UnionId;
25 #[salsa::interned] 24 #[salsa::interned]
26 fn intern_enum(&self, loc: crate::ItemLoc<ast::EnumDef>) -> crate::EnumId; 25 fn intern_enum(&self, loc: crate::ItemLoc<ast::EnumDef>) -> crate::EnumId;
27 #[salsa::interned] 26 #[salsa::interned]
@@ -49,10 +48,7 @@ pub trait DefDatabase2: InternDatabase + AstDatabase {
49 fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>; 48 fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>;
50 49
51 #[salsa::invoke(StructData::struct_data_query)] 50 #[salsa::invoke(StructData::struct_data_query)]
52 fn struct_data(&self, s: StructId) -> Arc<StructData>; 51 fn struct_data(&self, id: StructOrUnionId) -> Arc<StructData>;
53
54 #[salsa::invoke(StructData::union_data_query)]
55 fn union_data(&self, s: UnionId) -> Arc<StructData>;
56 52
57 #[salsa::invoke(EnumData::enum_data_query)] 53 #[salsa::invoke(EnumData::enum_data_query)]
58 fn enum_data(&self, e: EnumId) -> Arc<EnumData>; 54 fn enum_data(&self, e: EnumId) -> Arc<EnumData>;
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index 63ed2a098..239317efe 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -205,26 +205,30 @@ impl AstItemDef<ast::FnDef> for FunctionId {
205} 205}
206 206
207#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 207#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
208pub struct StructId(salsa::InternId); 208pub struct StructOrUnionId(salsa::InternId);
209impl_intern_key!(StructId); 209impl_intern_key!(StructOrUnionId);
210impl AstItemDef<ast::StructDef> for StructId { 210impl AstItemDef<ast::StructDef> for StructOrUnionId {
211 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self { 211 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
212 db.intern_struct(loc) 212 db.intern_struct_or_union(loc)
213 } 213 }
214 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> { 214 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> {
215 db.lookup_intern_struct(self) 215 db.lookup_intern_struct_or_union(self)
216 } 216 }
217} 217}
218 218
219#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 219#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
220pub struct UnionId(salsa::InternId); 220pub struct StructId(pub StructOrUnionId);
221impl_intern_key!(UnionId); 221impl From<StructId> for StructOrUnionId {
222impl AstItemDef<ast::StructDef> for UnionId { 222 fn from(id: StructId) -> StructOrUnionId {
223 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self { 223 id.0
224 db.intern_union(loc)
225 } 224 }
226 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> { 225}
227 db.lookup_intern_union(self) 226
227#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
228pub struct UnionId(pub StructOrUnionId);
229impl From<UnionId> for StructOrUnionId {
230 fn from(id: UnionId) -> StructOrUnionId {
231 id.0
228 } 232 }
229} 233}
230 234
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index aacd50df8..7e6083961 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -19,7 +19,8 @@ use crate::{
19 }, 19 },
20 path::{Path, PathKind}, 20 path::{Path, PathKind},
21 AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId, 21 AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId,
22 LocationCtx, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId, 22 LocationCtx, ModuleDefId, ModuleId, StaticId, StructId, StructOrUnionId, TraitId, TypeAliasId,
23 UnionId,
23}; 24};
24 25
25pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) -> CrateDefMap { 26pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) -> CrateDefMap {
@@ -664,12 +665,14 @@ where
664 PerNs::values(FunctionId::from_ast_id(ctx, ast_id).into()) 665 PerNs::values(FunctionId::from_ast_id(ctx, ast_id).into())
665 } 666 }
666 raw::DefKind::Struct(ast_id) => { 667 raw::DefKind::Struct(ast_id) => {
667 let s = StructId::from_ast_id(ctx, ast_id).into(); 668 let id = StructOrUnionId::from_ast_id(ctx, ast_id).into();
669 let s = StructId(id).into();
668 PerNs::both(s, s) 670 PerNs::both(s, s)
669 } 671 }
670 raw::DefKind::Union(ast_id) => { 672 raw::DefKind::Union(ast_id) => {
671 let s = UnionId::from_ast_id(ctx, ast_id).into(); 673 let id = StructOrUnionId::from_ast_id(ctx, ast_id).into();
672 PerNs::both(s, s) 674 let u = UnionId(id).into();
675 PerNs::both(u, u)
673 } 676 }
674 raw::DefKind::Enum(ast_id) => PerNs::types(EnumId::from_ast_id(ctx, ast_id).into()), 677 raw::DefKind::Enum(ast_id) => PerNs::types(EnumId::from_ast_id(ctx, ast_id).into()),
675 raw::DefKind::Const(ast_id) => PerNs::values(ConstId::from_ast_id(ctx, ast_id).into()), 678 raw::DefKind::Const(ast_id) => PerNs::values(ConstId::from_ast_id(ctx, ast_id).into()),
diff --git a/crates/ra_hir_expand/Cargo.toml b/crates/ra_hir_expand/Cargo.toml
index 9bf5b7918..8f29bf7d9 100644
--- a/crates/ra_hir_expand/Cargo.toml
+++ b/crates/ra_hir_expand/Cargo.toml
@@ -10,6 +10,7 @@ log = "0.4.5"
10ra_arena = { path = "../ra_arena" } 10ra_arena = { path = "../ra_arena" }
11ra_db = { path = "../ra_db" } 11ra_db = { path = "../ra_db" }
12ra_syntax = { path = "../ra_syntax" } 12ra_syntax = { path = "../ra_syntax" }
13ra_parser = { path = "../ra_parser" }
13ra_prof = { path = "../ra_prof" } 14ra_prof = { path = "../ra_prof" }
14tt = { path = "../ra_tt", package = "ra_tt" } 15tt = { path = "../ra_tt", package = "ra_tt" }
15mbe = { path = "../ra_mbe", package = "ra_mbe" } 16mbe = { path = "../ra_mbe", package = "ra_mbe" }
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs
index a4ee9a529..b4dafe1d8 100644
--- a/crates/ra_hir_expand/src/db.rs
+++ b/crates/ra_hir_expand/src/db.rs
@@ -4,6 +4,7 @@ use std::sync::Arc;
4 4
5use mbe::MacroRules; 5use mbe::MacroRules;
6use ra_db::{salsa, SourceDatabase}; 6use ra_db::{salsa, SourceDatabase};
7use ra_parser::FragmentKind;
7use ra_prof::profile; 8use ra_prof::profile;
8use ra_syntax::{AstNode, Parse, SyntaxNode}; 9use ra_syntax::{AstNode, Parse, SyntaxNode};
9 10
@@ -22,9 +23,12 @@ pub trait AstDatabase: SourceDatabase {
22 23
23 #[salsa::interned] 24 #[salsa::interned]
24 fn intern_macro(&self, macro_call: MacroCallLoc) -> MacroCallId; 25 fn intern_macro(&self, macro_call: MacroCallLoc) -> MacroCallId;
25 fn macro_arg(&self, id: MacroCallId) -> Option<Arc<tt::Subtree>>; 26 fn macro_arg(&self, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>>;
26 fn macro_def(&self, id: MacroDefId) -> Option<Arc<mbe::MacroRules>>; 27 fn macro_def(&self, id: MacroDefId) -> Option<Arc<(mbe::MacroRules, mbe::TokenMap)>>;
27 fn parse_macro(&self, macro_file: MacroFile) -> Option<Parse<SyntaxNode>>; 28 fn parse_macro(
29 &self,
30 macro_file: MacroFile,
31 ) -> Option<(Parse<SyntaxNode>, Arc<mbe::RevTokenMap>)>;
28 fn macro_expand(&self, macro_call: MacroCallId) -> Result<Arc<tt::Subtree>, String>; 32 fn macro_expand(&self, macro_call: MacroCallId) -> Result<Arc<tt::Subtree>, String>;
29} 33}
30 34
@@ -34,10 +38,13 @@ pub(crate) fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdM
34 Arc::new(map) 38 Arc::new(map)
35} 39}
36 40
37pub(crate) fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> { 41pub(crate) fn macro_def(
42 db: &dyn AstDatabase,
43 id: MacroDefId,
44) -> Option<Arc<(mbe::MacroRules, mbe::TokenMap)>> {
38 let macro_call = id.ast_id.to_node(db); 45 let macro_call = id.ast_id.to_node(db);
39 let arg = macro_call.token_tree()?; 46 let arg = macro_call.token_tree()?;
40 let (tt, _) = mbe::ast_to_token_tree(&arg).or_else(|| { 47 let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
41 log::warn!("fail on macro_def to token tree: {:#?}", arg); 48 log::warn!("fail on macro_def to token tree: {:#?}", arg);
42 None 49 None
43 })?; 50 })?;
@@ -45,15 +52,18 @@ pub(crate) fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<Macr
45 log::warn!("fail on macro_def parse: {:#?}", tt); 52 log::warn!("fail on macro_def parse: {:#?}", tt);
46 None 53 None
47 })?; 54 })?;
48 Some(Arc::new(rules)) 55 Some(Arc::new((rules, tmap)))
49} 56}
50 57
51pub(crate) fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<tt::Subtree>> { 58pub(crate) fn macro_arg(
59 db: &dyn AstDatabase,
60 id: MacroCallId,
61) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> {
52 let loc = db.lookup_intern_macro(id); 62 let loc = db.lookup_intern_macro(id);
53 let macro_call = loc.ast_id.to_node(db); 63 let macro_call = loc.ast_id.to_node(db);
54 let arg = macro_call.token_tree()?; 64 let arg = macro_call.token_tree()?;
55 let (tt, _) = mbe::ast_to_token_tree(&arg)?; 65 let (tt, tmap) = mbe::ast_to_token_tree(&arg)?;
56 Some(Arc::new(tt)) 66 Some(Arc::new((tt, tmap)))
57} 67}
58 68
59pub(crate) fn macro_expand( 69pub(crate) fn macro_expand(
@@ -64,7 +74,7 @@ pub(crate) fn macro_expand(
64 let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?; 74 let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?;
65 75
66 let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?; 76 let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?;
67 let tt = macro_rules.expand(&macro_arg).map_err(|err| format!("{:?}", err))?; 77 let tt = macro_rules.0.expand(&macro_arg.0).map_err(|err| format!("{:?}", err))?;
68 // Set a hard limit for the expanded tt 78 // Set a hard limit for the expanded tt
69 let count = tt.count(); 79 let count = tt.count();
70 if count > 65536 { 80 if count > 65536 {
@@ -77,7 +87,7 @@ pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Optio
77 match file_id.0 { 87 match file_id.0 {
78 HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()), 88 HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
79 HirFileIdRepr::MacroFile(macro_file) => { 89 HirFileIdRepr::MacroFile(macro_file) => {
80 db.parse_macro(macro_file).map(|it| it.syntax_node()) 90 db.parse_macro(macro_file).map(|(it, _)| it.syntax_node())
81 } 91 }
82 } 92 }
83} 93}
@@ -85,8 +95,9 @@ pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Optio
85pub(crate) fn parse_macro( 95pub(crate) fn parse_macro(
86 db: &dyn AstDatabase, 96 db: &dyn AstDatabase,
87 macro_file: MacroFile, 97 macro_file: MacroFile,
88) -> Option<Parse<SyntaxNode>> { 98) -> Option<(Parse<SyntaxNode>, Arc<mbe::RevTokenMap>)> {
89 let _p = profile("parse_macro_query"); 99 let _p = profile("parse_macro_query");
100
90 let macro_call_id = macro_file.macro_call_id; 101 let macro_call_id = macro_file.macro_call_id;
91 let tt = db 102 let tt = db
92 .macro_expand(macro_call_id) 103 .macro_expand(macro_call_id)
@@ -97,8 +108,11 @@ pub(crate) fn parse_macro(
97 log::warn!("fail on macro_parse: (reason: {})", err,); 108 log::warn!("fail on macro_parse: (reason: {})", err,);
98 }) 109 })
99 .ok()?; 110 .ok()?;
100 match macro_file.macro_file_kind { 111
101 MacroFileKind::Items => mbe::token_tree_to_items(&tt).ok().map(Parse::to_syntax), 112 let fragment_kind = match macro_file.macro_file_kind {
102 MacroFileKind::Expr => mbe::token_tree_to_expr(&tt).ok().map(Parse::to_syntax), 113 MacroFileKind::Items => FragmentKind::Items,
103 } 114 MacroFileKind::Expr => FragmentKind::Expr,
115 };
116 let (parse, rev_token_map) = mbe::token_tree_to_syntax_node(&tt, fragment_kind).ok()?;
117 Some((parse, Arc::new(rev_token_map)))
104} 118}
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index dd07a16b4..151d1d785 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -12,11 +12,12 @@ pub mod hygiene;
12pub mod diagnostics; 12pub mod diagnostics;
13 13
14use std::hash::{Hash, Hasher}; 14use std::hash::{Hash, Hasher};
15use std::sync::Arc;
15 16
16use ra_db::{salsa, CrateId, FileId}; 17use ra_db::{salsa, CrateId, FileId};
17use ra_syntax::{ 18use ra_syntax::{
18 ast::{self, AstNode}, 19 ast::{self, AstNode},
19 SyntaxNode, 20 SyntaxNode, TextRange, TextUnit,
20}; 21};
21 22
22use crate::ast_id_map::FileAstId; 23use crate::ast_id_map::FileAstId;
@@ -66,6 +67,30 @@ impl HirFileId {
66 } 67 }
67 } 68 }
68 } 69 }
70
71 /// Return expansion information if it is a macro-expansion file
72 pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option<ExpansionInfo> {
73 match self.0 {
74 HirFileIdRepr::FileId(_) => None,
75 HirFileIdRepr::MacroFile(macro_file) => {
76 let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);
77
78 let arg_start = loc.ast_id.to_node(db).token_tree()?.syntax().text_range().start();
79 let def_start =
80 loc.def.ast_id.to_node(db).token_tree()?.syntax().text_range().start();
81
82 let macro_def = db.macro_def(loc.def)?;
83 let shift = macro_def.0.shift();
84 let exp_map = db.parse_macro(macro_file)?.1;
85 let macro_arg = db.macro_arg(macro_file.macro_call_id)?;
86
87 let arg_start = (loc.ast_id.file_id, arg_start);
88 let def_start = (loc.def.ast_id.file_id, def_start);
89
90 Some(ExpansionInfo { arg_start, def_start, macro_arg, macro_def, exp_map, shift })
91 }
92 }
93 }
69} 94}
70 95
71#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 96#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -112,6 +137,38 @@ impl MacroCallId {
112 } 137 }
113} 138}
114 139
140#[derive(Debug, Clone, PartialEq, Eq)]
141/// ExpansionInfo mainly describes how to map text range between src and expanded macro
142pub struct ExpansionInfo {
143 pub(crate) arg_start: (HirFileId, TextUnit),
144 pub(crate) def_start: (HirFileId, TextUnit),
145 pub(crate) shift: u32,
146
147 pub(crate) macro_def: Arc<(mbe::MacroRules, mbe::TokenMap)>,
148 pub(crate) macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>,
149 pub(crate) exp_map: Arc<mbe::RevTokenMap>,
150}
151
152impl ExpansionInfo {
153 pub fn find_range(&self, from: TextRange) -> Option<(HirFileId, TextRange)> {
154 let token_id = look_in_rev_map(&self.exp_map, from)?;
155
156 let (token_map, (file_id, start_offset), token_id) = if token_id.0 >= self.shift {
157 (&self.macro_arg.1, self.arg_start, tt::TokenId(token_id.0 - self.shift).into())
158 } else {
159 (&self.macro_def.1, self.def_start, token_id)
160 };
161
162 let range = token_map.relative_range_of(token_id)?;
163
164 return Some((file_id, range + start_offset));
165
166 fn look_in_rev_map(exp_map: &mbe::RevTokenMap, from: TextRange) -> Option<tt::TokenId> {
167 exp_map.ranges.iter().find(|&it| it.0.is_subrange(&from)).map(|it| it.1)
168 }
169 }
170}
171
115/// `AstId` points to an AST node in any file. 172/// `AstId` points to an AST node in any file.
116/// 173///
117/// It is stable across reparses, and can be used as salsa key/value. 174/// It is stable across reparses, and can be used as salsa key/value.
diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs
index 5cb67fb95..1bf81e7d5 100644
--- a/crates/ra_ide_api/src/display/navigation_target.rs
+++ b/crates/ra_ide_api/src/display/navigation_target.rs
@@ -29,6 +29,21 @@ pub struct NavigationTarget {
29 docs: Option<String>, 29 docs: Option<String>,
30} 30}
31 31
32fn find_range_from_node(
33 db: &RootDatabase,
34 src: hir::HirFileId,
35 node: &SyntaxNode,
36) -> (FileId, TextRange) {
37 let text_range = node.text_range();
38 let (file_id, text_range) = src
39 .expansion_info(db)
40 .and_then(|expansion_info| expansion_info.find_range(text_range))
41 .unwrap_or((src, text_range));
42
43 // FIXME: handle recursive macro generated macro
44 (file_id.original_file(db), text_range)
45}
46
32impl NavigationTarget { 47impl NavigationTarget {
33 /// When `focus_range` is specified, returns it. otherwise 48 /// When `focus_range` is specified, returns it. otherwise
34 /// returns `full_range` 49 /// returns `full_range`
@@ -72,8 +87,12 @@ impl NavigationTarget {
72 self.focus_range 87 self.focus_range
73 } 88 }
74 89
75 pub(crate) fn from_bind_pat(file_id: FileId, pat: &ast::BindPat) -> NavigationTarget { 90 pub(crate) fn from_bind_pat(
76 NavigationTarget::from_named(file_id, pat, None, None) 91 db: &RootDatabase,
92 file_id: FileId,
93 pat: &ast::BindPat,
94 ) -> NavigationTarget {
95 NavigationTarget::from_named(db, file_id.into(), pat, None, None)
77 } 96 }
78 97
79 pub(crate) fn from_symbol(db: &RootDatabase, symbol: FileSymbol) -> NavigationTarget { 98 pub(crate) fn from_symbol(db: &RootDatabase, symbol: FileSymbol) -> NavigationTarget {
@@ -96,7 +115,7 @@ impl NavigationTarget {
96 ) -> NavigationTarget { 115 ) -> NavigationTarget {
97 let parse = db.parse(file_id); 116 let parse = db.parse(file_id);
98 let pat = pat.to_node(parse.tree().syntax()); 117 let pat = pat.to_node(parse.tree().syntax());
99 NavigationTarget::from_bind_pat(file_id, &pat) 118 NavigationTarget::from_bind_pat(db, file_id, &pat)
100 } 119 }
101 120
102 pub(crate) fn from_self_param( 121 pub(crate) fn from_self_param(
@@ -119,31 +138,46 @@ impl NavigationTarget {
119 138
120 pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget { 139 pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
121 let src = module.definition_source(db); 140 let src = module.definition_source(db);
122 let file_id = src.file_id.original_file(db);
123 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); 141 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
124 match src.ast { 142 match src.ast {
125 ModuleSource::SourceFile(node) => { 143 ModuleSource::SourceFile(node) => {
126 NavigationTarget::from_syntax(file_id, name, None, node.syntax(), None, None) 144 let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax());
145
146 NavigationTarget::from_syntax(
147 file_id,
148 name,
149 None,
150 text_range,
151 node.syntax(),
152 None,
153 None,
154 )
155 }
156 ModuleSource::Module(node) => {
157 let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax());
158
159 NavigationTarget::from_syntax(
160 file_id,
161 name,
162 None,
163 text_range,
164 node.syntax(),
165 node.doc_comment_text(),
166 node.short_label(),
167 )
127 } 168 }
128 ModuleSource::Module(node) => NavigationTarget::from_syntax(
129 file_id,
130 name,
131 None,
132 node.syntax(),
133 node.doc_comment_text(),
134 node.short_label(),
135 ),
136 } 169 }
137 } 170 }
138 171
139 pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { 172 pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
140 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); 173 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
141 if let Some(src) = module.declaration_source(db) { 174 if let Some(src) = module.declaration_source(db) {
142 let file_id = src.file_id.original_file(db); 175 let (file_id, text_range) = find_range_from_node(db, src.file_id, src.ast.syntax());
143 return NavigationTarget::from_syntax( 176 return NavigationTarget::from_syntax(
144 file_id, 177 file_id,
145 name, 178 name,
146 None, 179 None,
180 text_range,
147 src.ast.syntax(), 181 src.ast.syntax(),
148 src.ast.doc_comment_text(), 182 src.ast.doc_comment_text(),
149 src.ast.short_label(), 183 src.ast.short_label(),
@@ -154,13 +188,25 @@ impl NavigationTarget {
154 188
155 pub(crate) fn from_field(db: &RootDatabase, field: hir::StructField) -> NavigationTarget { 189 pub(crate) fn from_field(db: &RootDatabase, field: hir::StructField) -> NavigationTarget {
156 let src = field.source(db); 190 let src = field.source(db);
157 let file_id = src.file_id.original_file(db);
158 match src.ast { 191 match src.ast {
159 FieldSource::Named(it) => { 192 FieldSource::Named(it) => NavigationTarget::from_named(
160 NavigationTarget::from_named(file_id, &it, it.doc_comment_text(), it.short_label()) 193 db,
161 } 194 src.file_id,
195 &it,
196 it.doc_comment_text(),
197 it.short_label(),
198 ),
162 FieldSource::Pos(it) => { 199 FieldSource::Pos(it) => {
163 NavigationTarget::from_syntax(file_id, "".into(), None, it.syntax(), None, None) 200 let (file_id, text_range) = find_range_from_node(db, src.file_id, it.syntax());
201 NavigationTarget::from_syntax(
202 file_id,
203 "".into(),
204 None,
205 text_range,
206 it.syntax(),
207 None,
208 None,
209 )
164 } 210 }
165 } 211 }
166 } 212 }
@@ -172,7 +218,8 @@ impl NavigationTarget {
172 { 218 {
173 let src = def.source(db); 219 let src = def.source(db);
174 NavigationTarget::from_named( 220 NavigationTarget::from_named(
175 src.file_id.original_file(db), 221 db,
222 src.file_id,
176 &src.ast, 223 &src.ast,
177 src.ast.doc_comment_text(), 224 src.ast.doc_comment_text(),
178 src.ast.short_label(), 225 src.ast.short_label(),
@@ -212,10 +259,13 @@ impl NavigationTarget {
212 impl_block: hir::ImplBlock, 259 impl_block: hir::ImplBlock,
213 ) -> NavigationTarget { 260 ) -> NavigationTarget {
214 let src = impl_block.source(db); 261 let src = impl_block.source(db);
262 let (file_id, text_range) = find_range_from_node(db, src.file_id, src.ast.syntax());
263
215 NavigationTarget::from_syntax( 264 NavigationTarget::from_syntax(
216 src.file_id.original_file(db), 265 file_id,
217 "impl".into(), 266 "impl".into(),
218 None, 267 None,
268 text_range,
219 src.ast.syntax(), 269 src.ast.syntax(),
220 None, 270 None,
221 None, 271 None,
@@ -236,12 +286,7 @@ impl NavigationTarget {
236 pub(crate) fn from_macro_def(db: &RootDatabase, macro_call: hir::MacroDef) -> NavigationTarget { 286 pub(crate) fn from_macro_def(db: &RootDatabase, macro_call: hir::MacroDef) -> NavigationTarget {
237 let src = macro_call.source(db); 287 let src = macro_call.source(db);
238 log::debug!("nav target {:#?}", src.ast.syntax()); 288 log::debug!("nav target {:#?}", src.ast.syntax());
239 NavigationTarget::from_named( 289 NavigationTarget::from_named(db, src.file_id, &src.ast, src.ast.doc_comment_text(), None)
240 src.file_id.original_file(db),
241 &src.ast,
242 src.ast.doc_comment_text(),
243 None,
244 )
245 } 290 }
246 291
247 #[cfg(test)] 292 #[cfg(test)]
@@ -270,21 +315,33 @@ impl NavigationTarget {
270 315
271 /// Allows `NavigationTarget` to be created from a `NameOwner` 316 /// Allows `NavigationTarget` to be created from a `NameOwner`
272 pub(crate) fn from_named( 317 pub(crate) fn from_named(
273 file_id: FileId, 318 db: &RootDatabase,
319 file_id: hir::HirFileId,
274 node: &impl ast::NameOwner, 320 node: &impl ast::NameOwner,
275 docs: Option<String>, 321 docs: Option<String>,
276 description: Option<String>, 322 description: Option<String>,
277 ) -> NavigationTarget { 323 ) -> NavigationTarget {
278 //FIXME: use `_` instead of empty string 324 //FIXME: use `_` instead of empty string
279 let name = node.name().map(|it| it.text().clone()).unwrap_or_default(); 325 let name = node.name().map(|it| it.text().clone()).unwrap_or_default();
280 let focus_range = node.name().map(|it| it.syntax().text_range()); 326 let focus_range = node.name().map(|it| find_range_from_node(db, file_id, it.syntax()).1);
281 NavigationTarget::from_syntax(file_id, name, focus_range, node.syntax(), docs, description) 327 let (file_id, full_range) = find_range_from_node(db, file_id, node.syntax());
328
329 NavigationTarget::from_syntax(
330 file_id,
331 name,
332 focus_range,
333 full_range,
334 node.syntax(),
335 docs,
336 description,
337 )
282 } 338 }
283 339
284 fn from_syntax( 340 fn from_syntax(
285 file_id: FileId, 341 file_id: FileId,
286 name: SmolStr, 342 name: SmolStr,
287 focus_range: Option<TextRange>, 343 focus_range: Option<TextRange>,
344 full_range: TextRange,
288 node: &SyntaxNode, 345 node: &SyntaxNode,
289 docs: Option<String>, 346 docs: Option<String>,
290 description: Option<String>, 347 description: Option<String>,
@@ -293,9 +350,8 @@ impl NavigationTarget {
293 file_id, 350 file_id,
294 name, 351 name,
295 kind: node.kind(), 352 kind: node.kind(),
296 full_range: node.text_range(), 353 full_range,
297 focus_range, 354 focus_range,
298 // ptr: Some(LocalSyntaxPtr::new(node)),
299 container_name: None, 355 container_name: None,
300 description, 356 description,
301 docs, 357 docs,
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index c1ce54bea..afa59cbe3 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -101,19 +101,20 @@ pub(crate) fn name_definition(
101 } 101 }
102 } 102 }
103 103
104 if let Some(nav) = named_target(file_id, &parent) { 104 if let Some(nav) = named_target(db, file_id, &parent) {
105 return Some(vec![nav]); 105 return Some(vec![nav]);
106 } 106 }
107 107
108 None 108 None
109} 109}
110 110
111fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> { 111fn named_target(db: &RootDatabase, file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> {
112 match_ast! { 112 match_ast! {
113 match node { 113 match node {
114 ast::StructDef(it) => { 114 ast::StructDef(it) => {
115 Some(NavigationTarget::from_named( 115 Some(NavigationTarget::from_named(
116 file_id, 116 db,
117 file_id.into(),
117 &it, 118 &it,
118 it.doc_comment_text(), 119 it.doc_comment_text(),
119 it.short_label(), 120 it.short_label(),
@@ -121,7 +122,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget>
121 }, 122 },
122 ast::EnumDef(it) => { 123 ast::EnumDef(it) => {
123 Some(NavigationTarget::from_named( 124 Some(NavigationTarget::from_named(
124 file_id, 125 db,
126 file_id.into(),
125 &it, 127 &it,
126 it.doc_comment_text(), 128 it.doc_comment_text(),
127 it.short_label(), 129 it.short_label(),
@@ -129,7 +131,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget>
129 }, 131 },
130 ast::EnumVariant(it) => { 132 ast::EnumVariant(it) => {
131 Some(NavigationTarget::from_named( 133 Some(NavigationTarget::from_named(
132 file_id, 134 db,
135 file_id.into(),
133 &it, 136 &it,
134 it.doc_comment_text(), 137 it.doc_comment_text(),
135 it.short_label(), 138 it.short_label(),
@@ -137,7 +140,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget>
137 }, 140 },
138 ast::FnDef(it) => { 141 ast::FnDef(it) => {
139 Some(NavigationTarget::from_named( 142 Some(NavigationTarget::from_named(
140 file_id, 143 db,
144 file_id.into(),
141 &it, 145 &it,
142 it.doc_comment_text(), 146 it.doc_comment_text(),
143 it.short_label(), 147 it.short_label(),
@@ -145,7 +149,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget>
145 }, 149 },
146 ast::TypeAliasDef(it) => { 150 ast::TypeAliasDef(it) => {
147 Some(NavigationTarget::from_named( 151 Some(NavigationTarget::from_named(
148 file_id, 152 db,
153 file_id.into(),
149 &it, 154 &it,
150 it.doc_comment_text(), 155 it.doc_comment_text(),
151 it.short_label(), 156 it.short_label(),
@@ -153,7 +158,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget>
153 }, 158 },
154 ast::ConstDef(it) => { 159 ast::ConstDef(it) => {
155 Some(NavigationTarget::from_named( 160 Some(NavigationTarget::from_named(
156 file_id, 161 db,
162 file_id.into(),
157 &it, 163 &it,
158 it.doc_comment_text(), 164 it.doc_comment_text(),
159 it.short_label(), 165 it.short_label(),
@@ -161,7 +167,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget>
161 }, 167 },
162 ast::StaticDef(it) => { 168 ast::StaticDef(it) => {
163 Some(NavigationTarget::from_named( 169 Some(NavigationTarget::from_named(
164 file_id, 170 db,
171 file_id.into(),
165 &it, 172 &it,
166 it.doc_comment_text(), 173 it.doc_comment_text(),
167 it.short_label(), 174 it.short_label(),
@@ -169,7 +176,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget>
169 }, 176 },
170 ast::TraitDef(it) => { 177 ast::TraitDef(it) => {
171 Some(NavigationTarget::from_named( 178 Some(NavigationTarget::from_named(
172 file_id, 179 db,
180 file_id.into(),
173 &it, 181 &it,
174 it.doc_comment_text(), 182 it.doc_comment_text(),
175 it.short_label(), 183 it.short_label(),
@@ -177,7 +185,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget>
177 }, 185 },
178 ast::RecordFieldDef(it) => { 186 ast::RecordFieldDef(it) => {
179 Some(NavigationTarget::from_named( 187 Some(NavigationTarget::from_named(
180 file_id, 188 db,
189 file_id.into(),
181 &it, 190 &it,
182 it.doc_comment_text(), 191 it.doc_comment_text(),
183 it.short_label(), 192 it.short_label(),
@@ -185,7 +194,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget>
185 }, 194 },
186 ast::Module(it) => { 195 ast::Module(it) => {
187 Some(NavigationTarget::from_named( 196 Some(NavigationTarget::from_named(
188 file_id, 197 db,
198 file_id.into(),
189 &it, 199 &it,
190 it.doc_comment_text(), 200 it.doc_comment_text(),
191 it.short_label(), 201 it.short_label(),
@@ -193,7 +203,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget>
193 }, 203 },
194 ast::MacroCall(it) => { 204 ast::MacroCall(it) => {
195 Some(NavigationTarget::from_named( 205 Some(NavigationTarget::from_named(
196 file_id, 206 db,
207 file_id.into(),
197 &it, 208 &it,
198 it.doc_comment_text(), 209 it.doc_comment_text(),
199 None, 210 None,
@@ -335,6 +346,46 @@ mod tests {
335 } 346 }
336 347
337 #[test] 348 #[test]
349 fn goto_definition_works_for_macro_defined_fn_with_arg() {
350 check_goto(
351 "
352 //- /lib.rs
353 macro_rules! define_fn {
354 ($name:ident) => (fn $name() {})
355 }
356
357 define_fn!(
358 foo
359 )
360
361 fn bar() {
362 <|>foo();
363 }
364 ",
365 "foo FN_DEF FileId(1) [80; 83) [80; 83)",
366 );
367 }
368
369 #[test]
370 fn goto_definition_works_for_macro_defined_fn_no_arg() {
371 check_goto(
372 "
373 //- /lib.rs
374 macro_rules! define_fn {
375 () => (fn foo() {})
376 }
377
378 define_fn!();
379
380 fn bar() {
381 <|>foo();
382 }
383 ",
384 "foo FN_DEF FileId(1) [39; 42) [39; 42)",
385 );
386 }
387
388 #[test]
338 fn goto_definition_works_for_methods() { 389 fn goto_definition_works_for_methods() {
339 covers!(goto_definition_works_for_methods); 390 covers!(goto_definition_works_for_methods);
340 check_goto( 391 check_goto(
diff --git a/crates/ra_ide_api/src/status.rs b/crates/ra_ide_api/src/status.rs
index f91f16c8e..1bb27eb85 100644
--- a/crates/ra_ide_api/src/status.rs
+++ b/crates/ra_ide_api/src/status.rs
@@ -94,10 +94,10 @@ impl FromIterator<TableEntry<FileId, Parse<ast::SourceFile>>> for SyntaxTreeStat
94 } 94 }
95} 95}
96 96
97impl FromIterator<TableEntry<MacroFile, Option<Parse<SyntaxNode>>>> for SyntaxTreeStats { 97impl<M> FromIterator<TableEntry<MacroFile, Option<(Parse<SyntaxNode>, M)>>> for SyntaxTreeStats {
98 fn from_iter<T>(iter: T) -> SyntaxTreeStats 98 fn from_iter<T>(iter: T) -> SyntaxTreeStats
99 where 99 where
100 T: IntoIterator<Item = TableEntry<MacroFile, Option<Parse<SyntaxNode>>>>, 100 T: IntoIterator<Item = TableEntry<MacroFile, Option<(Parse<SyntaxNode>, M)>>>,
101 { 101 {
102 let mut res = SyntaxTreeStats::default(); 102 let mut res = SyntaxTreeStats::default();
103 for entry in iter { 103 for entry in iter {
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index 15f000175..8a31d1c36 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -31,8 +31,7 @@ pub enum ExpandError {
31} 31}
32 32
33pub use crate::syntax_bridge::{ 33pub use crate::syntax_bridge::{
34 ast_to_token_tree, syntax_node_to_token_tree, token_tree_to_expr, token_tree_to_items, 34 ast_to_token_tree, syntax_node_to_token_tree, token_tree_to_syntax_node, RevTokenMap, TokenMap,
35 token_tree_to_macro_stmts, token_tree_to_pat, token_tree_to_ty,
36}; 35};
37 36
38/// This struct contains AST for a single `macro_rules` definition. What might 37/// This struct contains AST for a single `macro_rules` definition. What might
@@ -118,6 +117,10 @@ impl MacroRules {
118 shift_subtree(&mut tt, self.shift); 117 shift_subtree(&mut tt, self.shift);
119 mbe_expander::expand(self, &tt) 118 mbe_expander::expand(self, &tt)
120 } 119 }
120
121 pub fn shift(&self) -> u32 {
122 self.shift
123 }
121} 124}
122 125
123impl Rule { 126impl Rule {
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index 592fcf527..3f57ce3b5 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -1,9 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_parser::{ 3use ra_parser::{FragmentKind, ParseError, TreeSink};
4 FragmentKind::{self, *},
5 ParseError, TreeSink,
6};
7use ra_syntax::{ 4use ra_syntax::{
8 ast, AstNode, AstToken, NodeOrToken, Parse, SmolStr, SyntaxKind, SyntaxKind::*, SyntaxNode, 5 ast, AstNode, AstToken, NodeOrToken, Parse, SmolStr, SyntaxKind, SyntaxKind::*, SyntaxNode,
9 SyntaxTreeBuilder, TextRange, TextUnit, T, 6 SyntaxTreeBuilder, TextRange, TextUnit, T,
@@ -14,12 +11,18 @@ use crate::subtree_source::SubtreeTokenSource;
14use crate::ExpandError; 11use crate::ExpandError;
15 12
16/// Maps `tt::TokenId` to the relative range of the original token. 13/// Maps `tt::TokenId` to the relative range of the original token.
17#[derive(Default)] 14#[derive(Debug, PartialEq, Eq, Default)]
18pub struct TokenMap { 15pub struct TokenMap {
19 /// Maps `tt::TokenId` to the *relative* source range. 16 /// Maps `tt::TokenId` to the *relative* source range.
20 tokens: Vec<TextRange>, 17 tokens: Vec<TextRange>,
21} 18}
22 19
20/// Maps relative range of the expanded syntax node to `tt::TokenId`
21#[derive(Debug, PartialEq, Eq, Default)]
22pub struct RevTokenMap {
23 pub ranges: Vec<(TextRange, tt::TokenId)>,
24}
25
23/// Convert the syntax tree (what user has written) to a `TokenTree` (what macro 26/// Convert the syntax tree (what user has written) to a `TokenTree` (what macro
24/// will consume). 27/// will consume).
25pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap)> { 28pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap)> {
@@ -49,10 +52,10 @@ pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> Option<(tt::Subtree, Toke
49// * ImplItems(SmallVec<[ast::ImplItem; 1]>) 52// * ImplItems(SmallVec<[ast::ImplItem; 1]>)
50// * ForeignItems(SmallVec<[ast::ForeignItem; 1]> 53// * ForeignItems(SmallVec<[ast::ForeignItem; 1]>
51 54
52fn fragment_to_syntax_node( 55pub fn token_tree_to_syntax_node(
53 tt: &tt::Subtree, 56 tt: &tt::Subtree,
54 fragment_kind: FragmentKind, 57 fragment_kind: FragmentKind,
55) -> Result<Parse<SyntaxNode>, ExpandError> { 58) -> Result<(Parse<SyntaxNode>, RevTokenMap), ExpandError> {
56 let tmp; 59 let tmp;
57 let tokens = match tt { 60 let tokens = match tt {
58 tt::Subtree { delimiter: tt::Delimiter::None, token_trees } => token_trees.as_slice(), 61 tt::Subtree { delimiter: tt::Delimiter::None, token_trees } => token_trees.as_slice(),
@@ -69,38 +72,8 @@ fn fragment_to_syntax_node(
69 return Err(ExpandError::ConversionError); 72 return Err(ExpandError::ConversionError);
70 } 73 }
71 //FIXME: would be cool to report errors 74 //FIXME: would be cool to report errors
72 let parse = tree_sink.inner.finish(); 75 let (parse, range_map) = tree_sink.finish();
73 Ok(parse) 76 Ok((parse, range_map))
74}
75
76/// Parses the token tree (result of macro expansion) to an expression
77pub fn token_tree_to_expr(tt: &tt::Subtree) -> Result<Parse<ast::Expr>, ExpandError> {
78 let parse = fragment_to_syntax_node(tt, Expr)?;
79 parse.cast().ok_or_else(|| crate::ExpandError::ConversionError)
80}
81
82/// Parses the token tree (result of macro expansion) to a Pattern
83pub fn token_tree_to_pat(tt: &tt::Subtree) -> Result<Parse<ast::Pat>, ExpandError> {
84 let parse = fragment_to_syntax_node(tt, Pattern)?;
85 parse.cast().ok_or_else(|| crate::ExpandError::ConversionError)
86}
87
88/// Parses the token tree (result of macro expansion) to a Type
89pub fn token_tree_to_ty(tt: &tt::Subtree) -> Result<Parse<ast::TypeRef>, ExpandError> {
90 let parse = fragment_to_syntax_node(tt, Type)?;
91 parse.cast().ok_or_else(|| crate::ExpandError::ConversionError)
92}
93
94/// Parses the token tree (result of macro expansion) as a sequence of stmts
95pub fn token_tree_to_macro_stmts(tt: &tt::Subtree) -> Result<Parse<ast::MacroStmts>, ExpandError> {
96 let parse = fragment_to_syntax_node(tt, Statements)?;
97 parse.cast().ok_or_else(|| crate::ExpandError::ConversionError)
98}
99
100/// Parses the token tree (result of macro expansion) as a sequence of items
101pub fn token_tree_to_items(tt: &tt::Subtree) -> Result<Parse<ast::MacroItems>, ExpandError> {
102 let parse = fragment_to_syntax_node(tt, Items)?;
103 parse.cast().ok_or_else(|| crate::ExpandError::ConversionError)
104} 77}
105 78
106impl TokenMap { 79impl TokenMap {
@@ -116,6 +89,12 @@ impl TokenMap {
116 } 89 }
117} 90}
118 91
92impl RevTokenMap {
93 fn add(&mut self, relative_range: TextRange, token_id: tt::TokenId) {
94 self.ranges.push((relative_range, token_id.clone()))
95 }
96}
97
119/// Returns the textual content of a doc comment block as a quoted string 98/// Returns the textual content of a doc comment block as a quoted string
120/// That is, strips leading `///` (or `/**`, etc) 99/// That is, strips leading `///` (or `/**`, etc)
121/// and strips the ending `*/` 100/// and strips the ending `*/`
@@ -262,6 +241,7 @@ struct TtTreeSink<'a> {
262 cursor: Cursor<'a>, 241 cursor: Cursor<'a>,
263 text_pos: TextUnit, 242 text_pos: TextUnit,
264 inner: SyntaxTreeBuilder, 243 inner: SyntaxTreeBuilder,
244 range_map: RevTokenMap,
265 245
266 // Number of roots 246 // Number of roots
267 // Use for detect ill-form tree which is not single root 247 // Use for detect ill-form tree which is not single root
@@ -276,8 +256,13 @@ impl<'a> TtTreeSink<'a> {
276 text_pos: 0.into(), 256 text_pos: 0.into(),
277 inner: SyntaxTreeBuilder::default(), 257 inner: SyntaxTreeBuilder::default(),
278 roots: smallvec::SmallVec::new(), 258 roots: smallvec::SmallVec::new(),
259 range_map: RevTokenMap::default(),
279 } 260 }
280 } 261 }
262
263 fn finish(self) -> (Parse<SyntaxNode>, RevTokenMap) {
264 (self.inner.finish(), self.range_map)
265 }
281} 266}
282 267
283fn delim_to_str(d: tt::Delimiter, closing: bool) -> SmolStr { 268fn delim_to_str(d: tt::Delimiter, closing: bool) -> SmolStr {
@@ -307,6 +292,15 @@ impl<'a> TreeSink for TtTreeSink<'a> {
307 292
308 match self.cursor.token_tree() { 293 match self.cursor.token_tree() {
309 Some(tt::TokenTree::Leaf(leaf)) => { 294 Some(tt::TokenTree::Leaf(leaf)) => {
295 // Mark the range if needed
296 if let tt::Leaf::Ident(ident) = leaf {
297 if kind == IDENT {
298 let range =
299 TextRange::offset_len(self.text_pos, TextUnit::of_str(&ident.text));
300 self.range_map.add(range, ident.id);
301 }
302 }
303
310 self.cursor = self.cursor.bump(); 304 self.cursor = self.cursor.bump();
311 self.buf += &format!("{}", leaf); 305 self.buf += &format!("{}", leaf);
312 } 306 }
@@ -337,6 +331,7 @@ impl<'a> TreeSink for TtTreeSink<'a> {
337 { 331 {
338 if curr.spacing == tt::Spacing::Alone { 332 if curr.spacing == tt::Spacing::Alone {
339 self.inner.token(WHITESPACE, " ".into()); 333 self.inner.token(WHITESPACE, " ".into());
334 self.text_pos += TextUnit::of_char(' ');
340 } 335 }
341 } 336 }
342 } 337 }
@@ -423,6 +418,6 @@ mod tests {
423 "#, 418 "#,
424 ); 419 );
425 let expansion = expand(&rules, "stmts!();"); 420 let expansion = expand(&rules, "stmts!();");
426 assert!(token_tree_to_expr(&expansion).is_err()); 421 assert!(token_tree_to_syntax_node(&expansion, FragmentKind::Expr).is_err());
427 } 422 }
428} 423}
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs
index a23e3afe3..0109a4d98 100644
--- a/crates/ra_mbe/src/tests.rs
+++ b/crates/ra_mbe/src/tests.rs
@@ -1,3 +1,4 @@
1use ra_parser::FragmentKind;
1use ra_syntax::{ast, AstNode, NodeOrToken, WalkEvent}; 2use ra_syntax::{ast, AstNode, NodeOrToken, WalkEvent};
2use test_utils::assert_eq_text; 3use test_utils::assert_eq_text;
3 4
@@ -126,9 +127,9 @@ fn test_expr_order() {
126"#, 127"#,
127 ); 128 );
128 let expanded = expand(&rules, "foo! { 1 + 1}"); 129 let expanded = expand(&rules, "foo! { 1 + 1}");
129 let tree = token_tree_to_items(&expanded).unwrap().tree(); 130 let tree = token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap().0.syntax_node();
130 131
131 let dump = format!("{:#?}", tree.syntax()); 132 let dump = format!("{:#?}", tree);
132 assert_eq_text!( 133 assert_eq_text!(
133 dump.trim(), 134 dump.trim(),
134 r#"MACRO_ITEMS@[0; 15) 135 r#"MACRO_ITEMS@[0; 15)
@@ -383,9 +384,9 @@ fn test_expand_to_item_list() {
383 ", 384 ",
384 ); 385 );
385 let expansion = expand(&rules, "structs!(Foo, Bar);"); 386 let expansion = expand(&rules, "structs!(Foo, Bar);");
386 let tree = token_tree_to_items(&expansion).unwrap().tree(); 387 let tree = token_tree_to_syntax_node(&expansion, FragmentKind::Items).unwrap().0.syntax_node();
387 assert_eq!( 388 assert_eq!(
388 format!("{:#?}", tree.syntax()).trim(), 389 format!("{:#?}", tree).trim(),
389 r#" 390 r#"
390MACRO_ITEMS@[0; 40) 391MACRO_ITEMS@[0; 40)
391 STRUCT_DEF@[0; 20) 392 STRUCT_DEF@[0; 20)
@@ -501,10 +502,11 @@ fn test_tt_to_stmts() {
501 ); 502 );
502 503
503 let expanded = expand(&rules, "foo!{}"); 504 let expanded = expand(&rules, "foo!{}");
504 let stmts = token_tree_to_macro_stmts(&expanded).unwrap().tree(); 505 let stmts =
506 token_tree_to_syntax_node(&expanded, FragmentKind::Statements).unwrap().0.syntax_node();
505 507
506 assert_eq!( 508 assert_eq!(
507 format!("{:#?}", stmts.syntax()).trim(), 509 format!("{:#?}", stmts).trim(),
508 r#"MACRO_STMTS@[0; 15) 510 r#"MACRO_STMTS@[0; 15)
509 LET_STMT@[0; 7) 511 LET_STMT@[0; 7)
510 LET_KW@[0; 3) "let" 512 LET_KW@[0; 3) "let"
@@ -754,7 +756,10 @@ fn test_all_items() {
754 } 756 }
755"#, 757"#,
756 ); 758 );
757 assert_expansion(MacroKind::Items, &rules, r#" 759 assert_expansion(
760 MacroKind::Items,
761 &rules,
762 r#"
758 foo! { 763 foo! {
759 extern crate a; 764 extern crate a;
760 mod b; 765 mod b;
@@ -770,7 +775,9 @@ fn test_all_items() {
770 extern {} 775 extern {}
771 type T = u8; 776 type T = u8;
772 } 777 }
773"#, r#"extern crate a ; mod b ; mod c {} use d ; const E : i32 = 0 ; static F : i32 = 0 ; impl G {} struct H ; enum I {Foo} trait J {} fn h () {} extern {} type T = u8 ;"#); 778"#,
779 r#"extern crate a ; mod b ; mod c {} use d ; const E : i32 = 0 ; static F : i32 = 0 ; impl G {} struct H ; enum I {Foo} trait J {} fn h () {} extern {} type T = u8 ;"#,
780 );
774} 781}
775 782
776#[test] 783#[test]
@@ -946,10 +953,10 @@ fn test_vec() {
946 ); 953 );
947 954
948 let expansion = expand(&rules, r#"vec![1u32,2];"#); 955 let expansion = expand(&rules, r#"vec![1u32,2];"#);
949 let tree = token_tree_to_expr(&expansion).unwrap().tree(); 956 let tree = token_tree_to_syntax_node(&expansion, FragmentKind::Expr).unwrap().0.syntax_node();
950 957
951 assert_eq!( 958 assert_eq!(
952 format!("{:#?}", tree.syntax()).trim(), 959 format!("{:#?}", tree).trim(),
953 r#"BLOCK_EXPR@[0; 45) 960 r#"BLOCK_EXPR@[0; 45)
954 BLOCK@[0; 45) 961 BLOCK@[0; 45)
955 L_CURLY@[0; 1) "{" 962 L_CURLY@[0; 1) "{"
@@ -1088,8 +1095,12 @@ macro_rules! generate_pattern_iterators {
1088"#, 1095"#,
1089 ); 1096 );
1090 1097
1091 assert_expansion(MacroKind::Items, &rules, r#"generate_pattern_iterators ! ( double ended ; with # [ stable ( feature = "rust1" , since = "1.0.0" ) ] , Split , RSplit , & 'a str );"#, 1098 assert_expansion(
1092 "fn foo () {}"); 1099 MacroKind::Items,
1100 &rules,
1101 r#"generate_pattern_iterators ! ( double ended ; with # [ stable ( feature = "rust1" , since = "1.0.0" ) ] , Split , RSplit , & 'a str );"#,
1102 "fn foo () {}",
1103 );
1093} 1104}
1094 1105
1095#[test] 1106#[test]
@@ -1171,8 +1182,12 @@ fn test_impl_nonzero_fmt() {
1171"#, 1182"#,
1172 ); 1183 );
1173 1184
1174 assert_expansion(MacroKind::Items, &rules, r#"impl_nonzero_fmt! { # [stable(feature= "nonzero",since="1.28.0")] (Debug,Display,Binary,Octal,LowerHex,UpperHex) for NonZeroU8}"#, 1185 assert_expansion(
1175 "fn foo () {}"); 1186 MacroKind::Items,
1187 &rules,
1188 r#"impl_nonzero_fmt! { # [stable(feature= "nonzero",since="1.28.0")] (Debug,Display,Binary,Octal,LowerHex,UpperHex) for NonZeroU8}"#,
1189 "fn foo () {}",
1190 );
1176} 1191}
1177 1192
1178#[test] 1193#[test]
@@ -1189,8 +1204,12 @@ fn test_cfg_if_items() {
1189"#, 1204"#,
1190 ); 1205 );
1191 1206
1192 assert_expansion(MacroKind::Items, &rules, r#"__cfg_if_items ! { ( rustdoc , ) ; ( ( ) ( # [ cfg ( any ( target_os = "redox" , unix ) ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as unix ; # [ cfg ( windows ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as windows ; # [ cfg ( any ( target_os = "linux" , target_os = "l4re" ) ) ] pub mod linux ; ) ) , }"#, 1207 assert_expansion(
1193 "__cfg_if_items ! {(rustdoc ,) ;}"); 1208 MacroKind::Items,
1209 &rules,
1210 r#"__cfg_if_items ! { ( rustdoc , ) ; ( ( ) ( # [ cfg ( any ( target_os = "redox" , unix ) ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as unix ; # [ cfg ( windows ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as windows ; # [ cfg ( any ( target_os = "linux" , target_os = "l4re" ) ) ] pub mod linux ; ) ) , }"#,
1211 "__cfg_if_items ! {(rustdoc ,) ;}",
1212 );
1194} 1213}
1195 1214
1196#[test] 1215#[test]
@@ -1233,10 +1252,13 @@ cfg_if ! {
1233"#, 1252"#,
1234 "__cfg_if_items ! {() ; ((target_env = \"msvc\") ()) , ((all (target_arch = \"wasm32\" , not (target_os = \"emscripten\"))) ()) , (() (mod libunwind ; pub use libunwind :: * ;)) ,}"); 1253 "__cfg_if_items ! {() ; ((target_env = \"msvc\") ()) , ((all (target_arch = \"wasm32\" , not (target_os = \"emscripten\"))) ()) , (() (mod libunwind ; pub use libunwind :: * ;)) ,}");
1235 1254
1236 assert_expansion(MacroKind::Items, &rules, r#" 1255 assert_expansion(
1256 MacroKind::Items,
1257 &rules,
1258 r#"
1237cfg_if ! { @ __apply cfg ( all ( not ( any ( not ( any ( target_os = "solaris" , target_os = "illumos" ) ) ) ) ) ) , } 1259cfg_if ! { @ __apply cfg ( all ( not ( any ( not ( any ( target_os = "solaris" , target_os = "illumos" ) ) ) ) ) ) , }
1238"#, 1260"#,
1239 "" 1261 "",
1240 ); 1262 );
1241} 1263}
1242 1264
@@ -1291,10 +1313,13 @@ macro_rules! RIDL {
1291}"#, 1313}"#,
1292 ); 1314 );
1293 1315
1294 let expanded = expand(&rules, r#" 1316 let expanded = expand(
1317 &rules,
1318 r#"
1295RIDL!{interface ID3D11Asynchronous(ID3D11AsynchronousVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) { 1319RIDL!{interface ID3D11Asynchronous(ID3D11AsynchronousVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) {
1296 fn GetDataSize(&mut self) -> UINT 1320 fn GetDataSize(&mut self) -> UINT
1297}}"#); 1321}}"#,
1322 );
1298 assert_eq!(expanded.to_string(), "impl ID3D11Asynchronous {pub unsafe fn GetDataSize (& mut self) -> UINT {((* self . lpVtbl) .GetDataSize) (self)}}"); 1323 assert_eq!(expanded.to_string(), "impl ID3D11Asynchronous {pub unsafe fn GetDataSize (& mut self) -> UINT {((* self . lpVtbl) .GetDataSize) (self)}}");
1299} 1324}
1300 1325
@@ -1340,7 +1365,8 @@ quick_error ! (SORT [enum Wrapped # [derive (Debug)]] items [
1340 1365
1341#[test] 1366#[test]
1342fn test_empty_repeat_vars_in_empty_repeat_vars() { 1367fn test_empty_repeat_vars_in_empty_repeat_vars() {
1343 let rules = create_rules(r#" 1368 let rules = create_rules(
1369 r#"
1344macro_rules! delegate_impl { 1370macro_rules! delegate_impl {
1345 ([$self_type:ident, $self_wrap:ty, $self_map:ident] 1371 ([$self_type:ident, $self_wrap:ty, $self_map:ident]
1346 pub trait $name:ident $(: $sup:ident)* $(+ $more_sup:ident)* { 1372 pub trait $name:ident $(: $sup:ident)* $(+ $more_sup:ident)* {
@@ -1385,9 +1411,15 @@ macro_rules! delegate_impl {
1385 } 1411 }
1386 } 1412 }
1387} 1413}
1388"#); 1414"#,
1415 );
1389 1416
1390 assert_expansion(MacroKind::Items, &rules, r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#, "impl <> Data for & \'a mut G where G : Data {}"); 1417 assert_expansion(
1418 MacroKind::Items,
1419 &rules,
1420 r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#,
1421 "impl <> Data for & \'a mut G where G : Data {}",
1422 );
1391} 1423}
1392 1424
1393pub(crate) fn create_rules(macro_definition: &str) -> MacroRules { 1425pub(crate) fn create_rules(macro_definition: &str) -> MacroRules {
@@ -1436,22 +1468,30 @@ pub(crate) fn assert_expansion(
1436 }; 1468 };
1437 let (expanded_tree, expected_tree) = match kind { 1469 let (expanded_tree, expected_tree) = match kind {
1438 MacroKind::Items => { 1470 MacroKind::Items => {
1439 let expanded_tree = token_tree_to_items(&expanded).unwrap().tree(); 1471 let expanded_tree =
1440 let expected_tree = token_tree_to_items(&expected).unwrap().tree(); 1472 token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap().0.syntax_node();
1473 let expected_tree =
1474 token_tree_to_syntax_node(&expected, FragmentKind::Items).unwrap().0.syntax_node();
1441 1475
1442 ( 1476 (
1443 debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(), 1477 debug_dump_ignore_spaces(&expanded_tree).trim().to_string(),
1444 debug_dump_ignore_spaces(expected_tree.syntax()).trim().to_string(), 1478 debug_dump_ignore_spaces(&expected_tree).trim().to_string(),
1445 ) 1479 )
1446 } 1480 }
1447 1481
1448 MacroKind::Stmts => { 1482 MacroKind::Stmts => {
1449 let expanded_tree = token_tree_to_macro_stmts(&expanded).unwrap().tree(); 1483 let expanded_tree = token_tree_to_syntax_node(&expanded, FragmentKind::Statements)
1450 let expected_tree = token_tree_to_macro_stmts(&expected).unwrap().tree(); 1484 .unwrap()
1485 .0
1486 .syntax_node();
1487 let expected_tree = token_tree_to_syntax_node(&expected, FragmentKind::Statements)
1488 .unwrap()
1489 .0
1490 .syntax_node();
1451 1491
1452 ( 1492 (
1453 debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(), 1493 debug_dump_ignore_spaces(&expanded_tree).trim().to_string(),
1454 debug_dump_ignore_spaces(expected_tree.syntax()).trim().to_string(), 1494 debug_dump_ignore_spaces(&expected_tree).trim().to_string(),
1455 ) 1495 )
1456 } 1496 }
1457 }; 1497 };