diff options
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r-- | crates/ra_ide_api/src/name_kind.rs | 116 | ||||
-rw-r--r-- | crates/ra_ide_api/src/search_scope.rs | 186 |
2 files changed, 86 insertions, 216 deletions
diff --git a/crates/ra_ide_api/src/name_kind.rs b/crates/ra_ide_api/src/name_kind.rs index 64adb1784..0effeb8a1 100644 --- a/crates/ra_ide_api/src/name_kind.rs +++ b/crates/ra_ide_api/src/name_kind.rs | |||
@@ -102,36 +102,92 @@ pub(crate) fn classify_name( | |||
102 | let parent = name.syntax().parent()?; | 102 | let parent = name.syntax().parent()?; |
103 | let file_id = file_id.into(); | 103 | let file_id = file_id.into(); |
104 | 104 | ||
105 | if let Some(pat) = ast::BindPat::cast(parent.clone()) { | 105 | macro_rules! match_ast { |
106 | return Some(Pat(AstPtr::new(&pat))); | 106 | (match $node:ident { |
107 | $( ast::$ast:ident($it:ident) => $res:block, )* | ||
108 | _ => $catch_all:expr, | ||
109 | }) => {{ | ||
110 | $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* | ||
111 | { $catch_all } | ||
112 | }}; | ||
107 | } | 113 | } |
108 | if let Some(var) = ast::EnumVariant::cast(parent.clone()) { | ||
109 | let src = hir::Source { file_id, ast: var }; | ||
110 | let var = hir::EnumVariant::from_source(db, src)?; | ||
111 | return Some(Def(var.into())); | ||
112 | } | ||
113 | if let Some(field) = ast::RecordFieldDef::cast(parent.clone()) { | ||
114 | let src = hir::Source { file_id, ast: hir::FieldSource::Named(field) }; | ||
115 | let field = hir::StructField::from_source(db, src)?; | ||
116 | return Some(FieldAccess(field)); | ||
117 | } | ||
118 | if let Some(field) = ast::TupleFieldDef::cast(parent.clone()) { | ||
119 | let src = hir::Source { file_id, ast: hir::FieldSource::Pos(field) }; | ||
120 | let field = hir::StructField::from_source(db, src)?; | ||
121 | return Some(FieldAccess(field)); | ||
122 | } | ||
123 | if let Some(_) = parent.parent().and_then(ast::ItemList::cast) { | ||
124 | let ast = ast::ImplItem::cast(parent.clone())?; | ||
125 | let src = hir::Source { file_id, ast }; | ||
126 | let item = hir::AssocItem::from_source(db, src)?; | ||
127 | return Some(AssocItem(item)); | ||
128 | } | ||
129 | if let Some(item) = ast::ModuleItem::cast(parent.clone()) { | ||
130 | let src = hir::Source { file_id, ast: item }; | ||
131 | let def = hir::ModuleDef::from_source(db, src)?; | ||
132 | return Some(Def(def)); | ||
133 | } | ||
134 | // FIXME: TYPE_PARAM, ALIAS, MACRO_CALL; Union | ||
135 | 114 | ||
136 | None | 115 | // FIXME: add ast::MacroCall(it) |
116 | match_ast! { | ||
117 | match parent { | ||
118 | ast::BindPat(it) => { | ||
119 | let pat = AstPtr::new(&it); | ||
120 | Some(Pat(pat)) | ||
121 | }, | ||
122 | ast::RecordFieldDef(it) => { | ||
123 | let src = hir::Source { file_id, ast: hir::FieldSource::Named(it) }; | ||
124 | let field = hir::StructField::from_source(db, src)?; | ||
125 | Some(FieldAccess(field)) | ||
126 | }, | ||
127 | ast::FnDef(it) => { | ||
128 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | ||
129 | let src = hir::Source { file_id, ast: ast::ImplItem::from(it) }; | ||
130 | let item = hir::AssocItem::from_source(db, src)?; | ||
131 | Some(AssocItem(item)) | ||
132 | } else { | ||
133 | let src = hir::Source { file_id, ast: it }; | ||
134 | let def = hir::Function::from_source(db, src)?; | ||
135 | Some(Def(def.into())) | ||
136 | } | ||
137 | }, | ||
138 | ast::ConstDef(it) => { | ||
139 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | ||
140 | let src = hir::Source { file_id, ast: ast::ImplItem::from(it) }; | ||
141 | let item = hir::AssocItem::from_source(db, src)?; | ||
142 | Some(AssocItem(item)) | ||
143 | } else { | ||
144 | let src = hir::Source { file_id, ast: it }; | ||
145 | let def = hir::Const::from_source(db, src)?; | ||
146 | Some(Def(def.into())) | ||
147 | } | ||
148 | }, | ||
149 | ast::TypeAliasDef(it) => { | ||
150 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | ||
151 | let src = hir::Source { file_id, ast: ast::ImplItem::from(it) }; | ||
152 | let item = hir::AssocItem::from_source(db, src)?; | ||
153 | Some(AssocItem(item)) | ||
154 | } else { | ||
155 | let src = hir::Source { file_id, ast: it }; | ||
156 | let def = hir::TypeAlias::from_source(db, src)?; | ||
157 | Some(Def(def.into())) | ||
158 | } | ||
159 | }, | ||
160 | ast::Module(it) => { | ||
161 | let src = hir::Source { file_id, ast: hir::ModuleSource::Module(it) }; | ||
162 | let def = hir::Module::from_definition(db, src)?; | ||
163 | Some(Def(def.into())) | ||
164 | }, | ||
165 | ast::StructDef(it) => { | ||
166 | let src = hir::Source { file_id, ast: it }; | ||
167 | let def = hir::Struct::from_source(db, src)?; | ||
168 | Some(Def(def.into())) | ||
169 | }, | ||
170 | ast::EnumDef(it) => { | ||
171 | let src = hir::Source { file_id, ast: it }; | ||
172 | let def = hir::Enum::from_source(db, src)?; | ||
173 | Some(Def(def.into())) | ||
174 | }, | ||
175 | ast::TraitDef(it) => { | ||
176 | let src = hir::Source { file_id, ast: it }; | ||
177 | let def = hir::Trait::from_source(db, src)?; | ||
178 | Some(Def(def.into())) | ||
179 | }, | ||
180 | ast::StaticDef(it) => { | ||
181 | let src = hir::Source { file_id, ast: it }; | ||
182 | let def = hir::Static::from_source(db, src)?; | ||
183 | Some(Def(def.into())) | ||
184 | }, | ||
185 | ast::EnumVariant(it) => { | ||
186 | let src = hir::Source { file_id, ast: it }; | ||
187 | let def = hir::EnumVariant::from_source(db, src)?; | ||
188 | Some(Def(def.into())) | ||
189 | }, | ||
190 | _ => None, | ||
191 | } | ||
192 | } | ||
137 | } | 193 | } |
diff --git a/crates/ra_ide_api/src/search_scope.rs b/crates/ra_ide_api/src/search_scope.rs deleted file mode 100644 index ca1ac2b03..000000000 --- a/crates/ra_ide_api/src/search_scope.rs +++ /dev/null | |||
@@ -1,186 +0,0 @@ | |||
1 | pub enum SearchScope { | ||
2 | Function(hir::Function), | ||
3 | Module(hir::Module), | ||
4 | Crate(hir::Crate), | ||
5 | Crates(Vec<hir::Crate>), | ||
6 | } | ||
7 | |||
8 | pub struct SearchScope{ | ||
9 | pub scope: Vec<SyntaxNode> | ||
10 | } | ||
11 | |||
12 | pub fn find_all_refs(db: &RootDatabase, decl: NameKind) -> Vec<ReferenceDescriptor> { | ||
13 | let (module, visibility) = match decl { | ||
14 | FieldAccess(field) => { | ||
15 | let parent = field.parent_def(db); | ||
16 | let module = parent.module(db); | ||
17 | let visibility = match parent { | ||
18 | VariantDef::Struct(s) => s.source(db).ast.visibility(), | ||
19 | VariantDef::EnumVariant(v) => v.parent_enum(db).source(db).ast.visibility(), | ||
20 | }; | ||
21 | (module, visibility) | ||
22 | } | ||
23 | AssocItem(item) => { | ||
24 | let parent = item.parent_trait(db)?; | ||
25 | let module = parent.module(db); | ||
26 | let visibility = parent.source(db).ast.visibility(); | ||
27 | (module, visibility) | ||
28 | } | ||
29 | Def(def) => { | ||
30 | let (module, visibility) = match def { | ||
31 | ModuleDef::Module(m) => (m, ), | ||
32 | ModuleDef::Function(f) => (f.module(db), f.source(db).ast.visibility()), | ||
33 | ModuleDef::Adt::Struct(s) => (s.module(db), s.source(db).ast.visibility()), | ||
34 | ModuleDef::Adt::Union(u) => (u.module(db), u.source(db).ast.visibility()), | ||
35 | ModuleDef::Adt::Enum(e) => (e.module(db), e.source(db).ast.visibility()), | ||
36 | ModuleDef::EnumVariant(v) => (v.module(db), v.source(db).ast.visibility()), | ||
37 | ModuleDef::Const(c) => (c.module(db), c.source(db).ast.visibility()), | ||
38 | ModuleDef::Static(s) => (s.module(db), s.source(db).ast.visibility()), | ||
39 | ModuleDef::Trait(t) => (t.module(db), t.source(db).ast.visibility()), | ||
40 | ModuleDef::TypeAlias(a) => (a.module(db), a.source(db).ast.visibility()), | ||
41 | ModuleDef::BuiltinType(_) => return vec![]; | ||
42 | }; | ||
43 | (module, visibility) | ||
44 | } | ||
45 | // FIXME: add missing kinds | ||
46 | _ => return vec![]; | ||
47 | }; | ||
48 | let scope = scope(db, module, visibility); | ||
49 | } | ||
50 | |||
51 | fn scope(db: &RootDatabase, module: hir::Module, item_vis: Option<ast::Visibility>) -> SearchScope { | ||
52 | if let Some(v) = item_vis { | ||
53 | let krate = module.krate(db)?; | ||
54 | |||
55 | if v.syntax().text() == "pub" { | ||
56 | SearchScope::Crate(krate) | ||
57 | } | ||
58 | if v.syntax().text() == "pub(crate)" { | ||
59 | let crate_graph = db.crate_graph(); | ||
60 | let crates = crate_graph.iter().filter(|id| { | ||
61 | crate_graph.dependencies(id).any(|d| d.crate_id() == krate.crate_id()) | ||
62 | }).map(|id| Crate { id }).collect::<Vec<_>>(); | ||
63 | crates.insert(0, krate); | ||
64 | SearchScope::Crates(crates) | ||
65 | } | ||
66 | // FIXME: "pub(super)", "pub(in path)" | ||
67 | SearchScope::Module(module) | ||
68 | } | ||
69 | SearchScope::Module(module) | ||
70 | } | ||
71 | |||
72 | fn process_one(db, scope: SearchScope, pat) { | ||
73 | match scope { | ||
74 | SearchScope::Crate(krate) => { | ||
75 | let text = db.file_text(position.file_id).as_str(); | ||
76 | let parse = SourceFile::parse(text); | ||
77 | for (offset, name) in text.match_indices(pat) { | ||
78 | if let Some() = find_node_at_offset<ast::NameRef>(parse, offset) { | ||
79 | |||
80 | } | ||
81 | } | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | |||
86 | #[cfg(test)] | ||
87 | mod tests { | ||
88 | use crate::{ | ||
89 | mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, FileId, | ||
90 | ReferenceSearchResult, | ||
91 | }; | ||
92 | use insta::assert_debug_snapshot; | ||
93 | use test_utils::assert_eq_text; | ||
94 | |||
95 | #[test] | ||
96 | fn test_find_all_refs_for_local() { | ||
97 | let code = r#" | ||
98 | fn main() { | ||
99 | let mut i = 1; | ||
100 | let j = 1; | ||
101 | i = i<|> + j; | ||
102 | |||
103 | { | ||
104 | i = 0; | ||
105 | } | ||
106 | |||
107 | i = 5; | ||
108 | } | ||
109 | "#; | ||
110 | |||
111 | let refs = get_all_refs(code); | ||
112 | assert_eq!(refs.len(), 5); | ||
113 | } | ||
114 | |||
115 | #[test] | ||
116 | fn test_find_all_refs_for_param_inside() { | ||
117 | let code = r#" | ||
118 | fn foo(i : u32) -> u32 { | ||
119 | i<|> | ||
120 | }"#; | ||
121 | |||
122 | let refs = get_all_refs(code); | ||
123 | assert_eq!(refs.len(), 2); | ||
124 | } | ||
125 | |||
126 | #[test] | ||
127 | fn test_find_all_refs_for_fn_param() { | ||
128 | let code = r#" | ||
129 | fn foo(i<|> : u32) -> u32 { | ||
130 | i | ||
131 | }"#; | ||
132 | |||
133 | let refs = get_all_refs(code); | ||
134 | assert_eq!(refs.len(), 2); | ||
135 | } | ||
136 | |||
137 | #[test] | ||
138 | fn test_find_all_refs_field_name() { | ||
139 | let code = r#" | ||
140 | //- /lib.rs | ||
141 | struct Foo { | ||
142 | spam<|>: u32, | ||
143 | } | ||
144 | "#; | ||
145 | |||
146 | let refs = get_all_refs(code); | ||
147 | assert_eq!(refs.len(), 1); | ||
148 | } | ||
149 | |||
150 | #[test] | ||
151 | fn test_find_all_refs_methods() { | ||
152 | let code = r#" | ||
153 | //- /lib.rs | ||
154 | struct Foo; | ||
155 | impl Foo { | ||
156 | pub fn a() { | ||
157 | self.b() | ||
158 | } | ||
159 | fn b(&self) {} | ||
160 | } | ||
161 | "#; | ||
162 | |||
163 | let refs = get_all_refs(code); | ||
164 | assert_eq!(refs.len(), 1); | ||
165 | } | ||
166 | |||
167 | #[test] | ||
168 | fn test_find_all_refs_pub_enum() { | ||
169 | let code = r#" | ||
170 | //- /lib.rs | ||
171 | pub enum Foo { | ||
172 | A, | ||
173 | B<|>, | ||
174 | C, | ||
175 | } | ||
176 | "#; | ||
177 | |||
178 | let refs = get_all_refs(code); | ||
179 | assert_eq!(refs.len(), 1); | ||
180 | } | ||
181 | |||
182 | fn get_all_refs(text: &str) -> ReferenceSearchResult { | ||
183 | let (analysis, position) = single_file_with_position(text); | ||
184 | analysis.find_all_refs(position).unwrap().unwrap() | ||
185 | } | ||
186 | } \ No newline at end of file | ||