@@ -43,8 +43,8 @@ use syntax::{
43
43
44
44
use crate :: {
45
45
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 ,
48
48
} ;
49
49
50
50
/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
@@ -429,36 +429,72 @@ impl SourceAnalyzer {
429
429
}
430
430
}
431
431
432
- let is_path_of_attr = path
432
+ let meta_path = path
433
433
. syntax ( )
434
434
. 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
+ } )
437
439
. last ( )
438
- . map_or ( false , ast:: Meta :: can_cast ) ;
440
+ . and_then ( ast:: Meta :: cast ) ;
439
441
440
442
// Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
441
443
// trying to resolve foo::bar.
442
444
if path. parent_path ( ) . is_some ( ) {
443
445
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 ( ) => {
445
447
path. first_segment ( ) . and_then ( |it| it. name_ref ( ) ) . and_then ( |name_ref| {
446
448
ToolModule :: by_name ( db, self . resolver . krate ( ) . into ( ) , & name_ref. text ( ) )
447
449
. map ( PathResolution :: ToolModule )
448
450
} )
449
451
}
450
452
res => res,
451
453
} ;
452
- } else if is_path_of_attr {
454
+ } else if let Some ( meta_path ) = meta_path {
453
455
// Case where we are resolving the final path segment of a path in an attribute
454
456
// in this case we have to check for inert/builtin attributes and tools and prioritize
455
457
// 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
+ }
462
498
}
463
499
return match resolve_hir_path_as_macro ( db, & self . resolver , & hir_path) {
464
500
Some ( m) => Some ( PathResolution :: Def ( ModuleDef :: Macro ( m) ) ) ,
0 commit comments