1+ use std:: collections:: HashMap ;
2+
13use crate :: config:: file_lines:: FileLines ;
24use crate :: config:: options:: { IgnoreList , WidthHeuristics } ;
35
@@ -50,6 +52,82 @@ impl ConfigType for IgnoreList {
5052 }
5153}
5254
55+ /// Store a map of all Unstable options used in in the configuration.
56+ #[ derive( Clone , Debug ) ]
57+ pub struct UnstableOptions {
58+ pub ( crate ) options : HashMap < & ' static str , String > ,
59+ }
60+
61+ impl std:: fmt:: Display for UnstableOptions {
62+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
63+ if let Some ( message) = self . abort_message ( ) {
64+ write ! ( f, "{}" , message)
65+ } else {
66+ write ! ( f, "No unstable options were used." )
67+ }
68+ }
69+ }
70+
71+ impl UnstableOptions {
72+ /// Create a new UnstableOptions struct
73+ pub ( crate ) fn new ( ) -> Self {
74+ Self {
75+ options : HashMap :: new ( ) ,
76+ }
77+ }
78+
79+ /// Insert an unstable option and a user supplied value for that unstable option
80+ pub ( crate ) fn insert ( & mut self , option : & ' static str , user_supplied_value : String ) {
81+ self . options . insert ( option, user_supplied_value) ;
82+ }
83+
84+ /// Check if any unstable options have been set
85+ pub ( crate ) fn has_unstable_options ( & self ) -> bool {
86+ !self . options . is_empty ( )
87+ }
88+
89+ /// Generate the Warning message
90+ pub ( crate ) fn warning_message ( & self ) -> Option < String > {
91+ if self . options . is_empty ( ) {
92+ return None ;
93+ }
94+ let mut result = String :: new ( ) ;
95+
96+ for ( k, v) in self . options . iter ( ) {
97+ result. push_str ( & format ! (
98+ "Warning: can't set `{} = {}`, unstable features are only \
99+ available in nightly channel.\n ",
100+ k, v,
101+ ) ) ;
102+ }
103+
104+ let upgrade_to_abort_message = "\n Set `abort_on_unrecognised_options = true` \
105+ to convert this warning into an error\n \n ";
106+
107+ result. push_str ( upgrade_to_abort_message) ;
108+
109+ Some ( result)
110+ }
111+
112+ /// Generate the Abort message
113+ pub ( crate ) fn abort_message ( & self ) -> Option < String > {
114+ if self . options . is_empty ( ) {
115+ return None ;
116+ }
117+
118+ let mut result = String :: new ( ) ;
119+ result. push_str ( "Can't set nightly options when using stable rustfmt\n " ) ;
120+
121+ for ( k, v) in self . options . iter ( ) {
122+ result. push_str ( & format ! ( " - `{} = {}`\n " , k, v) ) ;
123+ }
124+ let to_warning_message = "\n Set `abort_on_unrecognised_options = false` \
125+ to convert this error into a warning\n \n ";
126+ result. push_str ( to_warning_message) ;
127+ Some ( result)
128+ }
129+ }
130+
53131macro_rules! create_config {
54132 ( $( $i: ident: $ty: ty, $def: expr, $stb: expr, $( $dstring: expr ) ,+ ) ;+ $( ; ) * ) => (
55133 #[ cfg( test) ]
@@ -64,6 +142,8 @@ macro_rules! create_config {
64142 // if a license_template_path has been specified, successfully read, parsed and compiled
65143 // into a regex, it will be stored here
66144 pub license_template: Option <Regex >,
145+ // Unstable Options specified on the stable channel
146+ configured_unstable_options: UnstableOptions ,
67147 // For each config item, we store a bool indicating whether it has
68148 // been accessed and the value, and a bool whether the option was
69149 // manually initialised, or taken from the default,
@@ -145,21 +225,35 @@ macro_rules! create_config {
145225 ConfigWasSet ( self )
146226 }
147227
228+ /// Insert all unstable options and their values into the UnstableOptions struct.
229+ /// The only exception is the "abort_on_unrecognised_options", which helps
230+ /// determine if we should abort or warn when using unstable options on stable rustfmt
231+ #[ allow( unreachable_pub) ]
232+ pub fn insert_unstable_options( & mut self , option: & ' static str , value: String ) {
233+ if option == "abort_on_unrecognised_options" {
234+ return
235+ }
236+
237+ match option {
238+ $(
239+ stringify!( $i) => {
240+ // If its an unstable option then add it to the unstable list
241+ if !self . $i. 3 {
242+ self . configured_unstable_options. insert( option, value) ;
243+ }
244+ }
245+ ) +
246+ _ => panic!( "Unknown config key in override: {}" , option)
247+ }
248+
249+ }
250+
148251 fn fill_from_parsed_config( mut self , parsed: PartialConfig , dir: & Path ) -> Config {
149252 $(
150253 if let Some ( val) = parsed. $i {
151- if self . $i. 3 {
152- self . $i. 1 = true ;
153- self . $i. 2 = val;
154- } else {
155- if crate :: is_nightly_channel!( ) {
156- self . $i. 1 = true ;
157- self . $i. 2 = val;
158- } else {
159- eprintln!( "Warning: can't set `{} = {:?}`, unstable features are only \
160- available in nightly channel.", stringify!( $i) , val) ;
161- }
162- }
254+ self . insert_unstable_options( stringify!( $i) , format!( "{:?}" , & val) ) ;
255+ self . $i. 1 = true ;
256+ self . $i. 2 = val;
163257 }
164258 ) +
165259 self . set_heuristics( ) ;
@@ -220,6 +314,12 @@ macro_rules! create_config {
220314 }
221315 }
222316
317+ /// Get a reference to the UnstableOptions set on the configuration.
318+ #[ allow( unreachable_pub) ]
319+ pub fn unstable_options( & self ) -> & UnstableOptions {
320+ & self . configured_unstable_options
321+ }
322+
223323 #[ allow( unreachable_pub) ]
224324 pub fn override_value( & mut self , key: & str , val: & str )
225325 {
@@ -232,6 +332,7 @@ macro_rules! create_config {
232332 stringify!( $i) ,
233333 val,
234334 stringify!( $ty) ) ) ;
335+ self . insert_unstable_options( stringify!( $i) , val. to_owned( ) ) ;
235336 }
236337 ) +
237338 _ => panic!( "Unknown config key in override: {}" , key)
@@ -438,6 +539,7 @@ macro_rules! create_config {
438539 fn default ( ) -> Config {
439540 Config {
440541 license_template: None ,
542+ configured_unstable_options: UnstableOptions :: new( ) ,
441543 $(
442544 $i: ( Cell :: new( false ) , false , $def, $stb) ,
443545 ) +
0 commit comments