aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-01-03 18:31:41 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-01-03 18:31:41 +0000
commit2fcc6bdafa1caffd4ddf98968ee967e9fb091cc0 (patch)
tree5a278ad534d2de9f308bbdfef323c3b20bf9a653 /crates
parent6c0bca5984a6b66d306f9a413b0433c15d450500 (diff)
parentd61707b4e1f0bdfc7f62b1abf78fdc45c0128699 (diff)
Merge #421
421: Index macros r=matklad a=matklad So, this is pretty cool! We now index items which are the result of macro expansion! (of a single currently hard-coded macro). So, workspace symbols can now be used to navigate to `HirDatabase`, for example Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_analysis/Cargo.toml1
-rw-r--r--crates/ra_analysis/src/symbol_index.rs56
-rw-r--r--crates/ra_analysis/tests/test/main.rs19
-rw-r--r--crates/ra_hir/src/ids.rs7
-rw-r--r--crates/ra_hir/src/module/nameres.rs8
-rw-r--r--crates/ra_hir/src/source_binder.rs39
6 files changed, 102 insertions, 28 deletions
diff --git a/crates/ra_analysis/Cargo.toml b/crates/ra_analysis/Cargo.toml
index c0174cdc5..7a4fdaed9 100644
--- a/crates/ra_analysis/Cargo.toml
+++ b/crates/ra_analysis/Cargo.toml
@@ -13,6 +13,7 @@ fst = "0.3.1"
13salsa = "0.9.0" 13salsa = "0.9.0"
14rustc-hash = "1.0" 14rustc-hash = "1.0"
15parking_lot = "0.7.0" 15parking_lot = "0.7.0"
16unicase = "2.2.0"
16 17
17ra_syntax = { path = "../ra_syntax" } 18ra_syntax = { path = "../ra_syntax" }
18ra_editor = { path = "../ra_editor" } 19ra_editor = { path = "../ra_editor" }
diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs
index b355b14ed..e2b1c88fe 100644
--- a/crates/ra_analysis/src/symbol_index.rs
+++ b/crates/ra_analysis/src/symbol_index.rs
@@ -20,6 +20,7 @@
20//! file in the current workspace, and run a query aginst the union of all 20//! file in the current workspace, and run a query aginst the union of all
21//! thouse fsts. 21//! thouse fsts.
22use std::{ 22use std::{
23 cmp::Ordering,
23 hash::{Hash, Hasher}, 24 hash::{Hash, Hasher},
24 sync::Arc, 25 sync::Arc,
25}; 26};
@@ -27,11 +28,11 @@ use std::{
27use fst::{self, Streamer}; 28use fst::{self, Streamer};
28use ra_syntax::{ 29use ra_syntax::{
29 SyntaxNodeRef, SourceFileNode, SmolStr, 30 SyntaxNodeRef, SourceFileNode, SmolStr,
30 algo::visit::{visitor, Visitor}, 31 algo::{visit::{visitor, Visitor}, find_covering_node},
31 SyntaxKind::{self, *}, 32 SyntaxKind::{self, *},
32 ast::{self, NameOwner}, 33 ast::{self, NameOwner},
33}; 34};
34use ra_db::{SyntaxDatabase, SourceRootId, FilesDatabase, LocalSyntaxPtr}; 35use ra_db::{SourceRootId, FilesDatabase, LocalSyntaxPtr};
35use salsa::ParallelDatabase; 36use salsa::ParallelDatabase;
36use rayon::prelude::*; 37use rayon::prelude::*;
37 38
@@ -41,7 +42,7 @@ use crate::{
41}; 42};
42 43
43salsa::query_group! { 44salsa::query_group! {
44 pub(crate) trait SymbolsDatabase: SyntaxDatabase { 45 pub(crate) trait SymbolsDatabase: hir::db::HirDatabase {
45 fn file_symbols(file_id: FileId) -> Cancelable<Arc<SymbolIndex>> { 46 fn file_symbols(file_id: FileId) -> Cancelable<Arc<SymbolIndex>> {
46 type FileSymbolsQuery; 47 type FileSymbolsQuery;
47 } 48 }
@@ -52,10 +53,23 @@ salsa::query_group! {
52 } 53 }
53} 54}
54 55
55fn file_symbols(db: &impl SyntaxDatabase, file_id: FileId) -> Cancelable<Arc<SymbolIndex>> { 56fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Cancelable<Arc<SymbolIndex>> {
56 db.check_canceled()?; 57 db.check_canceled()?;
57 let syntax = db.source_file(file_id); 58 let source_file = db.source_file(file_id);
58 Ok(Arc::new(SymbolIndex::for_file(file_id, syntax))) 59 let mut symbols = source_file
60 .syntax()
61 .descendants()
62 .filter_map(to_symbol)
63 .map(move |(name, ptr)| FileSymbol { name, ptr, file_id })
64 .collect::<Vec<_>>();
65
66 for (name, text_range) in hir::source_binder::macro_symbols(db, file_id)? {
67 let node = find_covering_node(source_file.syntax(), text_range);
68 let ptr = LocalSyntaxPtr::new(node);
69 symbols.push(FileSymbol { file_id, name, ptr })
70 }
71
72 Ok(Arc::new(SymbolIndex::new(symbols)))
59} 73}
60 74
61pub(crate) fn world_symbols(db: &RootDatabase, query: Query) -> Cancelable<Vec<FileSymbol>> { 75pub(crate) fn world_symbols(db: &RootDatabase, query: Query) -> Cancelable<Vec<FileSymbol>> {
@@ -111,6 +125,17 @@ impl Hash for SymbolIndex {
111} 125}
112 126
113impl SymbolIndex { 127impl SymbolIndex {
128 fn new(mut symbols: Vec<FileSymbol>) -> SymbolIndex {
129 fn cmp(s1: &FileSymbol, s2: &FileSymbol) -> Ordering {
130 unicase::Ascii::new(s1.name.as_str()).cmp(&unicase::Ascii::new(s2.name.as_str()))
131 }
132 symbols.par_sort_by(cmp);
133 symbols.dedup_by(|s1, s2| cmp(s1, s2) == Ordering::Equal);
134 let names = symbols.iter().map(|it| it.name.as_str().to_lowercase());
135 let map = fst::Map::from_iter(names.into_iter().zip(0u64..)).unwrap();
136 SymbolIndex { symbols, map }
137 }
138
114 pub(crate) fn len(&self) -> usize { 139 pub(crate) fn len(&self) -> usize {
115 self.symbols.len() 140 self.symbols.len()
116 } 141 }
@@ -118,29 +143,16 @@ impl SymbolIndex {
118 pub(crate) fn for_files( 143 pub(crate) fn for_files(
119 files: impl ParallelIterator<Item = (FileId, SourceFileNode)>, 144 files: impl ParallelIterator<Item = (FileId, SourceFileNode)>,
120 ) -> SymbolIndex { 145 ) -> SymbolIndex {
121 let mut symbols = files 146 let symbols = files
122 .flat_map(|(file_id, file)| { 147 .flat_map(|(file_id, file)| {
123 file.syntax() 148 file.syntax()
124 .descendants() 149 .descendants()
125 .filter_map(to_symbol) 150 .filter_map(to_symbol)
126 .map(move |(name, ptr)| { 151 .map(move |(name, ptr)| FileSymbol { name, ptr, file_id })
127 (
128 name.as_str().to_lowercase(),
129 FileSymbol { name, ptr, file_id },
130 )
131 })
132 .collect::<Vec<_>>() 152 .collect::<Vec<_>>()
133 }) 153 })
134 .collect::<Vec<_>>(); 154 .collect::<Vec<_>>();
135 symbols.par_sort_by(|s1, s2| s1.0.cmp(&s2.0)); 155 SymbolIndex::new(symbols)
136 symbols.dedup_by(|s1, s2| s1.0 == s2.0);
137 let (names, symbols): (Vec<String>, Vec<FileSymbol>) = symbols.into_iter().unzip();
138 let map = fst::Map::from_iter(names.into_iter().zip(0u64..)).unwrap();
139 SymbolIndex { symbols, map }
140 }
141
142 pub(crate) fn for_file(file_id: FileId, file: SourceFileNode) -> SymbolIndex {
143 SymbolIndex::for_files(rayon::iter::once((file_id, file)))
144 } 156 }
145} 157}
146 158
diff --git a/crates/ra_analysis/tests/test/main.rs b/crates/ra_analysis/tests/test/main.rs
index 23a5799b9..bfdf8aef2 100644
--- a/crates/ra_analysis/tests/test/main.rs
+++ b/crates/ra_analysis/tests/test/main.rs
@@ -6,7 +6,7 @@ use test_utils::{assert_eq_dbg, assert_eq_text};
6 6
7use ra_analysis::{ 7use ra_analysis::{
8 mock_analysis::{analysis_and_position, single_file, single_file_with_position, MockAnalysis}, 8 mock_analysis::{analysis_and_position, single_file, single_file_with_position, MockAnalysis},
9 AnalysisChange, CrateGraph, FileId, FnSignatureInfo, 9 AnalysisChange, CrateGraph, FileId, FnSignatureInfo, Query
10}; 10};
11 11
12fn get_signature(text: &str) -> (FnSignatureInfo, Option<usize>) { 12fn get_signature(text: &str) -> (FnSignatureInfo, Option<usize>) {
@@ -531,6 +531,7 @@ fn test_rename_for_mut_param() {
531 }"#, 531 }"#,
532 ); 532 );
533} 533}
534
534fn test_rename(text: &str, new_name: &str, expected: &str) { 535fn test_rename(text: &str, new_name: &str, expected: &str) {
535 let (analysis, position) = single_file_with_position(text); 536 let (analysis, position) = single_file_with_position(text);
536 let edits = analysis.rename(position, new_name).unwrap(); 537 let edits = analysis.rename(position, new_name).unwrap();
@@ -547,3 +548,19 @@ fn test_rename(text: &str, new_name: &str, expected: &str) {
547 .apply(&*analysis.file_text(file_id.unwrap())); 548 .apply(&*analysis.file_text(file_id.unwrap()));
548 assert_eq_text!(expected, &*result); 549 assert_eq_text!(expected, &*result);
549} 550}
551
552#[test]
553fn world_symbols_include_stuff_from_macros() {
554 let (analysis, _) = single_file(
555 "
556salsa::query_group! {
557pub trait HirDatabase: SyntaxDatabase {}
558}
559 ",
560 );
561
562 let mut symbols = analysis.symbol_search(Query::new("Hir".into())).unwrap();
563 let s = symbols.pop().unwrap();
564 assert_eq!(s.name(), "HirDatabase");
565 assert_eq!(s.range(), TextRange::from_to(33.into(), 44.into()));
566}
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index a09dee8b1..4c7ebe3ea 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -48,6 +48,13 @@ impl HirFileId {
48 } 48 }
49 } 49 }
50 50
51 pub(crate) fn as_macro_call_id(self) -> Option<MacroCallId> {
52 match self.0 {
53 HirFileIdRepr::Macro(it) => Some(it),
54 _ => None,
55 }
56 }
57
51 pub(crate) fn hir_source_file(db: &impl HirDatabase, file_id: HirFileId) -> SourceFileNode { 58 pub(crate) fn hir_source_file(db: &impl HirDatabase, file_id: HirFileId) -> SourceFileNode {
52 match file_id.0 { 59 match file_id.0 {
53 HirFileIdRepr::File(file_id) => db.source_file(file_id), 60 HirFileIdRepr::File(file_id) => db.source_file(file_id),
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs
index 40aa33ffa..8d1209626 100644
--- a/crates/ra_hir/src/module/nameres.rs
+++ b/crates/ra_hir/src/module/nameres.rs
@@ -64,14 +64,14 @@ impl ModuleScope {
64/// running name resolution. 64/// running name resolution.
65#[derive(Debug, Default, PartialEq, Eq)] 65#[derive(Debug, Default, PartialEq, Eq)]
66pub struct InputModuleItems { 66pub struct InputModuleItems {
67 items: Vec<ModuleItem>, 67 pub(crate) items: Vec<ModuleItem>,
68 imports: Vec<Import>, 68 imports: Vec<Import>,
69} 69}
70 70
71#[derive(Debug, PartialEq, Eq)] 71#[derive(Debug, PartialEq, Eq)]
72struct ModuleItem { 72pub(crate) struct ModuleItem {
73 id: SourceItemId, 73 pub(crate) id: SourceItemId,
74 name: Name, 74 pub(crate) name: Name,
75 kind: SyntaxKind, 75 kind: SyntaxKind,
76 vis: Vis, 76 vis: Vis,
77} 77}
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 24490d119..85bd84469 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -8,8 +8,8 @@
8use ra_db::{FileId, FilePosition, Cancelable}; 8use ra_db::{FileId, FilePosition, Cancelable};
9use ra_editor::find_node_at_offset; 9use ra_editor::find_node_at_offset;
10use ra_syntax::{ 10use ra_syntax::{
11 SmolStr, TextRange, SyntaxNodeRef,
11 ast::{self, AstNode, NameOwner}, 12 ast::{self, AstNode, NameOwner},
12 SyntaxNodeRef,
13}; 13};
14 14
15use crate::{ 15use crate::{
@@ -126,3 +126,40 @@ pub fn function_from_child_node(
126 let fn_def = ctry!(node.ancestors().find_map(ast::FnDef::cast)); 126 let fn_def = ctry!(node.ancestors().find_map(ast::FnDef::cast));
127 function_from_source(db, file_id, fn_def) 127 function_from_source(db, file_id, fn_def)
128} 128}
129
130pub fn macro_symbols(
131 db: &impl HirDatabase,
132 file_id: FileId,
133) -> Cancelable<Vec<(SmolStr, TextRange)>> {
134 let module = match module_from_file_id(db, file_id)? {
135 Some(it) => it,
136 None => return Ok(Vec::new()),
137 };
138 let items = db.input_module_items(module.source_root_id, module.module_id)?;
139 let mut res = Vec::new();
140
141 for macro_call_id in items
142 .items
143 .iter()
144 .filter_map(|it| it.id.file_id.as_macro_call_id())
145 {
146 if let Some(exp) = db.expand_macro_invocation(macro_call_id) {
147 let loc = macro_call_id.loc(db);
148 let syntax = db.file_item(loc.source_item_id);
149 let syntax = syntax.borrowed();
150 let macro_call = ast::MacroCall::cast(syntax).unwrap();
151 let off = macro_call.token_tree().unwrap().syntax().range().start();
152 let file = exp.file();
153 for trait_def in file.syntax().descendants().filter_map(ast::TraitDef::cast) {
154 if let Some(name) = trait_def.name() {
155 let dst_range = name.syntax().range();
156 if let Some(src_range) = exp.map_range_back(dst_range) {
157 res.push((name.text(), src_range + off))
158 }
159 }
160 }
161 }
162 }
163
164 Ok(res)
165}