aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-01-02 13:05:54 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-01-02 13:05:54 +0000
commitafa972e78d2d81598c02b742ab84d70c88208300 (patch)
tree2ec32a586d0ee00e0d35a489efeaf31c91d14a15 /crates/ra_analysis/src
parente4ffd7b31780b1f2ac6dcb731566b583bf562647 (diff)
parent1076e82856f353763de8426d378fcd1e371cbed4 (diff)
Merge #403
403: initial support for macros r=matklad a=matklad I'll write a more comprehensive description when this is closer to being done. Basically this investigates one question: "how do we represent code which is a result of a macro call". This is an interesting question: currently everything is `FileId` based, but macro expansion does not have a file! Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_analysis/src')
-rw-r--r--crates/ra_analysis/src/completion/complete_scope.rs2
-rw-r--r--crates/ra_analysis/src/db.rs16
-rw-r--r--crates/ra_analysis/src/extend_selection.rs10
-rw-r--r--crates/ra_analysis/src/imp.rs4
-rw-r--r--crates/ra_analysis/src/lib.rs1
-rw-r--r--crates/ra_analysis/src/macros.rs75
-rw-r--r--crates/ra_analysis/src/syntax_highlighting.rs30
7 files changed, 46 insertions, 92 deletions
diff --git a/crates/ra_analysis/src/completion/complete_scope.rs b/crates/ra_analysis/src/completion/complete_scope.rs
index daf666505..4dead3689 100644
--- a/crates/ra_analysis/src/completion/complete_scope.rs
+++ b/crates/ra_analysis/src/completion/complete_scope.rs
@@ -27,7 +27,7 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) ->
27 match res.import { 27 match res.import {
28 None => true, 28 None => true,
29 Some(import) => { 29 Some(import) => {
30 let range = import.range(ctx.db, module.source().file_id()); 30 let range = import.range(ctx.db, module.file_id());
31 !range.is_subrange(&ctx.leaf.range()) 31 !range.is_subrange(&ctx.leaf.range())
32 } 32 }
33 } 33 }
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs
index b072a5eba..d7740f0c4 100644
--- a/crates/ra_analysis/src/db.rs
+++ b/crates/ra_analysis/src/db.rs
@@ -1,7 +1,6 @@
1use std::{fmt, sync::Arc}; 1use std::{fmt, sync::Arc};
2use salsa::{self, Database}; 2use salsa::{self, Database};
3use ra_db::{LocationIntener, BaseDatabase}; 3use ra_db::{LocationIntener, BaseDatabase};
4use hir::{self, DefId, DefLoc};
5 4
6use crate::{ 5use crate::{
7 symbol_index, 6 symbol_index,
@@ -15,7 +14,8 @@ pub(crate) struct RootDatabase {
15 14
16#[derive(Default)] 15#[derive(Default)]
17struct IdMaps { 16struct IdMaps {
18 defs: LocationIntener<DefLoc, DefId>, 17 defs: LocationIntener<hir::DefLoc, hir::DefId>,
18 macros: LocationIntener<hir::MacroCallLoc, hir::MacroCallId>,
19} 19}
20 20
21impl fmt::Debug for IdMaps { 21impl fmt::Debug for IdMaps {
@@ -59,12 +59,18 @@ impl salsa::ParallelDatabase for RootDatabase {
59 59
60impl BaseDatabase for RootDatabase {} 60impl BaseDatabase for RootDatabase {}
61 61
62impl AsRef<LocationIntener<DefLoc, DefId>> for RootDatabase { 62impl AsRef<LocationIntener<hir::DefLoc, hir::DefId>> for RootDatabase {
63 fn as_ref(&self) -> &LocationIntener<DefLoc, DefId> { 63 fn as_ref(&self) -> &LocationIntener<hir::DefLoc, hir::DefId> {
64 &self.id_maps.defs 64 &self.id_maps.defs
65 } 65 }
66} 66}
67 67
68impl AsRef<LocationIntener<hir::MacroCallLoc, hir::MacroCallId>> for RootDatabase {
69 fn as_ref(&self) -> &LocationIntener<hir::MacroCallLoc, hir::MacroCallId> {
70 &self.id_maps.macros
71 }
72}
73
68salsa::database_storage! { 74salsa::database_storage! {
69 pub(crate) struct RootDatabaseStorage for RootDatabase { 75 pub(crate) struct RootDatabaseStorage for RootDatabase {
70 impl ra_db::FilesDatabase { 76 impl ra_db::FilesDatabase {
@@ -85,6 +91,8 @@ salsa::database_storage! {
85 fn library_symbols() for symbol_index::LibrarySymbolsQuery; 91 fn library_symbols() for symbol_index::LibrarySymbolsQuery;
86 } 92 }
87 impl hir::db::HirDatabase { 93 impl hir::db::HirDatabase {
94 fn hir_source_file() for hir::db::HirSourceFileQuery;
95 fn expand_macro_invocation() for hir::db::ExpandMacroCallQuery;
88 fn module_tree() for hir::db::ModuleTreeQuery; 96 fn module_tree() for hir::db::ModuleTreeQuery;
89 fn fn_scopes() for hir::db::FnScopesQuery; 97 fn fn_scopes() for hir::db::FnScopesQuery;
90 fn file_items() for hir::db::SourceFileItemsQuery; 98 fn file_items() for hir::db::SourceFileItemsQuery;
diff --git a/crates/ra_analysis/src/extend_selection.rs b/crates/ra_analysis/src/extend_selection.rs
index 805e9059e..f1b77f981 100644
--- a/crates/ra_analysis/src/extend_selection.rs
+++ b/crates/ra_analysis/src/extend_selection.rs
@@ -18,15 +18,15 @@ pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRang
18} 18}
19 19
20fn extend_selection_in_macro( 20fn extend_selection_in_macro(
21 db: &RootDatabase, 21 _db: &RootDatabase,
22 source_file: &SourceFileNode, 22 source_file: &SourceFileNode,
23 frange: FileRange, 23 frange: FileRange,
24) -> Option<TextRange> { 24) -> Option<TextRange> {
25 let macro_call = find_macro_call(source_file.syntax(), frange.range)?; 25 let macro_call = find_macro_call(source_file.syntax(), frange.range)?;
26 let exp = crate::macros::expand(db, frange.file_id, macro_call)?; 26 let (off, exp) = hir::MacroDef::ast_expand(macro_call)?;
27 let dst_range = exp.map_range_forward(frange.range)?; 27 let dst_range = exp.map_range_forward(frange.range - off)?;
28 let dst_range = ra_editor::extend_selection(exp.source_file().syntax(), dst_range)?; 28 let dst_range = ra_editor::extend_selection(exp.syntax().borrowed(), dst_range)?;
29 let src_range = exp.map_range_back(dst_range)?; 29 let src_range = exp.map_range_back(dst_range)? + off;
30 Some(src_range) 30 Some(src_range)
31} 31}
32 32
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 5669aa94d..ec7da437a 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -230,7 +230,7 @@ impl AnalysisImpl {
230 Some(it) => it, 230 Some(it) => it,
231 }; 231 };
232 let root = descr.crate_root(); 232 let root = descr.crate_root();
233 let file_id = root.source().file_id(); 233 let file_id = root.file_id();
234 234
235 let crate_graph = self.db.crate_graph(); 235 let crate_graph = self.db.crate_graph();
236 let crate_id = crate_graph.crate_id_for_crate_root(file_id); 236 let crate_id = crate_graph.crate_id_for_crate_root(file_id);
@@ -283,7 +283,7 @@ impl AnalysisImpl {
283 if let Some(child_module) = 283 if let Some(child_module) =
284 source_binder::module_from_declaration(&*self.db, position.file_id, module)? 284 source_binder::module_from_declaration(&*self.db, position.file_id, module)?
285 { 285 {
286 let file_id = child_module.source().file_id(); 286 let file_id = child_module.file_id();
287 let name = match child_module.name() { 287 let name = match child_module.name() {
288 Some(name) => name.to_string().into(), 288 Some(name) => name.to_string().into(),
289 None => "".into(), 289 None => "".into(),
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index e6cfaecc3..08ecb125a 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -19,7 +19,6 @@ mod runnables;
19 19
20mod extend_selection; 20mod extend_selection;
21mod syntax_highlighting; 21mod syntax_highlighting;
22mod macros;
23 22
24use std::{fmt, sync::Arc}; 23use std::{fmt, sync::Arc};
25 24
diff --git a/crates/ra_analysis/src/macros.rs b/crates/ra_analysis/src/macros.rs
deleted file mode 100644
index b9feb7fad..000000000
--- a/crates/ra_analysis/src/macros.rs
+++ /dev/null
@@ -1,75 +0,0 @@
1/// Begining of macro expansion.
2///
3/// This code should be moved out of ra_analysis into hir (?) ideally.
4use ra_syntax::{ast, AstNode, SourceFileNode, TextRange};
5
6use crate::{db::RootDatabase, FileId};
7
8pub(crate) fn expand(
9 _db: &RootDatabase,
10 _file_id: FileId,
11 macro_call: ast::MacroCall,
12) -> Option<MacroExpansion> {
13 let path = macro_call.path()?;
14 if path.qualifier().is_some() {
15 return None;
16 }
17 let name_ref = path.segment()?.name_ref()?;
18 if name_ref.text() != "ctry" {
19 return None;
20 }
21
22 let arg = macro_call.token_tree()?;
23 let text = format!(
24 r"
25 fn dummy() {{
26 match {} {{
27 None => return Ok(None),
28 Some(it) => it,
29 }}
30 }}",
31 arg.syntax().text()
32 );
33 let file = SourceFileNode::parse(&text);
34 let match_expr = file.syntax().descendants().find_map(ast::MatchExpr::cast)?;
35 let match_arg = match_expr.expr()?;
36 let ranges_map = vec![(arg.syntax().range(), match_arg.syntax().range())];
37 let res = MacroExpansion {
38 source_file: file,
39 ranges_map,
40 };
41 Some(res)
42}
43
44pub(crate) struct MacroExpansion {
45 pub(crate) source_file: SourceFileNode,
46 pub(crate) ranges_map: Vec<(TextRange, TextRange)>,
47}
48
49impl MacroExpansion {
50 pub(crate) fn source_file(&self) -> &SourceFileNode {
51 &self.source_file
52 }
53 pub(crate) fn map_range_back(&self, tgt_range: TextRange) -> Option<TextRange> {
54 for (s_range, t_range) in self.ranges_map.iter() {
55 if tgt_range.is_subrange(&t_range) {
56 let tgt_at_zero_range = tgt_range - tgt_range.start();
57 let tgt_range_offset = tgt_range.start() - t_range.start();
58 let src_range = tgt_at_zero_range + tgt_range_offset + s_range.start();
59 return Some(src_range);
60 }
61 }
62 None
63 }
64 pub(crate) fn map_range_forward(&self, src_range: TextRange) -> Option<TextRange> {
65 for (s_range, t_range) in self.ranges_map.iter() {
66 if src_range.is_subrange(&s_range) {
67 let src_at_zero_range = src_range - src_range.start();
68 let src_range_offset = src_range.start() - s_range.start();
69 let src_range = src_at_zero_range + src_range_offset + t_range.start();
70 return Some(src_range);
71 }
72 }
73 None
74 }
75}
diff --git a/crates/ra_analysis/src/syntax_highlighting.rs b/crates/ra_analysis/src/syntax_highlighting.rs
index 7e9139a74..ccea4aee3 100644
--- a/crates/ra_analysis/src/syntax_highlighting.rs
+++ b/crates/ra_analysis/src/syntax_highlighting.rs
@@ -15,13 +15,13 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Cancelable<Vec<Hi
15 .descendants() 15 .descendants()
16 .filter_map(ast::MacroCall::cast) 16 .filter_map(ast::MacroCall::cast)
17 { 17 {
18 if let Some(exp) = crate::macros::expand(db, file_id, macro_call) { 18 if let Some((off, exp)) = hir::MacroDef::ast_expand(macro_call) {
19 let mapped_ranges = ra_editor::highlight(exp.source_file().syntax()) 19 let mapped_ranges = ra_editor::highlight(exp.syntax().borrowed())
20 .into_iter() 20 .into_iter()
21 .filter_map(|r| { 21 .filter_map(|r| {
22 let mapped_range = exp.map_range_back(r.range)?; 22 let mapped_range = exp.map_range_back(r.range)?;
23 let res = HighlightedRange { 23 let res = HighlightedRange {
24 range: mapped_range, 24 range: mapped_range + off,
25 tag: r.tag, 25 tag: r.tag,
26 }; 26 };
27 Some(res) 27 Some(res)
@@ -44,7 +44,7 @@ mod tests {
44 fn main() { 44 fn main() {
45 ctry!({ let x = 92; x}); 45 ctry!({ let x = 92; x});
46 } 46 }
47 ", 47 ",
48 ); 48 );
49 let highlights = analysis.highlight(file_id).unwrap(); 49 let highlights = analysis.highlight(file_id).unwrap();
50 assert_eq_dbg( 50 assert_eq_dbg(
@@ -60,4 +60,26 @@ mod tests {
60 &highlights, 60 &highlights,
61 ) 61 )
62 } 62 }
63
64 // FIXME: this test is not really necessary: artifact of the inital hacky
65 // macros implementation.
66 #[test]
67 fn highlight_query_group_macro() {
68 let (analysis, file_id) = single_file(
69 "
70 salsa::query_group! {
71 pub trait HirDatabase: SyntaxDatabase {}
72 }
73 ",
74 );
75 let highlights = analysis.highlight(file_id).unwrap();
76 assert_eq_dbg(
77 r#"[HighlightedRange { range: [20; 32), tag: "macro" },
78 HighlightedRange { range: [13; 18), tag: "text" },
79 HighlightedRange { range: [51; 54), tag: "keyword" },
80 HighlightedRange { range: [55; 60), tag: "keyword" },
81 HighlightedRange { range: [61; 72), tag: "function" }]"#,
82 &highlights,
83 )
84 }
63} 85}