@@ -43,8 +43,8 @@ use syntax::{
4343
4444use crate :: {
4545 db:: HirDatabase , semantics:: PathResolution , Adt , AssocItem , BindingMode , BuiltinAttr ,
46- BuiltinType , Callable , Const , Field , Function , Local , Macro , ModuleDef , Static , Struct ,
47- ToolModule , Trait , Type , TypeAlias , Variant ,
46+ BuiltinType , Callable , Const , DeriveHelper , Field , Function , Local , Macro , ModuleDef , Static ,
47+ Struct , ToolModule , Trait , Type , TypeAlias , Variant ,
4848} ;
4949
5050/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
@@ -429,36 +429,72 @@ impl SourceAnalyzer {
429429 }
430430 }
431431
432- let is_path_of_attr = path
432+ let meta_path = path
433433 . syntax ( )
434434 . ancestors ( )
435- . map ( |it| it. kind ( ) )
436- . take_while ( |& kind| ast:: Path :: can_cast ( kind) || ast:: Meta :: can_cast ( kind) )
435+ . take_while ( |it| {
436+ let kind = it. kind ( ) ;
437+ ast:: Path :: can_cast ( kind) || ast:: Meta :: can_cast ( kind)
438+ } )
437439 . last ( )
438- . map_or ( false , ast:: Meta :: can_cast ) ;
440+ . and_then ( ast:: Meta :: cast ) ;
439441
440442 // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
441443 // trying to resolve foo::bar.
442444 if path. parent_path ( ) . is_some ( ) {
443445 return match resolve_hir_path_qualifier ( db, & self . resolver , & hir_path) {
444- None if is_path_of_attr => {
446+ None if meta_path . is_some ( ) => {
445447 path. first_segment ( ) . and_then ( |it| it. name_ref ( ) ) . and_then ( |name_ref| {
446448 ToolModule :: by_name ( db, self . resolver . krate ( ) . into ( ) , & name_ref. text ( ) )
447449 . map ( PathResolution :: ToolModule )
448450 } )
449451 }
450452 res => res,
451453 } ;
452- } else if is_path_of_attr {
454+ } else if let Some ( meta_path ) = meta_path {
453455 // Case where we are resolving the final path segment of a path in an attribute
454456 // in this case we have to check for inert/builtin attributes and tools and prioritize
455457 // resolution of attributes over other namespaces
456- let name_ref = path. as_single_name_ref ( ) ;
457- let builtin = name_ref. as_ref ( ) . and_then ( |name_ref| {
458- BuiltinAttr :: by_name ( db, self . resolver . krate ( ) . into ( ) , & name_ref. text ( ) )
459- } ) ;
460- if let Some ( _) = builtin {
461- return builtin. map ( PathResolution :: BuiltinAttr ) ;
458+ if let Some ( name_ref) = path. as_single_name_ref ( ) {
459+ let builtin =
460+ BuiltinAttr :: by_name ( db, self . resolver . krate ( ) . into ( ) , & name_ref. text ( ) ) ;
461+ if let Some ( _) = builtin {
462+ return builtin. map ( PathResolution :: BuiltinAttr ) ;
463+ }
464+
465+ if let Some ( attr) = meta_path. parent_attr ( ) {
466+ let adt = if let Some ( field) =
467+ attr. syntax ( ) . parent ( ) . and_then ( ast:: RecordField :: cast)
468+ {
469+ field. syntax ( ) . ancestors ( ) . take ( 4 ) . find_map ( ast:: Adt :: cast)
470+ } else if let Some ( field) =
471+ attr. syntax ( ) . parent ( ) . and_then ( ast:: TupleField :: cast)
472+ {
473+ field. syntax ( ) . ancestors ( ) . take ( 4 ) . find_map ( ast:: Adt :: cast)
474+ } else if let Some ( variant) =
475+ attr. syntax ( ) . parent ( ) . and_then ( ast:: Variant :: cast)
476+ {
477+ variant. syntax ( ) . ancestors ( ) . nth ( 2 ) . and_then ( ast:: Adt :: cast)
478+ } else {
479+ None
480+ } ;
481+ if let Some ( adt) = adt {
482+ let ast_id = db. ast_id_map ( self . file_id ) . ast_id ( & adt) ;
483+ if let Some ( helpers) = self
484+ . resolver
485+ . def_map ( )
486+ . derive_helpers_in_scope ( InFile :: new ( self . file_id , ast_id) )
487+ {
488+ // FIXME: Multiple derives can have the same helper
489+ let name_ref = name_ref. as_name ( ) ;
490+ if let Some ( & ( _, derive, _) ) =
491+ helpers. iter ( ) . find ( |( name, ..) | * name == name_ref)
492+ {
493+ return Some ( PathResolution :: DeriveHelper ( DeriveHelper { derive } ) ) ;
494+ }
495+ }
496+ }
497+ }
462498 }
463499 return match resolve_hir_path_as_macro ( db, & self . resolver , & hir_path) {
464500 Some ( m) => Some ( PathResolution :: Def ( ModuleDef :: Macro ( m) ) ) ,
0 commit comments