aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/source_binder.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/source_binder.rs')
-rw-r--r--crates/ra_hir/src/source_binder.rs100
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".
8use std::sync::Arc;
9
8use ra_db::{FileId, FilePosition}; 10use ra_db::{FileId, FilePosition};
9use ra_syntax::{ 11use 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
15use crate::{ 17use 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)]
266pub 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)]
273pub 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
284impl 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
347impl 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}