1 use crate::config::file_lines::FileLines;
2 use crate::config::macro_names::MacroSelectors;
3 use crate::config::options::{IgnoreList, WidthHeuristics};
5 /// Trait for types that can be used in `Config`.
6 pub(crate) trait ConfigType: Sized {
7 /// Returns hint text for use in `Config::print_docs()`. For enum types, this is a
8 /// pipe-separated list of variants; for other types it returns `<type>`.
9 fn doc_hint() -> String;
11 /// Return `true` if the variant (i.e. value of this type) is stable.
13 /// By default, return true for all values. Enums annotated with `#[config_type]`
14 /// are automatically implemented, based on the `#[unstable_variant]` annotation.
15 fn stable_variant(&self) -> bool {
20 impl ConfigType for bool {
21 fn doc_hint() -> String {
22 String::from("<boolean>")
26 impl ConfigType for usize {
27 fn doc_hint() -> String {
28 String::from("<unsigned integer>")
32 impl ConfigType for isize {
33 fn doc_hint() -> String {
34 String::from("<signed integer>")
38 impl ConfigType for String {
39 fn doc_hint() -> String {
40 String::from("<string>")
44 impl ConfigType for FileLines {
45 fn doc_hint() -> String {
46 String::from("<json>")
50 impl ConfigType for MacroSelectors {
51 fn doc_hint() -> String {
52 String::from("[<string>, ...]")
56 impl ConfigType for WidthHeuristics {
57 fn doc_hint() -> String {
62 impl ConfigType for IgnoreList {
63 fn doc_hint() -> String {
64 String::from("[<string>,..]")
68 macro_rules! create_config {
69 // Options passed in to the macro.
71 // - $i: the ident name of the option
72 // - $ty: the type of the option value
73 // - $def: the default value of the option
74 // - $stb: true if the option is stable
75 // - $dstring: description of the option
76 ($($i:ident: $ty:ty, $def:expr, $stb:expr, $( $dstring:expr ),+ );+ $(;)*) => (
78 use std::collections::HashSet;
81 use serde::{Deserialize, Serialize};
84 #[allow(unreachable_pub)]
86 // For each config item, we store:
88 // - 0: true if the value has been access
89 // - 1: true if the option was manually initialized
90 // - 2: the option value
91 // - 3: true if the option is unstable
92 $($i: (Cell<bool>, bool, $ty, bool)),+
95 // Just like the Config struct but with each property wrapped
96 // as Option<T>. This is used to parse a rustfmt.toml that doesn't
97 // specify all properties of `Config`.
98 // We first parse into `PartialConfig`, then create a default `Config`
99 // and overwrite the properties with corresponding values from `PartialConfig`.
100 #[derive(Deserialize, Serialize, Clone)]
101 #[allow(unreachable_pub)]
102 pub struct PartialConfig {
103 $(pub $i: Option<$ty>),+
106 // Macro hygiene won't allow us to make `set_$i()` methods on Config
107 // for each item, so this struct is used to give the API to set values:
108 // `config.set().option(false)`. It's pretty ugly. Consider replacing
109 // with `config.set_option(false)` if we ever get a stable/usable
110 // `concat_idents!()`.
111 #[allow(unreachable_pub)]
112 pub struct ConfigSetter<'a>(&'a mut Config);
114 impl<'a> ConfigSetter<'a> {
116 #[allow(unreachable_pub)]
117 pub fn $i(&mut self, value: $ty) {
118 (self.0).$i.2 = value;
119 match stringify!($i) {
121 | "use_small_heuristics"
123 | "single_line_if_else_max_width"
124 | "attr_fn_like_width"
126 | "struct_variant_width"
128 | "chain_width" => self.0.set_heuristics(),
129 "merge_imports" => self.0.set_merge_imports(),
130 "fn_args_layout" => self.0.set_fn_args_layout(),
137 // Query each option, returns true if the user set the option, false if
138 // a default was used.
139 #[allow(unreachable_pub)]
140 pub struct ConfigWasSet<'a>(&'a Config);
142 impl<'a> ConfigWasSet<'a> {
144 #[allow(unreachable_pub)]
145 pub fn $i(&self) -> bool {
153 #[allow(unreachable_pub)]
154 pub fn $i(&self) -> $ty {
160 #[allow(unreachable_pub)]
161 pub fn set(&mut self) -> ConfigSetter<'_> {
165 #[allow(unreachable_pub)]
166 pub fn was_set(&self) -> ConfigWasSet<'_> {
170 fn fill_from_parsed_config(mut self, parsed: PartialConfig, dir: &Path) -> Config {
172 if let Some(option_value) = parsed.$i {
173 let option_stable = self.$i.3;
174 if $crate::config::config_type::is_stable_option_and_value(
175 stringify!($i), option_stable, &option_value
178 self.$i.2 = option_value;
182 self.set_heuristics();
183 self.set_ignore(dir);
184 self.set_merge_imports();
185 self.set_fn_args_layout();
189 /// Returns a hash set initialized with every user-facing config option name.
191 pub(crate) fn hash_set() -> HashSet<String> {
192 let mut hash_set = HashSet::new();
194 hash_set.insert(stringify!($i).to_owned());
199 pub(crate) fn is_valid_name(name: &str) -> bool {
202 stringify!($i) => true,
208 #[allow(unreachable_pub)]
209 pub fn is_valid_key_val(key: &str, val: &str) -> bool {
212 stringify!($i) => val.parse::<$ty>().is_ok(),
218 #[allow(unreachable_pub)]
219 pub fn used_options(&self) -> PartialConfig {
222 $i: if self.$i.0.get() {
223 Some(self.$i.2.clone())
231 #[allow(unreachable_pub)]
232 pub fn all_options(&self) -> PartialConfig {
235 $i: Some(self.$i.2.clone()),
240 #[allow(unreachable_pub)]
241 pub fn override_value(&mut self, key: &str, val: &str)
246 let option_value = val.parse::<$ty>()
247 .expect(&format!("Failed to parse override for {} (\"{}\") as a {}",
252 // Users are currently allowed to set unstable
253 // options/variants via the `--config` options override.
255 // There is ongoing discussion about how to move forward here:
256 // https://github.com/rust-lang/rustfmt/pull/5379
258 // For now, do not validate whether the option or value is stable,
259 // just always set it.
261 self.$i.2 = option_value;
264 _ => panic!("Unknown config key in override: {}", key)
269 | "use_small_heuristics"
271 | "single_line_if_else_max_width"
272 | "attr_fn_like_width"
274 | "struct_variant_width"
276 | "chain_width" => self.set_heuristics(),
277 "merge_imports" => self.set_merge_imports(),
278 "fn_args_layout" => self.set_fn_args_layout(),
283 #[allow(unreachable_pub)]
284 pub fn is_hidden_option(name: &str) -> bool {
285 const HIDE_OPTIONS: [&str; 6] = [
293 HIDE_OPTIONS.contains(&name)
296 #[allow(unreachable_pub)]
297 pub fn print_docs(out: &mut dyn Write, include_unstable: bool) {
300 $( let max = cmp::max(max, stringify!($i).len()+1); )+
301 let space_str = " ".repeat(max);
302 writeln!(out, "Configuration Options:").unwrap();
304 if $stb || include_unstable {
305 let name_raw = stringify!($i);
307 if !Config::is_hidden_option(name_raw) {
308 let mut name_out = String::with_capacity(max);
309 for _ in name_raw.len()..max-1 {
312 name_out.push_str(name_raw);
314 let mut default_str = format!("{}", $def);
315 if default_str.is_empty() {
316 default_str = String::from("\"\"");
319 "{}{} Default: {}{}",
323 if !$stb { " (unstable)" } else { "" }).unwrap();
325 writeln!(out, "{}{}", space_str, $dstring).unwrap();
327 writeln!(out).unwrap();
333 fn set_width_heuristics(&mut self, heuristics: WidthHeuristics) {
334 let max_width = self.max_width.2;
335 let get_width_value = |
337 override_value: usize,
338 heuristic_value: usize,
342 return heuristic_value;
344 if override_value > max_width {
346 "`{0}` cannot have a value that exceeds `max_width`. \
347 `{0}` will be set to the same value as `max_width`",
355 let fn_call_width = get_width_value(
356 self.was_set().fn_call_width(),
357 self.fn_call_width.2,
358 heuristics.fn_call_width,
361 self.fn_call_width.2 = fn_call_width;
363 let attr_fn_like_width = get_width_value(
364 self.was_set().attr_fn_like_width(),
365 self.attr_fn_like_width.2,
366 heuristics.attr_fn_like_width,
367 "attr_fn_like_width",
369 self.attr_fn_like_width.2 = attr_fn_like_width;
371 let struct_lit_width = get_width_value(
372 self.was_set().struct_lit_width(),
373 self.struct_lit_width.2,
374 heuristics.struct_lit_width,
377 self.struct_lit_width.2 = struct_lit_width;
379 let struct_variant_width = get_width_value(
380 self.was_set().struct_variant_width(),
381 self.struct_variant_width.2,
382 heuristics.struct_variant_width,
383 "struct_variant_width",
385 self.struct_variant_width.2 = struct_variant_width;
387 let array_width = get_width_value(
388 self.was_set().array_width(),
390 heuristics.array_width,
393 self.array_width.2 = array_width;
395 let chain_width = get_width_value(
396 self.was_set().chain_width(),
398 heuristics.chain_width,
401 self.chain_width.2 = chain_width;
403 let single_line_if_else_max_width = get_width_value(
404 self.was_set().single_line_if_else_max_width(),
405 self.single_line_if_else_max_width.2,
406 heuristics.single_line_if_else_max_width,
407 "single_line_if_else_max_width",
409 self.single_line_if_else_max_width.2 = single_line_if_else_max_width;
412 fn set_heuristics(&mut self) {
413 let max_width = self.max_width.2;
414 match self.use_small_heuristics.2 {
415 Heuristics::Default =>
416 self.set_width_heuristics(WidthHeuristics::scaled(max_width)),
417 Heuristics::Max => self.set_width_heuristics(WidthHeuristics::set(max_width)),
418 Heuristics::Off => self.set_width_heuristics(WidthHeuristics::null()),
422 fn set_ignore(&mut self, dir: &Path) {
423 self.ignore.2.add_prefix(dir);
426 fn set_merge_imports(&mut self) {
427 if self.was_set().merge_imports() {
429 "Warning: the `merge_imports` option is deprecated. \
430 Use `imports_granularity=\"Crate\"` instead"
432 if !self.was_set().imports_granularity() {
433 self.imports_granularity.2 = if self.merge_imports() {
434 ImportGranularity::Crate
436 ImportGranularity::Preserve
442 fn set_fn_args_layout(&mut self) {
443 if self.was_set().fn_args_layout() {
445 "Warning: the `fn_args_layout` option is deprecated. \
446 Use `fn_params_layout`. instead"
448 if !self.was_set().fn_params_layout() {
449 self.fn_params_layout.2 = self.fn_args_layout();
454 #[allow(unreachable_pub)]
455 /// Returns `true` if the config key was explicitly set and is the default value.
456 pub fn is_default(&self, key: &str) -> bool {
458 if let stringify!($i) = key {
459 return self.$i.1 && self.$i.2 == $def;
466 // Template for the default configuration
467 impl Default for Config {
468 fn default() -> Config {
471 $i: (Cell::new(false), false, $def, $stb),
479 pub(crate) fn is_stable_option_and_value<T>(
485 T: PartialEq + std::fmt::Debug + ConfigType,
487 let nightly = crate::is_nightly_channel!();
488 let variant_stable = option_value.stable_variant();
489 match (nightly, option_stable, variant_stable) {
490 // Stable with an unstable option
491 (false, false, _) => {
493 "Warning: can't set `{} = {:?}`, unstable features are only \
494 available in nightly channel.",
495 option_name, option_value
499 // Stable with a stable option, but an unstable variant
500 (false, true, false) => {
502 "Warning: can't set `{} = {:?}`, unstable variants are only \
503 available in nightly channel.",
504 option_name, option_value
508 // Nightly: everything allowed
509 // Stable with stable option and variant: allowed
510 (true, _, _) | (false, true, true) => true,