@@ -20,16 +20,19 @@ use hir_def::{
2020use hir_expand:: {
2121 hygiene:: Hygiene , name:: AsName , AstId , HirFileId , InFile , MacroCallId , MacroCallKind ,
2222} ;
23- use hir_ty:: { InEnvironment , InferenceResult , TraitEnvironment } ;
23+ use hir_ty:: {
24+ method_resolution:: { iterate_method_candidates, LookupMode } ,
25+ Canonical , InEnvironment , InferenceResult , TraitEnvironment ,
26+ } ;
2427use ra_syntax:: {
2528 ast:: { self , AstNode } ,
2629 AstPtr , SyntaxNode , SyntaxNodePtr , SyntaxToken , TextRange , TextUnit ,
2730} ;
2831use rustc_hash:: FxHashSet ;
2932
3033use crate :: {
31- db:: HirDatabase , Adt , Const , DefWithBody , EnumVariant , Function , Local , MacroDef , Name , Path ,
32- ScopeDef , Static , Struct , Trait , Type , TypeAlias , TypeParam ,
34+ db:: HirDatabase , Adt , AssocItem , Const , DefWithBody , EnumVariant , Function , Local , MacroDef ,
35+ ModuleDef , Name , Path , ScopeDef , Static , Struct , Trait , Type , TypeAlias , TypeParam ,
3336} ;
3437
3538/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
@@ -289,9 +292,11 @@ impl SourceAnalyzer {
289292
290293 pub fn resolve_path ( & self , db : & impl HirDatabase , path : & ast:: Path ) -> Option < PathResolution > {
291294 if let Some ( path_expr) = path. syntax ( ) . parent ( ) . and_then ( ast:: PathExpr :: cast) {
292- let expr_id = self . expr_id ( & path_expr. into ( ) ) ?;
293- if let Some ( assoc) = self . infer . as_ref ( ) ?. assoc_resolutions_for_expr ( expr_id) {
294- return Some ( PathResolution :: AssocItem ( assoc. into ( ) ) ) ;
295+ let path_resolution = self
296+ . resolve_as_full_path ( path_expr. clone ( ) )
297+ . or_else ( || self . resolve_as_path_to_method ( db, & path_expr) ) ;
298+ if path_resolution. is_some ( ) {
299+ return path_resolution;
295300 }
296301 }
297302 if let Some ( path_pat) = path. syntax ( ) . parent ( ) . and_then ( ast:: PathPat :: cast) {
@@ -305,6 +310,49 @@ impl SourceAnalyzer {
305310 self . resolve_hir_path ( db, & hir_path)
306311 }
307312
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+
308356 fn resolve_local_name ( & self , name_ref : & ast:: NameRef ) -> Option < ScopeEntryWithSyntax > {
309357 let name = name_ref. as_name ( ) ;
310358 let source_map = self . body_source_map . as_ref ( ) ?;
0 commit comments