@@ -5,15 +5,16 @@ use log::debug;
55use rustc:: hir:: def:: { Def , CtorKind , Namespace :: * } ;
66use rustc:: hir:: def_id:: { CRATE_DEF_INDEX , DefId } ;
77use rustc:: session:: config:: nightly_options;
8- use syntax:: ast:: { Expr , ExprKind } ;
8+ use syntax:: ast:: { Expr , ExprKind , Ident } ;
9+ use syntax:: ext:: base:: MacroKind ;
910use syntax:: symbol:: keywords;
1011use syntax_pos:: Span ;
1112
1213use crate :: macros:: ParentScope ;
13- use crate :: resolve_imports:: ImportResolver ;
14+ use crate :: resolve_imports:: { ImportDirective , ImportResolver } ;
1415use crate :: { import_candidate_to_enum_paths, is_self_type, is_self_value, path_names_to_string} ;
1516use crate :: { AssocSuggestion , CrateLint , ImportSuggestion , ModuleOrUniformRoot , PathResult ,
16- PathSource , Resolver , Segment } ;
17+ PathSource , Resolver , Segment , Suggestion } ;
1718
1819impl < ' a > Resolver < ' a > {
1920 /// Handles error reporting for `smart_resolve_path_fragment` function.
@@ -428,7 +429,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
428429 span : Span ,
429430 mut path : Vec < Segment > ,
430431 parent_scope : & ParentScope < ' b > ,
431- ) -> Option < ( Vec < Segment > , Option < String > ) > {
432+ ) -> Option < ( Vec < Segment > , Vec < String > ) > {
432433 debug ! ( "make_path_suggestion: span={:?} path={:?}" , span, path) ;
433434
434435 match ( path. get ( 0 ) , path. get ( 1 ) ) {
@@ -463,13 +464,13 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
463464 span : Span ,
464465 mut path : Vec < Segment > ,
465466 parent_scope : & ParentScope < ' b > ,
466- ) -> Option < ( Vec < Segment > , Option < String > ) > {
467+ ) -> Option < ( Vec < Segment > , Vec < String > ) > {
467468 // Replace first ident with `self` and check if that is valid.
468469 path[ 0 ] . ident . name = keywords:: SelfLower . name ( ) ;
469470 let result = self . resolve_path ( & path, None , parent_scope, false , span, CrateLint :: No ) ;
470471 debug ! ( "make_missing_self_suggestion: path={:?} result={:?}" , path, result) ;
471472 if let PathResult :: Module ( ..) = result {
472- Some ( ( path, None ) )
473+ Some ( ( path, Vec :: new ( ) ) )
473474 } else {
474475 None
475476 }
@@ -487,19 +488,19 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
487488 span : Span ,
488489 mut path : Vec < Segment > ,
489490 parent_scope : & ParentScope < ' b > ,
490- ) -> Option < ( Vec < Segment > , Option < String > ) > {
491+ ) -> Option < ( Vec < Segment > , Vec < String > ) > {
491492 // Replace first ident with `crate` and check if that is valid.
492493 path[ 0 ] . ident . name = keywords:: Crate . name ( ) ;
493494 let result = self . resolve_path ( & path, None , parent_scope, false , span, CrateLint :: No ) ;
494495 debug ! ( "make_missing_crate_suggestion: path={:?} result={:?}" , path, result) ;
495496 if let PathResult :: Module ( ..) = result {
496497 Some ( (
497498 path,
498- Some (
499+ vec ! [
499500 "`use` statements changed in Rust 2018; read more at \
500501 <https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-\
501502 clarity.html>". to_string( )
502- ) ,
503+ ] ,
503504 ) )
504505 } else {
505506 None
@@ -518,13 +519,13 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
518519 span : Span ,
519520 mut path : Vec < Segment > ,
520521 parent_scope : & ParentScope < ' b > ,
521- ) -> Option < ( Vec < Segment > , Option < String > ) > {
522+ ) -> Option < ( Vec < Segment > , Vec < String > ) > {
522523 // Replace first ident with `crate` and check if that is valid.
523524 path[ 0 ] . ident . name = keywords:: Super . name ( ) ;
524525 let result = self . resolve_path ( & path, None , parent_scope, false , span, CrateLint :: No ) ;
525526 debug ! ( "make_missing_super_suggestion: path={:?} result={:?}" , path, result) ;
526527 if let PathResult :: Module ( ..) = result {
527- Some ( ( path, None ) )
528+ Some ( ( path, Vec :: new ( ) ) )
528529 } else {
529530 None
530531 }
@@ -545,7 +546,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
545546 span : Span ,
546547 mut path : Vec < Segment > ,
547548 parent_scope : & ParentScope < ' b > ,
548- ) -> Option < ( Vec < Segment > , Option < String > ) > {
549+ ) -> Option < ( Vec < Segment > , Vec < String > ) > {
549550 if path[ 1 ] . ident . span . rust_2015 ( ) {
550551 return None ;
551552 }
@@ -564,10 +565,65 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
564565 debug ! ( "make_external_crate_suggestion: name={:?} path={:?} result={:?}" ,
565566 name, path, result) ;
566567 if let PathResult :: Module ( ..) = result {
567- return Some ( ( path, None ) ) ;
568+ return Some ( ( path, Vec :: new ( ) ) ) ;
568569 }
569570 }
570571
571572 None
572573 }
574+
575+ /// Suggests importing a macro from the root of the crate rather than a module within
576+ /// the crate.
577+ ///
578+ /// ```
579+ /// help: a macro with this name exists at the root of the crate
580+ /// |
581+ /// LL | use issue_59764::makro;
582+ /// | ^^^^^^^^^^^^^^^^^^
583+ /// |
584+ /// = note: this could be because a macro annotated with `#[macro_export]` will be exported
585+ /// at the root of the crate instead of the module where it is defined
586+ /// ```
587+ pub ( crate ) fn check_for_module_export_macro (
588+ & self ,
589+ directive : & ' b ImportDirective < ' b > ,
590+ module : ModuleOrUniformRoot < ' b > ,
591+ ident : Ident ,
592+ ) -> Option < ( Option < Suggestion > , Vec < String > ) > {
593+ let mut crate_module = if let ModuleOrUniformRoot :: Module ( module) = module {
594+ module
595+ } else {
596+ return None ;
597+ } ;
598+
599+ while let Some ( parent) = crate_module. parent {
600+ crate_module = parent;
601+ }
602+
603+ if ModuleOrUniformRoot :: same_def ( ModuleOrUniformRoot :: Module ( crate_module) , module) {
604+ // Don't make a suggestion if the import was already from the root of the
605+ // crate.
606+ return None ;
607+ }
608+
609+ let resolutions = crate_module. resolutions . borrow ( ) ;
610+ let resolution = resolutions. get ( & ( ident, MacroNS ) ) ?;
611+ let binding = resolution. borrow ( ) . binding ( ) ?;
612+ if let Def :: Macro ( _, MacroKind :: Bang ) = binding. def ( ) {
613+ let name = crate_module. kind . name ( ) . unwrap ( ) ;
614+ let suggestion = Some ( (
615+ directive. span ,
616+ String :: from ( "a macro with this name exists at the root of the crate" ) ,
617+ format ! ( "{}::{}" , name, ident) ,
618+ Applicability :: MaybeIncorrect ,
619+ ) ) ;
620+ let note = vec ! [
621+ "this could be because a macro annotated with `#[macro_export]` will be exported \
622+ at the root of the crate instead of the module where it is defined". to_string( ) ,
623+ ] ;
624+ Some ( ( suggestion, note) )
625+ } else {
626+ None
627+ }
628+ }
573629}
0 commit comments