• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 mod delimited;
2 mod expr;
3 mod item;
4 
5 use crate::pp::Breaks::{Consistent, Inconsistent};
6 use crate::pp::{self, Breaks};
7 use rustc_ast::attr::AttrIdGenerator;
8 use rustc_ast::ptr::P;
9 use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, Token, TokenKind};
10 use rustc_ast::tokenstream::{TokenStream, TokenTree};
11 use rustc_ast::util::classify;
12 use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
13 use rustc_ast::util::parser;
14 use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind};
15 use rustc_ast::{attr, BindingAnnotation, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term};
16 use rustc_ast::{GenericArg, GenericBound, SelfKind, TraitBoundModifier};
17 use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
18 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
19 use rustc_span::edition::Edition;
20 use rustc_span::source_map::{SourceMap, Spanned};
21 use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol};
22 use rustc_span::{BytePos, FileName, Span, DUMMY_SP};
23 use std::borrow::Cow;
24 use thin_vec::ThinVec;
25 
26 pub use self::delimited::IterDelimited;
27 
28 pub enum MacHeader<'a> {
29     Path(&'a ast::Path),
30     Keyword(&'static str),
31 }
32 
33 pub enum AnnNode<'a> {
34     Ident(&'a Ident),
35     Name(&'a Symbol),
36     Block(&'a ast::Block),
37     Item(&'a ast::Item),
38     SubItem(ast::NodeId),
39     Expr(&'a ast::Expr),
40     Pat(&'a ast::Pat),
41     Crate(&'a ast::Crate),
42 }
43 
44 pub trait PpAnn {
pre(&self, _state: &mut State<'_>, _node: AnnNode<'_>)45     fn pre(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
post(&self, _state: &mut State<'_>, _node: AnnNode<'_>)46     fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
47 }
48 
49 #[derive(Copy, Clone)]
50 pub struct NoAnn;
51 
52 impl PpAnn for NoAnn {}
53 
54 pub struct Comments<'a> {
55     sm: &'a SourceMap,
56     comments: Vec<Comment>,
57     current: usize,
58 }
59 
60 impl<'a> Comments<'a> {
new(sm: &'a SourceMap, filename: FileName, input: String) -> Comments<'a>61     pub fn new(sm: &'a SourceMap, filename: FileName, input: String) -> Comments<'a> {
62         let comments = gather_comments(sm, filename, input);
63         Comments { sm, comments, current: 0 }
64     }
65 
66     // FIXME: This shouldn't probably clone lmao
next(&self) -> Option<Comment>67     pub fn next(&self) -> Option<Comment> {
68         self.comments.get(self.current).cloned()
69     }
70 
trailing_comment( &self, span: rustc_span::Span, next_pos: Option<BytePos>, ) -> Option<Comment>71     pub fn trailing_comment(
72         &self,
73         span: rustc_span::Span,
74         next_pos: Option<BytePos>,
75     ) -> Option<Comment> {
76         if let Some(cmnt) = self.next() {
77             if cmnt.style != CommentStyle::Trailing {
78                 return None;
79             }
80             let span_line = self.sm.lookup_char_pos(span.hi());
81             let comment_line = self.sm.lookup_char_pos(cmnt.pos);
82             let next = next_pos.unwrap_or_else(|| cmnt.pos + BytePos(1));
83             if span.hi() < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line {
84                 return Some(cmnt);
85             }
86         }
87 
88         None
89     }
90 }
91 
92 pub struct State<'a> {
93     pub s: pp::Printer,
94     comments: Option<Comments<'a>>,
95     ann: &'a (dyn PpAnn + 'a),
96 }
97 
98 pub(crate) const INDENT_UNIT: isize = 4;
99 
100 /// Requires you to pass an input filename and reader so that
101 /// it can scan the input text for comments to copy forward.
print_crate<'a>( sm: &'a SourceMap, krate: &ast::Crate, filename: FileName, input: String, ann: &'a dyn PpAnn, is_expanded: bool, edition: Edition, g: &AttrIdGenerator, ) -> String102 pub fn print_crate<'a>(
103     sm: &'a SourceMap,
104     krate: &ast::Crate,
105     filename: FileName,
106     input: String,
107     ann: &'a dyn PpAnn,
108     is_expanded: bool,
109     edition: Edition,
110     g: &AttrIdGenerator,
111 ) -> String {
112     let mut s =
113         State { s: pp::Printer::new(), comments: Some(Comments::new(sm, filename, input)), ann };
114 
115     if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) {
116         // We need to print `#![no_std]` (and its feature gate) so that
117         // compiling pretty-printed source won't inject libstd again.
118         // However, we don't want these attributes in the AST because
119         // of the feature gate, so we fake them up here.
120 
121         // `#![feature(prelude_import)]`
122         let fake_attr = attr::mk_attr_nested_word(
123             g,
124             ast::AttrStyle::Inner,
125             sym::feature,
126             sym::prelude_import,
127             DUMMY_SP,
128         );
129         s.print_attribute(&fake_attr);
130 
131         // Currently, in Rust 2018 we don't have `extern crate std;` at the crate
132         // root, so this is not needed, and actually breaks things.
133         if edition.is_rust_2015() {
134             // `#![no_std]`
135             let fake_attr = attr::mk_attr_word(g, ast::AttrStyle::Inner, sym::no_std, DUMMY_SP);
136             s.print_attribute(&fake_attr);
137         }
138     }
139 
140     s.print_inner_attributes(&krate.attrs);
141     for item in &krate.items {
142         s.print_item(item);
143     }
144     s.print_remaining_comments();
145     s.ann.post(&mut s, AnnNode::Crate(krate));
146     s.s.eof()
147 }
148 
149 /// This makes printed token streams look slightly nicer,
150 /// and also addresses some specific regressions described in #63896 and #73345.
tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool151 fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
152     if let TokenTree::Token(token, _) = prev {
153         if matches!(token.kind, token::Dot | token::Dollar) {
154             return false;
155         }
156         if let token::DocComment(comment_kind, ..) = token.kind {
157             return comment_kind != CommentKind::Line;
158         }
159     }
160     match tt {
161         TokenTree::Token(token, _) => !matches!(token.kind, token::Comma | token::Not | token::Dot),
162         TokenTree::Delimited(_, Delimiter::Parenthesis, _) => {
163             !matches!(prev, TokenTree::Token(Token { kind: token::Ident(..), .. }, _))
164         }
165         TokenTree::Delimited(_, Delimiter::Bracket, _) => {
166             !matches!(prev, TokenTree::Token(Token { kind: token::Pound, .. }, _))
167         }
168         TokenTree::Delimited(..) => true,
169     }
170 }
171 
binop_to_string(op: BinOpToken) -> &'static str172 fn binop_to_string(op: BinOpToken) -> &'static str {
173     match op {
174         token::Plus => "+",
175         token::Minus => "-",
176         token::Star => "*",
177         token::Slash => "/",
178         token::Percent => "%",
179         token::Caret => "^",
180         token::And => "&",
181         token::Or => "|",
182         token::Shl => "<<",
183         token::Shr => ">>",
184     }
185 }
186 
doc_comment_to_string( comment_kind: CommentKind, attr_style: ast::AttrStyle, data: Symbol, ) -> String187 fn doc_comment_to_string(
188     comment_kind: CommentKind,
189     attr_style: ast::AttrStyle,
190     data: Symbol,
191 ) -> String {
192     match (comment_kind, attr_style) {
193         (CommentKind::Line, ast::AttrStyle::Outer) => format!("///{data}"),
194         (CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{data}"),
195         (CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{data}*/"),
196         (CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{data}*/"),
197     }
198 }
199 
literal_to_string(lit: token::Lit) -> String200 pub fn literal_to_string(lit: token::Lit) -> String {
201     let token::Lit { kind, symbol, suffix } = lit;
202     let mut out = match kind {
203         token::Byte => format!("b'{symbol}'"),
204         token::Char => format!("'{symbol}'"),
205         token::Str => format!("\"{symbol}\""),
206         token::StrRaw(n) => {
207             format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
208         }
209         token::ByteStr => format!("b\"{symbol}\""),
210         token::ByteStrRaw(n) => {
211             format!("br{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
212         }
213         token::CStr => format!("c\"{symbol}\""),
214         token::CStrRaw(n) => {
215             format!("cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize))
216         }
217         token::Integer | token::Float | token::Bool | token::Err => symbol.to_string(),
218     };
219 
220     if let Some(suffix) = suffix {
221         out.push_str(suffix.as_str())
222     }
223 
224     out
225 }
226 
227 impl std::ops::Deref for State<'_> {
228     type Target = pp::Printer;
deref(&self) -> &Self::Target229     fn deref(&self) -> &Self::Target {
230         &self.s
231     }
232 }
233 
234 impl std::ops::DerefMut for State<'_> {
deref_mut(&mut self) -> &mut Self::Target235     fn deref_mut(&mut self) -> &mut Self::Target {
236         &mut self.s
237     }
238 }
239 
240 pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::DerefMut {
comments(&mut self) -> &mut Option<Comments<'a>>241     fn comments(&mut self) -> &mut Option<Comments<'a>>;
print_ident(&mut self, ident: Ident)242     fn print_ident(&mut self, ident: Ident);
print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool)243     fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
244 
strsep<T, F>( &mut self, sep: &'static str, space_before: bool, b: Breaks, elts: &[T], mut op: F, ) where F: FnMut(&mut Self, &T),245     fn strsep<T, F>(
246         &mut self,
247         sep: &'static str,
248         space_before: bool,
249         b: Breaks,
250         elts: &[T],
251         mut op: F,
252     ) where
253         F: FnMut(&mut Self, &T),
254     {
255         self.rbox(0, b);
256         if let Some((first, rest)) = elts.split_first() {
257             op(self, first);
258             for elt in rest {
259                 if space_before {
260                     self.space();
261                 }
262                 self.word_space(sep);
263                 op(self, elt);
264             }
265         }
266         self.end();
267     }
268 
commasep<T, F>(&mut self, b: Breaks, elts: &[T], op: F) where F: FnMut(&mut Self, &T),269     fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], op: F)
270     where
271         F: FnMut(&mut Self, &T),
272     {
273         self.strsep(",", false, b, elts, op)
274     }
275 
maybe_print_comment(&mut self, pos: BytePos) -> bool276     fn maybe_print_comment(&mut self, pos: BytePos) -> bool {
277         let mut has_comment = false;
278         while let Some(cmnt) = self.next_comment() {
279             if cmnt.pos < pos {
280                 has_comment = true;
281                 self.print_comment(&cmnt);
282             } else {
283                 break;
284             }
285         }
286         has_comment
287     }
288 
print_comment(&mut self, cmnt: &Comment)289     fn print_comment(&mut self, cmnt: &Comment) {
290         match cmnt.style {
291             CommentStyle::Mixed => {
292                 if !self.is_beginning_of_line() {
293                     self.zerobreak();
294                 }
295                 if let Some((last, lines)) = cmnt.lines.split_last() {
296                     self.ibox(0);
297 
298                     for line in lines {
299                         self.word(line.clone());
300                         self.hardbreak()
301                     }
302 
303                     self.word(last.clone());
304                     self.space();
305 
306                     self.end();
307                 }
308                 self.zerobreak()
309             }
310             CommentStyle::Isolated => {
311                 self.hardbreak_if_not_bol();
312                 for line in &cmnt.lines {
313                     // Don't print empty lines because they will end up as trailing
314                     // whitespace.
315                     if !line.is_empty() {
316                         self.word(line.clone());
317                     }
318                     self.hardbreak();
319                 }
320             }
321             CommentStyle::Trailing => {
322                 if !self.is_beginning_of_line() {
323                     self.word(" ");
324                 }
325                 if cmnt.lines.len() == 1 {
326                     self.word(cmnt.lines[0].clone());
327                     self.hardbreak()
328                 } else {
329                     self.visual_align();
330                     for line in &cmnt.lines {
331                         if !line.is_empty() {
332                             self.word(line.clone());
333                         }
334                         self.hardbreak();
335                     }
336                     self.end();
337                 }
338             }
339             CommentStyle::BlankLine => {
340                 // We need to do at least one, possibly two hardbreaks.
341                 let twice = match self.last_token() {
342                     Some(pp::Token::String(s)) => ";" == s,
343                     Some(pp::Token::Begin(_)) => true,
344                     Some(pp::Token::End) => true,
345                     _ => false,
346                 };
347                 if twice {
348                     self.hardbreak();
349                 }
350                 self.hardbreak();
351             }
352         }
353         if let Some(cmnts) = self.comments() {
354             cmnts.current += 1;
355         }
356     }
357 
next_comment(&mut self) -> Option<Comment>358     fn next_comment(&mut self) -> Option<Comment> {
359         self.comments().as_mut().and_then(|c| c.next())
360     }
361 
maybe_print_trailing_comment(&mut self, span: rustc_span::Span, next_pos: Option<BytePos>)362     fn maybe_print_trailing_comment(&mut self, span: rustc_span::Span, next_pos: Option<BytePos>) {
363         if let Some(cmnts) = self.comments() {
364             if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
365                 self.print_comment(&cmnt);
366             }
367         }
368     }
369 
print_remaining_comments(&mut self)370     fn print_remaining_comments(&mut self) {
371         // If there aren't any remaining comments, then we need to manually
372         // make sure there is a line break at the end.
373         if self.next_comment().is_none() {
374             self.hardbreak();
375         }
376         while let Some(cmnt) = self.next_comment() {
377             self.print_comment(&cmnt)
378         }
379     }
380 
print_meta_item_lit(&mut self, lit: &ast::MetaItemLit)381     fn print_meta_item_lit(&mut self, lit: &ast::MetaItemLit) {
382         self.print_token_literal(lit.as_token_lit(), lit.span)
383     }
384 
print_token_literal(&mut self, token_lit: token::Lit, span: Span)385     fn print_token_literal(&mut self, token_lit: token::Lit, span: Span) {
386         self.maybe_print_comment(span.lo());
387         self.word(token_lit.to_string())
388     }
389 
print_string(&mut self, st: &str, style: ast::StrStyle)390     fn print_string(&mut self, st: &str, style: ast::StrStyle) {
391         let st = match style {
392             ast::StrStyle::Cooked => format!("\"{}\"", st.escape_debug()),
393             ast::StrStyle::Raw(n) => {
394                 format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = st)
395             }
396         };
397         self.word(st)
398     }
399 
print_symbol(&mut self, sym: Symbol, style: ast::StrStyle)400     fn print_symbol(&mut self, sym: Symbol, style: ast::StrStyle) {
401         self.print_string(sym.as_str(), style);
402     }
403 
print_inner_attributes(&mut self, attrs: &[ast::Attribute]) -> bool404     fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) -> bool {
405         self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
406     }
407 
print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) -> bool408     fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) -> bool {
409         self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false)
410     }
411 
print_outer_attributes(&mut self, attrs: &[ast::Attribute]) -> bool412     fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) -> bool {
413         self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
414     }
415 
print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool416     fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool {
417         self.print_either_attributes(attrs, ast::AttrStyle::Inner, true, true)
418     }
419 
print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool420     fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool {
421         self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true)
422     }
423 
print_either_attributes( &mut self, attrs: &[ast::Attribute], kind: ast::AttrStyle, is_inline: bool, trailing_hardbreak: bool, ) -> bool424     fn print_either_attributes(
425         &mut self,
426         attrs: &[ast::Attribute],
427         kind: ast::AttrStyle,
428         is_inline: bool,
429         trailing_hardbreak: bool,
430     ) -> bool {
431         let mut printed = false;
432         for attr in attrs {
433             if attr.style == kind {
434                 self.print_attribute_inline(attr, is_inline);
435                 if is_inline {
436                     self.nbsp();
437                 }
438                 printed = true;
439             }
440         }
441         if printed && trailing_hardbreak && !is_inline {
442             self.hardbreak_if_not_bol();
443         }
444         printed
445     }
446 
print_attribute(&mut self, attr: &ast::Attribute)447     fn print_attribute(&mut self, attr: &ast::Attribute) {
448         self.print_attribute_inline(attr, false)
449     }
450 
print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool)451     fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) {
452         if !is_inline {
453             self.hardbreak_if_not_bol();
454         }
455         self.maybe_print_comment(attr.span.lo());
456         match &attr.kind {
457             ast::AttrKind::Normal(normal) => {
458                 match attr.style {
459                     ast::AttrStyle::Inner => self.word("#!["),
460                     ast::AttrStyle::Outer => self.word("#["),
461                 }
462                 self.print_attr_item(&normal.item, attr.span);
463                 self.word("]");
464             }
465             ast::AttrKind::DocComment(comment_kind, data) => {
466                 self.word(doc_comment_to_string(*comment_kind, attr.style, *data));
467                 self.hardbreak()
468             }
469         }
470     }
471 
print_attr_item(&mut self, item: &ast::AttrItem, span: Span)472     fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
473         self.ibox(0);
474         match &item.args {
475             AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common(
476                 Some(MacHeader::Path(&item.path)),
477                 false,
478                 None,
479                 delim.to_token(),
480                 tokens,
481                 true,
482                 span,
483             ),
484             AttrArgs::Empty => {
485                 self.print_path(&item.path, false, 0);
486             }
487             AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => {
488                 self.print_path(&item.path, false, 0);
489                 self.space();
490                 self.word_space("=");
491                 let token_str = self.expr_to_string(expr);
492                 self.word(token_str);
493             }
494             AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => {
495                 self.print_path(&item.path, false, 0);
496                 self.space();
497                 self.word_space("=");
498                 let token_str = self.meta_item_lit_to_string(lit);
499                 self.word(token_str);
500             }
501         }
502         self.end();
503     }
504 
print_meta_list_item(&mut self, item: &ast::NestedMetaItem)505     fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) {
506         match item {
507             ast::NestedMetaItem::MetaItem(mi) => self.print_meta_item(mi),
508             ast::NestedMetaItem::Lit(lit) => self.print_meta_item_lit(lit),
509         }
510     }
511 
print_meta_item(&mut self, item: &ast::MetaItem)512     fn print_meta_item(&mut self, item: &ast::MetaItem) {
513         self.ibox(INDENT_UNIT);
514         match &item.kind {
515             ast::MetaItemKind::Word => self.print_path(&item.path, false, 0),
516             ast::MetaItemKind::NameValue(value) => {
517                 self.print_path(&item.path, false, 0);
518                 self.space();
519                 self.word_space("=");
520                 self.print_meta_item_lit(value);
521             }
522             ast::MetaItemKind::List(items) => {
523                 self.print_path(&item.path, false, 0);
524                 self.popen();
525                 self.commasep(Consistent, items, |s, i| s.print_meta_list_item(i));
526                 self.pclose();
527             }
528         }
529         self.end();
530     }
531 
532     /// This doesn't deserve to be called "pretty" printing, but it should be
533     /// meaning-preserving. A quick hack that might help would be to look at the
534     /// spans embedded in the TTs to decide where to put spaces and newlines.
535     /// But it'd be better to parse these according to the grammar of the
536     /// appropriate macro, transcribe back into the grammar we just parsed from,
537     /// and then pretty-print the resulting AST nodes (so, e.g., we print
538     /// expression arguments as expressions). It can be done! I think.
print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool)539     fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) {
540         match tt {
541             TokenTree::Token(token, _) => {
542                 let token_str = self.token_to_string_ext(token, convert_dollar_crate);
543                 self.word(token_str);
544                 if let token::DocComment(..) = token.kind {
545                     self.hardbreak()
546                 }
547             }
548             TokenTree::Delimited(dspan, delim, tts) => {
549                 self.print_mac_common(
550                     None,
551                     false,
552                     None,
553                     *delim,
554                     tts,
555                     convert_dollar_crate,
556                     dspan.entire(),
557                 );
558             }
559         }
560     }
561 
print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool)562     fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
563         let mut iter = tts.trees().peekable();
564         while let Some(tt) = iter.next() {
565             self.print_tt(tt, convert_dollar_crate);
566             if let Some(next) = iter.peek() {
567                 if tt_prepend_space(next, tt) {
568                     self.space();
569                 }
570             }
571         }
572     }
573 
print_mac_common( &mut self, header: Option<MacHeader<'_>>, has_bang: bool, ident: Option<Ident>, delim: Delimiter, tts: &TokenStream, convert_dollar_crate: bool, span: Span, )574     fn print_mac_common(
575         &mut self,
576         header: Option<MacHeader<'_>>,
577         has_bang: bool,
578         ident: Option<Ident>,
579         delim: Delimiter,
580         tts: &TokenStream,
581         convert_dollar_crate: bool,
582         span: Span,
583     ) {
584         if delim == Delimiter::Brace {
585             self.cbox(INDENT_UNIT);
586         }
587         match header {
588             Some(MacHeader::Path(path)) => self.print_path(path, false, 0),
589             Some(MacHeader::Keyword(kw)) => self.word(kw),
590             None => {}
591         }
592         if has_bang {
593             self.word("!");
594         }
595         if let Some(ident) = ident {
596             self.nbsp();
597             self.print_ident(ident);
598         }
599         match delim {
600             Delimiter::Brace => {
601                 if header.is_some() || has_bang || ident.is_some() {
602                     self.nbsp();
603                 }
604                 self.word("{");
605                 if !tts.is_empty() {
606                     self.space();
607                 }
608                 self.ibox(0);
609                 self.print_tts(tts, convert_dollar_crate);
610                 self.end();
611                 let empty = tts.is_empty();
612                 self.bclose(span, empty);
613             }
614             delim => {
615                 let token_str = self.token_kind_to_string(&token::OpenDelim(delim));
616                 self.word(token_str);
617                 self.ibox(0);
618                 self.print_tts(tts, convert_dollar_crate);
619                 self.end();
620                 let token_str = self.token_kind_to_string(&token::CloseDelim(delim));
621                 self.word(token_str);
622             }
623         }
624     }
625 
print_mac_def( &mut self, macro_def: &ast::MacroDef, ident: &Ident, sp: Span, print_visibility: impl FnOnce(&mut Self), )626     fn print_mac_def(
627         &mut self,
628         macro_def: &ast::MacroDef,
629         ident: &Ident,
630         sp: Span,
631         print_visibility: impl FnOnce(&mut Self),
632     ) {
633         let (kw, has_bang) = if macro_def.macro_rules {
634             ("macro_rules", true)
635         } else {
636             print_visibility(self);
637             ("macro", false)
638         };
639         self.print_mac_common(
640             Some(MacHeader::Keyword(kw)),
641             has_bang,
642             Some(*ident),
643             macro_def.body.delim.to_token(),
644             &macro_def.body.tokens.clone(),
645             true,
646             sp,
647         );
648         if macro_def.body.need_semicolon() {
649             self.word(";");
650         }
651     }
652 
print_path(&mut self, path: &ast::Path, colons_before_params: bool, depth: usize)653     fn print_path(&mut self, path: &ast::Path, colons_before_params: bool, depth: usize) {
654         self.maybe_print_comment(path.span.lo());
655 
656         for (i, segment) in path.segments[..path.segments.len() - depth].iter().enumerate() {
657             if i > 0 {
658                 self.word("::")
659             }
660             self.print_path_segment(segment, colons_before_params);
661         }
662     }
663 
print_path_segment(&mut self, segment: &ast::PathSegment, colons_before_params: bool)664     fn print_path_segment(&mut self, segment: &ast::PathSegment, colons_before_params: bool) {
665         if segment.ident.name != kw::PathRoot {
666             self.print_ident(segment.ident);
667             if let Some(args) = &segment.args {
668                 self.print_generic_args(args, colons_before_params);
669             }
670         }
671     }
672 
head<S: Into<Cow<'static, str>>>(&mut self, w: S)673     fn head<S: Into<Cow<'static, str>>>(&mut self, w: S) {
674         let w = w.into();
675         // Outer-box is consistent.
676         self.cbox(INDENT_UNIT);
677         // Head-box is inconsistent.
678         self.ibox(0);
679         // Keyword that starts the head.
680         if !w.is_empty() {
681             self.word_nbsp(w);
682         }
683     }
684 
bopen(&mut self)685     fn bopen(&mut self) {
686         self.word("{");
687         self.end(); // Close the head-box.
688     }
689 
bclose_maybe_open(&mut self, span: rustc_span::Span, empty: bool, close_box: bool)690     fn bclose_maybe_open(&mut self, span: rustc_span::Span, empty: bool, close_box: bool) {
691         let has_comment = self.maybe_print_comment(span.hi());
692         if !empty || has_comment {
693             self.break_offset_if_not_bol(1, -INDENT_UNIT);
694         }
695         self.word("}");
696         if close_box {
697             self.end(); // Close the outer-box.
698         }
699     }
700 
bclose(&mut self, span: rustc_span::Span, empty: bool)701     fn bclose(&mut self, span: rustc_span::Span, empty: bool) {
702         let close_box = true;
703         self.bclose_maybe_open(span, empty, close_box)
704     }
705 
break_offset_if_not_bol(&mut self, n: usize, off: isize)706     fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
707         if !self.is_beginning_of_line() {
708             self.break_offset(n, off)
709         } else if off != 0 {
710             if let Some(last_token) = self.last_token_still_buffered() {
711                 if last_token.is_hardbreak_tok() {
712                     // We do something pretty sketchy here: tuck the nonzero
713                     // offset-adjustment we were going to deposit along with the
714                     // break into the previous hardbreak.
715                     self.replace_last_token_still_buffered(pp::Printer::hardbreak_tok_offset(off));
716                 }
717             }
718         }
719     }
720 
nonterminal_to_string(&self, nt: &Nonterminal) -> String721     fn nonterminal_to_string(&self, nt: &Nonterminal) -> String {
722         match nt {
723             token::NtExpr(e) => self.expr_to_string(e),
724             token::NtMeta(e) => self.attr_item_to_string(e),
725             token::NtTy(e) => self.ty_to_string(e),
726             token::NtPath(e) => self.path_to_string(e),
727             token::NtItem(e) => self.item_to_string(e),
728             token::NtBlock(e) => self.block_to_string(e),
729             token::NtStmt(e) => self.stmt_to_string(e),
730             token::NtPat(e) => self.pat_to_string(e),
731             token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(*e, *is_raw).to_string(),
732             token::NtLifetime(e) => e.to_string(),
733             token::NtLiteral(e) => self.expr_to_string(e),
734             token::NtVis(e) => self.vis_to_string(e),
735         }
736     }
737 
738     /// Print the token kind precisely, without converting `$crate` into its respective crate name.
token_kind_to_string(&self, tok: &TokenKind) -> Cow<'static, str>739     fn token_kind_to_string(&self, tok: &TokenKind) -> Cow<'static, str> {
740         self.token_kind_to_string_ext(tok, None)
741     }
742 
token_kind_to_string_ext( &self, tok: &TokenKind, convert_dollar_crate: Option<Span>, ) -> Cow<'static, str>743     fn token_kind_to_string_ext(
744         &self,
745         tok: &TokenKind,
746         convert_dollar_crate: Option<Span>,
747     ) -> Cow<'static, str> {
748         match *tok {
749             token::Eq => "=".into(),
750             token::Lt => "<".into(),
751             token::Le => "<=".into(),
752             token::EqEq => "==".into(),
753             token::Ne => "!=".into(),
754             token::Ge => ">=".into(),
755             token::Gt => ">".into(),
756             token::Not => "!".into(),
757             token::Tilde => "~".into(),
758             token::OrOr => "||".into(),
759             token::AndAnd => "&&".into(),
760             token::BinOp(op) => binop_to_string(op).into(),
761             token::BinOpEq(op) => format!("{}=", binop_to_string(op)).into(),
762 
763             /* Structural symbols */
764             token::At => "@".into(),
765             token::Dot => ".".into(),
766             token::DotDot => "..".into(),
767             token::DotDotDot => "...".into(),
768             token::DotDotEq => "..=".into(),
769             token::Comma => ",".into(),
770             token::Semi => ";".into(),
771             token::Colon => ":".into(),
772             token::ModSep => "::".into(),
773             token::RArrow => "->".into(),
774             token::LArrow => "<-".into(),
775             token::FatArrow => "=>".into(),
776             token::OpenDelim(Delimiter::Parenthesis) => "(".into(),
777             token::CloseDelim(Delimiter::Parenthesis) => ")".into(),
778             token::OpenDelim(Delimiter::Bracket) => "[".into(),
779             token::CloseDelim(Delimiter::Bracket) => "]".into(),
780             token::OpenDelim(Delimiter::Brace) => "{".into(),
781             token::CloseDelim(Delimiter::Brace) => "}".into(),
782             token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible) => {
783                 "".into()
784             }
785             token::Pound => "#".into(),
786             token::Dollar => "$".into(),
787             token::Question => "?".into(),
788             token::SingleQuote => "'".into(),
789 
790             /* Literals */
791             token::Literal(lit) => literal_to_string(lit).into(),
792 
793             /* Name components */
794             token::Ident(s, is_raw) => {
795                 IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string().into()
796             }
797             token::Lifetime(s) => s.to_string().into(),
798 
799             /* Other */
800             token::DocComment(comment_kind, attr_style, data) => {
801                 doc_comment_to_string(comment_kind, attr_style, data).into()
802             }
803             token::Eof => "<eof>".into(),
804 
805             token::Interpolated(ref nt) => self.nonterminal_to_string(nt).into(),
806         }
807     }
808 
809     /// Print the token precisely, without converting `$crate` into its respective crate name.
token_to_string(&self, token: &Token) -> Cow<'static, str>810     fn token_to_string(&self, token: &Token) -> Cow<'static, str> {
811         self.token_to_string_ext(token, false)
812     }
813 
token_to_string_ext(&self, token: &Token, convert_dollar_crate: bool) -> Cow<'static, str>814     fn token_to_string_ext(&self, token: &Token, convert_dollar_crate: bool) -> Cow<'static, str> {
815         let convert_dollar_crate = convert_dollar_crate.then_some(token.span);
816         self.token_kind_to_string_ext(&token.kind, convert_dollar_crate)
817     }
818 
ty_to_string(&self, ty: &ast::Ty) -> String819     fn ty_to_string(&self, ty: &ast::Ty) -> String {
820         Self::to_string(|s| s.print_type(ty))
821     }
822 
bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String823     fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String {
824         Self::to_string(|s| s.print_type_bounds(bounds))
825     }
826 
where_bound_predicate_to_string( &self, where_bound_predicate: &ast::WhereBoundPredicate, ) -> String827     fn where_bound_predicate_to_string(
828         &self,
829         where_bound_predicate: &ast::WhereBoundPredicate,
830     ) -> String {
831         Self::to_string(|s| s.print_where_bound_predicate(where_bound_predicate))
832     }
833 
pat_to_string(&self, pat: &ast::Pat) -> String834     fn pat_to_string(&self, pat: &ast::Pat) -> String {
835         Self::to_string(|s| s.print_pat(pat))
836     }
837 
expr_to_string(&self, e: &ast::Expr) -> String838     fn expr_to_string(&self, e: &ast::Expr) -> String {
839         Self::to_string(|s| s.print_expr(e))
840     }
841 
meta_item_lit_to_string(&self, lit: &ast::MetaItemLit) -> String842     fn meta_item_lit_to_string(&self, lit: &ast::MetaItemLit) -> String {
843         Self::to_string(|s| s.print_meta_item_lit(lit))
844     }
845 
tt_to_string(&self, tt: &TokenTree) -> String846     fn tt_to_string(&self, tt: &TokenTree) -> String {
847         Self::to_string(|s| s.print_tt(tt, false))
848     }
849 
tts_to_string(&self, tokens: &TokenStream) -> String850     fn tts_to_string(&self, tokens: &TokenStream) -> String {
851         Self::to_string(|s| s.print_tts(tokens, false))
852     }
853 
stmt_to_string(&self, stmt: &ast::Stmt) -> String854     fn stmt_to_string(&self, stmt: &ast::Stmt) -> String {
855         Self::to_string(|s| s.print_stmt(stmt))
856     }
857 
item_to_string(&self, i: &ast::Item) -> String858     fn item_to_string(&self, i: &ast::Item) -> String {
859         Self::to_string(|s| s.print_item(i))
860     }
861 
assoc_item_to_string(&self, i: &ast::AssocItem) -> String862     fn assoc_item_to_string(&self, i: &ast::AssocItem) -> String {
863         Self::to_string(|s| s.print_assoc_item(i))
864     }
865 
foreign_item_to_string(&self, i: &ast::ForeignItem) -> String866     fn foreign_item_to_string(&self, i: &ast::ForeignItem) -> String {
867         Self::to_string(|s| s.print_foreign_item(i))
868     }
869 
generic_params_to_string(&self, generic_params: &[ast::GenericParam]) -> String870     fn generic_params_to_string(&self, generic_params: &[ast::GenericParam]) -> String {
871         Self::to_string(|s| s.print_generic_params(generic_params))
872     }
873 
path_to_string(&self, p: &ast::Path) -> String874     fn path_to_string(&self, p: &ast::Path) -> String {
875         Self::to_string(|s| s.print_path(p, false, 0))
876     }
877 
path_segment_to_string(&self, p: &ast::PathSegment) -> String878     fn path_segment_to_string(&self, p: &ast::PathSegment) -> String {
879         Self::to_string(|s| s.print_path_segment(p, false))
880     }
881 
vis_to_string(&self, v: &ast::Visibility) -> String882     fn vis_to_string(&self, v: &ast::Visibility) -> String {
883         Self::to_string(|s| s.print_visibility(v))
884     }
885 
block_to_string(&self, blk: &ast::Block) -> String886     fn block_to_string(&self, blk: &ast::Block) -> String {
887         Self::to_string(|s| {
888             // Containing cbox, will be closed by `print_block` at `}`.
889             s.cbox(INDENT_UNIT);
890             // Head-ibox, will be closed by `print_block` after `{`.
891             s.ibox(0);
892             s.print_block(blk)
893         })
894     }
895 
meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String896     fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String {
897         Self::to_string(|s| s.print_meta_list_item(li))
898     }
899 
attr_item_to_string(&self, ai: &ast::AttrItem) -> String900     fn attr_item_to_string(&self, ai: &ast::AttrItem) -> String {
901         Self::to_string(|s| s.print_attr_item(ai, ai.path.span))
902     }
903 
attribute_to_string(&self, attr: &ast::Attribute) -> String904     fn attribute_to_string(&self, attr: &ast::Attribute) -> String {
905         Self::to_string(|s| s.print_attribute(attr))
906     }
907 
param_to_string(&self, arg: &ast::Param) -> String908     fn param_to_string(&self, arg: &ast::Param) -> String {
909         Self::to_string(|s| s.print_param(arg, false))
910     }
911 
to_string(f: impl FnOnce(&mut State<'_>)) -> String912     fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
913         let mut printer = State::new();
914         f(&mut printer);
915         printer.s.eof()
916     }
917 }
918 
919 impl<'a> PrintState<'a> for State<'a> {
comments(&mut self) -> &mut Option<Comments<'a>>920     fn comments(&mut self) -> &mut Option<Comments<'a>> {
921         &mut self.comments
922     }
923 
print_ident(&mut self, ident: Ident)924     fn print_ident(&mut self, ident: Ident) {
925         self.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string());
926         self.ann.post(self, AnnNode::Ident(&ident))
927     }
928 
print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool)929     fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool) {
930         if colons_before_params {
931             self.word("::")
932         }
933 
934         match args {
935             ast::GenericArgs::AngleBracketed(data) => {
936                 self.word("<");
937                 self.commasep(Inconsistent, &data.args, |s, arg| match arg {
938                     ast::AngleBracketedArg::Arg(a) => s.print_generic_arg(a),
939                     ast::AngleBracketedArg::Constraint(c) => s.print_assoc_constraint(c),
940                 });
941                 self.word(">")
942             }
943 
944             ast::GenericArgs::Parenthesized(data) => {
945                 self.word("(");
946                 self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(ty));
947                 self.word(")");
948                 self.print_fn_ret_ty(&data.output);
949             }
950         }
951     }
952 }
953 
954 impl<'a> State<'a> {
new() -> State<'a>955     pub fn new() -> State<'a> {
956         State { s: pp::Printer::new(), comments: None, ann: &NoAnn }
957     }
958 
commasep_cmnt<T, F, G>( &mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G, ) where F: FnMut(&mut State<'_>, &T), G: FnMut(&T) -> rustc_span::Span,959     pub(crate) fn commasep_cmnt<T, F, G>(
960         &mut self,
961         b: Breaks,
962         elts: &[T],
963         mut op: F,
964         mut get_span: G,
965     ) where
966         F: FnMut(&mut State<'_>, &T),
967         G: FnMut(&T) -> rustc_span::Span,
968     {
969         self.rbox(0, b);
970         let len = elts.len();
971         let mut i = 0;
972         for elt in elts {
973             self.maybe_print_comment(get_span(elt).hi());
974             op(self, elt);
975             i += 1;
976             if i < len {
977                 self.word(",");
978                 self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi()));
979                 self.space_if_not_bol();
980             }
981         }
982         self.end();
983     }
984 
commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>])985     pub(crate) fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) {
986         self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
987     }
988 
print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>)989     pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) {
990         if let Some(lt) = *lifetime {
991             self.print_lifetime(lt);
992             self.nbsp();
993         }
994     }
995 
print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint)996     pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) {
997         self.print_ident(constraint.ident);
998         if let Some(args) = constraint.gen_args.as_ref() {
999             self.print_generic_args(args, false)
1000         }
1001         self.space();
1002         match &constraint.kind {
1003             ast::AssocConstraintKind::Equality { term } => {
1004                 self.word_space("=");
1005                 match term {
1006                     Term::Ty(ty) => self.print_type(ty),
1007                     Term::Const(c) => self.print_expr_anon_const(c, &[]),
1008                 }
1009             }
1010             ast::AssocConstraintKind::Bound { bounds } => {
1011                 if !bounds.is_empty() {
1012                     self.word_nbsp(":");
1013                     self.print_type_bounds(bounds);
1014                 }
1015             }
1016         }
1017     }
1018 
print_generic_arg(&mut self, generic_arg: &GenericArg)1019     pub fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
1020         match generic_arg {
1021             GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
1022             GenericArg::Type(ty) => self.print_type(ty),
1023             GenericArg::Const(ct) => self.print_expr(&ct.value),
1024         }
1025     }
1026 
print_type(&mut self, ty: &ast::Ty)1027     pub fn print_type(&mut self, ty: &ast::Ty) {
1028         self.maybe_print_comment(ty.span.lo());
1029         self.ibox(0);
1030         match &ty.kind {
1031             ast::TyKind::Slice(ty) => {
1032                 self.word("[");
1033                 self.print_type(ty);
1034                 self.word("]");
1035             }
1036             ast::TyKind::Ptr(mt) => {
1037                 self.word("*");
1038                 self.print_mt(mt, true);
1039             }
1040             ast::TyKind::Ref(lifetime, mt) => {
1041                 self.word("&");
1042                 self.print_opt_lifetime(lifetime);
1043                 self.print_mt(mt, false);
1044             }
1045             ast::TyKind::Never => {
1046                 self.word("!");
1047             }
1048             ast::TyKind::Tup(elts) => {
1049                 self.popen();
1050                 self.commasep(Inconsistent, elts, |s, ty| s.print_type(ty));
1051                 if elts.len() == 1 {
1052                     self.word(",");
1053                 }
1054                 self.pclose();
1055             }
1056             ast::TyKind::Paren(typ) => {
1057                 self.popen();
1058                 self.print_type(typ);
1059                 self.pclose();
1060             }
1061             ast::TyKind::BareFn(f) => {
1062                 self.print_ty_fn(f.ext, f.unsafety, &f.decl, None, &f.generic_params);
1063             }
1064             ast::TyKind::Path(None, path) => {
1065                 self.print_path(path, false, 0);
1066             }
1067             ast::TyKind::Path(Some(qself), path) => self.print_qpath(path, qself, false),
1068             ast::TyKind::TraitObject(bounds, syntax) => {
1069                 if *syntax == ast::TraitObjectSyntax::Dyn {
1070                     self.word_nbsp("dyn");
1071                 }
1072                 self.print_type_bounds(bounds);
1073             }
1074             ast::TyKind::ImplTrait(_, bounds) => {
1075                 self.word_nbsp("impl");
1076                 self.print_type_bounds(bounds);
1077             }
1078             ast::TyKind::Array(ty, length) => {
1079                 self.word("[");
1080                 self.print_type(ty);
1081                 self.word("; ");
1082                 self.print_expr(&length.value);
1083                 self.word("]");
1084             }
1085             ast::TyKind::Typeof(e) => {
1086                 self.word("typeof(");
1087                 self.print_expr(&e.value);
1088                 self.word(")");
1089             }
1090             ast::TyKind::Infer => {
1091                 self.word("_");
1092             }
1093             ast::TyKind::Err => {
1094                 self.popen();
1095                 self.word("/*ERROR*/");
1096                 self.pclose();
1097             }
1098             ast::TyKind::ImplicitSelf => {
1099                 self.word("Self");
1100             }
1101             ast::TyKind::MacCall(m) => {
1102                 self.print_mac(m);
1103             }
1104             ast::TyKind::CVarArgs => {
1105                 self.word("...");
1106             }
1107         }
1108         self.end();
1109     }
1110 
print_trait_ref(&mut self, t: &ast::TraitRef)1111     fn print_trait_ref(&mut self, t: &ast::TraitRef) {
1112         self.print_path(&t.path, false, 0)
1113     }
1114 
print_formal_generic_params(&mut self, generic_params: &[ast::GenericParam])1115     fn print_formal_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
1116         if !generic_params.is_empty() {
1117             self.word("for");
1118             self.print_generic_params(generic_params);
1119             self.nbsp();
1120         }
1121     }
1122 
print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef)1123     fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) {
1124         self.print_formal_generic_params(&t.bound_generic_params);
1125         self.print_trait_ref(&t.trait_ref)
1126     }
1127 
print_stmt(&mut self, st: &ast::Stmt)1128     pub(crate) fn print_stmt(&mut self, st: &ast::Stmt) {
1129         self.maybe_print_comment(st.span.lo());
1130         match &st.kind {
1131             ast::StmtKind::Local(loc) => {
1132                 self.print_outer_attributes(&loc.attrs);
1133                 self.space_if_not_bol();
1134                 self.ibox(INDENT_UNIT);
1135                 self.word_nbsp("let");
1136 
1137                 self.ibox(INDENT_UNIT);
1138                 self.print_local_decl(loc);
1139                 self.end();
1140                 if let Some((init, els)) = loc.kind.init_else_opt() {
1141                     self.nbsp();
1142                     self.word_space("=");
1143                     self.print_expr(init);
1144                     if let Some(els) = els {
1145                         self.cbox(INDENT_UNIT);
1146                         self.ibox(INDENT_UNIT);
1147                         self.word(" else ");
1148                         self.print_block(els);
1149                     }
1150                 }
1151                 self.word(";");
1152                 self.end(); // `let` ibox
1153             }
1154             ast::StmtKind::Item(item) => self.print_item(item),
1155             ast::StmtKind::Expr(expr) => {
1156                 self.space_if_not_bol();
1157                 self.print_expr_outer_attr_style(expr, false);
1158                 if classify::expr_requires_semi_to_be_stmt(expr) {
1159                     self.word(";");
1160                 }
1161             }
1162             ast::StmtKind::Semi(expr) => {
1163                 self.space_if_not_bol();
1164                 self.print_expr_outer_attr_style(expr, false);
1165                 self.word(";");
1166             }
1167             ast::StmtKind::Empty => {
1168                 self.space_if_not_bol();
1169                 self.word(";");
1170             }
1171             ast::StmtKind::MacCall(mac) => {
1172                 self.space_if_not_bol();
1173                 self.print_outer_attributes(&mac.attrs);
1174                 self.print_mac(&mac.mac);
1175                 if mac.style == ast::MacStmtStyle::Semicolon {
1176                     self.word(";");
1177                 }
1178             }
1179         }
1180         self.maybe_print_trailing_comment(st.span, None)
1181     }
1182 
print_block(&mut self, blk: &ast::Block)1183     pub(crate) fn print_block(&mut self, blk: &ast::Block) {
1184         self.print_block_with_attrs(blk, &[])
1185     }
1186 
print_block_unclosed_indent(&mut self, blk: &ast::Block)1187     pub(crate) fn print_block_unclosed_indent(&mut self, blk: &ast::Block) {
1188         self.print_block_maybe_unclosed(blk, &[], false)
1189     }
1190 
print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute])1191     pub(crate) fn print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute]) {
1192         self.print_block_maybe_unclosed(blk, attrs, true)
1193     }
1194 
print_block_maybe_unclosed( &mut self, blk: &ast::Block, attrs: &[ast::Attribute], close_box: bool, )1195     pub(crate) fn print_block_maybe_unclosed(
1196         &mut self,
1197         blk: &ast::Block,
1198         attrs: &[ast::Attribute],
1199         close_box: bool,
1200     ) {
1201         match blk.rules {
1202             BlockCheckMode::Unsafe(..) => self.word_space("unsafe"),
1203             BlockCheckMode::Default => (),
1204         }
1205         self.maybe_print_comment(blk.span.lo());
1206         self.ann.pre(self, AnnNode::Block(blk));
1207         self.bopen();
1208 
1209         let has_attrs = self.print_inner_attributes(attrs);
1210 
1211         for (i, st) in blk.stmts.iter().enumerate() {
1212             match &st.kind {
1213                 ast::StmtKind::Expr(expr) if i == blk.stmts.len() - 1 => {
1214                     self.maybe_print_comment(st.span.lo());
1215                     self.space_if_not_bol();
1216                     self.print_expr_outer_attr_style(expr, false);
1217                     self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
1218                 }
1219                 _ => self.print_stmt(st),
1220             }
1221         }
1222 
1223         let empty = !has_attrs && blk.stmts.is_empty();
1224         self.bclose_maybe_open(blk.span, empty, close_box);
1225         self.ann.post(self, AnnNode::Block(blk))
1226     }
1227 
1228     /// Print a `let pat = expr` expression.
print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr)1229     pub(crate) fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr) {
1230         self.word("let ");
1231         self.print_pat(pat);
1232         self.space();
1233         self.word_space("=");
1234         let npals = || parser::needs_par_as_let_scrutinee(expr.precedence().order());
1235         self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
1236     }
1237 
print_mac(&mut self, m: &ast::MacCall)1238     pub(crate) fn print_mac(&mut self, m: &ast::MacCall) {
1239         self.print_mac_common(
1240             Some(MacHeader::Path(&m.path)),
1241             true,
1242             None,
1243             m.args.delim.to_token(),
1244             &m.args.tokens.clone(),
1245             true,
1246             m.span(),
1247         );
1248     }
1249 
print_inline_asm(&mut self, asm: &ast::InlineAsm)1250     fn print_inline_asm(&mut self, asm: &ast::InlineAsm) {
1251         enum AsmArg<'a> {
1252             Template(String),
1253             Operand(&'a InlineAsmOperand),
1254             ClobberAbi(Symbol),
1255             Options(InlineAsmOptions),
1256         }
1257 
1258         let mut args = vec![AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template))];
1259         args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
1260         for (abi, _) in &asm.clobber_abis {
1261             args.push(AsmArg::ClobberAbi(*abi));
1262         }
1263         if !asm.options.is_empty() {
1264             args.push(AsmArg::Options(asm.options));
1265         }
1266 
1267         self.popen();
1268         self.commasep(Consistent, &args, |s, arg| match arg {
1269             AsmArg::Template(template) => s.print_string(template, ast::StrStyle::Cooked),
1270             AsmArg::Operand(op) => {
1271                 let print_reg_or_class = |s: &mut Self, r: &InlineAsmRegOrRegClass| match r {
1272                     InlineAsmRegOrRegClass::Reg(r) => s.print_symbol(*r, ast::StrStyle::Cooked),
1273                     InlineAsmRegOrRegClass::RegClass(r) => s.word(r.to_string()),
1274                 };
1275                 match op {
1276                     InlineAsmOperand::In { reg, expr } => {
1277                         s.word("in");
1278                         s.popen();
1279                         print_reg_or_class(s, reg);
1280                         s.pclose();
1281                         s.space();
1282                         s.print_expr(expr);
1283                     }
1284                     InlineAsmOperand::Out { reg, late, expr } => {
1285                         s.word(if *late { "lateout" } else { "out" });
1286                         s.popen();
1287                         print_reg_or_class(s, reg);
1288                         s.pclose();
1289                         s.space();
1290                         match expr {
1291                             Some(expr) => s.print_expr(expr),
1292                             None => s.word("_"),
1293                         }
1294                     }
1295                     InlineAsmOperand::InOut { reg, late, expr } => {
1296                         s.word(if *late { "inlateout" } else { "inout" });
1297                         s.popen();
1298                         print_reg_or_class(s, reg);
1299                         s.pclose();
1300                         s.space();
1301                         s.print_expr(expr);
1302                     }
1303                     InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
1304                         s.word(if *late { "inlateout" } else { "inout" });
1305                         s.popen();
1306                         print_reg_or_class(s, reg);
1307                         s.pclose();
1308                         s.space();
1309                         s.print_expr(in_expr);
1310                         s.space();
1311                         s.word_space("=>");
1312                         match out_expr {
1313                             Some(out_expr) => s.print_expr(out_expr),
1314                             None => s.word("_"),
1315                         }
1316                     }
1317                     InlineAsmOperand::Const { anon_const } => {
1318                         s.word("const");
1319                         s.space();
1320                         s.print_expr(&anon_const.value);
1321                     }
1322                     InlineAsmOperand::Sym { sym } => {
1323                         s.word("sym");
1324                         s.space();
1325                         if let Some(qself) = &sym.qself {
1326                             s.print_qpath(&sym.path, qself, true);
1327                         } else {
1328                             s.print_path(&sym.path, true, 0);
1329                         }
1330                     }
1331                 }
1332             }
1333             AsmArg::ClobberAbi(abi) => {
1334                 s.word("clobber_abi");
1335                 s.popen();
1336                 s.print_symbol(*abi, ast::StrStyle::Cooked);
1337                 s.pclose();
1338             }
1339             AsmArg::Options(opts) => {
1340                 s.word("options");
1341                 s.popen();
1342                 let mut options = vec![];
1343                 if opts.contains(InlineAsmOptions::PURE) {
1344                     options.push("pure");
1345                 }
1346                 if opts.contains(InlineAsmOptions::NOMEM) {
1347                     options.push("nomem");
1348                 }
1349                 if opts.contains(InlineAsmOptions::READONLY) {
1350                     options.push("readonly");
1351                 }
1352                 if opts.contains(InlineAsmOptions::PRESERVES_FLAGS) {
1353                     options.push("preserves_flags");
1354                 }
1355                 if opts.contains(InlineAsmOptions::NORETURN) {
1356                     options.push("noreturn");
1357                 }
1358                 if opts.contains(InlineAsmOptions::NOSTACK) {
1359                     options.push("nostack");
1360                 }
1361                 if opts.contains(InlineAsmOptions::ATT_SYNTAX) {
1362                     options.push("att_syntax");
1363                 }
1364                 if opts.contains(InlineAsmOptions::RAW) {
1365                     options.push("raw");
1366                 }
1367                 if opts.contains(InlineAsmOptions::MAY_UNWIND) {
1368                     options.push("may_unwind");
1369                 }
1370                 s.commasep(Inconsistent, &options, |s, &opt| {
1371                     s.word(opt);
1372                 });
1373                 s.pclose();
1374             }
1375         });
1376         self.pclose();
1377     }
1378 
print_local_decl(&mut self, loc: &ast::Local)1379     pub(crate) fn print_local_decl(&mut self, loc: &ast::Local) {
1380         self.print_pat(&loc.pat);
1381         if let Some(ty) = &loc.ty {
1382             self.word_space(":");
1383             self.print_type(ty);
1384         }
1385     }
1386 
print_name(&mut self, name: Symbol)1387     pub(crate) fn print_name(&mut self, name: Symbol) {
1388         self.word(name.to_string());
1389         self.ann.post(self, AnnNode::Name(&name))
1390     }
1391 
print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_params: bool)1392     fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_params: bool) {
1393         self.word("<");
1394         self.print_type(&qself.ty);
1395         if qself.position > 0 {
1396             self.space();
1397             self.word_space("as");
1398             let depth = path.segments.len() - qself.position;
1399             self.print_path(path, false, depth);
1400         }
1401         self.word(">");
1402         for item_segment in &path.segments[qself.position..] {
1403             self.word("::");
1404             self.print_ident(item_segment.ident);
1405             if let Some(args) = &item_segment.args {
1406                 self.print_generic_args(args, colons_before_params)
1407             }
1408         }
1409     }
1410 
print_pat(&mut self, pat: &ast::Pat)1411     pub(crate) fn print_pat(&mut self, pat: &ast::Pat) {
1412         self.maybe_print_comment(pat.span.lo());
1413         self.ann.pre(self, AnnNode::Pat(pat));
1414         /* Pat isn't normalized, but the beauty of it
1415         is that it doesn't matter */
1416         match &pat.kind {
1417             PatKind::Wild => self.word("_"),
1418             PatKind::Ident(BindingAnnotation(by_ref, mutbl), ident, sub) => {
1419                 if *by_ref == ByRef::Yes {
1420                     self.word_nbsp("ref");
1421                 }
1422                 if mutbl.is_mut() {
1423                     self.word_nbsp("mut");
1424                 }
1425                 self.print_ident(*ident);
1426                 if let Some(p) = sub {
1427                     self.space();
1428                     self.word_space("@");
1429                     self.print_pat(p);
1430                 }
1431             }
1432             PatKind::TupleStruct(qself, path, elts) => {
1433                 if let Some(qself) = qself {
1434                     self.print_qpath(path, qself, true);
1435                 } else {
1436                     self.print_path(path, true, 0);
1437                 }
1438                 self.popen();
1439                 self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
1440                 self.pclose();
1441             }
1442             PatKind::Or(pats) => {
1443                 self.strsep("|", true, Inconsistent, pats, |s, p| s.print_pat(p));
1444             }
1445             PatKind::Path(None, path) => {
1446                 self.print_path(path, true, 0);
1447             }
1448             PatKind::Path(Some(qself), path) => {
1449                 self.print_qpath(path, qself, false);
1450             }
1451             PatKind::Struct(qself, path, fields, etc) => {
1452                 if let Some(qself) = qself {
1453                     self.print_qpath(path, qself, true);
1454                 } else {
1455                     self.print_path(path, true, 0);
1456                 }
1457                 self.nbsp();
1458                 self.word("{");
1459                 let empty = fields.is_empty() && !etc;
1460                 if !empty {
1461                     self.space();
1462                 }
1463                 self.commasep_cmnt(
1464                     Consistent,
1465                     fields,
1466                     |s, f| {
1467                         s.cbox(INDENT_UNIT);
1468                         if !f.is_shorthand {
1469                             s.print_ident(f.ident);
1470                             s.word_nbsp(":");
1471                         }
1472                         s.print_pat(&f.pat);
1473                         s.end();
1474                     },
1475                     |f| f.pat.span,
1476                 );
1477                 if *etc {
1478                     if !fields.is_empty() {
1479                         self.word_space(",");
1480                     }
1481                     self.word("..");
1482                 }
1483                 if !empty {
1484                     self.space();
1485                 }
1486                 self.word("}");
1487             }
1488             PatKind::Tuple(elts) => {
1489                 self.popen();
1490                 self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
1491                 if elts.len() == 1 {
1492                     self.word(",");
1493                 }
1494                 self.pclose();
1495             }
1496             PatKind::Box(inner) => {
1497                 self.word("box ");
1498                 self.print_pat(inner);
1499             }
1500             PatKind::Ref(inner, mutbl) => {
1501                 self.word("&");
1502                 if mutbl.is_mut() {
1503                     self.word("mut ");
1504                 }
1505                 if let PatKind::Ident(ast::BindingAnnotation::MUT, ..) = inner.kind {
1506                     self.popen();
1507                     self.print_pat(inner);
1508                     self.pclose();
1509                 } else {
1510                     self.print_pat(inner);
1511                 }
1512             }
1513             PatKind::Lit(e) => self.print_expr(e),
1514             PatKind::Range(begin, end, Spanned { node: end_kind, .. }) => {
1515                 if let Some(e) = begin {
1516                     self.print_expr(e);
1517                 }
1518                 match end_kind {
1519                     RangeEnd::Included(RangeSyntax::DotDotDot) => self.word("..."),
1520                     RangeEnd::Included(RangeSyntax::DotDotEq) => self.word("..="),
1521                     RangeEnd::Excluded => self.word(".."),
1522                 }
1523                 if let Some(e) = end {
1524                     self.print_expr(e);
1525                 }
1526             }
1527             PatKind::Slice(elts) => {
1528                 self.word("[");
1529                 self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
1530                 self.word("]");
1531             }
1532             PatKind::Rest => self.word(".."),
1533             PatKind::Paren(inner) => {
1534                 self.popen();
1535                 self.print_pat(inner);
1536                 self.pclose();
1537             }
1538             PatKind::MacCall(m) => self.print_mac(m),
1539         }
1540         self.ann.post(self, AnnNode::Pat(pat))
1541     }
1542 
print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf)1543     fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) {
1544         match &explicit_self.node {
1545             SelfKind::Value(m) => {
1546                 self.print_mutability(*m, false);
1547                 self.word("self")
1548             }
1549             SelfKind::Region(lt, m) => {
1550                 self.word("&");
1551                 self.print_opt_lifetime(lt);
1552                 self.print_mutability(*m, false);
1553                 self.word("self")
1554             }
1555             SelfKind::Explicit(typ, m) => {
1556                 self.print_mutability(*m, false);
1557                 self.word("self");
1558                 self.word_space(":");
1559                 self.print_type(typ)
1560             }
1561         }
1562     }
1563 
print_asyncness(&mut self, asyncness: ast::Async)1564     pub(crate) fn print_asyncness(&mut self, asyncness: ast::Async) {
1565         if asyncness.is_async() {
1566             self.word_nbsp("async");
1567         }
1568     }
1569 
print_type_bounds(&mut self, bounds: &[ast::GenericBound])1570     pub fn print_type_bounds(&mut self, bounds: &[ast::GenericBound]) {
1571         let mut first = true;
1572         for bound in bounds {
1573             if first {
1574                 first = false;
1575             } else {
1576                 self.nbsp();
1577                 self.word_space("+");
1578             }
1579 
1580             match bound {
1581                 GenericBound::Trait(tref, modifier) => {
1582                     match modifier {
1583                         TraitBoundModifier::None => {}
1584                         TraitBoundModifier::Negative => {
1585                             self.word("!");
1586                         }
1587                         TraitBoundModifier::Maybe => {
1588                             self.word("?");
1589                         }
1590                         TraitBoundModifier::MaybeConst => {
1591                             self.word_space("~const");
1592                         }
1593                         TraitBoundModifier::MaybeConstNegative => {
1594                             self.word_space("~const");
1595                             self.word("!");
1596                         }
1597                         TraitBoundModifier::MaybeConstMaybe => {
1598                             self.word_space("~const");
1599                             self.word("?");
1600                         }
1601                     }
1602                     self.print_poly_trait_ref(tref);
1603                 }
1604                 GenericBound::Outlives(lt) => self.print_lifetime(*lt),
1605             }
1606         }
1607     }
1608 
print_lifetime(&mut self, lifetime: ast::Lifetime)1609     pub(crate) fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
1610         self.print_name(lifetime.ident.name)
1611     }
1612 
print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds)1613     pub(crate) fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) {
1614         for (i, bound) in bounds.iter().enumerate() {
1615             if i != 0 {
1616                 self.word(" + ");
1617             }
1618             match bound {
1619                 ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt),
1620                 _ => panic!(),
1621             }
1622         }
1623     }
1624 
print_generic_params(&mut self, generic_params: &[ast::GenericParam])1625     pub(crate) fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
1626         if generic_params.is_empty() {
1627             return;
1628         }
1629 
1630         self.word("<");
1631 
1632         self.commasep(Inconsistent, generic_params, |s, param| {
1633             s.print_outer_attributes_inline(&param.attrs);
1634 
1635             match &param.kind {
1636                 ast::GenericParamKind::Lifetime => {
1637                     let lt = ast::Lifetime { id: param.id, ident: param.ident };
1638                     s.print_lifetime(lt);
1639                     if !param.bounds.is_empty() {
1640                         s.word_nbsp(":");
1641                         s.print_lifetime_bounds(&param.bounds)
1642                     }
1643                 }
1644                 ast::GenericParamKind::Type { default } => {
1645                     s.print_ident(param.ident);
1646                     if !param.bounds.is_empty() {
1647                         s.word_nbsp(":");
1648                         s.print_type_bounds(&param.bounds);
1649                     }
1650                     if let Some(default) = default {
1651                         s.space();
1652                         s.word_space("=");
1653                         s.print_type(default)
1654                     }
1655                 }
1656                 ast::GenericParamKind::Const { ty, default, .. } => {
1657                     s.word_space("const");
1658                     s.print_ident(param.ident);
1659                     s.space();
1660                     s.word_space(":");
1661                     s.print_type(ty);
1662                     if !param.bounds.is_empty() {
1663                         s.word_nbsp(":");
1664                         s.print_type_bounds(&param.bounds);
1665                     }
1666                     if let Some(default) = default {
1667                         s.space();
1668                         s.word_space("=");
1669                         s.print_expr(&default.value);
1670                     }
1671                 }
1672             }
1673         });
1674 
1675         self.word(">");
1676     }
1677 
print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool)1678     pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) {
1679         match mutbl {
1680             ast::Mutability::Mut => self.word_nbsp("mut"),
1681             ast::Mutability::Not => {
1682                 if print_const {
1683                     self.word_nbsp("const");
1684                 }
1685             }
1686         }
1687     }
1688 
print_mt(&mut self, mt: &ast::MutTy, print_const: bool)1689     pub(crate) fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) {
1690         self.print_mutability(mt.mutbl, print_const);
1691         self.print_type(&mt.ty)
1692     }
1693 
print_param(&mut self, input: &ast::Param, is_closure: bool)1694     pub(crate) fn print_param(&mut self, input: &ast::Param, is_closure: bool) {
1695         self.ibox(INDENT_UNIT);
1696 
1697         self.print_outer_attributes_inline(&input.attrs);
1698 
1699         match input.ty.kind {
1700             ast::TyKind::Infer if is_closure => self.print_pat(&input.pat),
1701             _ => {
1702                 if let Some(eself) = input.to_self() {
1703                     self.print_explicit_self(&eself);
1704                 } else {
1705                     let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind {
1706                         ident.name == kw::Empty
1707                     } else {
1708                         false
1709                     };
1710                     if !invalid {
1711                         self.print_pat(&input.pat);
1712                         self.word(":");
1713                         self.space();
1714                     }
1715                     self.print_type(&input.ty);
1716                 }
1717             }
1718         }
1719         self.end();
1720     }
1721 
print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy)1722     pub(crate) fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy) {
1723         if let ast::FnRetTy::Ty(ty) = fn_ret_ty {
1724             self.space_if_not_bol();
1725             self.ibox(INDENT_UNIT);
1726             self.word_space("->");
1727             self.print_type(ty);
1728             self.end();
1729             self.maybe_print_comment(ty.span.lo());
1730         }
1731     }
1732 
print_ty_fn( &mut self, ext: ast::Extern, unsafety: ast::Unsafe, decl: &ast::FnDecl, name: Option<Ident>, generic_params: &[ast::GenericParam], )1733     pub(crate) fn print_ty_fn(
1734         &mut self,
1735         ext: ast::Extern,
1736         unsafety: ast::Unsafe,
1737         decl: &ast::FnDecl,
1738         name: Option<Ident>,
1739         generic_params: &[ast::GenericParam],
1740     ) {
1741         self.ibox(INDENT_UNIT);
1742         self.print_formal_generic_params(generic_params);
1743         let generics = ast::Generics {
1744             params: ThinVec::new(),
1745             where_clause: ast::WhereClause {
1746                 has_where_token: false,
1747                 predicates: ThinVec::new(),
1748                 span: DUMMY_SP,
1749             },
1750             span: DUMMY_SP,
1751         };
1752         let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() };
1753         self.print_fn(decl, header, name, &generics);
1754         self.end();
1755     }
1756 
print_fn_header_info(&mut self, header: ast::FnHeader)1757     pub(crate) fn print_fn_header_info(&mut self, header: ast::FnHeader) {
1758         self.print_constness(header.constness);
1759         self.print_asyncness(header.asyncness);
1760         self.print_unsafety(header.unsafety);
1761 
1762         match header.ext {
1763             ast::Extern::None => {}
1764             ast::Extern::Implicit(_) => {
1765                 self.word_nbsp("extern");
1766             }
1767             ast::Extern::Explicit(abi, _) => {
1768                 self.word_nbsp("extern");
1769                 self.print_token_literal(abi.as_token_lit(), abi.span);
1770                 self.nbsp();
1771             }
1772         }
1773 
1774         self.word("fn")
1775     }
1776 
print_unsafety(&mut self, s: ast::Unsafe)1777     pub(crate) fn print_unsafety(&mut self, s: ast::Unsafe) {
1778         match s {
1779             ast::Unsafe::No => {}
1780             ast::Unsafe::Yes(_) => self.word_nbsp("unsafe"),
1781         }
1782     }
1783 
print_constness(&mut self, s: ast::Const)1784     pub(crate) fn print_constness(&mut self, s: ast::Const) {
1785         match s {
1786             ast::Const::No => {}
1787             ast::Const::Yes(_) => self.word_nbsp("const"),
1788         }
1789     }
1790 
print_is_auto(&mut self, s: ast::IsAuto)1791     pub(crate) fn print_is_auto(&mut self, s: ast::IsAuto) {
1792         match s {
1793             ast::IsAuto::Yes => self.word_nbsp("auto"),
1794             ast::IsAuto::No => {}
1795         }
1796     }
1797 }
1798