diff options
Diffstat (limited to 'crates/ra_hir/src/source_binder.rs')
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 100 |
1 files changed, 98 insertions, 2 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 182ed4c91..79e304383 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -5,15 +5,17 @@ | |||
5 | /// | 5 | /// |
6 | /// So, this modules should not be used during hir construction, it exists | 6 | /// So, this modules should not be used during hir construction, it exists |
7 | /// purely for "IDE needs". | 7 | /// purely for "IDE needs". |
8 | use std::sync::Arc; | ||
9 | |||
8 | use ra_db::{FileId, FilePosition}; | 10 | use ra_db::{FileId, FilePosition}; |
9 | use ra_syntax::{ | 11 | use ra_syntax::{ |
10 | SyntaxNode, | 12 | SyntaxNode, AstPtr, |
11 | ast::{self, AstNode, NameOwner}, | 13 | ast::{self, AstNode, NameOwner}, |
12 | algo::{find_node_at_offset, find_token_at_offset}, | 14 | algo::{find_node_at_offset, find_token_at_offset}, |
13 | }; | 15 | }; |
14 | 16 | ||
15 | use crate::{ | 17 | use crate::{ |
16 | HirDatabase, Function, Struct, Enum,Const,Static, | 18 | HirDatabase, Function, Struct, Enum, Const, Static, Either, |
17 | AsName, Module, HirFileId, Crate, Trait, Resolver, | 19 | AsName, Module, HirFileId, Crate, Trait, Resolver, |
18 | ids::LocationCtx, | 20 | ids::LocationCtx, |
19 | expr, AstId | 21 | expr, AstId |
@@ -258,3 +260,97 @@ fn try_get_resolver_for_node( | |||
258 | None | 260 | None |
259 | } | 261 | } |
260 | } | 262 | } |
263 | |||
264 | // Name is bad, don't use inside HIR | ||
265 | #[derive(Debug)] | ||
266 | pub struct SourceAnalyser { | ||
267 | resolver: Resolver, | ||
268 | body_source_map: Option<Arc<crate::expr::BodySourceMap>>, | ||
269 | infer: Option<Arc<crate::ty::InferenceResult>>, | ||
270 | } | ||
271 | |||
272 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
273 | pub enum PathResolution { | ||
274 | /// An item | ||
275 | Def(crate::ModuleDef), | ||
276 | /// A local binding (only value namespace) | ||
277 | LocalBinding(crate::expr::PatId), | ||
278 | /// A generic parameter | ||
279 | GenericParam(u32), | ||
280 | SelfType(crate::ImplBlock), | ||
281 | AssocItem(crate::ImplItem), | ||
282 | } | ||
283 | |||
284 | impl SourceAnalyser { | ||
285 | pub fn new(db: &impl HirDatabase, file_id: FileId, node: &SyntaxNode) -> SourceAnalyser { | ||
286 | let resolver = resolver_for_node(db, file_id, node); | ||
287 | let function = function_from_child_node(db, file_id, node); | ||
288 | if let Some(function) = function { | ||
289 | SourceAnalyser { | ||
290 | resolver, | ||
291 | body_source_map: Some(function.body_source_map(db)), | ||
292 | infer: Some(function.infer(db)), | ||
293 | } | ||
294 | } else { | ||
295 | SourceAnalyser { resolver, body_source_map: None, infer: None } | ||
296 | } | ||
297 | } | ||
298 | |||
299 | pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option<crate::Ty> { | ||
300 | let expr_id = self.body_source_map.as_ref()?.node_expr(expr)?; | ||
301 | Some(self.infer.as_ref()?[expr_id].clone()) | ||
302 | } | ||
303 | |||
304 | pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option<crate::Ty> { | ||
305 | let pat_id = self.body_source_map.as_ref()?.node_pat(pat)?; | ||
306 | Some(self.infer.as_ref()?[pat_id].clone()) | ||
307 | } | ||
308 | |||
309 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | ||
310 | let expr_id = self.body_source_map.as_ref()?.node_expr(call.into())?; | ||
311 | self.infer.as_ref()?.method_resolution(expr_id) | ||
312 | } | ||
313 | |||
314 | pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> { | ||
315 | let expr_id = self.body_source_map.as_ref()?.node_expr(field.into())?; | ||
316 | self.infer.as_ref()?.field_resolution(expr_id) | ||
317 | } | ||
318 | |||
319 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> { | ||
320 | if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { | ||
321 | let expr_id = self.body_source_map.as_ref()?.node_expr(path_expr.into())?; | ||
322 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { | ||
323 | return Some(PathResolution::AssocItem(assoc)); | ||
324 | } | ||
325 | } | ||
326 | if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) { | ||
327 | let pat_id = self.body_source_map.as_ref()?.node_pat(path_pat.into())?; | ||
328 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) { | ||
329 | return Some(PathResolution::AssocItem(assoc)); | ||
330 | } | ||
331 | } | ||
332 | let hir_path = crate::Path::from_ast(path)?; | ||
333 | let res = self.resolver.resolve_path(db, &hir_path); | ||
334 | let res = res.clone().take_types().or_else(|| res.take_values())?; | ||
335 | Some(res.into()) | ||
336 | } | ||
337 | |||
338 | pub fn pat_syntax( | ||
339 | &self, | ||
340 | _db: &impl HirDatabase, | ||
341 | pat: crate::expr::PatId, | ||
342 | ) -> Option<Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>> { | ||
343 | self.body_source_map.as_ref()?.pat_syntax(pat) | ||
344 | } | ||
345 | } | ||
346 | |||
347 | impl From<crate::Resolution> for PathResolution { | ||
348 | fn from(res: crate::Resolution) -> PathResolution { | ||
349 | match res { | ||
350 | crate::Resolution::Def(it) => PathResolution::Def(it), | ||
351 | crate::Resolution::LocalBinding(it) => PathResolution::LocalBinding(it), | ||
352 | crate::Resolution::GenericParam(it) => PathResolution::GenericParam(it), | ||
353 | crate::Resolution::SelfType(it) => PathResolution::SelfType(it), | ||
354 | } | ||
355 | } | ||
356 | } | ||