diff options
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/adt.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model/src.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/expr/scope.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/from_source.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_def/src/adt.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir_def/src/db.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir_def/src/lib.rs | 28 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/collector.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir_expand/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/db.rs | 46 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/lib.rs | 59 | ||||
-rw-r--r-- | crates/ra_ide_api/src/display/navigation_target.rs | 120 | ||||
-rw-r--r-- | crates/ra_ide_api/src/goto_definition.rs | 77 | ||||
-rw-r--r-- | crates/ra_ide_api/src/status.rs | 4 | ||||
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 7 | ||||
-rw-r--r-- | crates/ra_mbe/src/syntax_bridge.rs | 75 | ||||
-rw-r--r-- | crates/ra_mbe/src/tests.rs | 102 |
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 | ||
13 | impl Struct { | 13 | impl 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 | ||
289 | impl Struct { | 289 | impl 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 | ||
347 | impl Union { | 347 | impl 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 { | |||
78 | impl HasSource for Struct { | 78 | impl 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 | } |
84 | impl HasSource for Union { | 84 | impl 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 | } |
90 | impl HasSource for Enum { | 90 | impl 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 | ||
3 | use hir_def::{StructId, StructOrUnionId, UnionId}; | ||
3 | use hir_expand::name::AsName; | 4 | use hir_expand::name::AsName; |
4 | use ra_syntax::ast::{self, AstNode, NameOwner}; | 5 | use 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 | ||
18 | impl FromSource for Struct { | 20 | impl 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 | } |
25 | impl FromSource for Union { | 27 | impl 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 | } |
32 | impl FromSource for Enum { | 34 | impl 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 | ||
667 | fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig { | 667 | fn 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. |
683 | fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty { | 683 | fn 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 | ||
9 | use crate::{ | 9 | use 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 | ||
51 | impl StructData { | 51 | impl 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)] |
208 | pub struct StructId(salsa::InternId); | 208 | pub struct StructOrUnionId(salsa::InternId); |
209 | impl_intern_key!(StructId); | 209 | impl_intern_key!(StructOrUnionId); |
210 | impl AstItemDef<ast::StructDef> for StructId { | 210 | impl 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)] |
220 | pub struct UnionId(salsa::InternId); | 220 | pub struct StructId(pub StructOrUnionId); |
221 | impl_intern_key!(UnionId); | 221 | impl From<StructId> for StructOrUnionId { |
222 | impl 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)] | ||
228 | pub struct UnionId(pub StructOrUnionId); | ||
229 | impl 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 | ||
25 | pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) -> CrateDefMap { | 26 | pub(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" | |||
10 | ra_arena = { path = "../ra_arena" } | 10 | ra_arena = { path = "../ra_arena" } |
11 | ra_db = { path = "../ra_db" } | 11 | ra_db = { path = "../ra_db" } |
12 | ra_syntax = { path = "../ra_syntax" } | 12 | ra_syntax = { path = "../ra_syntax" } |
13 | ra_parser = { path = "../ra_parser" } | ||
13 | ra_prof = { path = "../ra_prof" } | 14 | ra_prof = { path = "../ra_prof" } |
14 | tt = { path = "../ra_tt", package = "ra_tt" } | 15 | tt = { path = "../ra_tt", package = "ra_tt" } |
15 | mbe = { path = "../ra_mbe", package = "ra_mbe" } | 16 | mbe = { 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 | ||
5 | use mbe::MacroRules; | 5 | use mbe::MacroRules; |
6 | use ra_db::{salsa, SourceDatabase}; | 6 | use ra_db::{salsa, SourceDatabase}; |
7 | use ra_parser::FragmentKind; | ||
7 | use ra_prof::profile; | 8 | use ra_prof::profile; |
8 | use ra_syntax::{AstNode, Parse, SyntaxNode}; | 9 | use 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 | ||
37 | pub(crate) fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> { | 41 | pub(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 | ||
51 | pub(crate) fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<tt::Subtree>> { | 58 | pub(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 | ||
59 | pub(crate) fn macro_expand( | 69 | pub(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(¯o_arg).map_err(|err| format!("{:?}", err))?; | 77 | let tt = macro_rules.0.expand(¯o_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 | |||
85 | pub(crate) fn parse_macro( | 95 | pub(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; | |||
12 | pub mod diagnostics; | 12 | pub mod diagnostics; |
13 | 13 | ||
14 | use std::hash::{Hash, Hasher}; | 14 | use std::hash::{Hash, Hasher}; |
15 | use std::sync::Arc; | ||
15 | 16 | ||
16 | use ra_db::{salsa, CrateId, FileId}; | 17 | use ra_db::{salsa, CrateId, FileId}; |
17 | use ra_syntax::{ | 18 | use ra_syntax::{ |
18 | ast::{self, AstNode}, | 19 | ast::{self, AstNode}, |
19 | SyntaxNode, | 20 | SyntaxNode, TextRange, TextUnit, |
20 | }; | 21 | }; |
21 | 22 | ||
22 | use crate::ast_id_map::FileAstId; | 23 | use 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 | ||
142 | pub 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 | |||
152 | impl 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 | ||
32 | fn 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 | |||
32 | impl NavigationTarget { | 47 | impl 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 | ||
111 | fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> { | 111 | fn 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 | ||
97 | impl FromIterator<TableEntry<MacroFile, Option<Parse<SyntaxNode>>>> for SyntaxTreeStats { | 97 | impl<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 | ||
33 | pub use crate::syntax_bridge::{ | 33 | pub 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 | ||
123 | impl Rule { | 126 | impl 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 | ||
3 | use ra_parser::{ | 3 | use ra_parser::{FragmentKind, ParseError, TreeSink}; |
4 | FragmentKind::{self, *}, | ||
5 | ParseError, TreeSink, | ||
6 | }; | ||
7 | use ra_syntax::{ | 4 | use 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; | |||
14 | use crate::ExpandError; | 11 | use 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)] |
18 | pub struct TokenMap { | 15 | pub 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)] | ||
22 | pub 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). |
25 | pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap)> { | 28 | pub 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 | ||
52 | fn fragment_to_syntax_node( | 55 | pub 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 | ||
77 | pub 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 | ||
83 | pub 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 | ||
89 | pub 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 | ||
95 | pub 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 | ||
101 | pub 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 | ||
106 | impl TokenMap { | 79 | impl TokenMap { |
@@ -116,6 +89,12 @@ impl TokenMap { | |||
116 | } | 89 | } |
117 | } | 90 | } |
118 | 91 | ||
92 | impl 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 | ||
283 | fn delim_to_str(d: tt::Delimiter, closing: bool) -> SmolStr { | 268 | fn 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 @@ | |||
1 | use ra_parser::FragmentKind; | ||
1 | use ra_syntax::{ast, AstNode, NodeOrToken, WalkEvent}; | 2 | use ra_syntax::{ast, AstNode, NodeOrToken, WalkEvent}; |
2 | use test_utils::assert_eq_text; | 3 | use 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#" |
390 | MACRO_ITEMS@[0; 40) | 391 | MACRO_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#" | ||
1237 | cfg_if ! { @ __apply cfg ( all ( not ( any ( not ( any ( target_os = "solaris" , target_os = "illumos" ) ) ) ) ) ) , } | 1259 | cfg_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#" | ||
1295 | RIDL!{interface ID3D11Asynchronous(ID3D11AsynchronousVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) { | 1319 | RIDL!{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] |
1342 | fn test_empty_repeat_vars_in_empty_repeat_vars() { | 1367 | fn test_empty_repeat_vars_in_empty_repeat_vars() { |
1343 | let rules = create_rules(r#" | 1368 | let rules = create_rules( |
1369 | r#" | ||
1344 | macro_rules! delegate_impl { | 1370 | macro_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 | ||
1393 | pub(crate) fn create_rules(macro_definition: &str) -> MacroRules { | 1425 | pub(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 | }; |