Skip to content

Commit 43e6ac9

Browse files
committed
Add new configuration option abort_on_unrecognised_options
This option was proposed in issue 5022 and allows rustfmt to exit early in the event that any unstable options are used while using stable rustfmt.
1 parent f40b1d9 commit 43e6ac9

File tree

7 files changed

+501
-26
lines changed

7 files changed

+501
-26
lines changed

Configurations.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ To enable unstable options, set `unstable_features = true` in `rustfmt.toml` or
1717

1818
Below you find a detailed visual guide on all the supported configuration options of rustfmt:
1919

20+
## `abort_on_unrecognised_options`
21+
22+
Exit early when using nightly only options on the stable channel
23+
24+
- **Default value**: `false`
25+
- **Possible values**: `true`, `false`
26+
- **Stable**: No (tracking issue: [#5022](https://github.com/rust-lang/rustfmt/issues/5022))
27+
28+
2029
## `array_width`
2130

2231
Maximum width of an array literal before falling back to vertical formatting.

src/bin/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ fn format(
302302
}
303303

304304
let out = &mut stdout();
305+
305306
let mut session = Session::new(config, Some(out));
306307

307308
for file in files {

src/config/config_type.rs

Lines changed: 110 additions & 12 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)]
@@ -64,6 +138,8 @@ macro_rules! create_config {
64138
// if a license_template_path has been specified, successfully read, parsed and compiled
65139
// into a regex, it will be stored here
66140
pub license_template: Option<Regex>,
141+
// Unstable Options specified on the stable channel
142+
configured_unstable_options: UnstableOptions,
67143
// For each config item, we store a bool indicating whether it has
68144
// been accessed and the value, and a bool whether the option was
69145
// manually initialised, or taken from the default,
@@ -145,21 +221,35 @@ macro_rules! create_config {
145221
ConfigWasSet(self)
146222
}
147223

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
227+
#[allow(unreachable_pub)]
228+
pub fn insert_unstable_options(&mut self, option: &'static str, value: String) {
229+
if option == "abort_on_unrecognised_options" {
230+
return
231+
}
232+
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+
}
240+
}
241+
)+
242+
_ => panic!("Unknown config key in override: {}", option)
243+
}
244+
245+
}
246+
148247
fn fill_from_parsed_config(mut self, parsed: PartialConfig, dir: &Path) -> Config {
149248
$(
150249
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-
}
250+
self.insert_unstable_options(stringify!($i), format!("{:?}", &val));
251+
self.$i.1 = true;
252+
self.$i.2 = val;
163253
}
164254
)+
165255
self.set_heuristics();
@@ -220,6 +310,12 @@ macro_rules! create_config {
220310
}
221311
}
222312

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+
223319
#[allow(unreachable_pub)]
224320
pub fn override_value(&mut self, key: &str, val: &str)
225321
{
@@ -232,6 +328,7 @@ macro_rules! create_config {
232328
stringify!($i),
233329
val,
234330
stringify!($ty)));
331+
self.insert_unstable_options(stringify!($i), val.to_owned());
235332
}
236333
)+
237334
_ => panic!("Unknown config key in override: {}", key)
@@ -438,6 +535,7 @@ macro_rules! create_config {
438535
fn default() -> Config {
439536
Config {
440537
license_template: None,
538+
configured_unstable_options: UnstableOptions::new(),
441539
$(
442540
$i: (Cell::new(false), false, $def, $stb),
443541
)+

0 commit comments

Comments
 (0)