From 42f51d4fd42c95e0c51c3f8742d63db0548cd5a0 Mon Sep 17 00:00:00 2001 From: Frank King Date: Wed, 5 Feb 2025 18:58:29 +0800 Subject: Implment `#[cfg]` and `#[cfg_attr]` in `where` clauses --- src/tools/rustfmt/src/spanned.rs | 7 +- src/tools/rustfmt/src/types.rs | 35 ++++++- .../rustfmt/tests/target/cfg_attribute_in_where.rs | 116 +++++++++++++++++++++ 3 files changed, 151 insertions(+), 7 deletions(-) create mode 100644 src/tools/rustfmt/tests/target/cfg_attribute_in_where.rs (limited to 'src/tools/rustfmt') diff --git a/src/tools/rustfmt/src/spanned.rs b/src/tools/rustfmt/src/spanned.rs index e93eb53cd87..507647566d4 100644 --- a/src/tools/rustfmt/src/spanned.rs +++ b/src/tools/rustfmt/src/spanned.rs @@ -58,6 +58,7 @@ implement_spanned!(ast::ExprField); implement_spanned!(ast::ForeignItem); implement_spanned!(ast::Item); implement_spanned!(ast::Local); +implement_spanned!(ast::WherePredicate); impl Spanned for ast::Stmt { fn span(&self) -> Span { @@ -149,12 +150,6 @@ impl Spanned for ast::FieldDef { } } -impl Spanned for ast::WherePredicate { - fn span(&self) -> Span { - self.span - } -} - impl Spanned for ast::FnRetTy { fn span(&self) -> Span { match *self { diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 0009490e86f..281be957819 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -463,8 +463,9 @@ impl Rewrite for ast::WherePredicate { } fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { + let attrs_str = self.attrs.rewrite_result(context, shape)?; // FIXME: dead spans? - let result = match self.kind { + let pred_str = &match self.kind { ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate { ref bound_generic_params, ref bounded_ty, @@ -499,6 +500,38 @@ impl Rewrite for ast::WherePredicate { } }; + let mut result = String::with_capacity(attrs_str.len() + pred_str.len() + 1); + result.push_str(&attrs_str); + let pred_start = self.span.lo(); + let line_len = last_line_width(&attrs_str) + 1 + first_line_width(&pred_str); + if let Some(last_attr) = self.attrs.last().filter(|last_attr| { + contains_comment(context.snippet(mk_sp(last_attr.span.hi(), pred_start))) + }) { + result = combine_strs_with_missing_comments( + context, + &result, + &pred_str, + mk_sp(last_attr.span.hi(), pred_start), + Shape { + width: shape.width.min(context.config.inline_attribute_width()), + ..shape + }, + !last_attr.is_doc_comment(), + )?; + } else { + if !self.attrs.is_empty() { + if context.config.inline_attribute_width() < line_len + || self.attrs.len() > 1 + || self.attrs.last().is_some_and(|a| a.is_doc_comment()) + { + result.push_str(&shape.indent.to_string_with_newline(context.config)); + } else { + result.push(' '); + } + } + result.push_str(&pred_str); + } + Ok(result) } } diff --git a/src/tools/rustfmt/tests/target/cfg_attribute_in_where.rs b/src/tools/rustfmt/tests/target/cfg_attribute_in_where.rs new file mode 100644 index 00000000000..11f495b1629 --- /dev/null +++ b/src/tools/rustfmt/tests/target/cfg_attribute_in_where.rs @@ -0,0 +1,116 @@ +// rustfmt-inline_attribute_width: 40 + +#![crate_type = "lib"] +#![feature(cfg_attribute_in_where)] +use std::marker::PhantomData; + +#[cfg(a)] +trait TraitA {} + +#[cfg(b)] +trait TraitB {} + +trait A +where + #[cfg = a_very_long_attribute_name] + T: TraitA, + #[cfg = another_very_long_attribute_name] + T: TraitB, +{ + type B + where + #[cfg = a] + // line comment after the attribute + U: TraitA, + #[cfg = b] + /* block comment after the attribute */ + U: TraitB, + #[cfg = a] // short + U: TraitA, + #[cfg = b] /* short */ U: TraitB; + + fn foo(&self) + where + /// line doc comment before the attribute + U: TraitA, + /** line doc block comment before the attribute */ + U: TraitB; +} + +impl A for T +where + #[doc = "line doc before the attribute"] + T: TraitA, + /** short doc */ + T: TraitB, +{ + type B + = () + where + #[doc = "short"] U: TraitA, + #[doc = "short"] + #[cfg = a] + U: TraitB; + + fn foo(&self) + where + #[cfg = a] + #[cfg = b] + U: TraitA, + /// line doc + #[cfg = c] + U: TraitB, + { + } +} + +struct C +where + #[cfg = a] T: TraitA, + #[cfg = b] T: TraitB, +{ + _t: PhantomData, +} + +union D +where + #[cfg = a] T: TraitA, + #[cfg = b] T: TraitB, +{ + _t: PhantomData, +} + +enum E +where + #[cfg = a] T: TraitA, + #[cfg = b] T: TraitB, +{ + E(PhantomData), +} + +#[allow(type_alias_bounds)] +type F +where + #[cfg = a] T: TraitA, + #[cfg = b] T: TraitB, += T; + +impl C +where + #[cfg = a] T: TraitA, + #[cfg = b] T: TraitB, +{ + fn new() + where + #[cfg = a] U: TraitA, + #[cfg = b] U: TraitB, + { + } +} + +fn foo() +where + #[cfg = a] T: TraitA, + #[cfg = b] T: TraitB, +{ +} -- cgit 1.4.1-3-g733a5