aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r--crates/ra_analysis/src/completion/complete_path.rs39
-rw-r--r--crates/ra_analysis/src/completion/completion_item.rs1
-rw-r--r--crates/ra_analysis/src/extend_selection.rs44
-rw-r--r--crates/ra_analysis/src/macros.rs11
-rw-r--r--crates/ra_analysis/src/mock_analysis.rs17
5 files changed, 99 insertions, 13 deletions
diff --git a/crates/ra_analysis/src/completion/complete_path.rs b/crates/ra_analysis/src/completion/complete_path.rs
index aaa2c7cee..c73a083a4 100644
--- a/crates/ra_analysis/src/completion/complete_path.rs
+++ b/crates/ra_analysis/src/completion/complete_path.rs
@@ -1,6 +1,6 @@
1use crate::{ 1use crate::{
2 Cancelable, 2 Cancelable,
3 completion::{CompletionItem, Completions, CompletionKind, CompletionContext}, 3 completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext},
4}; 4};
5 5
6pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> Cancelable<()> { 6pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> Cancelable<()> {
@@ -12,16 +12,25 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> C
12 Some(it) => it, 12 Some(it) => it,
13 None => return Ok(()), 13 None => return Ok(()),
14 }; 14 };
15 let target_module = match def_id.resolve(ctx.db)? { 15 match def_id.resolve(ctx.db)? {
16 hir::Def::Module(it) => it, 16 hir::Def::Module(module) => {
17 let module_scope = module.scope(ctx.db)?;
18 module_scope.entries().for_each(|(name, res)| {
19 CompletionItem::new(CompletionKind::Reference, name.to_string())
20 .from_resolution(ctx.db, res)
21 .add_to(acc)
22 });
23 }
24 hir::Def::Enum(e) => e
25 .variants(ctx.db)?
26 .into_iter()
27 .for_each(|(name, _variant)| {
28 CompletionItem::new(CompletionKind::Reference, name.to_string())
29 .kind(CompletionItemKind::EnumVariant)
30 .add_to(acc)
31 }),
17 _ => return Ok(()), 32 _ => return Ok(()),
18 }; 33 };
19 let module_scope = target_module.scope(ctx.db)?;
20 module_scope.entries().for_each(|(name, res)| {
21 CompletionItem::new(CompletionKind::Reference, name.to_string())
22 .from_resolution(ctx.db, res)
23 .add_to(acc)
24 });
25 Ok(()) 34 Ok(())
26} 35}
27 36
@@ -92,4 +101,16 @@ mod tests {
92 "Spam", 101 "Spam",
93 ); 102 );
94 } 103 }
104
105 #[test]
106 fn completes_enum_variant() {
107 check_reference_completion(
108 "
109 //- /lib.rs
110 enum E { Foo, Bar(i32) }
111 fn foo() { let _ = E::<|> }
112 ",
113 "Foo;Bar",
114 );
115 }
95} 116}
diff --git a/crates/ra_analysis/src/completion/completion_item.rs b/crates/ra_analysis/src/completion/completion_item.rs
index c9f9f495d..1d294c553 100644
--- a/crates/ra_analysis/src/completion/completion_item.rs
+++ b/crates/ra_analysis/src/completion/completion_item.rs
@@ -29,6 +29,7 @@ pub enum CompletionItemKind {
29 Function, 29 Function,
30 Struct, 30 Struct,
31 Enum, 31 Enum,
32 EnumVariant,
32 Binding, 33 Binding,
33 Field, 34 Field,
34} 35}
diff --git a/crates/ra_analysis/src/extend_selection.rs b/crates/ra_analysis/src/extend_selection.rs
index 5e1fbee18..cde6ee101 100644
--- a/crates/ra_analysis/src/extend_selection.rs
+++ b/crates/ra_analysis/src/extend_selection.rs
@@ -1,4 +1,8 @@
1use ra_db::SyntaxDatabase; 1use ra_db::SyntaxDatabase;
2use ra_syntax::{
3 SyntaxNodeRef, AstNode,
4 ast, algo::find_covering_node,
5};
2 6
3use crate::{ 7use crate::{
4 TextRange, FileRange, 8 TextRange, FileRange,
@@ -6,6 +10,42 @@ use crate::{
6}; 10};
7 11
8pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange { 12pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange {
9 let file = db.source_file(frange.file_id); 13 let source_file = db.source_file(frange.file_id);
10 ra_editor::extend_selection(&file, frange.range).unwrap_or(frange.range) 14 if let Some(macro_call) = find_macro_call(source_file.syntax(), frange.range) {
15 if let Some(exp) = crate::macros::expand(db, frange.file_id, macro_call) {
16 if let Some(dst_range) = exp.map_range_forward(frange.range) {
17 if let Some(dst_range) = ra_editor::extend_selection(exp.source_file(), dst_range) {
18 if let Some(src_range) = exp.map_range_back(dst_range) {
19 return src_range;
20 }
21 }
22 }
23 }
24 }
25 ra_editor::extend_selection(&source_file, frange.range).unwrap_or(frange.range)
26}
27
28fn find_macro_call(node: SyntaxNodeRef, range: TextRange) -> Option<ast::MacroCall> {
29 find_covering_node(node, range)
30 .ancestors()
31 .find_map(ast::MacroCall::cast)
32}
33
34#[cfg(test)]
35mod tests {
36 use crate::mock_analysis::single_file_with_range;
37 use test_utils::assert_eq_dbg;
38
39 #[test]
40 fn extend_selection_inside_macros() {
41 let (analysis, frange) = single_file_with_range(
42 "
43 fn main() {
44 ctry!(foo(|x| <|>x<|>));
45 }
46 ",
47 );
48 let r = analysis.extend_selection(frange);
49 assert_eq_dbg("[51; 56)", &r);
50 }
11} 51}
diff --git a/crates/ra_analysis/src/macros.rs b/crates/ra_analysis/src/macros.rs
index c0dd49dc8..b9feb7fad 100644
--- a/crates/ra_analysis/src/macros.rs
+++ b/crates/ra_analysis/src/macros.rs
@@ -61,4 +61,15 @@ impl MacroExpansion {
61 } 61 }
62 None 62 None
63 } 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 }
64} 75}
diff --git a/crates/ra_analysis/src/mock_analysis.rs b/crates/ra_analysis/src/mock_analysis.rs
index 5ce2aa2b4..960529404 100644
--- a/crates/ra_analysis/src/mock_analysis.rs
+++ b/crates/ra_analysis/src/mock_analysis.rs
@@ -1,10 +1,10 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use relative_path::RelativePathBuf; 3use relative_path::RelativePathBuf;
4use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; 4use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER};
5use ra_db::mock::FileMap; 5use ra_db::mock::FileMap;
6 6
7use crate::{Analysis, AnalysisChange, AnalysisHost, FileId, FilePosition, SourceRootId}; 7use crate::{Analysis, AnalysisChange, AnalysisHost, FileId, FilePosition, FileRange, SourceRootId};
8 8
9/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis 9/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
10/// from a set of in-memory files. 10/// from a set of in-memory files.
@@ -66,6 +66,12 @@ impl MockAnalysis {
66 self.files.push((path.to_string(), text.to_string())); 66 self.files.push((path.to_string(), text.to_string()));
67 FilePosition { file_id, offset } 67 FilePosition { file_id, offset }
68 } 68 }
69 pub fn add_file_with_range(&mut self, path: &str, text: &str) -> FileRange {
70 let (range, text) = extract_range(text);
71 let file_id = FileId((self.files.len() + 1) as u32);
72 self.files.push((path.to_string(), text.to_string()));
73 FileRange { file_id, range }
74 }
69 pub fn id_of(&self, path: &str) -> FileId { 75 pub fn id_of(&self, path: &str) -> FileId {
70 let (idx, _) = self 76 let (idx, _) = self
71 .files 77 .files
@@ -115,3 +121,10 @@ pub fn single_file_with_position(code: &str) -> (Analysis, FilePosition) {
115 let pos = mock.add_file_with_position("/main.rs", code); 121 let pos = mock.add_file_with_position("/main.rs", code);
116 (mock.analysis(), pos) 122 (mock.analysis(), pos)
117} 123}
124
125/// Creates analysis for a single file, returns range marked with a pair of <|>.
126pub fn single_file_with_range(code: &str) -> (Analysis, FileRange) {
127 let mut mock = MockAnalysis::new();
128 let pos = mock.add_file_with_range("/main.rs", code);
129 (mock.analysis(), pos)
130}