22
33#![ allow( clippy:: module_name_repetitions) ]  
44
5+ use  rustc_session:: Session ; 
6+ use  rustc_span:: { BytePos ,  Pos ,  SourceFile ,  Span ,  SyntaxContext } ; 
57use  serde:: de:: { Deserializer ,  IgnoredAny ,  IntoDeserializer ,  MapAccess ,  Visitor } ; 
68use  serde:: Deserialize ; 
7- use  std:: error:: Error ; 
9+ use  std:: fmt:: { Debug ,  Display ,  Formatter } ; 
10+ use  std:: ops:: Range ; 
811use  std:: path:: { Path ,  PathBuf } ; 
912use  std:: str:: FromStr ; 
10- use  std:: { cmp,  env,  fmt,  fs,  io,  iter } ; 
13+ use  std:: { cmp,  env,  fmt,  fs,  io} ; 
1114
1215#[ rustfmt:: skip]  
1316const  DEFAULT_DOC_VALID_IDENTS :  & [ & str ]  = & [ 
@@ -67,33 +70,61 @@ impl DisallowedPath {
6770#[ derive( Default ) ]  
6871pub  struct  TryConf  { 
6972    pub  conf :  Conf , 
70-     pub  errors :  Vec < Box < dyn   Error > > , 
71-     pub  warnings :  Vec < Box < dyn   Error > > , 
73+     pub  errors :  Vec < ConfError > , 
74+     pub  warnings :  Vec < ConfError > , 
7275} 
7376
7477impl  TryConf  { 
75-     fn  from_error ( error :  impl  Error  + ' static )  -> Self  { 
78+     fn  from_toml_error ( file :  & SourceFile ,  error :  & toml:: de:: Error )  -> Self  { 
79+         ConfError :: from_toml ( file,  error) . into ( ) 
80+     } 
81+ } 
82+ 
83+ impl  From < ConfError >  for  TryConf  { 
84+     fn  from ( value :  ConfError )  -> Self  { 
7685        Self  { 
7786            conf :  Conf :: default ( ) , 
78-             errors :  vec ! [ Box :: new ( error ) ] , 
87+             errors :  vec ! [ value ] , 
7988            warnings :  vec ! [ ] , 
8089        } 
8190    } 
8291} 
8392
93+ impl  From < io:: Error >  for  TryConf  { 
94+     fn  from ( value :  io:: Error )  -> Self  { 
95+         ConfError :: from ( value) . into ( ) 
96+     } 
97+ } 
98+ 
8499#[ derive( Debug ) ]  
85- struct  ConfError ( String ) ; 
100+ pub   struct  ConfError ( pub   String ,   pub   Option < Span > ) ; 
86101
87- impl  fmt:: Display  for  ConfError  { 
88-     fn  fmt ( & self ,  f :  & mut  fmt:: Formatter < ' _ > )  -> fmt:: Result  { 
89-         <String  as  fmt:: Display >:: fmt ( & self . 0 ,  f) 
102+ impl  ConfError  { 
103+     fn  from_toml ( file :  & SourceFile ,  error :  & toml:: de:: Error )  -> Self  { 
104+         if  let  Some ( span)  = error. span ( )  { 
105+             Self :: spanned ( file,  error. message ( ) ,  span) 
106+         }  else  { 
107+             Self ( error. message ( ) . to_string ( ) ,  None ) 
108+         } 
90109    } 
91- } 
92110
93- impl  Error  for  ConfError  { } 
111+     fn  spanned ( file :  & SourceFile ,  message :  impl  Into < String > ,  span :  Range < usize > )  -> Self  { 
112+         Self ( 
113+             message. into ( ) , 
114+             Some ( Span :: new ( 
115+                 file. start_pos  + BytePos :: from_usize ( span. start ) , 
116+                 file. start_pos  + BytePos :: from_usize ( span. end ) , 
117+                 SyntaxContext :: root ( ) , 
118+                 None , 
119+             ) ) , 
120+         ) 
121+     } 
122+ } 
94123
95- fn  conf_error ( s :  impl  Into < String > )  -> Box < dyn  Error >  { 
96-     Box :: new ( ConfError ( s. into ( ) ) ) 
124+ impl  From < io:: Error >  for  ConfError  { 
125+     fn  from ( value :  io:: Error )  -> Self  { 
126+         Self ( value. to_string ( ) ,  None ) 
127+     } 
97128} 
98129
99130macro_rules!  define_Conf { 
@@ -117,20 +148,14 @@ macro_rules! define_Conf {
117148            } 
118149        } 
119150
120-         impl <' de> Deserialize <' de> for  TryConf  { 
121-             fn  deserialize<D >( deserializer:  D )  -> Result <Self ,  D :: Error > where  D :  Deserializer <' de> { 
122-                 deserializer. deserialize_map( ConfVisitor ) 
123-             } 
124-         } 
125- 
126151        #[ derive( Deserialize ) ] 
127152        #[ serde( field_identifier,  rename_all = "kebab-case" ) ] 
128153        #[ allow( non_camel_case_types) ] 
129154        enum  Field  {  $( $name, ) *  third_party,  } 
130155
131-         struct  ConfVisitor ; 
156+         struct  ConfVisitor < ' a> ( & ' a  SourceFile ) ; 
132157
133-         impl <' de> Visitor <' de> for  ConfVisitor  { 
158+         impl <' de> Visitor <' de> for  ConfVisitor < ' _>  { 
134159            type  Value  = TryConf ; 
135160
136161            fn  expecting( & self ,  formatter:  & mut  fmt:: Formatter <' _>)  -> fmt:: Result  { 
@@ -141,32 +166,38 @@ macro_rules! define_Conf {
141166                let  mut  errors = Vec :: new( ) ; 
142167                let  mut  warnings = Vec :: new( ) ; 
143168                $( let  mut  $name = None ; ) * 
144-                 // could get `Field` here directly, but get `str` first for diagnostics 
145-                 while  let  Some ( name)  = map. next_key:: <& str >( ) ? { 
146-                     match  Field :: deserialize( name. into_deserializer( ) ) ? { 
147-                         $( Field :: $name => { 
148-                             $( warnings. push( conf_error( format!( "deprecated field `{}`. {}" ,  name,  $dep) ) ) ; ) ?
149-                             match  map. next_value( )  { 
150-                                 Err ( e)  => errors. push( conf_error( e. to_string( ) ) ) , 
169+                 // could get `Field` here directly, but get `String` first for diagnostics 
170+                 while  let  Some ( name)  = map. next_key:: <toml:: Spanned <String >>( ) ? { 
171+                     match  Field :: deserialize( name. get_ref( ) . as_str( ) . into_deserializer( ) )  { 
172+                         Err ( e)  => { 
173+                             let  e:  FieldError  = e; 
174+                             errors. push( ConfError :: spanned( self . 0 ,  e. 0 ,  name. span( ) ) ) ; 
175+                         } 
176+                         $( Ok ( Field :: $name)  => { 
177+                             $( warnings. push( ConfError :: spanned( self . 0 ,  format!( "deprecated field `{}`. {}" ,  name. get_ref( ) ,  $dep) ,  name. span( ) ) ) ; ) ?
178+                             let  raw_value = map. next_value:: <toml:: Spanned <toml:: Value >>( ) ?; 
179+                             let  value_span = raw_value. span( ) ; 
180+                             match  <$ty>:: deserialize( raw_value. into_inner( ) )  { 
181+                                 Err ( e)  => errors. push( ConfError :: spanned( self . 0 ,  e. to_string( ) . replace( '\n' ,  " " ) . trim( ) ,  value_span) ) , 
151182                                Ok ( value)  => match  $name { 
152-                                     Some ( _)  => errors. push( conf_error ( format!( "duplicate field `{}`" ,  name) ) ) , 
183+                                     Some ( _)  => errors. push( ConfError :: spanned ( self . 0 ,   format!( "duplicate field `{}`" ,  name. get_ref ( ) ) ,  name . span ( ) ) ) , 
153184                                    None  => { 
154185                                        $name = Some ( value) ; 
155186                                        // $new_conf is the same as one of the defined `$name`s, so 
156187                                        // this variable is defined in line 2 of this function. 
157188                                        $( match  $new_conf { 
158-                                             Some ( _)  => errors. push( conf_error ( concat!( 
189+                                             Some ( _)  => errors. push( ConfError :: spanned ( self . 0 ,   concat!( 
159190                                                "duplicate field `" ,  stringify!( $new_conf) , 
160191                                                "` (provided as `" ,  stringify!( $name) ,  "`)" 
161-                                             ) ) ) , 
192+                                             ) ,  name . span ( ) ) ) , 
162193                                            None  => $new_conf = $name. clone( ) , 
163194                                        } ) ?
164195                                    } , 
165196                                } 
166197                            } 
167198                        } ) * 
168-                         // white-listed;  ignore 
169-                         Field :: third_party => drop( map. next_value:: <IgnoredAny >( ) ) 
199+                         // ignore contents of the third_party key  
200+                         Ok ( Field :: third_party)  => drop( map. next_value:: <IgnoredAny >( ) ) 
170201                    } 
171202                } 
172203                let  conf = Conf  {  $( $name:  $name. unwrap_or_else( defaults:: $name) , ) *  } ; 
@@ -521,19 +552,19 @@ pub fn lookup_conf_file() -> io::Result<(Option<PathBuf>, Vec<String>)> {
521552/// Read the `toml` configuration file. 
522553/// 
523554/// In case of error, the function tries to continue as much as possible. 
524- pub  fn  read ( path :  & Path )  -> TryConf  { 
525-     let  content  = match  fs :: read_to_string ( path)  { 
526-         Err ( e)  => return  TryConf :: from_error ( e ) , 
527-         Ok ( content )  => content , 
555+ pub  fn  read ( sess :   & Session ,   path :  & Path )  -> TryConf  { 
556+     let  file  = match  sess . source_map ( ) . load_file ( path)  { 
557+         Err ( e)  => return  e . into ( ) , 
558+         Ok ( file )  => file , 
528559    } ; 
529-     match  toml:: from_str :: < TryConf > ( & content )  { 
560+     match  toml:: de :: Deserializer :: new ( file . src . as_ref ( ) . unwrap ( ) ) . deserialize_map ( ConfVisitor ( & file ) )  { 
530561        Ok ( mut  conf)  => { 
531562            extend_vec_if_indicator_present ( & mut  conf. conf . doc_valid_idents ,  DEFAULT_DOC_VALID_IDENTS ) ; 
532563            extend_vec_if_indicator_present ( & mut  conf. conf . disallowed_names ,  DEFAULT_DISALLOWED_NAMES ) ; 
533564
534565            conf
535566        } , 
536-         Err ( e)  => TryConf :: from_error ( e) , 
567+         Err ( e)  => TryConf :: from_toml_error ( & file ,   & e) , 
537568    } 
538569} 
539570
@@ -545,65 +576,42 @@ fn extend_vec_if_indicator_present(vec: &mut Vec<String>, default: &[&str]) {
545576
546577const  SEPARATOR_WIDTH :  usize  = 4 ; 
547578
548- // Check whether the error is "unknown field" and, if so, list the available fields sorted and at 
549- // least one per line, more if `CLIPPY_TERMINAL_WIDTH` is set and allows it. 
550- pub  fn  format_error ( error :  Box < dyn  Error > )  -> String  { 
551-     let  s = error. to_string ( ) ; 
552- 
553-     if_chain !  { 
554-         if  error. downcast:: <toml:: de:: Error >( ) . is_ok( ) ; 
555-         if  let  Some ( ( prefix,  mut  fields,  suffix) )  = parse_unknown_field_message( & s) ; 
556-         then { 
557-             use  fmt:: Write ; 
558- 
559-             fields. sort_unstable( ) ; 
560- 
561-             let  ( rows,  column_widths)  = calculate_dimensions( & fields) ; 
562- 
563-             let  mut  msg = String :: from( prefix) ; 
564-             for  row in 0 ..rows { 
565-                 writeln!( msg) . unwrap( ) ; 
566-                 for  ( column,  column_width)  in column_widths. iter( ) . copied( ) . enumerate( )  { 
567-                     let  index = column *  rows + row; 
568-                     let  field = fields. get( index) . copied( ) . unwrap_or_default( ) ; 
569-                     write!( 
570-                         msg, 
571-                         "{:SEPARATOR_WIDTH$}{field:column_width$}" , 
572-                         " " 
573-                     ) 
574-                     . unwrap( ) ; 
575-                 } 
576-             } 
577-             write!( msg,  "\n {suffix}" ) . unwrap( ) ; 
578-             msg
579-         }  else { 
580-             s
581-         } 
579+ #[ derive( Debug ) ]  
580+ struct  FieldError ( String ) ; 
581+ 
582+ impl  std:: error:: Error  for  FieldError  { } 
583+ 
584+ impl  Display  for  FieldError  { 
585+     fn  fmt ( & self ,  f :  & mut  Formatter < ' _ > )  -> fmt:: Result  { 
586+         f. pad ( & self . 0 ) 
582587    } 
583588} 
584589
585- // `parse_unknown_field_message` will become unnecessary if 
586- // https://github.com/alexcrichton/toml-rs/pull/364 is merged. 
587- fn  parse_unknown_field_message ( s :  & str )  -> Option < ( & str ,  Vec < & str > ,  & str ) >  { 
588-     // An "unknown field" message has the following form: 
589-     //   unknown field `UNKNOWN`, expected one of `FIELD0`, `FIELD1`, ..., `FIELDN` at line X column Y 
590-     //                                           ^^      ^^^^                     ^^ 
591-     if_chain !  { 
592-         if  s. starts_with( "unknown field" ) ; 
593-         let  slices = s. split( "`, `" ) . collect:: <Vec <_>>( ) ; 
594-         let  n = slices. len( ) ; 
595-         if  n >= 2 ; 
596-         if  let  Some ( ( prefix,  first_field) )  = slices[ 0 ] . rsplit_once( " `" ) ; 
597-         if  let  Some ( ( last_field,  suffix) )  = slices[ n - 1 ] . split_once( "` " ) ; 
598-         then { 
599-             let  fields = iter:: once( first_field) 
600-                 . chain( slices[ 1 ..n - 1 ] . iter( ) . copied( ) ) 
601-                 . chain( iter:: once( last_field) ) 
602-                 . collect:: <Vec <_>>( ) ; 
603-             Some ( ( prefix,  fields,  suffix) ) 
604-         }  else { 
605-             None 
590+ impl  serde:: de:: Error  for  FieldError  { 
591+     fn  custom < T :  Display > ( msg :  T )  -> Self  { 
592+         Self ( msg. to_string ( ) ) 
593+     } 
594+ 
595+     fn  unknown_field ( field :  & str ,  expected :  & ' static  [ & ' static  str ] )  -> Self  { 
596+         // List the available fields sorted and at least one per line, more if `CLIPPY_TERMINAL_WIDTH` is 
597+         // set and allows it. 
598+         use  fmt:: Write ; 
599+ 
600+         let  mut  expected = expected. to_vec ( ) ; 
601+         expected. sort_unstable ( ) ; 
602+ 
603+         let  ( rows,  column_widths)  = calculate_dimensions ( & expected) ; 
604+ 
605+         let  mut  msg = format ! ( "unknown field `{field}`, expected one of" ) ; 
606+         for  row in  0 ..rows { 
607+             writeln ! ( msg) . unwrap ( ) ; 
608+             for  ( column,  column_width)  in  column_widths. iter ( ) . copied ( ) . enumerate ( )  { 
609+                 let  index = column *  rows + row; 
610+                 let  field = expected. get ( index) . copied ( ) . unwrap_or_default ( ) ; 
611+                 write ! ( msg,  "{:SEPARATOR_WIDTH$}{field:column_width$}" ,  " " ) . unwrap ( ) ; 
612+             } 
606613        } 
614+         Self ( msg) 
607615    } 
608616} 
609617
0 commit comments