aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_db/src/defs.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-10-15 16:27:50 +0100
committerAleksey Kladov <[email protected]>2020-10-15 16:38:17 +0100
commit56e67e3a392d7c7c7f30ca39d8e83446ea8bbec3 (patch)
tree4fe5fa460ddaf0bc19347d42bb91215614b5e840 /crates/ide_db/src/defs.rs
parentf9c1336873d65805ad34129939d800dbf59daf61 (diff)
More idiomatic classification API
Diffstat (limited to 'crates/ide_db/src/defs.rs')
-rw-r--r--crates/ide_db/src/defs.rs338
1 files changed, 169 insertions, 169 deletions
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index 717581593..3cef0baf7 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -110,121 +110,121 @@ impl NameClass {
110 NameClass::PatFieldShorthand { local_def: _, field_ref } => field_ref, 110 NameClass::PatFieldShorthand { local_def: _, field_ref } => field_ref,
111 } 111 }
112 } 112 }
113}
114 113
115pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> { 114 pub fn classify(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> {
116 let _p = profile::span("classify_name"); 115 let _p = profile::span("classify_name");
117 116
118 let parent = name.syntax().parent()?; 117 let parent = name.syntax().parent()?;
119 118
120 if let Some(bind_pat) = ast::IdentPat::cast(parent.clone()) { 119 if let Some(bind_pat) = ast::IdentPat::cast(parent.clone()) {
121 if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) { 120 if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) {
122 return Some(NameClass::ConstReference(Definition::ModuleDef(def))); 121 return Some(NameClass::ConstReference(Definition::ModuleDef(def)));
122 }
123 } 123 }
124 }
125 124
126 match_ast! { 125 match_ast! {
127 match parent { 126 match parent {
128 ast::Rename(it) => { 127 ast::Rename(it) => {
129 if let Some(use_tree) = it.syntax().parent().and_then(ast::UseTree::cast) { 128 if let Some(use_tree) = it.syntax().parent().and_then(ast::UseTree::cast) {
130 let path = use_tree.path()?; 129 let path = use_tree.path()?;
131 let path_segment = path.segment()?; 130 let path_segment = path.segment()?;
132 let name_ref_class = path_segment 131 let name_ref_class = path_segment
133 .name_ref() 132 .name_ref()
134 // The rename might be from a `self` token, so fallback to the name higher 133 // The rename might be from a `self` token, so fallback to the name higher
135 // in the use tree. 134 // in the use tree.
136 .or_else(||{ 135 .or_else(||{
137 if path_segment.self_token().is_none() { 136 if path_segment.self_token().is_none() {
138 return None; 137 return None;
139 } 138 }
140 139
141 let use_tree = use_tree 140 let use_tree = use_tree
142 .syntax() 141 .syntax()
143 .parent() 142 .parent()
144 .as_ref() 143 .as_ref()
145 // Skip over UseTreeList 144 // Skip over UseTreeList
146 .and_then(SyntaxNode::parent) 145 .and_then(SyntaxNode::parent)
147 .and_then(ast::UseTree::cast)?; 146 .and_then(ast::UseTree::cast)?;
148 let path = use_tree.path()?; 147 let path = use_tree.path()?;
149 let path_segment = path.segment()?; 148 let path_segment = path.segment()?;
150 path_segment.name_ref() 149 path_segment.name_ref()
151 }) 150 })
152 .and_then(|name_ref| classify_name_ref(sema, &name_ref))?; 151 .and_then(|name_ref| NameRefClass::classify(sema, &name_ref))?;
153 152
154 Some(NameClass::Definition(name_ref_class.definition(sema.db))) 153 Some(NameClass::Definition(name_ref_class.definition(sema.db)))
155 } else { 154 } else {
156 let extern_crate = it.syntax().parent().and_then(ast::ExternCrate::cast)?; 155 let extern_crate = it.syntax().parent().and_then(ast::ExternCrate::cast)?;
157 let resolved = sema.resolve_extern_crate(&extern_crate)?; 156 let resolved = sema.resolve_extern_crate(&extern_crate)?;
158 Some(NameClass::ExternCrate(resolved)) 157 Some(NameClass::ExternCrate(resolved))
159 } 158 }
160 }, 159 },
161 ast::IdentPat(it) => { 160 ast::IdentPat(it) => {
162 let local = sema.to_def(&it)?; 161 let local = sema.to_def(&it)?;
163 162
164 if let Some(record_pat_field) = it.syntax().parent().and_then(ast::RecordPatField::cast) { 163 if let Some(record_pat_field) = it.syntax().parent().and_then(ast::RecordPatField::cast) {
165 if record_pat_field.name_ref().is_none() { 164 if record_pat_field.name_ref().is_none() {
166 if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) { 165 if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) {
167 let field = Definition::Field(field); 166 let field = Definition::Field(field);
168 return Some(NameClass::PatFieldShorthand { local_def: local, field_ref: field }); 167 return Some(NameClass::PatFieldShorthand { local_def: local, field_ref: field });
168 }
169 } 169 }
170 } 170 }
171 }
172 171
173 Some(NameClass::Definition(Definition::Local(local))) 172 Some(NameClass::Definition(Definition::Local(local)))
174 }, 173 },
175 ast::RecordField(it) => { 174 ast::RecordField(it) => {
176 let field: hir::Field = sema.to_def(&it)?; 175 let field: hir::Field = sema.to_def(&it)?;
177 Some(NameClass::Definition(Definition::Field(field))) 176 Some(NameClass::Definition(Definition::Field(field)))
178 }, 177 },
179 ast::Module(it) => { 178 ast::Module(it) => {
180 let def = sema.to_def(&it)?; 179 let def = sema.to_def(&it)?;
181 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 180 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
182 }, 181 },
183 ast::Struct(it) => { 182 ast::Struct(it) => {
184 let def: hir::Struct = sema.to_def(&it)?; 183 let def: hir::Struct = sema.to_def(&it)?;
185 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 184 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
186 }, 185 },
187 ast::Union(it) => { 186 ast::Union(it) => {
188 let def: hir::Union = sema.to_def(&it)?; 187 let def: hir::Union = sema.to_def(&it)?;
189 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 188 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
190 }, 189 },
191 ast::Enum(it) => { 190 ast::Enum(it) => {
192 let def: hir::Enum = sema.to_def(&it)?; 191 let def: hir::Enum = sema.to_def(&it)?;
193 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 192 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
194 }, 193 },
195 ast::Trait(it) => { 194 ast::Trait(it) => {
196 let def: hir::Trait = sema.to_def(&it)?; 195 let def: hir::Trait = sema.to_def(&it)?;
197 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 196 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
198 }, 197 },
199 ast::Static(it) => { 198 ast::Static(it) => {
200 let def: hir::Static = sema.to_def(&it)?; 199 let def: hir::Static = sema.to_def(&it)?;
201 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 200 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
202 }, 201 },
203 ast::Variant(it) => { 202 ast::Variant(it) => {
204 let def: hir::EnumVariant = sema.to_def(&it)?; 203 let def: hir::EnumVariant = sema.to_def(&it)?;
205 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 204 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
206 }, 205 },
207 ast::Fn(it) => { 206 ast::Fn(it) => {
208 let def: hir::Function = sema.to_def(&it)?; 207 let def: hir::Function = sema.to_def(&it)?;
209 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 208 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
210 }, 209 },
211 ast::Const(it) => { 210 ast::Const(it) => {
212 let def: hir::Const = sema.to_def(&it)?; 211 let def: hir::Const = sema.to_def(&it)?;
213 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 212 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
214 }, 213 },
215 ast::TypeAlias(it) => { 214 ast::TypeAlias(it) => {
216 let def: hir::TypeAlias = sema.to_def(&it)?; 215 let def: hir::TypeAlias = sema.to_def(&it)?;
217 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 216 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
218 }, 217 },
219 ast::MacroCall(it) => { 218 ast::MacroCall(it) => {
220 let def = sema.to_def(&it)?; 219 let def = sema.to_def(&it)?;
221 Some(NameClass::Definition(Definition::Macro(def))) 220 Some(NameClass::Definition(Definition::Macro(def)))
222 }, 221 },
223 ast::TypeParam(it) => { 222 ast::TypeParam(it) => {
224 let def = sema.to_def(&it)?; 223 let def = sema.to_def(&it)?;
225 Some(NameClass::Definition(Definition::TypeParam(def))) 224 Some(NameClass::Definition(Definition::TypeParam(def)))
226 }, 225 },
227 _ => None, 226 _ => None,
227 }
228 } 228 }
229 } 229 }
230} 230}
@@ -244,91 +244,91 @@ impl NameRefClass {
244 NameRefClass::FieldShorthand { local, field: _ } => Definition::Local(local), 244 NameRefClass::FieldShorthand { local, field: _ } => Definition::Local(local),
245 } 245 }
246 } 246 }
247}
248 247
249// Note: we don't have unit-tests for this rather important function. 248 // Note: we don't have unit-tests for this rather important function.
250// It is primarily exercised via goto definition tests in `ide`. 249 // It is primarily exercised via goto definition tests in `ide`.
251pub fn classify_name_ref( 250 pub fn classify(
252 sema: &Semantics<RootDatabase>, 251 sema: &Semantics<RootDatabase>,
253 name_ref: &ast::NameRef, 252 name_ref: &ast::NameRef,
254) -> Option<NameRefClass> { 253 ) -> Option<NameRefClass> {
255 let _p = profile::span("classify_name_ref"); 254 let _p = profile::span("classify_name_ref");
256 255
257 let parent = name_ref.syntax().parent()?; 256 let parent = name_ref.syntax().parent()?;
258 257
259 if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { 258 if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
260 if let Some(func) = sema.resolve_method_call(&method_call) { 259 if let Some(func) = sema.resolve_method_call(&method_call) {
261 return Some(NameRefClass::Definition(Definition::ModuleDef(func.into()))); 260 return Some(NameRefClass::Definition(Definition::ModuleDef(func.into())));
261 }
262 } 262 }
263 }
264 263
265 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { 264 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
266 if let Some(field) = sema.resolve_field(&field_expr) { 265 if let Some(field) = sema.resolve_field(&field_expr) {
267 return Some(NameRefClass::Definition(Definition::Field(field))); 266 return Some(NameRefClass::Definition(Definition::Field(field)));
267 }
268 } 268 }
269 }
270 269
271 if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) { 270 if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) {
272 if let Some((field, local)) = sema.resolve_record_field(&record_field) { 271 if let Some((field, local)) = sema.resolve_record_field(&record_field) {
273 let field = Definition::Field(field); 272 let field = Definition::Field(field);
274 let res = match local { 273 let res = match local {
275 None => NameRefClass::Definition(field), 274 None => NameRefClass::Definition(field),
276 Some(local) => NameRefClass::FieldShorthand { field, local }, 275 Some(local) => NameRefClass::FieldShorthand { field, local },
277 }; 276 };
278 return Some(res); 277 return Some(res);
278 }
279 } 279 }
280 }
281 280
282 if let Some(record_pat_field) = ast::RecordPatField::cast(parent.clone()) { 281 if let Some(record_pat_field) = ast::RecordPatField::cast(parent.clone()) {
283 if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) { 282 if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) {
284 let field = Definition::Field(field); 283 let field = Definition::Field(field);
285 return Some(NameRefClass::Definition(field)); 284 return Some(NameRefClass::Definition(field));
285 }
286 } 286 }
287 }
288 287
289 if ast::AssocTypeArg::cast(parent.clone()).is_some() { 288 if ast::AssocTypeArg::cast(parent.clone()).is_some() {
290 // `Trait<Assoc = Ty>` 289 // `Trait<Assoc = Ty>`
291 // ^^^^^ 290 // ^^^^^
292 let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; 291 let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
293 let resolved = sema.resolve_path(&path)?; 292 let resolved = sema.resolve_path(&path)?;
294 if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved { 293 if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved {
295 if let Some(ty) = tr 294 if let Some(ty) = tr
296 .items(sema.db) 295 .items(sema.db)
297 .iter() 296 .iter()
298 .filter_map(|assoc| match assoc { 297 .filter_map(|assoc| match assoc {
299 hir::AssocItem::TypeAlias(it) => Some(*it), 298 hir::AssocItem::TypeAlias(it) => Some(*it),
300 _ => None, 299 _ => None,
301 }) 300 })
302 .find(|alias| alias.name(sema.db).to_string() == **name_ref.text()) 301 .find(|alias| alias.name(sema.db).to_string() == **name_ref.text())
303 { 302 {
304 return Some(NameRefClass::Definition(Definition::ModuleDef( 303 return Some(NameRefClass::Definition(Definition::ModuleDef(
305 ModuleDef::TypeAlias(ty), 304 ModuleDef::TypeAlias(ty),
306 ))); 305 )));
306 }
307 } 307 }
308 } 308 }
309 }
310 309
311 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { 310 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
312 if let Some(path) = macro_call.path() { 311 if let Some(path) = macro_call.path() {
313 if path.qualifier().is_none() { 312 if path.qualifier().is_none() {
314 // Only use this to resolve single-segment macro calls like `foo!()`. Multi-segment 313 // Only use this to resolve single-segment macro calls like `foo!()`. Multi-segment
315 // paths are handled below (allowing `log<|>::info!` to resolve to the log crate). 314 // paths are handled below (allowing `log<|>::info!` to resolve to the log crate).
316 if let Some(macro_def) = sema.resolve_macro_call(&macro_call) { 315 if let Some(macro_def) = sema.resolve_macro_call(&macro_call) {
317 return Some(NameRefClass::Definition(Definition::Macro(macro_def))); 316 return Some(NameRefClass::Definition(Definition::Macro(macro_def)));
317 }
318 } 318 }
319 } 319 }
320 } 320 }
321 }
322 321
323 if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) { 322 if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) {
324 if let Some(resolved) = sema.resolve_path(&path) { 323 if let Some(resolved) = sema.resolve_path(&path) {
325 return Some(NameRefClass::Definition(resolved.into())); 324 return Some(NameRefClass::Definition(resolved.into()));
325 }
326 } 326 }
327 }
328 327
329 let extern_crate = ast::ExternCrate::cast(parent)?; 328 let extern_crate = ast::ExternCrate::cast(parent)?;
330 let resolved = sema.resolve_extern_crate(&extern_crate)?; 329 let resolved = sema.resolve_extern_crate(&extern_crate)?;
331 Some(NameRefClass::ExternCrate(resolved)) 330 Some(NameRefClass::ExternCrate(resolved))
331 }
332} 332}
333 333
334impl From<PathResolution> for Definition { 334impl From<PathResolution> for Definition {