rustc_ast/
format.rs

1use rustc_data_structures::fx::FxHashMap;
2use rustc_macros::{Decodable, Encodable};
3use rustc_span::{Ident, Span, Symbol};
4
5use crate::Expr;
6use crate::ptr::P;
7use crate::token::LitKind;
8
9// Definitions:
10//
11// format_args!("hello {abc:.xyz$}!!", abc="world");
12// └──────────────────────────────────────────────┘
13//                     FormatArgs
14//
15// format_args!("hello {abc:.xyz$}!!", abc="world");
16//                                     └─────────┘
17//                                      argument
18//
19// format_args!("hello {abc:.xyz$}!!", abc="world");
20//              └───────────────────┘
21//                     template
22//
23// format_args!("hello {abc:.xyz$}!!", abc="world");
24//               └────┘└─────────┘└┘
25//                      pieces
26//
27// format_args!("hello {abc:.xyz$}!!", abc="world");
28//               └────┘           └┘
29//                   literal pieces
30//
31// format_args!("hello {abc:.xyz$}!!", abc="world");
32//                     └─────────┘
33//                     placeholder
34//
35// format_args!("hello {abc:.xyz$}!!", abc="world");
36//                      └─┘  └─┘
37//                      positions (could be names, numbers, empty, or `*`)
38
39/// (Parsed) format args.
40///
41/// Basically the "AST" for a complete `format_args!()`.
42///
43/// E.g., `format_args!("hello {name}");`.
44#[derive(Clone, Encodable, Decodable, Debug)]
45pub struct FormatArgs {
46    pub span: Span,
47    pub template: Vec<FormatArgsPiece>,
48    pub arguments: FormatArguments,
49    /// The raw, un-split format string literal, with no escaping or processing.
50    ///
51    /// Generally only useful for lints that care about the raw bytes the user wrote.
52    pub uncooked_fmt_str: (LitKind, Symbol),
53}
54
55/// A piece of a format template string.
56///
57/// E.g. "hello" or "{name}".
58#[derive(Clone, Encodable, Decodable, Debug)]
59pub enum FormatArgsPiece {
60    Literal(Symbol),
61    Placeholder(FormatPlaceholder),
62}
63
64/// The arguments to format_args!().
65///
66/// E.g. `1, 2, name="ferris", n=3`,
67/// but also implicit captured arguments like `x` in `format_args!("{x}")`.
68#[derive(Clone, Encodable, Decodable, Debug)]
69pub struct FormatArguments {
70    arguments: Vec<FormatArgument>,
71    num_unnamed_args: usize,
72    num_explicit_args: usize,
73    names: FxHashMap<Symbol, usize>,
74}
75
76impl FormatArguments {
77    pub fn new() -> Self {
78        Self {
79            arguments: Vec::new(),
80            names: FxHashMap::default(),
81            num_unnamed_args: 0,
82            num_explicit_args: 0,
83        }
84    }
85
86    pub fn add(&mut self, arg: FormatArgument) -> usize {
87        let index = self.arguments.len();
88        if let Some(name) = arg.kind.ident() {
89            self.names.insert(name.name, index);
90        } else if self.names.is_empty() {
91            // Only count the unnamed args before the first named arg.
92            // (Any later ones are errors.)
93            self.num_unnamed_args += 1;
94        }
95        if !matches!(arg.kind, FormatArgumentKind::Captured(..)) {
96            // This is an explicit argument.
97            // Make sure that all arguments so far are explicit.
98            assert_eq!(
99                self.num_explicit_args,
100                self.arguments.len(),
101                "captured arguments must be added last"
102            );
103            self.num_explicit_args += 1;
104        }
105        self.arguments.push(arg);
106        index
107    }
108
109    pub fn by_name(&self, name: Symbol) -> Option<(usize, &FormatArgument)> {
110        let i = *self.names.get(&name)?;
111        Some((i, &self.arguments[i]))
112    }
113
114    pub fn by_index(&self, i: usize) -> Option<&FormatArgument> {
115        (i < self.num_explicit_args).then(|| &self.arguments[i])
116    }
117
118    pub fn unnamed_args(&self) -> &[FormatArgument] {
119        &self.arguments[..self.num_unnamed_args]
120    }
121
122    pub fn named_args(&self) -> &[FormatArgument] {
123        &self.arguments[self.num_unnamed_args..self.num_explicit_args]
124    }
125
126    pub fn explicit_args(&self) -> &[FormatArgument] {
127        &self.arguments[..self.num_explicit_args]
128    }
129
130    pub fn all_args(&self) -> &[FormatArgument] {
131        &self.arguments[..]
132    }
133
134    pub fn all_args_mut(&mut self) -> &mut Vec<FormatArgument> {
135        &mut self.arguments
136    }
137}
138
139#[derive(Clone, Encodable, Decodable, Debug)]
140pub struct FormatArgument {
141    pub kind: FormatArgumentKind,
142    pub expr: P<Expr>,
143}
144
145#[derive(Clone, Encodable, Decodable, Debug)]
146pub enum FormatArgumentKind {
147    /// `format_args(…, arg)`
148    Normal,
149    /// `format_args(…, arg = 1)`
150    Named(Ident),
151    /// `format_args("… {arg} …")`
152    Captured(Ident),
153}
154
155impl FormatArgumentKind {
156    pub fn ident(&self) -> Option<Ident> {
157        match self {
158            &Self::Normal => None,
159            &Self::Named(id) => Some(id),
160            &Self::Captured(id) => Some(id),
161        }
162    }
163}
164
165#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
166pub struct FormatPlaceholder {
167    /// Index into [`FormatArgs::arguments`].
168    pub argument: FormatArgPosition,
169    /// The span inside the format string for the full `{…}` placeholder.
170    pub span: Option<Span>,
171    /// `{}`, `{:?}`, or `{:x}`, etc.
172    pub format_trait: FormatTrait,
173    /// `{}` or `{:.5}` or `{:-^20}`, etc.
174    pub format_options: FormatOptions,
175}
176
177#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
178pub struct FormatArgPosition {
179    /// Which argument this position refers to (Ok),
180    /// or would've referred to if it existed (Err).
181    pub index: Result<usize, usize>,
182    /// What kind of position this is. See [`FormatArgPositionKind`].
183    pub kind: FormatArgPositionKind,
184    /// The span of the name or number.
185    pub span: Option<Span>,
186}
187
188#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
189pub enum FormatArgPositionKind {
190    /// `{}` or `{:.*}`
191    Implicit,
192    /// `{1}` or `{:1$}` or `{:.1$}`
193    Number,
194    /// `{a}` or `{:a$}` or `{:.a$}`
195    Named,
196}
197
198#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq, Hash)]
199pub enum FormatTrait {
200    /// `{}`
201    Display,
202    /// `{:?}`
203    Debug,
204    /// `{:e}`
205    LowerExp,
206    /// `{:E}`
207    UpperExp,
208    /// `{:o}`
209    Octal,
210    /// `{:p}`
211    Pointer,
212    /// `{:b}`
213    Binary,
214    /// `{:x}`
215    LowerHex,
216    /// `{:X}`
217    UpperHex,
218}
219
220#[derive(Clone, Encodable, Decodable, Default, Debug, PartialEq, Eq)]
221pub struct FormatOptions {
222    /// The width. E.g. `{:5}` or `{:width$}`.
223    pub width: Option<FormatCount>,
224    /// The precision. E.g. `{:.5}` or `{:.precision$}`.
225    pub precision: Option<FormatCount>,
226    /// The alignment. E.g. `{:>}` or `{:<}` or `{:^}`.
227    pub alignment: Option<FormatAlignment>,
228    /// The fill character. E.g. the `.` in `{:.>10}`.
229    pub fill: Option<char>,
230    /// The `+` or `-` flag.
231    pub sign: Option<FormatSign>,
232    /// The `#` flag.
233    pub alternate: bool,
234    /// The `0` flag. E.g. the `0` in `{:02x}`.
235    pub zero_pad: bool,
236    /// The `x` or `X` flag (for `Debug` only). E.g. the `x` in `{:x?}`.
237    pub debug_hex: Option<FormatDebugHex>,
238}
239
240#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
241pub enum FormatSign {
242    /// The `+` flag.
243    Plus,
244    /// The `-` flag.
245    Minus,
246}
247
248#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
249pub enum FormatDebugHex {
250    /// The `x` flag in `{:x?}`.
251    Lower,
252    /// The `X` flag in `{:X?}`.
253    Upper,
254}
255
256#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
257pub enum FormatAlignment {
258    /// `{:<}`
259    Left,
260    /// `{:>}`
261    Right,
262    /// `{:^}`
263    Center,
264}
265
266#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
267pub enum FormatCount {
268    /// `{:5}` or `{:.5}`
269    Literal(usize),
270    /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc.
271    Argument(FormatArgPosition),
272}