Skip to content

Commit 312c454

Browse files
committed
Add UnstableOptions struct to Config
The UnstableOptions struct internally contains the map used to store user specified unstable options. All unstable options Are stored in this struct and when a LoadConfigurationError::AbortOnUnstableOptions error occurs in ``load_config``, the UnstableOptions struct is returned to the caller to give more context as to which ustable options were set.
1 parent be5e68d commit 312c454

File tree

2 files changed

+140
-171
lines changed

2 files changed

+140
-171
lines changed

src/config/config_type.rs

Lines changed: 98 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::collections::HashMap;
2+
13
use crate::config::file_lines::FileLines;
24
use crate::config::options::{IgnoreList, WidthHeuristics};
35

@@ -50,6 +52,78 @@ 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+
options: HashMap<&'static str, String>,
59+
}
60+
61+
impl UnstableOptions {
62+
/// Create a new UnstableOptions struct
63+
pub(crate) fn new() -> Self {
64+
Self {
65+
options: HashMap::new(),
66+
}
67+
}
68+
69+
/// Insert an unstable option and a user supplied value for that unstable option
70+
pub(crate) fn insert(&mut self, option: &'static str, user_supplied_value: String) {
71+
self.options.insert(option, user_supplied_value);
72+
}
73+
74+
/// Check if any unstable options have been set
75+
pub(crate) fn has_unstable_options(&self) -> bool {
76+
!self.options.is_empty()
77+
}
78+
79+
// primarily used for testing
80+
#[allow(dead_code)]
81+
pub(crate) fn options(&self) -> &HashMap<&'static str, String> {
82+
&self.options
83+
}
84+
85+
/// Generate the Warning message
86+
pub fn warning_message(&self) -> Option<String> {
87+
if self.options.is_empty() {
88+
return None;
89+
}
90+
let mut result = String::new();
91+
92+
for (k, v) in self.options.iter() {
93+
result.push_str(&format!(
94+
"Warning: can't set `{} = {}`, unstable features are only \
95+
available in nightly channel.\n",
96+
k, v,
97+
));
98+
}
99+
100+
let upgrade_to_abort_message = "\nSet `abort_on_unrecognised_options = true` \
101+
to convert this warning into an error\n\n";
102+
103+
result.push_str(upgrade_to_abort_message);
104+
105+
Some(result)
106+
}
107+
108+
/// Generate the Abort message
109+
pub fn abort_message(&self) -> Option<String> {
110+
if self.options.is_empty() {
111+
return None;
112+
}
113+
114+
let mut result = String::new();
115+
result.push_str("Can't set nightly options when using stable rustfmt\n");
116+
117+
for (k, v) in self.options.iter() {
118+
result.push_str(&format!(" - `{} = {}`\n", k, v));
119+
}
120+
let to_warning_message = "\nSet `abort_on_unrecognised_options = false` \
121+
to convert this error into a warning\n\n";
122+
result.push_str(to_warning_message);
123+
Some(result)
124+
}
125+
}
126+
53127
macro_rules! create_config {
54128
($($i:ident: $ty:ty, $def:expr, $stb:expr, $( $dstring:expr ),+ );+ $(;)*) => (
55129
#[cfg(test)]
@@ -65,7 +139,7 @@ macro_rules! create_config {
65139
// into a regex, it will be stored here
66140
pub license_template: Option<Regex>,
67141
// Unstable Options specified on the stable channel
68-
configured_unstable_options: std::collections::HashMap<String, String>,
142+
configured_unstable_options: UnstableOptions,
69143
// For each config item, we store a bool indicating whether it has
70144
// been accessed and the value, and a bool whether the option was
71145
// manually initialised, or taken from the default,
@@ -147,103 +221,33 @@ macro_rules! create_config {
147221
ConfigWasSet(self)
148222
}
149223

150-
/// Returns None if using nightly or if no unstable options were set.
151-
/// Otherwise, return all unstable options set by the user.
224+
/// Insert all unstable options and their values into the UnstableOptions struct.
225+
/// The only exception is the "abort_on_unrecognised_options", which helps
226+
/// determine if we should abort or warn when using unstable options on stable rustfmt
152227
#[allow(unreachable_pub)]
153-
pub fn unstable_options_set_on_stable_channel(&self) -> Option<Vec<String>> {
154-
if crate::is_nightly_channel!() {
155-
return None;
156-
}
157-
158-
if self.using_unstable_options_on_stable_channel() {
159-
Some(self.configured_unstable_options.iter()
160-
.map(|(k, v)| format!("{} = {}", k, v))
161-
.collect::<Vec<_>>()
162-
)
163-
} else {
164-
None
165-
}
166-
}
167-
168-
/// Gather all unstable options specified by the user
169-
#[allow(unreachable_pub)]
170-
pub fn collect_unstable_options(&mut self) {
171-
if crate::is_nightly_channel!() {
228+
pub fn insert_unstable_options(&mut self, option: &'static str, value: String) {
229+
if option == "abort_on_unrecognised_options" {
172230
return
173231
}
174232

175-
let abort_option = "abort_on_unrecognised_options";
176-
177-
$({
178-
// self.$i.3 = 'is this a stable options'
179-
// self.$1.1 = 'was this set by the user'
180-
// the abort option is currently unstable so it needs to be special cased
181-
// otherwise we would abort when using it.
182-
if !(self.$i.3) && self.$i.1 && stringify!($i) != abort_option {
183-
self.configured_unstable_options.insert(
184-
stringify!($i).to_owned(), format!("{:?}", self.$i.2)
185-
);
233+
match option {
234+
$(
235+
stringify!($i) => {
236+
// If its an unstable option then add it to the unstable list
237+
if !self.$i.3 {
238+
self.configured_unstable_options.insert(option, value);
239+
}
186240
}
187-
188-
})+
189-
}
190-
191-
/// Returns true if any unstable options were set while on the stable channel
192-
#[allow(unreachable_pub)]
193-
pub fn using_unstable_options_on_stable_channel(&self) -> bool {
194-
!self.configured_unstable_options.is_empty()
195-
}
196-
197-
/// Return a String warning users about all unstable options used on the stable channel
198-
#[allow(unreachable_pub)]
199-
pub fn unstable_options_warning_message(&self) -> Option<String> {
200-
let unstable_options = self.unstable_options_set_on_stable_channel()?;
201-
let upgrade_to_abort_message = "\nSet `abort_on_unrecognised_options = true` \
202-
to convert this warning into an error\n\n";
203-
// Capacity of 120 * len should be enough space for all options.
204-
// the Warning string below is ~80 characters long so there is
205-
// ~40 char buffer for option name and value
206-
let mut output = String::with_capacity(
207-
upgrade_to_abort_message.len() + unstable_options.len() * 120
208-
);
209-
210-
for option in unstable_options {
211-
output.push_str(
212-
&format!("Warning: can't set `{}`, unstable features are only \
213-
available in nightly channel.\n", option
214-
)
215-
);
241+
)+
242+
_ => panic!("Unknown config key in override: {}", option)
216243
}
217244

218-
output.push_str(upgrade_to_abort_message);
219-
220-
Some(output)
221-
}
222-
223-
/// Returns a String explaining why rustfmt exited early when using unstable options
224-
/// on the stable channel
225-
#[allow(unreachable_pub)]
226-
pub fn unstable_options_abort_message(&self) -> Option<String> {
227-
let unstable_options = self.unstable_options_set_on_stable_channel()?;
228-
let first_line = "Can't set nightly options when using stable rustfmt\n";
229-
let to_warning_message = "\nSet `abort_on_unrecognised_options = false` \
230-
to convert this error into a warning\n\n";
231-
// 40 = buffer we'll use for all options. Most will be less than 40 char long
232-
let mut output = String::with_capacity(
233-
to_warning_message.len() + first_line.len() + unstable_options.len() * 40
234-
);
235-
output.push_str(first_line);
236-
237-
for option in unstable_options {
238-
output.push_str(&format!(" - `{}`\n", option));
239-
}
240-
output.push_str(to_warning_message);
241-
Some(output)
242245
}
243246

244247
fn fill_from_parsed_config(mut self, parsed: PartialConfig, dir: &Path) -> Config {
245248
$(
246249
if let Some(val) = parsed.$i {
250+
self.insert_unstable_options(stringify!($i), format!("{:?}", &val));
247251
self.$i.1 = true;
248252
self.$i.2 = val;
249253
}
@@ -252,7 +256,6 @@ macro_rules! create_config {
252256
self.set_license_template();
253257
self.set_ignore(dir);
254258
self.set_merge_imports();
255-
self.collect_unstable_options();
256259
self
257260
}
258261

@@ -307,6 +310,12 @@ macro_rules! create_config {
307310
}
308311
}
309312

313+
/// Get a reference to the UnstableOptions set on the configuration.
314+
#[allow(unreachable_pub)]
315+
pub fn unstable_options(&self) -> &UnstableOptions {
316+
&self.configured_unstable_options
317+
}
318+
310319
#[allow(unreachable_pub)]
311320
pub fn override_value(&mut self, key: &str, val: &str)
312321
{
@@ -319,6 +328,7 @@ macro_rules! create_config {
319328
stringify!($i),
320329
val,
321330
stringify!($ty)));
331+
self.insert_unstable_options(stringify!($i), val.to_owned());
322332
}
323333
)+
324334
_ => panic!("Unknown config key in override: {}", key)
@@ -525,7 +535,7 @@ macro_rules! create_config {
525535
fn default() -> Config {
526536
Config {
527537
license_template: None,
528-
configured_unstable_options: std::collections::HashMap::new(),
538+
configured_unstable_options: UnstableOptions::new(),
529539
$(
530540
$i: (Cell::new(false), false, $def, $stb),
531541
)+

0 commit comments

Comments
 (0)