diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/db.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/ids.rs | 25 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/macros.rs | 135 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 29 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 76 | ||||
-rw-r--r-- | crates/ra_ide_api/src/extend_selection.rs | 46 | ||||
-rw-r--r-- | crates/ra_ide_api/src/syntax_highlighting.rs | 36 |
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}; | |||
4 | use ra_db::{SourceDatabase, salsa, FileId}; | 4 | use ra_db::{SourceDatabase, salsa, FileId}; |
5 | 5 | ||
6 | use crate::{ | 6 | use 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 | ||
100 | fn 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(¯o_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)] |
104 | enum HirFileIdRepr { | 118 | enum HirFileIdRepr { |
105 | File(FileId), | 119 | File(FileId), |
@@ -373,7 +387,6 @@ impl SourceFileItems { | |||
373 | impl std::ops::Index<SourceFileItemId> for SourceFileItems { | 387 | impl 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; | |||
24 | pub mod source_binder; | 24 | pub mod source_binder; |
25 | 25 | ||
26 | mod ids; | 26 | mod ids; |
27 | mod macros; | ||
28 | mod name; | 27 | mod name; |
29 | mod nameres; | 28 | mod nameres; |
30 | mod adt; | 29 | mod 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! | ||
10 | use std::sync::Arc; | ||
11 | |||
12 | use ra_syntax::{ | ||
13 | TextRange, TextUnit, SourceFile, AstNode, SyntaxNode, TreeArc, SyntaxNodePtr, | ||
14 | ast, | ||
15 | }; | ||
16 | |||
17 | use crate::{MacroCallId, PersistentHirDatabase}; | ||
18 | |||
19 | // Hard-coded defs for now :-( | ||
20 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
21 | pub enum MacroDef { | ||
22 | Vec, | ||
23 | } | ||
24 | |||
25 | impl 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)] | ||
71 | pub struct MacroInput { | ||
72 | // Should be token trees | ||
73 | pub text: String, | ||
74 | } | ||
75 | |||
76 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
77 | pub 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 | |||
89 | impl 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 | |||
125 | pub(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; | |||
57 | use crate::{ | 57 | use 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 | ||
63 | pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap}; | 63 | pub(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 | ||
92 | impl 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)] | ||
101 | pub(crate) struct CrateMacroId(RawId); | ||
102 | impl_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)] |
92 | struct CrateModuleId(RawId); | 106 | pub(crate) struct CrateModuleId(RawId); |
93 | impl_arena_id!(CrateModuleId); | 107 | impl_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(¯o_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 | ||
7 | use crate::{ | 7 | use 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 | ||
15 | use super::{CrateDefMap, CrateModuleId, ModuleData}; | 15 | use super::{CrateDefMap, CrateModuleId, ModuleData, CrateMacroId}; |
16 | 16 | ||
17 | pub(super) fn collect_defs( | 17 | pub(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 | ||
58 | impl<'a, DB> DefCollector<&'a DB> | 58 | impl<'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(¯o_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(¯o_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 @@ | |||
1 | use ra_db::SourceDatabase; | 1 | use ra_db::SourceDatabase; |
2 | use ra_syntax::{ | 2 | use ra_syntax::AstNode; |
3 | SyntaxNode, AstNode, SourceFile, | ||
4 | ast, algo::find_covering_node, | ||
5 | }; | ||
6 | 3 | ||
7 | use crate::{ | 4 | use crate::{ |
8 | TextRange, FileRange, | 5 | TextRange, FileRange, |
9 | db::RootDatabase, | 6 | db::RootDatabase, |
10 | }; | 7 | }; |
11 | 8 | ||
9 | // FIXME: restore macro support | ||
12 | pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange { | 10 | pub(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 | |||
20 | fn 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 | |||
33 | fn 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)] | ||
38 | mod 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 @@ | |||
1 | use ra_syntax::{ast, AstNode,}; | 1 | use ra_syntax::AstNode; |
2 | use ra_db::SourceDatabase; | 2 | use ra_db::SourceDatabase; |
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{ |
@@ -8,37 +8,5 @@ use crate::{ | |||
8 | 8 | ||
9 | pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> { | 9 | pub(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)] | ||
27 | mod 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 | } |