diff options
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/source_analyzer.rs | 60 |
1 files changed, 54 insertions, 6 deletions
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index bb9a35c5d..49e1a10e0 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs | |||
@@ -20,7 +20,10 @@ use hir_def::{ | |||
20 | use hir_expand::{ | 20 | use hir_expand::{ |
21 | hygiene::Hygiene, name::AsName, AstId, HirFileId, InFile, MacroCallId, MacroCallKind, | 21 | hygiene::Hygiene, name::AsName, AstId, HirFileId, InFile, MacroCallId, MacroCallKind, |
22 | }; | 22 | }; |
23 | use hir_ty::{InEnvironment, InferenceResult, TraitEnvironment}; | 23 | use hir_ty::{ |
24 | method_resolution::{iterate_method_candidates, LookupMode}, | ||
25 | Canonical, InEnvironment, InferenceResult, TraitEnvironment, | ||
26 | }; | ||
24 | use ra_syntax::{ | 27 | use ra_syntax::{ |
25 | ast::{self, AstNode}, | 28 | ast::{self, AstNode}, |
26 | AstPtr, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextUnit, | 29 | AstPtr, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextUnit, |
@@ -28,8 +31,8 @@ use ra_syntax::{ | |||
28 | use rustc_hash::FxHashSet; | 31 | use rustc_hash::FxHashSet; |
29 | 32 | ||
30 | use crate::{ | 33 | use crate::{ |
31 | db::HirDatabase, Adt, Const, DefWithBody, EnumVariant, Function, Local, MacroDef, Name, Path, | 34 | db::HirDatabase, Adt, AssocItem, Const, DefWithBody, EnumVariant, Function, Local, MacroDef, |
32 | ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, | 35 | ModuleDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, |
33 | }; | 36 | }; |
34 | 37 | ||
35 | /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of | 38 | /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of |
@@ -289,9 +292,11 @@ impl SourceAnalyzer { | |||
289 | 292 | ||
290 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> { | 293 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> { |
291 | if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { | 294 | if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { |
292 | let expr_id = self.expr_id(&path_expr.into())?; | 295 | let path_resolution = self |
293 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { | 296 | .resolve_as_full_path(path_expr.clone()) |
294 | return Some(PathResolution::AssocItem(assoc.into())); | 297 | .or_else(|| self.resolve_as_path_to_method(db, &path_expr)); |
298 | if path_resolution.is_some() { | ||
299 | return path_resolution; | ||
295 | } | 300 | } |
296 | } | 301 | } |
297 | if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) { | 302 | if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) { |
@@ -305,6 +310,49 @@ impl SourceAnalyzer { | |||
305 | self.resolve_hir_path(db, &hir_path) | 310 | self.resolve_hir_path(db, &hir_path) |
306 | } | 311 | } |
307 | 312 | ||
313 | fn resolve_as_full_path(&self, path_expr: ast::PathExpr) -> Option<PathResolution> { | ||
314 | let expr_id = self.expr_id(&path_expr.into())?; | ||
315 | self.infer | ||
316 | .as_ref()? | ||
317 | .assoc_resolutions_for_expr(expr_id) | ||
318 | .map(|assoc| PathResolution::AssocItem(assoc.into())) | ||
319 | } | ||
320 | |||
321 | fn resolve_as_path_to_method( | ||
322 | &self, | ||
323 | db: &impl HirDatabase, | ||
324 | path_expr: &ast::PathExpr, | ||
325 | ) -> Option<PathResolution> { | ||
326 | let full_path = path_expr.path()?; | ||
327 | let path_to_method = full_path.qualifier()?; | ||
328 | let method_name = full_path.segment()?.syntax().to_string(); | ||
329 | match self.resolve_path(db, &path_to_method)? { | ||
330 | PathResolution::Def(ModuleDef::Adt(adt)) => { | ||
331 | let ty = adt.ty(db); | ||
332 | iterate_method_candidates( | ||
333 | &Canonical { value: ty.ty.value, num_vars: 0 }, | ||
334 | db, | ||
335 | ty.ty.environment, | ||
336 | self.resolver.krate()?, | ||
337 | &self.resolver.traits_in_scope(db), | ||
338 | None, | ||
339 | LookupMode::Path, | ||
340 | |_, assoc_item_id| { | ||
341 | let assoc = assoc_item_id.into(); | ||
342 | if let AssocItem::Function(function) = assoc { | ||
343 | if function.name(db).to_string() == method_name { | ||
344 | return Some(assoc); | ||
345 | } | ||
346 | } | ||
347 | None | ||
348 | }, | ||
349 | ) | ||
350 | } | ||
351 | _ => None, | ||
352 | } | ||
353 | .map(PathResolution::AssocItem) | ||
354 | } | ||
355 | |||
308 | fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> { | 356 | fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> { |
309 | let name = name_ref.as_name(); | 357 | let name = name_ref.as_name(); |
310 | let source_map = self.body_source_map.as_ref()?; | 358 | let source_map = self.body_source_map.as_ref()?; |