aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/db.rs7
-rw-r--r--crates/ra_hir/src/ids.rs25
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/macros.rs135
-rw-r--r--crates/ra_hir/src/nameres.rs29
-rw-r--r--crates/ra_hir/src/nameres/collector.rs76
-rw-r--r--crates/ra_ide_api/src/extend_selection.rs46
-rw-r--r--crates/ra_ide_api/src/syntax_highlighting.rs36
8 files changed, 95 insertions, 261 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index d2cc19b0f..c7bad7e2b 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -4,12 +4,10 @@ use ra_syntax::{SyntaxNode, TreeArc, SourceFile};
4use ra_db::{SourceDatabase, salsa, FileId}; 4use ra_db::{SourceDatabase, salsa, FileId};
5 5
6use crate::{ 6use crate::{
7 MacroCallId, HirFileId, 7 HirFileId, SourceFileItems, SourceItemId, Crate, Module, HirInterner,
8 SourceFileItems, SourceItemId, Crate, Module, HirInterner,
9 Function, FnSignature, ExprScopes, TypeAlias, 8 Function, FnSignature, ExprScopes, TypeAlias,
10 Struct, Enum, StructField, 9 Struct, Enum, StructField,
11 Const, ConstSignature, Static, 10 Const, ConstSignature, Static,
12 macros::MacroExpansion,
13 nameres::{Namespace, ImportSourceMap, RawItems, CrateDefMap}, 11 nameres::{Namespace, ImportSourceMap, RawItems, CrateDefMap},
14 ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig}, 12 ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig},
15 adt::{StructData, EnumData}, 13 adt::{StructData, EnumData},
@@ -23,9 +21,6 @@ pub trait PersistentHirDatabase: SourceDatabase + AsRef<HirInterner> {
23 #[salsa::invoke(HirFileId::hir_parse)] 21 #[salsa::invoke(HirFileId::hir_parse)]
24 fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>; 22 fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>;
25 23
26 #[salsa::invoke(crate::macros::expand_macro_invocation)]
27 fn expand_macro_invocation(&self, invoc: MacroCallId) -> Option<Arc<MacroExpansion>>;
28
29 #[salsa::invoke(crate::adt::StructData::struct_data_query)] 24 #[salsa::invoke(crate::adt::StructData::struct_data_query)]
30 fn struct_data(&self, s: Struct) -> Arc<StructData>; 25 fn struct_data(&self, s: Struct) -> Arc<StructData>;
31 26
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index a144e4a1e..9596488d3 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -89,17 +89,31 @@ impl HirFileId {
89 ) -> TreeArc<SourceFile> { 89 ) -> TreeArc<SourceFile> {
90 match file_id.0 { 90 match file_id.0 {
91 HirFileIdRepr::File(file_id) => db.parse(file_id), 91 HirFileIdRepr::File(file_id) => db.parse(file_id),
92 HirFileIdRepr::Macro(m) => { 92 HirFileIdRepr::Macro(macro_call_id) => {
93 if let Some(exp) = db.expand_macro_invocation(m) {
94 return exp.file();
95 }
96 // returning an empty string looks fishy... 93 // returning an empty string looks fishy...
97 SourceFile::parse("") 94 parse_macro(db, macro_call_id).unwrap_or_else(|| SourceFile::parse(""))
98 } 95 }
99 } 96 }
100 } 97 }
101} 98}
102 99
100fn parse_macro(
101 db: &impl PersistentHirDatabase,
102 macro_call_id: MacroCallId,
103) -> Option<TreeArc<SourceFile>> {
104 let loc = macro_call_id.loc(db);
105 let syntax = db.file_item(loc.source_item_id);
106 let macro_call = ast::MacroCall::cast(&syntax).unwrap();
107 let (macro_arg, _) = macro_call.token_tree().and_then(mbe::ast_to_token_tree)?;
108
109 let def_map = db.crate_def_map(loc.module.krate);
110 let (krate, macro_id) = def_map.resolve_macro(macro_call_id)?;
111 let def_map = db.crate_def_map(krate);
112 let macro_rules = &def_map[macro_id];
113 let tt = macro_rules.expand(&macro_arg).ok()?;
114 Some(mbe::token_tree_to_ast_item_list(&tt))
115}
116
103#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 117#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
104enum HirFileIdRepr { 118enum HirFileIdRepr {
105 File(FileId), 119 File(FileId),
@@ -373,7 +387,6 @@ impl SourceFileItems {
373impl std::ops::Index<SourceFileItemId> for SourceFileItems { 387impl std::ops::Index<SourceFileItemId> for SourceFileItems {
374 type Output = SyntaxNodePtr; 388 type Output = SyntaxNodePtr;
375 fn index(&self, idx: SourceFileItemId) -> &SyntaxNodePtr { 389 fn index(&self, idx: SourceFileItemId) -> &SyntaxNodePtr {
376 eprintln!("invalid SourceFileItemId({:?}) for file({:?})", idx, self.file_id);
377 &self.arena[idx] 390 &self.arena[idx]
378 } 391 }
379} 392}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index a188a3cc8..75c977d32 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -24,7 +24,6 @@ mod path;
24pub mod source_binder; 24pub mod source_binder;
25 25
26mod ids; 26mod ids;
27mod macros;
28mod name; 27mod name;
29mod nameres; 28mod nameres;
30mod adt; 29mod adt;
@@ -53,7 +52,6 @@ pub use self::{
53 path::{Path, PathKind}, 52 path::{Path, PathKind},
54 name::Name, 53 name::Name,
55 ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner}, 54 ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner},
56 macros::{MacroDef, MacroInput, MacroExpansion},
57 nameres::{PerNs, Namespace}, 55 nameres::{PerNs, Namespace},
58 ty::{Ty, Substs, display::HirDisplay}, 56 ty::{Ty, Substs, display::HirDisplay},
59 impl_block::{ImplBlock, ImplItem}, 57 impl_block::{ImplBlock, ImplItem},
diff --git a/crates/ra_hir/src/macros.rs b/crates/ra_hir/src/macros.rs
deleted file mode 100644
index 45128c7df..000000000
--- a/crates/ra_hir/src/macros.rs
+++ /dev/null
@@ -1,135 +0,0 @@
1/// Machinery for macro expansion.
2///
3/// One of the more complicated things about macros is managing the source code
4/// that is produced after expansion. See `HirFileId` and `MacroCallId` for how
5/// do we do that.
6///
7/// When the file-management question is resolved, all that is left is a
8/// token-tree-to-token-tree transformation plus hygiene. We don't have either of
9/// those yet, so all macros are string based at the moment!
10use std::sync::Arc;
11
12use ra_syntax::{
13 TextRange, TextUnit, SourceFile, AstNode, SyntaxNode, TreeArc, SyntaxNodePtr,
14 ast,
15};
16
17use crate::{MacroCallId, PersistentHirDatabase};
18
19// Hard-coded defs for now :-(
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub enum MacroDef {
22 Vec,
23}
24
25impl MacroDef {
26 /// Expands macro call, returning the expansion and offset to be used to
27 /// convert ranges between expansion and original source.
28 pub fn ast_expand(macro_call: &ast::MacroCall) -> Option<(TextUnit, MacroExpansion)> {
29 let (def, input) = MacroDef::from_call(macro_call)?;
30 let exp = def.expand(input)?;
31 let off = macro_call.token_tree()?.syntax().range().start();
32 Some((off, exp))
33 }
34
35 fn from_call(macro_call: &ast::MacroCall) -> Option<(MacroDef, MacroInput)> {
36 let def = {
37 let path = macro_call.path()?;
38 let name_ref = path.segment()?.name_ref()?;
39 if name_ref.text() == "vec" {
40 MacroDef::Vec
41 } else {
42 return None;
43 }
44 };
45
46 let input = {
47 let arg = macro_call.token_tree()?.syntax();
48 MacroInput { text: arg.text().to_string() }
49 };
50 Some((def, input))
51 }
52
53 fn expand(self, input: MacroInput) -> Option<MacroExpansion> {
54 match self {
55 MacroDef::Vec => self.expand_vec(input),
56 }
57 }
58 fn expand_vec(self, input: MacroInput) -> Option<MacroExpansion> {
59 let text = format!(r"fn dummy() {{ {}; }}", input.text);
60 let file = SourceFile::parse(&text);
61 let array_expr = file.syntax().descendants().find_map(ast::ArrayExpr::cast)?;
62 let ptr = SyntaxNodePtr::new(array_expr.syntax());
63 let src_range = TextRange::offset_len(0.into(), TextUnit::of_str(&input.text));
64 let ranges_map = vec![(src_range, array_expr.syntax().range())];
65 let res = MacroExpansion { text, ranges_map, ptr };
66 Some(res)
67 }
68}
69
70#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct MacroInput {
72 // Should be token trees
73 pub text: String,
74}
75
76#[derive(Debug, Clone, PartialEq, Eq)]
77pub struct MacroExpansion {
78 /// The result of macro expansion. Should be token tree as well.
79 text: String,
80 /// Correspondence between ranges in the original source code and ranges in
81 /// the macro.
82 ranges_map: Vec<(TextRange, TextRange)>,
83 /// Implementation detail: internally, a macro is expanded to the whole file,
84 /// even if it is an expression. This `ptr` selects the actual expansion from
85 /// the expanded file.
86 ptr: SyntaxNodePtr,
87}
88
89impl MacroExpansion {
90 // FIXME: does not really make sense, macro expansion is not necessary a
91 // whole file. See `MacroExpansion::ptr` as well.
92 pub(crate) fn file(&self) -> TreeArc<SourceFile> {
93 SourceFile::parse(&self.text)
94 }
95
96 pub fn syntax(&self) -> TreeArc<SyntaxNode> {
97 self.ptr.to_node(&self.file()).to_owned()
98 }
99 /// Maps range in the source code to the range in the expanded code.
100 pub fn map_range_forward(&self, src_range: TextRange) -> Option<TextRange> {
101 for (s_range, t_range) in self.ranges_map.iter() {
102 if src_range.is_subrange(&s_range) {
103 let src_at_zero_range = src_range - src_range.start();
104 let src_range_offset = src_range.start() - s_range.start();
105 let src_range = src_at_zero_range + src_range_offset + t_range.start();
106 return Some(src_range);
107 }
108 }
109 None
110 }
111 /// Maps range in the expanded code to the range in the source code.
112 pub fn map_range_back(&self, tgt_range: TextRange) -> Option<TextRange> {
113 for (s_range, t_range) in self.ranges_map.iter() {
114 if tgt_range.is_subrange(&t_range) {
115 let tgt_at_zero_range = tgt_range - tgt_range.start();
116 let tgt_range_offset = tgt_range.start() - t_range.start();
117 let src_range = tgt_at_zero_range + tgt_range_offset + s_range.start();
118 return Some(src_range);
119 }
120 }
121 None
122 }
123}
124
125pub(crate) fn expand_macro_invocation(
126 db: &impl PersistentHirDatabase,
127 invoc: MacroCallId,
128) -> Option<Arc<MacroExpansion>> {
129 let loc = invoc.loc(db);
130 let syntax = db.file_item(loc.source_item_id);
131 let macro_call = ast::MacroCall::cast(&syntax).unwrap();
132
133 let (def, input) = MacroDef::from_call(macro_call)?;
134 def.expand(input).map(Arc::new)
135}
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index eabaa5691..17602ee6b 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -57,7 +57,7 @@ use test_utils::tested_by;
57use crate::{ 57use crate::{
58 ModuleDef, Name, Crate, Module, Problem, 58 ModuleDef, Name, Crate, Module, Problem,
59 PersistentHirDatabase, Path, PathKind, HirFileId, 59 PersistentHirDatabase, Path, PathKind, HirFileId,
60 ids::{SourceItemId, SourceFileItemId}, 60 ids::{SourceItemId, SourceFileItemId, MacroCallId},
61}; 61};
62 62
63pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap}; 63pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap};
@@ -76,7 +76,9 @@ pub struct CrateDefMap {
76 extern_prelude: FxHashMap<Name, ModuleDef>, 76 extern_prelude: FxHashMap<Name, ModuleDef>,
77 root: CrateModuleId, 77 root: CrateModuleId,
78 modules: Arena<CrateModuleId, ModuleData>, 78 modules: Arena<CrateModuleId, ModuleData>,
79 public_macros: FxHashMap<Name, mbe::MacroRules>, 79 macros: Arena<CrateMacroId, mbe::MacroRules>,
80 public_macros: FxHashMap<Name, CrateMacroId>,
81 macro_resolutions: FxHashMap<MacroCallId, (Crate, CrateMacroId)>,
80 problems: CrateDefMapProblems, 82 problems: CrateDefMapProblems,
81} 83}
82 84
@@ -87,9 +89,21 @@ impl std::ops::Index<CrateModuleId> for CrateDefMap {
87 } 89 }
88} 90}
89 91
92impl std::ops::Index<CrateMacroId> for CrateDefMap {
93 type Output = mbe::MacroRules;
94 fn index(&self, id: CrateMacroId) -> &mbe::MacroRules {
95 &self.macros[id]
96 }
97}
98
99/// An ID of a macro, **local** to a specific crate
100#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
101pub(crate) struct CrateMacroId(RawId);
102impl_arena_id!(CrateMacroId);
103
90/// An ID of a module, **local** to a specific crate 104/// An ID of a module, **local** to a specific crate
91#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 105#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
92struct CrateModuleId(RawId); 106pub(crate) struct CrateModuleId(RawId);
93impl_arena_id!(CrateModuleId); 107impl_arena_id!(CrateModuleId);
94 108
95#[derive(Default, Debug, PartialEq, Eq)] 109#[derive(Default, Debug, PartialEq, Eq)]
@@ -192,7 +206,9 @@ impl CrateDefMap {
192 prelude: None, 206 prelude: None,
193 root, 207 root,
194 modules, 208 modules,
209 macros: Arena::default(),
195 public_macros: FxHashMap::default(), 210 public_macros: FxHashMap::default(),
211 macro_resolutions: FxHashMap::default(),
196 problems: CrateDefMapProblems::default(), 212 problems: CrateDefMapProblems::default(),
197 } 213 }
198 }; 214 };
@@ -221,6 +237,13 @@ impl CrateDefMap {
221 &self.extern_prelude 237 &self.extern_prelude
222 } 238 }
223 239
240 pub(crate) fn resolve_macro(
241 &self,
242 macro_call_id: MacroCallId,
243 ) -> Option<(Crate, CrateMacroId)> {
244 self.macro_resolutions.get(&macro_call_id).map(|&it| it)
245 }
246
224 pub(crate) fn find_module_by_source( 247 pub(crate) fn find_module_by_source(
225 &self, 248 &self,
226 file_id: HirFileId, 249 file_id: HirFileId,
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index f2336c271..9992e054d 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -6,13 +6,13 @@ use ra_db::FileId;
6 6
7use crate::{ 7use crate::{
8 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, 8 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias,
9 PersistentHirDatabase, HirFileId, Name, Path, Problem, 9 PersistentHirDatabase, HirFileId, Name, Path, Problem, Crate,
10 KnownName, 10 KnownName,
11 nameres::{Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, raw}, 11 nameres::{Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, raw},
12 ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId}, 12 ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId},
13}; 13};
14 14
15use super::{CrateDefMap, CrateModuleId, ModuleData}; 15use super::{CrateDefMap, CrateModuleId, ModuleData, CrateMacroId};
16 16
17pub(super) fn collect_defs( 17pub(super) fn collect_defs(
18 db: &impl PersistentHirDatabase, 18 db: &impl PersistentHirDatabase,
@@ -52,7 +52,7 @@ struct DefCollector<DB> {
52 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, 52 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>,
53 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, 53 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>,
54 unexpanded_macros: Vec<(CrateModuleId, MacroCallId, Path, tt::Subtree)>, 54 unexpanded_macros: Vec<(CrateModuleId, MacroCallId, Path, tt::Subtree)>,
55 global_macro_scope: FxHashMap<Name, mbe::MacroRules>, 55 global_macro_scope: FxHashMap<Name, CrateMacroId>,
56} 56}
57 57
58impl<'a, DB> DefCollector<&'a DB> 58impl<'a, DB> DefCollector<&'a DB>
@@ -95,10 +95,11 @@ where
95 95
96 fn define_macro(&mut self, name: Name, tt: &tt::Subtree, export: bool) { 96 fn define_macro(&mut self, name: Name, tt: &tt::Subtree, export: bool) {
97 if let Ok(rules) = mbe::MacroRules::parse(tt) { 97 if let Ok(rules) = mbe::MacroRules::parse(tt) {
98 let macro_id = self.def_map.macros.alloc(rules);
98 if export { 99 if export {
99 self.def_map.public_macros.insert(name.clone(), rules.clone()); 100 self.def_map.public_macros.insert(name.clone(), macro_id);
100 } 101 }
101 self.global_macro_scope.insert(name, rules); 102 self.global_macro_scope.insert(name, macro_id);
102 } 103 }
103 } 104 }
104 105
@@ -295,6 +296,7 @@ where
295 fn resolve_macros(&mut self) -> ReachedFixedPoint { 296 fn resolve_macros(&mut self) -> ReachedFixedPoint {
296 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); 297 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
297 let mut resolved = Vec::new(); 298 let mut resolved = Vec::new();
299 let mut res = ReachedFixedPoint::Yes;
298 macros.retain(|(module_id, call_id, path, tt)| { 300 macros.retain(|(module_id, call_id, path, tt)| {
299 if path.segments.len() != 2 { 301 if path.segments.len() != 2 {
300 return true; 302 return true;
@@ -308,19 +310,16 @@ where
308 Some(it) => it, 310 Some(it) => it,
309 _ => return true, 311 _ => return true,
310 }; 312 };
313 res = ReachedFixedPoint::No;
311 let def_map = self.db.crate_def_map(krate); 314 let def_map = self.db.crate_def_map(krate);
312 let rules = def_map.public_macros.get(&path.segments[1].name).cloned(); 315 if let Some(macro_id) = def_map.public_macros.get(&path.segments[1].name).cloned() {
313 resolved.push((*module_id, *call_id, rules, tt.clone())); 316 resolved.push((*module_id, *call_id, (krate, macro_id), tt.clone()));
317 }
314 false 318 false
315 }); 319 });
316 let res = if resolved.is_empty() { ReachedFixedPoint::Yes } else { ReachedFixedPoint::No };
317 320
318 for (module_id, macro_call_id, rules, arg) in resolved { 321 for (module_id, macro_call_id, macro_def_id, arg) in resolved {
319 if let Some(rules) = rules { 322 self.collect_macro_expansion(module_id, macro_call_id, macro_def_id, arg);
320 if let Ok(tt) = rules.expand(&arg) {
321 self.collect_macro_expansion(module_id, macro_call_id, tt);
322 }
323 }
324 } 323 }
325 res 324 res
326 } 325 }
@@ -329,20 +328,32 @@ where
329 &mut self, 328 &mut self,
330 module_id: CrateModuleId, 329 module_id: CrateModuleId,
331 macro_call_id: MacroCallId, 330 macro_call_id: MacroCallId,
332 expansion: tt::Subtree, 331 macro_def_id: (Crate, CrateMacroId),
332 macro_arg: tt::Subtree,
333 ) { 333 ) {
334 // XXX: this **does not** go through a database, because we can't 334 let (macro_krate, macro_id) = macro_def_id;
335 // identify macro_call without adding the whole state of name resolution 335 let dm;
336 // as a parameter to the query. 336 let rules = if macro_krate == self.def_map.krate {
337 // 337 &self.def_map[macro_id]
338 // So, we run the queries "manually" and we must ensure that 338 } else {
339 // `db.hir_parse(macro_call_id)` returns the same source_file. 339 dm = self.db.crate_def_map(macro_krate);
340 let file_id: HirFileId = macro_call_id.into(); 340 &dm[macro_id]
341 let source_file = mbe::token_tree_to_ast_item_list(&expansion); 341 };
342 342 if let Ok(expansion) = rules.expand(&macro_arg) {
343 let raw_items = raw::RawItems::from_source_file(&source_file, file_id); 343 self.def_map.macro_resolutions.insert(macro_call_id, macro_def_id);
344 ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items } 344 // XXX: this **does not** go through a database, because we can't
345 .collect(raw_items.items()) 345 // identify macro_call without adding the whole state of name resolution
346 // as a parameter to the query.
347 //
348 // So, we run the queries "manually" and we must ensure that
349 // `db.hir_parse(macro_call_id)` returns the same source_file.
350 let file_id: HirFileId = macro_call_id.into();
351 let source_file = mbe::token_tree_to_ast_item_list(&expansion);
352
353 let raw_items = raw::RawItems::from_source_file(&source_file, file_id);
354 ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items }
355 .collect(raw_items.items())
356 }
346 } 357 }
347 358
348 fn finish(self) -> CrateDefMap { 359 fn finish(self) -> CrateDefMap {
@@ -486,12 +497,15 @@ where
486 497
487 // Case 2: try to expand macro_rules from this crate, triggering 498 // Case 2: try to expand macro_rules from this crate, triggering
488 // recursive item collection. 499 // recursive item collection.
489 if let Some(rules) = 500 if let Some(&macro_id) =
490 mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(name)) 501 mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(name))
491 { 502 {
492 if let Ok(tt) = rules.expand(&mac.arg) { 503 self.def_collector.collect_macro_expansion(
493 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, tt); 504 self.module_id,
494 } 505 macro_call_id,
506 (self.def_collector.def_map.krate, macro_id),
507 mac.arg.clone(),
508 );
495 return; 509 return;
496 } 510 }
497 511
diff --git a/crates/ra_ide_api/src/extend_selection.rs b/crates/ra_ide_api/src/extend_selection.rs
index 4051728e1..d23290b74 100644
--- a/crates/ra_ide_api/src/extend_selection.rs
+++ b/crates/ra_ide_api/src/extend_selection.rs
@@ -1,55 +1,13 @@
1use ra_db::SourceDatabase; 1use ra_db::SourceDatabase;
2use ra_syntax::{ 2use ra_syntax::AstNode;
3 SyntaxNode, AstNode, SourceFile,
4 ast, algo::find_covering_node,
5};
6 3
7use crate::{ 4use crate::{
8 TextRange, FileRange, 5 TextRange, FileRange,
9 db::RootDatabase, 6 db::RootDatabase,
10}; 7};
11 8
9// FIXME: restore macro support
12pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange { 10pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange {
13 let source_file = db.parse(frange.file_id); 11 let source_file = db.parse(frange.file_id);
14 if let Some(range) = extend_selection_in_macro(db, &source_file, frange) {
15 return range;
16 }
17 ra_ide_api_light::extend_selection(source_file.syntax(), frange.range).unwrap_or(frange.range) 12 ra_ide_api_light::extend_selection(source_file.syntax(), frange.range).unwrap_or(frange.range)
18} 13}
19
20fn extend_selection_in_macro(
21 _db: &RootDatabase,
22 source_file: &SourceFile,
23 frange: FileRange,
24) -> Option<TextRange> {
25 let macro_call = find_macro_call(source_file.syntax(), frange.range)?;
26 let (off, exp) = hir::MacroDef::ast_expand(macro_call)?;
27 let dst_range = exp.map_range_forward(frange.range - off)?;
28 let dst_range = ra_ide_api_light::extend_selection(&exp.syntax(), dst_range)?;
29 let src_range = exp.map_range_back(dst_range)? + off;
30 Some(src_range)
31}
32
33fn find_macro_call(node: &SyntaxNode, range: TextRange) -> Option<&ast::MacroCall> {
34 find_covering_node(node, range).ancestors().find_map(ast::MacroCall::cast)
35}
36
37#[cfg(test)]
38mod tests {
39 use ra_syntax::TextRange;
40
41 use crate::mock_analysis::single_file_with_range;
42
43 #[test]
44 fn extend_selection_inside_macros() {
45 let (analysis, frange) = single_file_with_range(
46 "
47 fn main() {
48 vec![foo(|x| <|>x<|>)];
49 }
50 ",
51 );
52 let r = analysis.extend_selection(frange).unwrap();
53 assert_eq!(r, TextRange::from_to(50.into(), 55.into()));
54 }
55}
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs
index 345b6653d..fdd87bcff 100644
--- a/crates/ra_ide_api/src/syntax_highlighting.rs
+++ b/crates/ra_ide_api/src/syntax_highlighting.rs
@@ -1,4 +1,4 @@
1use ra_syntax::{ast, AstNode,}; 1use ra_syntax::AstNode;
2use ra_db::SourceDatabase; 2use ra_db::SourceDatabase;
3 3
4use crate::{ 4use crate::{
@@ -8,37 +8,5 @@ use crate::{
8 8
9pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> { 9pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> {
10 let source_file = db.parse(file_id); 10 let source_file = db.parse(file_id);
11 let mut res = ra_ide_api_light::highlight(source_file.syntax()); 11 ra_ide_api_light::highlight(source_file.syntax())
12 for macro_call in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) {
13 if let Some((off, exp)) = hir::MacroDef::ast_expand(macro_call) {
14 let mapped_ranges =
15 ra_ide_api_light::highlight(&exp.syntax()).into_iter().filter_map(|r| {
16 let mapped_range = exp.map_range_back(r.range)?;
17 let res = HighlightedRange { range: mapped_range + off, tag: r.tag };
18 Some(res)
19 });
20 res.extend(mapped_ranges);
21 }
22 }
23 res
24}
25
26#[cfg(test)]
27mod tests {
28 use crate::mock_analysis::single_file;
29
30 use insta::assert_debug_snapshot_matches;
31
32 #[test]
33 fn highlights_code_inside_macros() {
34 let (analysis, file_id) = single_file(
35 "
36 fn main() {
37 vec![{ let x = 92; x}];
38 }
39 ",
40 );
41 let highlights = analysis.highlight(file_id).unwrap();
42 assert_debug_snapshot_matches!("highlights_code_inside_macros", &highlights);
43 }
44} 12}