1mod expr;
6mod fixup;
7mod item;
8
9use std::borrow::Cow;
10use std::sync::Arc;
11
12use rustc_ast::attr::AttrIdGenerator;
13use rustc_ast::ptr::P;
14use rustc_ast::token::{
15 self, BinOpToken, CommentKind, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind,
16};
17use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
18use rustc_ast::util::classify;
19use rustc_ast::util::comments::{Comment, CommentStyle};
20use rustc_ast::{
21 self as ast, AttrArgs, BindingMode, BlockCheckMode, ByRef, DelimArgs, GenericArg, GenericBound,
22 InlineAsmOperand, InlineAsmOptions, InlineAsmRegOrRegClass, InlineAsmTemplatePiece, PatKind,
23 RangeEnd, RangeSyntax, Safety, SelfKind, Term, attr,
24};
25use rustc_span::edition::Edition;
26use rustc_span::source_map::{SourceMap, Spanned};
27use rustc_span::symbol::IdentPrinter;
28use rustc_span::{BytePos, CharPos, DUMMY_SP, FileName, Ident, Pos, Span, Symbol, kw, sym};
29use thin_vec::ThinVec;
30
31use crate::pp::Breaks::{Consistent, Inconsistent};
32use crate::pp::{self, Breaks};
33use crate::pprust::state::fixup::FixupContext;
34
35pub enum MacHeader<'a> {
36 Path(&'a ast::Path),
37 Keyword(&'static str),
38}
39
40pub enum AnnNode<'a> {
41 Ident(&'a Ident),
42 Name(&'a Symbol),
43 Block(&'a ast::Block),
44 Item(&'a ast::Item),
45 SubItem(ast::NodeId),
46 Expr(&'a ast::Expr),
47 Pat(&'a ast::Pat),
48 Crate(&'a ast::Crate),
49}
50
51pub trait PpAnn {
52 fn pre(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
53 fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
54}
55
56struct NoAnn;
57
58impl PpAnn for NoAnn {}
59
60pub struct Comments<'a> {
61 sm: &'a SourceMap,
62 reversed_comments: Vec<Comment>,
64}
65
66fn all_whitespace(s: &str, col: CharPos) -> Option<usize> {
70 let mut idx = 0;
71 for (i, ch) in s.char_indices().take(col.to_usize()) {
72 if !ch.is_whitespace() {
73 return None;
74 }
75 idx = i + ch.len_utf8();
76 }
77 Some(idx)
78}
79
80fn trim_whitespace_prefix(s: &str, col: CharPos) -> &str {
81 let len = s.len();
82 match all_whitespace(s, col) {
83 Some(col) => {
84 if col < len {
85 &s[col..]
86 } else {
87 ""
88 }
89 }
90 None => s,
91 }
92}
93
94fn split_block_comment_into_lines(text: &str, col: CharPos) -> Vec<String> {
95 let mut res: Vec<String> = vec![];
96 let mut lines = text.lines();
97 res.extend(lines.next().map(|it| it.to_string()));
99 for line in lines {
101 res.push(trim_whitespace_prefix(line, col).to_string())
102 }
103 res
104}
105
106fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comment> {
107 let sm = SourceMap::new(sm.path_mapping().clone());
108 let source_file = sm.new_source_file(path, src);
109 let text = Arc::clone(&(*source_file.src.as_ref().unwrap()));
110
111 let text: &str = text.as_str();
112 let start_bpos = source_file.start_pos;
113 let mut pos = 0;
114 let mut comments: Vec<Comment> = Vec::new();
115 let mut code_to_the_left = false;
116
117 if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
118 comments.push(Comment {
119 style: CommentStyle::Isolated,
120 lines: vec![text[..shebang_len].to_string()],
121 pos: start_bpos,
122 });
123 pos += shebang_len;
124 }
125
126 for token in rustc_lexer::tokenize(&text[pos..]) {
127 let token_text = &text[pos..pos + token.len as usize];
128 match token.kind {
129 rustc_lexer::TokenKind::Whitespace => {
130 if let Some(mut idx) = token_text.find('\n') {
131 code_to_the_left = false;
132 while let Some(next_newline) = &token_text[idx + 1..].find('\n') {
133 idx += 1 + next_newline;
134 comments.push(Comment {
135 style: CommentStyle::BlankLine,
136 lines: vec![],
137 pos: start_bpos + BytePos((pos + idx) as u32),
138 });
139 }
140 }
141 }
142 rustc_lexer::TokenKind::BlockComment { doc_style, .. } => {
143 if doc_style.is_none() {
144 let code_to_the_right = !matches!(
145 text[pos + token.len as usize..].chars().next(),
146 Some('\r' | '\n')
147 );
148 let style = match (code_to_the_left, code_to_the_right) {
149 (_, true) => CommentStyle::Mixed,
150 (false, false) => CommentStyle::Isolated,
151 (true, false) => CommentStyle::Trailing,
152 };
153
154 let pos_in_file = start_bpos + BytePos(pos as u32);
156 let line_begin_in_file = source_file.line_begin_pos(pos_in_file);
157 let line_begin_pos = (line_begin_in_file - start_bpos).to_usize();
158 let col = CharPos(text[line_begin_pos..pos].chars().count());
159
160 let lines = split_block_comment_into_lines(token_text, col);
161 comments.push(Comment { style, lines, pos: pos_in_file })
162 }
163 }
164 rustc_lexer::TokenKind::LineComment { doc_style } => {
165 if doc_style.is_none() {
166 comments.push(Comment {
167 style: if code_to_the_left {
168 CommentStyle::Trailing
169 } else {
170 CommentStyle::Isolated
171 },
172 lines: vec![token_text.to_string()],
173 pos: start_bpos + BytePos(pos as u32),
174 })
175 }
176 }
177 _ => {
178 code_to_the_left = true;
179 }
180 }
181 pos += token.len as usize;
182 }
183
184 comments
185}
186
187impl<'a> Comments<'a> {
188 pub fn new(sm: &'a SourceMap, filename: FileName, input: String) -> Comments<'a> {
189 let mut comments = gather_comments(sm, filename, input);
190 comments.reverse();
191 Comments { sm, reversed_comments: comments }
192 }
193
194 fn peek(&self) -> Option<&Comment> {
195 self.reversed_comments.last()
196 }
197
198 fn next(&mut self) -> Option<Comment> {
199 self.reversed_comments.pop()
200 }
201
202 fn trailing_comment(
203 &mut self,
204 span: rustc_span::Span,
205 next_pos: Option<BytePos>,
206 ) -> Option<Comment> {
207 if let Some(cmnt) = self.peek() {
208 if cmnt.style != CommentStyle::Trailing {
209 return None;
210 }
211 let span_line = self.sm.lookup_char_pos(span.hi());
212 let comment_line = self.sm.lookup_char_pos(cmnt.pos);
213 let next = next_pos.unwrap_or_else(|| cmnt.pos + BytePos(1));
214 if span.hi() < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line {
215 return Some(self.next().unwrap());
216 }
217 }
218
219 None
220 }
221}
222
223pub struct State<'a> {
224 pub s: pp::Printer,
225 comments: Option<Comments<'a>>,
226 ann: &'a (dyn PpAnn + 'a),
227}
228
229const INDENT_UNIT: isize = 4;
230
231pub fn print_crate<'a>(
234 sm: &'a SourceMap,
235 krate: &ast::Crate,
236 filename: FileName,
237 input: String,
238 ann: &'a dyn PpAnn,
239 is_expanded: bool,
240 edition: Edition,
241 g: &AttrIdGenerator,
242) -> String {
243 let mut s =
244 State { s: pp::Printer::new(), comments: Some(Comments::new(sm, filename, input)), ann };
245
246 if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) {
247 let fake_attr = attr::mk_attr_nested_word(
254 g,
255 ast::AttrStyle::Inner,
256 Safety::Default,
257 sym::feature,
258 sym::prelude_import,
259 DUMMY_SP,
260 );
261 s.print_attribute(&fake_attr);
262
263 if edition.is_rust_2015() {
266 let fake_attr = attr::mk_attr_word(
268 g,
269 ast::AttrStyle::Inner,
270 Safety::Default,
271 sym::no_std,
272 DUMMY_SP,
273 );
274 s.print_attribute(&fake_attr);
275 }
276 }
277
278 s.print_inner_attributes(&krate.attrs);
279 for item in &krate.items {
280 s.print_item(item);
281 }
282 s.print_remaining_comments();
283 s.ann.post(&mut s, AnnNode::Crate(krate));
284 s.s.eof()
285}
286
287fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool {
295 use Delimiter::*;
296 use TokenTree::{Delimited as Del, Token as Tok};
297 use token::*;
298
299 fn is_punct(tt: &TokenTree) -> bool {
300 matches!(tt, TokenTree::Token(tok, _) if tok.is_punct())
301 }
302
303 match (tt1, tt2) {
307 (Tok(Token { kind: DocComment(CommentKind::Line, ..), .. }, _), _) => false,
309
310 (Tok(Token { kind: Dot, .. }, _), tt2) if !is_punct(tt2) => false,
312
313 (Tok(Token { kind: Dollar, .. }, _), Tok(Token { kind: Ident(..), .. }, _)) => false,
315
316 (tt1, Tok(Token { kind: Comma | Semi | Dot, .. }, _)) if !is_punct(tt1) => false,
320
321 (Tok(Token { kind: Ident(sym, is_raw), span }, _), Tok(Token { kind: Not, .. }, _))
323 if !Ident::new(*sym, *span).is_reserved() || matches!(is_raw, IdentIsRaw::Yes) =>
324 {
325 false
326 }
327
328 (Tok(Token { kind: Ident(sym, is_raw), span }, _), Del(_, _, Parenthesis, _))
331 if !Ident::new(*sym, *span).is_reserved()
332 || *sym == kw::Fn
333 || *sym == kw::SelfUpper
334 || *sym == kw::Pub
335 || matches!(is_raw, IdentIsRaw::Yes) =>
336 {
337 false
338 }
339
340 (Tok(Token { kind: Pound, .. }, _), Del(_, _, Bracket, _)) => false,
342
343 _ => true,
344 }
345}
346
347fn binop_to_string(op: BinOpToken) -> &'static str {
348 match op {
349 token::Plus => "+",
350 token::Minus => "-",
351 token::Star => "*",
352 token::Slash => "/",
353 token::Percent => "%",
354 token::Caret => "^",
355 token::And => "&",
356 token::Or => "|",
357 token::Shl => "<<",
358 token::Shr => ">>",
359 }
360}
361
362pub fn doc_comment_to_string(
363 comment_kind: CommentKind,
364 attr_style: ast::AttrStyle,
365 data: Symbol,
366) -> String {
367 match (comment_kind, attr_style) {
368 (CommentKind::Line, ast::AttrStyle::Outer) => format!("///{data}"),
369 (CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{data}"),
370 (CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{data}*/"),
371 (CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{data}*/"),
372 }
373}
374
375fn literal_to_string(lit: token::Lit) -> String {
376 let token::Lit { kind, symbol, suffix } = lit;
377 let mut out = match kind {
378 token::Byte => format!("b'{symbol}'"),
379 token::Char => format!("'{symbol}'"),
380 token::Str => format!("\"{symbol}\""),
381 token::StrRaw(n) => {
382 format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
383 }
384 token::ByteStr => format!("b\"{symbol}\""),
385 token::ByteStrRaw(n) => {
386 format!("br{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
387 }
388 token::CStr => format!("c\"{symbol}\""),
389 token::CStrRaw(n) => {
390 format!("cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize))
391 }
392 token::Integer | token::Float | token::Bool | token::Err(_) => symbol.to_string(),
393 };
394
395 if let Some(suffix) = suffix {
396 out.push_str(suffix.as_str())
397 }
398
399 out
400}
401
402impl std::ops::Deref for State<'_> {
403 type Target = pp::Printer;
404 fn deref(&self) -> &Self::Target {
405 &self.s
406 }
407}
408
409impl std::ops::DerefMut for State<'_> {
410 fn deref_mut(&mut self) -> &mut Self::Target {
411 &mut self.s
412 }
413}
414
415pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::DerefMut {
417 fn comments(&self) -> Option<&Comments<'a>>;
418 fn comments_mut(&mut self) -> Option<&mut Comments<'a>>;
419 fn ann_post(&mut self, ident: Ident);
420 fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
421
422 fn print_ident(&mut self, ident: Ident) {
423 self.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string());
424 self.ann_post(ident)
425 }
426
427 fn strsep<T, F>(
428 &mut self,
429 sep: &'static str,
430 space_before: bool,
431 b: Breaks,
432 elts: &[T],
433 mut op: F,
434 ) where
435 F: FnMut(&mut Self, &T),
436 {
437 self.rbox(0, b);
438 if let Some((first, rest)) = elts.split_first() {
439 op(self, first);
440 for elt in rest {
441 if space_before {
442 self.space();
443 }
444 self.word_space(sep);
445 op(self, elt);
446 }
447 }
448 self.end();
449 }
450
451 fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], op: F)
452 where
453 F: FnMut(&mut Self, &T),
454 {
455 self.strsep(",", false, b, elts, op)
456 }
457
458 fn maybe_print_comment(&mut self, pos: BytePos) -> bool {
459 let mut has_comment = false;
460 while let Some(cmnt) = self.peek_comment() {
461 if cmnt.pos >= pos {
462 break;
463 }
464 has_comment = true;
465 let cmnt = self.next_comment().unwrap();
466 self.print_comment(cmnt);
467 }
468 has_comment
469 }
470
471 fn print_comment(&mut self, cmnt: Comment) {
472 match cmnt.style {
473 CommentStyle::Mixed => {
474 if !self.is_beginning_of_line() {
475 self.zerobreak();
476 }
477 if let Some((last, lines)) = cmnt.lines.split_last() {
478 self.ibox(0);
479
480 for line in lines {
481 self.word(line.clone());
482 self.hardbreak()
483 }
484
485 self.word(last.clone());
486 self.space();
487
488 self.end();
489 }
490 self.zerobreak()
491 }
492 CommentStyle::Isolated => {
493 self.hardbreak_if_not_bol();
494 for line in &cmnt.lines {
495 if !line.is_empty() {
498 self.word(line.clone());
499 }
500 self.hardbreak();
501 }
502 }
503 CommentStyle::Trailing => {
504 if !self.is_beginning_of_line() {
505 self.word(" ");
506 }
507 if let [line] = cmnt.lines.as_slice() {
508 self.word(line.clone());
509 self.hardbreak()
510 } else {
511 self.visual_align();
512 for line in &cmnt.lines {
513 if !line.is_empty() {
514 self.word(line.clone());
515 }
516 self.hardbreak();
517 }
518 self.end();
519 }
520 }
521 CommentStyle::BlankLine => {
522 let twice = match self.last_token() {
524 Some(pp::Token::String(s)) => ";" == s,
525 Some(pp::Token::Begin(_)) => true,
526 Some(pp::Token::End) => true,
527 _ => false,
528 };
529 if twice {
530 self.hardbreak();
531 }
532 self.hardbreak();
533 }
534 }
535 }
536
537 fn peek_comment<'b>(&'b self) -> Option<&'b Comment>
538 where
539 'a: 'b,
540 {
541 self.comments().and_then(|c| c.peek())
542 }
543
544 fn next_comment(&mut self) -> Option<Comment> {
545 self.comments_mut().and_then(|c| c.next())
546 }
547
548 fn maybe_print_trailing_comment(&mut self, span: rustc_span::Span, next_pos: Option<BytePos>) {
549 if let Some(cmnts) = self.comments_mut() {
550 if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
551 self.print_comment(cmnt);
552 }
553 }
554 }
555
556 fn print_remaining_comments(&mut self) {
557 if self.peek_comment().is_none() {
560 self.hardbreak();
561 }
562 while let Some(cmnt) = self.next_comment() {
563 self.print_comment(cmnt)
564 }
565 }
566
567 fn print_string(&mut self, st: &str, style: ast::StrStyle) {
568 let st = match style {
569 ast::StrStyle::Cooked => format!("\"{}\"", st.escape_debug()),
570 ast::StrStyle::Raw(n) => {
571 format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = st)
572 }
573 };
574 self.word(st)
575 }
576
577 fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) -> bool {
578 self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
579 }
580
581 fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) -> bool {
582 self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
583 }
584
585 fn print_either_attributes(
586 &mut self,
587 attrs: &[ast::Attribute],
588 kind: ast::AttrStyle,
589 is_inline: bool,
590 trailing_hardbreak: bool,
591 ) -> bool {
592 let mut printed = false;
593 for attr in attrs {
594 if attr.style == kind {
595 self.print_attribute_inline(attr, is_inline);
596 if is_inline {
597 self.nbsp();
598 }
599 printed = true;
600 }
601 }
602 if printed && trailing_hardbreak && !is_inline {
603 self.hardbreak_if_not_bol();
604 }
605 printed
606 }
607
608 fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) {
609 if !is_inline {
610 self.hardbreak_if_not_bol();
611 }
612 self.maybe_print_comment(attr.span.lo());
613 match &attr.kind {
614 ast::AttrKind::Normal(normal) => {
615 match attr.style {
616 ast::AttrStyle::Inner => self.word("#!["),
617 ast::AttrStyle::Outer => self.word("#["),
618 }
619 self.print_attr_item(&normal.item, attr.span);
620 self.word("]");
621 }
622 ast::AttrKind::DocComment(comment_kind, data) => {
623 self.word(doc_comment_to_string(*comment_kind, attr.style, *data));
624 self.hardbreak()
625 }
626 }
627 }
628
629 fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
630 self.ibox(0);
631 match item.unsafety {
632 ast::Safety::Unsafe(_) => {
633 self.word("unsafe");
634 self.popen();
635 }
636 ast::Safety::Default | ast::Safety::Safe(_) => {}
637 }
638 match &item.args {
639 AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common(
640 Some(MacHeader::Path(&item.path)),
641 false,
642 None,
643 *delim,
644 tokens,
645 true,
646 span,
647 ),
648 AttrArgs::Empty => {
649 self.print_path(&item.path, false, 0);
650 }
651 AttrArgs::Eq { expr, .. } => {
652 self.print_path(&item.path, false, 0);
653 self.space();
654 self.word_space("=");
655 let token_str = self.expr_to_string(expr);
656 self.word(token_str);
657 }
658 }
659 match item.unsafety {
660 ast::Safety::Unsafe(_) => self.pclose(),
661 ast::Safety::Default | ast::Safety::Safe(_) => {}
662 }
663 self.end();
664 }
665
666 fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) -> Spacing {
674 match tt {
675 TokenTree::Token(token, spacing) => {
676 let token_str = self.token_to_string_ext(token, convert_dollar_crate);
677 self.word(token_str);
678 if let token::DocComment(..) = token.kind {
679 self.hardbreak()
680 }
681 *spacing
682 }
683 TokenTree::Delimited(dspan, spacing, delim, tts) => {
684 self.print_mac_common(
685 None,
686 false,
687 None,
688 *delim,
689 tts,
690 convert_dollar_crate,
691 dspan.entire(),
692 );
693 spacing.close
694 }
695 }
696 }
697
698 fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
728 let mut iter = tts.iter().peekable();
729 while let Some(tt) = iter.next() {
730 let spacing = self.print_tt(tt, convert_dollar_crate);
731 if let Some(next) = iter.peek() {
732 if spacing == Spacing::Alone && space_between(tt, next) {
733 self.space();
734 }
735 }
736 }
737 }
738
739 fn print_mac_common(
740 &mut self,
741 header: Option<MacHeader<'_>>,
742 has_bang: bool,
743 ident: Option<Ident>,
744 delim: Delimiter,
745 tts: &TokenStream,
746 convert_dollar_crate: bool,
747 span: Span,
748 ) {
749 if delim == Delimiter::Brace {
750 self.cbox(INDENT_UNIT);
751 }
752 match header {
753 Some(MacHeader::Path(path)) => self.print_path(path, false, 0),
754 Some(MacHeader::Keyword(kw)) => self.word(kw),
755 None => {}
756 }
757 if has_bang {
758 self.word("!");
759 }
760 if let Some(ident) = ident {
761 self.nbsp();
762 self.print_ident(ident);
763 }
764 match delim {
765 Delimiter::Brace => {
766 if header.is_some() || has_bang || ident.is_some() {
767 self.nbsp();
768 }
769 self.word("{");
770 if !tts.is_empty() {
771 self.space();
772 }
773 self.ibox(0);
774 self.print_tts(tts, convert_dollar_crate);
775 self.end();
776 let empty = tts.is_empty();
777 self.bclose(span, empty);
778 }
779 delim => {
780 let token_str = self.token_kind_to_string(&token::OpenDelim(delim));
781 self.word(token_str);
782 self.ibox(0);
783 self.print_tts(tts, convert_dollar_crate);
784 self.end();
785 let token_str = self.token_kind_to_string(&token::CloseDelim(delim));
786 self.word(token_str);
787 }
788 }
789 }
790
791 fn print_mac_def(
792 &mut self,
793 macro_def: &ast::MacroDef,
794 ident: &Ident,
795 sp: Span,
796 print_visibility: impl FnOnce(&mut Self),
797 ) {
798 let (kw, has_bang) = if macro_def.macro_rules {
799 ("macro_rules", true)
800 } else {
801 print_visibility(self);
802 ("macro", false)
803 };
804 self.print_mac_common(
805 Some(MacHeader::Keyword(kw)),
806 has_bang,
807 Some(*ident),
808 macro_def.body.delim,
809 ¯o_def.body.tokens.clone(),
810 true,
811 sp,
812 );
813 if macro_def.body.need_semicolon() {
814 self.word(";");
815 }
816 }
817
818 fn print_path(&mut self, path: &ast::Path, colons_before_params: bool, depth: usize) {
819 self.maybe_print_comment(path.span.lo());
820
821 for (i, segment) in path.segments[..path.segments.len() - depth].iter().enumerate() {
822 if i > 0 {
823 self.word("::")
824 }
825 self.print_path_segment(segment, colons_before_params);
826 }
827 }
828
829 fn print_path_segment(&mut self, segment: &ast::PathSegment, colons_before_params: bool) {
830 if segment.ident.name != kw::PathRoot {
831 self.print_ident(segment.ident);
832 if let Some(args) = &segment.args {
833 self.print_generic_args(args, colons_before_params);
834 }
835 }
836 }
837
838 fn head<S: Into<Cow<'static, str>>>(&mut self, w: S) {
839 let w = w.into();
840 self.cbox(INDENT_UNIT);
842 self.ibox(0);
844 if !w.is_empty() {
846 self.word_nbsp(w);
847 }
848 }
849
850 fn bopen(&mut self) {
851 self.word("{");
852 self.end(); }
854
855 fn bclose_maybe_open(&mut self, span: rustc_span::Span, empty: bool, close_box: bool) {
856 let has_comment = self.maybe_print_comment(span.hi());
857 if !empty || has_comment {
858 self.break_offset_if_not_bol(1, -INDENT_UNIT);
859 }
860 self.word("}");
861 if close_box {
862 self.end(); }
864 }
865
866 fn bclose(&mut self, span: rustc_span::Span, empty: bool) {
867 let close_box = true;
868 self.bclose_maybe_open(span, empty, close_box)
869 }
870
871 fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
872 if !self.is_beginning_of_line() {
873 self.break_offset(n, off)
874 } else if off != 0 {
875 if let Some(last_token) = self.last_token_still_buffered() {
876 if last_token.is_hardbreak_tok() {
877 self.replace_last_token_still_buffered(pp::Printer::hardbreak_tok_offset(off));
881 }
882 }
883 }
884 }
885
886 fn nonterminal_to_string(&self, nt: &Nonterminal) -> String {
887 self.tts_to_string(&TokenStream::from_nonterminal_ast(nt))
892 }
893
894 fn token_kind_to_string(&self, tok: &TokenKind) -> Cow<'static, str> {
896 self.token_kind_to_string_ext(tok, None)
897 }
898
899 fn token_kind_to_string_ext(
900 &self,
901 tok: &TokenKind,
902 convert_dollar_crate: Option<Span>,
903 ) -> Cow<'static, str> {
904 match *tok {
905 token::Eq => "=".into(),
906 token::Lt => "<".into(),
907 token::Le => "<=".into(),
908 token::EqEq => "==".into(),
909 token::Ne => "!=".into(),
910 token::Ge => ">=".into(),
911 token::Gt => ">".into(),
912 token::Not => "!".into(),
913 token::Tilde => "~".into(),
914 token::OrOr => "||".into(),
915 token::AndAnd => "&&".into(),
916 token::BinOp(op) => binop_to_string(op).into(),
917 token::BinOpEq(op) => format!("{}=", binop_to_string(op)).into(),
918
919 token::At => "@".into(),
921 token::Dot => ".".into(),
922 token::DotDot => "..".into(),
923 token::DotDotDot => "...".into(),
924 token::DotDotEq => "..=".into(),
925 token::Comma => ",".into(),
926 token::Semi => ";".into(),
927 token::Colon => ":".into(),
928 token::PathSep => "::".into(),
929 token::RArrow => "->".into(),
930 token::LArrow => "<-".into(),
931 token::FatArrow => "=>".into(),
932 token::OpenDelim(Delimiter::Parenthesis) => "(".into(),
933 token::CloseDelim(Delimiter::Parenthesis) => ")".into(),
934 token::OpenDelim(Delimiter::Bracket) => "[".into(),
935 token::CloseDelim(Delimiter::Bracket) => "]".into(),
936 token::OpenDelim(Delimiter::Brace) => "{".into(),
937 token::CloseDelim(Delimiter::Brace) => "}".into(),
938 token::OpenDelim(Delimiter::Invisible(_))
939 | token::CloseDelim(Delimiter::Invisible(_)) => "".into(),
940 token::Pound => "#".into(),
941 token::Dollar => "$".into(),
942 token::Question => "?".into(),
943 token::SingleQuote => "'".into(),
944
945 token::Literal(lit) => literal_to_string(lit).into(),
947
948 token::Ident(name, is_raw) => {
950 IdentPrinter::new(name, is_raw.into(), convert_dollar_crate).to_string().into()
951 }
952 token::NtIdent(ident, is_raw) => {
953 IdentPrinter::for_ast_ident(ident, is_raw.into()).to_string().into()
954 }
955
956 token::Lifetime(name, IdentIsRaw::No)
957 | token::NtLifetime(Ident { name, .. }, IdentIsRaw::No) => name.to_string().into(),
958 token::Lifetime(name, IdentIsRaw::Yes)
959 | token::NtLifetime(Ident { name, .. }, IdentIsRaw::Yes) => {
960 format!("'r#{}", &name.as_str()[1..]).into()
961 }
962
963 token::DocComment(comment_kind, attr_style, data) => {
965 doc_comment_to_string(comment_kind, attr_style, data).into()
966 }
967 token::Eof => "<eof>".into(),
968
969 token::Interpolated(ref nt) => self.nonterminal_to_string(&nt).into(),
970 }
971 }
972
973 fn token_to_string(&self, token: &Token) -> Cow<'static, str> {
975 self.token_to_string_ext(token, false)
976 }
977
978 fn token_to_string_ext(&self, token: &Token, convert_dollar_crate: bool) -> Cow<'static, str> {
979 let convert_dollar_crate = convert_dollar_crate.then_some(token.span);
980 self.token_kind_to_string_ext(&token.kind, convert_dollar_crate)
981 }
982
983 fn ty_to_string(&self, ty: &ast::Ty) -> String {
984 Self::to_string(|s| s.print_type(ty))
985 }
986
987 fn pat_to_string(&self, pat: &ast::Pat) -> String {
988 Self::to_string(|s| s.print_pat(pat))
989 }
990
991 fn expr_to_string(&self, e: &ast::Expr) -> String {
992 Self::to_string(|s| s.print_expr(e, FixupContext::default()))
993 }
994
995 fn meta_item_lit_to_string(&self, lit: &ast::MetaItemLit) -> String {
996 Self::to_string(|s| s.print_meta_item_lit(lit))
997 }
998
999 fn stmt_to_string(&self, stmt: &ast::Stmt) -> String {
1000 Self::to_string(|s| s.print_stmt(stmt))
1001 }
1002
1003 fn item_to_string(&self, i: &ast::Item) -> String {
1004 Self::to_string(|s| s.print_item(i))
1005 }
1006
1007 fn path_to_string(&self, p: &ast::Path) -> String {
1008 Self::to_string(|s| s.print_path(p, false, 0))
1009 }
1010
1011 fn vis_to_string(&self, v: &ast::Visibility) -> String {
1012 Self::to_string(|s| s.print_visibility(v))
1013 }
1014
1015 fn block_to_string(&self, blk: &ast::Block) -> String {
1016 Self::to_string(|s| {
1017 s.cbox(INDENT_UNIT);
1019 s.ibox(0);
1021 s.print_block(blk)
1022 })
1023 }
1024
1025 fn attr_item_to_string(&self, ai: &ast::AttrItem) -> String {
1026 Self::to_string(|s| s.print_attr_item(ai, ai.path.span))
1027 }
1028
1029 fn tts_to_string(&self, tokens: &TokenStream) -> String {
1030 Self::to_string(|s| s.print_tts(tokens, false))
1031 }
1032
1033 fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
1034 let mut printer = State::new();
1035 f(&mut printer);
1036 printer.s.eof()
1037 }
1038}
1039
1040impl<'a> PrintState<'a> for State<'a> {
1041 fn comments(&self) -> Option<&Comments<'a>> {
1042 self.comments.as_ref()
1043 }
1044
1045 fn comments_mut(&mut self) -> Option<&mut Comments<'a>> {
1046 self.comments.as_mut()
1047 }
1048
1049 fn ann_post(&mut self, ident: Ident) {
1050 self.ann.post(self, AnnNode::Ident(&ident));
1051 }
1052
1053 fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool) {
1054 if colons_before_params {
1055 self.word("::")
1056 }
1057
1058 match args {
1059 ast::GenericArgs::AngleBracketed(data) => {
1060 self.word("<");
1061 self.commasep(Inconsistent, &data.args, |s, arg| match arg {
1062 ast::AngleBracketedArg::Arg(a) => s.print_generic_arg(a),
1063 ast::AngleBracketedArg::Constraint(c) => s.print_assoc_item_constraint(c),
1064 });
1065 self.word(">")
1066 }
1067
1068 ast::GenericArgs::Parenthesized(data) => {
1069 self.word("(");
1070 self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(ty));
1071 self.word(")");
1072 self.print_fn_ret_ty(&data.output);
1073 }
1074 ast::GenericArgs::ParenthesizedElided(_) => {
1075 self.word("(");
1076 self.word("..");
1077 self.word(")");
1078 }
1079 }
1080 }
1081}
1082
1083impl<'a> State<'a> {
1084 pub fn new() -> State<'a> {
1085 State { s: pp::Printer::new(), comments: None, ann: &NoAnn }
1086 }
1087
1088 fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
1089 where
1090 F: FnMut(&mut State<'_>, &T),
1091 G: FnMut(&T) -> rustc_span::Span,
1092 {
1093 self.rbox(0, b);
1094 let len = elts.len();
1095 let mut i = 0;
1096 for elt in elts {
1097 self.maybe_print_comment(get_span(elt).hi());
1098 op(self, elt);
1099 i += 1;
1100 if i < len {
1101 self.word(",");
1102 self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi()));
1103 self.space_if_not_bol();
1104 }
1105 }
1106 self.end();
1107 }
1108
1109 fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) {
1110 self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e, FixupContext::default()), |e| e.span)
1111 }
1112
1113 pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) {
1114 if let Some(lt) = *lifetime {
1115 self.print_lifetime(lt);
1116 self.nbsp();
1117 }
1118 }
1119
1120 pub fn print_assoc_item_constraint(&mut self, constraint: &ast::AssocItemConstraint) {
1121 self.print_ident(constraint.ident);
1122 if let Some(args) = constraint.gen_args.as_ref() {
1123 self.print_generic_args(args, false)
1124 }
1125 self.space();
1126 match &constraint.kind {
1127 ast::AssocItemConstraintKind::Equality { term } => {
1128 self.word_space("=");
1129 match term {
1130 Term::Ty(ty) => self.print_type(ty),
1131 Term::Const(c) => self.print_expr_anon_const(c, &[]),
1132 }
1133 }
1134 ast::AssocItemConstraintKind::Bound { bounds } => {
1135 if !bounds.is_empty() {
1136 self.word_nbsp(":");
1137 self.print_type_bounds(bounds);
1138 }
1139 }
1140 }
1141 }
1142
1143 pub fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
1144 match generic_arg {
1145 GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
1146 GenericArg::Type(ty) => self.print_type(ty),
1147 GenericArg::Const(ct) => self.print_expr(&ct.value, FixupContext::default()),
1148 }
1149 }
1150
1151 pub fn print_ty_pat(&mut self, pat: &ast::TyPat) {
1152 match &pat.kind {
1153 rustc_ast::TyPatKind::Range(start, end, include_end) => {
1154 if let Some(start) = start {
1155 self.print_expr_anon_const(start, &[]);
1156 }
1157 self.word("..");
1158 if let Some(end) = end {
1159 if let RangeEnd::Included(_) = include_end.node {
1160 self.word("=");
1161 }
1162 self.print_expr_anon_const(end, &[]);
1163 }
1164 }
1165 rustc_ast::TyPatKind::Err(_) => {
1166 self.popen();
1167 self.word("/*ERROR*/");
1168 self.pclose();
1169 }
1170 }
1171 }
1172
1173 pub fn print_type(&mut self, ty: &ast::Ty) {
1174 self.maybe_print_comment(ty.span.lo());
1175 self.ibox(0);
1176 match &ty.kind {
1177 ast::TyKind::Slice(ty) => {
1178 self.word("[");
1179 self.print_type(ty);
1180 self.word("]");
1181 }
1182 ast::TyKind::Ptr(mt) => {
1183 self.word("*");
1184 self.print_mt(mt, true);
1185 }
1186 ast::TyKind::Ref(lifetime, mt) => {
1187 self.word("&");
1188 self.print_opt_lifetime(lifetime);
1189 self.print_mt(mt, false);
1190 }
1191 ast::TyKind::PinnedRef(lifetime, mt) => {
1192 self.word("&");
1193 self.print_opt_lifetime(lifetime);
1194 self.word("pin ");
1195 self.print_mt(mt, true);
1196 }
1197 ast::TyKind::Never => {
1198 self.word("!");
1199 }
1200 ast::TyKind::Tup(elts) => {
1201 self.popen();
1202 self.commasep(Inconsistent, elts, |s, ty| s.print_type(ty));
1203 if elts.len() == 1 {
1204 self.word(",");
1205 }
1206 self.pclose();
1207 }
1208 ast::TyKind::Paren(typ) => {
1209 self.popen();
1210 self.print_type(typ);
1211 self.pclose();
1212 }
1213 ast::TyKind::BareFn(f) => {
1214 self.print_ty_fn(f.ext, f.safety, &f.decl, None, &f.generic_params);
1215 }
1216 ast::TyKind::UnsafeBinder(f) => {
1217 self.ibox(INDENT_UNIT);
1218 self.word("unsafe");
1219 self.print_generic_params(&f.generic_params);
1220 self.nbsp();
1221 self.print_type(&f.inner_ty);
1222 self.end();
1223 }
1224 ast::TyKind::Path(None, path) => {
1225 self.print_path(path, false, 0);
1226 }
1227 ast::TyKind::Path(Some(qself), path) => self.print_qpath(path, qself, false),
1228 ast::TyKind::TraitObject(bounds, syntax) => {
1229 match syntax {
1230 ast::TraitObjectSyntax::Dyn => self.word_nbsp("dyn"),
1231 ast::TraitObjectSyntax::DynStar => self.word_nbsp("dyn*"),
1232 ast::TraitObjectSyntax::None => {}
1233 }
1234 self.print_type_bounds(bounds);
1235 }
1236 ast::TyKind::ImplTrait(_, bounds) => {
1237 self.word_nbsp("impl");
1238 self.print_type_bounds(bounds);
1239 }
1240 ast::TyKind::Array(ty, length) => {
1241 self.word("[");
1242 self.print_type(ty);
1243 self.word("; ");
1244 self.print_expr(&length.value, FixupContext::default());
1245 self.word("]");
1246 }
1247 ast::TyKind::Typeof(e) => {
1248 self.word("typeof(");
1249 self.print_expr(&e.value, FixupContext::default());
1250 self.word(")");
1251 }
1252 ast::TyKind::Infer => {
1253 self.word("_");
1254 }
1255 ast::TyKind::Err(_) => {
1256 self.popen();
1257 self.word("/*ERROR*/");
1258 self.pclose();
1259 }
1260 ast::TyKind::Dummy => {
1261 self.popen();
1262 self.word("/*DUMMY*/");
1263 self.pclose();
1264 }
1265 ast::TyKind::ImplicitSelf => {
1266 self.word("Self");
1267 }
1268 ast::TyKind::MacCall(m) => {
1269 self.print_mac(m);
1270 }
1271 ast::TyKind::CVarArgs => {
1272 self.word("...");
1273 }
1274 ast::TyKind::Pat(ty, pat) => {
1275 self.print_type(ty);
1276 self.word(" is ");
1277 self.print_ty_pat(pat);
1278 }
1279 }
1280 self.end();
1281 }
1282
1283 fn print_trait_ref(&mut self, t: &ast::TraitRef) {
1284 self.print_path(&t.path, false, 0)
1285 }
1286
1287 fn print_formal_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
1288 if !generic_params.is_empty() {
1289 self.word("for");
1290 self.print_generic_params(generic_params);
1291 self.nbsp();
1292 }
1293 }
1294
1295 fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) {
1296 self.print_formal_generic_params(&t.bound_generic_params);
1297
1298 let ast::TraitBoundModifiers { constness, asyncness, polarity } = t.modifiers;
1299 match constness {
1300 ast::BoundConstness::Never => {}
1301 ast::BoundConstness::Always(_) | ast::BoundConstness::Maybe(_) => {
1302 self.word_space(constness.as_str());
1303 }
1304 }
1305 match asyncness {
1306 ast::BoundAsyncness::Normal => {}
1307 ast::BoundAsyncness::Async(_) => {
1308 self.word_space(asyncness.as_str());
1309 }
1310 }
1311 match polarity {
1312 ast::BoundPolarity::Positive => {}
1313 ast::BoundPolarity::Negative(_) | ast::BoundPolarity::Maybe(_) => {
1314 self.word(polarity.as_str());
1315 }
1316 }
1317
1318 self.print_trait_ref(&t.trait_ref)
1319 }
1320
1321 fn print_stmt(&mut self, st: &ast::Stmt) {
1322 self.maybe_print_comment(st.span.lo());
1323 match &st.kind {
1324 ast::StmtKind::Let(loc) => {
1325 self.print_outer_attributes(&loc.attrs);
1326 self.space_if_not_bol();
1327 self.ibox(INDENT_UNIT);
1328 self.word_nbsp("let");
1329
1330 self.ibox(INDENT_UNIT);
1331 self.print_local_decl(loc);
1332 self.end();
1333 if let Some((init, els)) = loc.kind.init_else_opt() {
1334 self.nbsp();
1335 self.word_space("=");
1336 self.print_expr_cond_paren(
1337 init,
1338 els.is_some() && classify::expr_trailing_brace(init).is_some(),
1339 FixupContext::default(),
1340 );
1341 if let Some(els) = els {
1342 self.cbox(INDENT_UNIT);
1343 self.ibox(INDENT_UNIT);
1344 self.word(" else ");
1345 self.print_block(els);
1346 }
1347 }
1348 self.word(";");
1349 self.end(); }
1351 ast::StmtKind::Item(item) => self.print_item(item),
1352 ast::StmtKind::Expr(expr) => {
1353 self.space_if_not_bol();
1354 self.print_expr_outer_attr_style(expr, false, FixupContext::new_stmt());
1355 if classify::expr_requires_semi_to_be_stmt(expr) {
1356 self.word(";");
1357 }
1358 }
1359 ast::StmtKind::Semi(expr) => {
1360 self.space_if_not_bol();
1361 self.print_expr_outer_attr_style(expr, false, FixupContext::new_stmt());
1362 self.word(";");
1363 }
1364 ast::StmtKind::Empty => {
1365 self.space_if_not_bol();
1366 self.word(";");
1367 }
1368 ast::StmtKind::MacCall(mac) => {
1369 self.space_if_not_bol();
1370 self.print_outer_attributes(&mac.attrs);
1371 self.print_mac(&mac.mac);
1372 if mac.style == ast::MacStmtStyle::Semicolon {
1373 self.word(";");
1374 }
1375 }
1376 }
1377 self.maybe_print_trailing_comment(st.span, None)
1378 }
1379
1380 fn print_block(&mut self, blk: &ast::Block) {
1381 self.print_block_with_attrs(blk, &[])
1382 }
1383
1384 fn print_block_unclosed_indent(&mut self, blk: &ast::Block) {
1385 self.print_block_maybe_unclosed(blk, &[], false)
1386 }
1387
1388 fn print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute]) {
1389 self.print_block_maybe_unclosed(blk, attrs, true)
1390 }
1391
1392 fn print_block_maybe_unclosed(
1393 &mut self,
1394 blk: &ast::Block,
1395 attrs: &[ast::Attribute],
1396 close_box: bool,
1397 ) {
1398 match blk.rules {
1399 BlockCheckMode::Unsafe(..) => self.word_space("unsafe"),
1400 BlockCheckMode::Default => (),
1401 }
1402 self.maybe_print_comment(blk.span.lo());
1403 self.ann.pre(self, AnnNode::Block(blk));
1404 self.bopen();
1405
1406 let has_attrs = self.print_inner_attributes(attrs);
1407
1408 for (i, st) in blk.stmts.iter().enumerate() {
1409 match &st.kind {
1410 ast::StmtKind::Expr(expr) if i == blk.stmts.len() - 1 => {
1411 self.maybe_print_comment(st.span.lo());
1412 self.space_if_not_bol();
1413 self.print_expr_outer_attr_style(expr, false, FixupContext::new_stmt());
1414 self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
1415 }
1416 _ => self.print_stmt(st),
1417 }
1418 }
1419
1420 let empty = !has_attrs && blk.stmts.is_empty();
1421 self.bclose_maybe_open(blk.span, empty, close_box);
1422 self.ann.post(self, AnnNode::Block(blk))
1423 }
1424
1425 fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr, fixup: FixupContext) {
1451 self.word("let ");
1452 self.print_pat(pat);
1453 self.space();
1454 self.word_space("=");
1455 self.print_expr_cond_paren(
1456 expr,
1457 fixup.needs_par_as_let_scrutinee(expr),
1458 FixupContext::default(),
1459 );
1460 }
1461
1462 fn print_mac(&mut self, m: &ast::MacCall) {
1463 self.print_mac_common(
1464 Some(MacHeader::Path(&m.path)),
1465 true,
1466 None,
1467 m.args.delim,
1468 &m.args.tokens.clone(),
1469 true,
1470 m.span(),
1471 );
1472 }
1473
1474 fn print_inline_asm(&mut self, asm: &ast::InlineAsm) {
1475 enum AsmArg<'a> {
1476 Template(String),
1477 Operand(&'a InlineAsmOperand),
1478 ClobberAbi(Symbol),
1479 Options(InlineAsmOptions),
1480 }
1481
1482 let mut args = vec![AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template))];
1483 args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
1484 for (abi, _) in &asm.clobber_abis {
1485 args.push(AsmArg::ClobberAbi(*abi));
1486 }
1487 if !asm.options.is_empty() {
1488 args.push(AsmArg::Options(asm.options));
1489 }
1490
1491 self.popen();
1492 self.commasep(Consistent, &args, |s, arg| match arg {
1493 AsmArg::Template(template) => s.print_string(template, ast::StrStyle::Cooked),
1494 AsmArg::Operand(op) => {
1495 let print_reg_or_class = |s: &mut Self, r: &InlineAsmRegOrRegClass| match r {
1496 InlineAsmRegOrRegClass::Reg(r) => s.print_symbol(*r, ast::StrStyle::Cooked),
1497 InlineAsmRegOrRegClass::RegClass(r) => s.word(r.to_string()),
1498 };
1499 match op {
1500 InlineAsmOperand::In { reg, expr } => {
1501 s.word("in");
1502 s.popen();
1503 print_reg_or_class(s, reg);
1504 s.pclose();
1505 s.space();
1506 s.print_expr(expr, FixupContext::default());
1507 }
1508 InlineAsmOperand::Out { reg, late, expr } => {
1509 s.word(if *late { "lateout" } else { "out" });
1510 s.popen();
1511 print_reg_or_class(s, reg);
1512 s.pclose();
1513 s.space();
1514 match expr {
1515 Some(expr) => s.print_expr(expr, FixupContext::default()),
1516 None => s.word("_"),
1517 }
1518 }
1519 InlineAsmOperand::InOut { reg, late, expr } => {
1520 s.word(if *late { "inlateout" } else { "inout" });
1521 s.popen();
1522 print_reg_or_class(s, reg);
1523 s.pclose();
1524 s.space();
1525 s.print_expr(expr, FixupContext::default());
1526 }
1527 InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
1528 s.word(if *late { "inlateout" } else { "inout" });
1529 s.popen();
1530 print_reg_or_class(s, reg);
1531 s.pclose();
1532 s.space();
1533 s.print_expr(in_expr, FixupContext::default());
1534 s.space();
1535 s.word_space("=>");
1536 match out_expr {
1537 Some(out_expr) => s.print_expr(out_expr, FixupContext::default()),
1538 None => s.word("_"),
1539 }
1540 }
1541 InlineAsmOperand::Const { anon_const } => {
1542 s.word("const");
1543 s.space();
1544 s.print_expr(&anon_const.value, FixupContext::default());
1545 }
1546 InlineAsmOperand::Sym { sym } => {
1547 s.word("sym");
1548 s.space();
1549 if let Some(qself) = &sym.qself {
1550 s.print_qpath(&sym.path, qself, true);
1551 } else {
1552 s.print_path(&sym.path, true, 0);
1553 }
1554 }
1555 InlineAsmOperand::Label { block } => {
1556 s.head("label");
1557 s.print_block(block);
1558 }
1559 }
1560 }
1561 AsmArg::ClobberAbi(abi) => {
1562 s.word("clobber_abi");
1563 s.popen();
1564 s.print_symbol(*abi, ast::StrStyle::Cooked);
1565 s.pclose();
1566 }
1567 AsmArg::Options(opts) => {
1568 s.word("options");
1569 s.popen();
1570 s.commasep(Inconsistent, &opts.human_readable_names(), |s, &opt| {
1571 s.word(opt);
1572 });
1573 s.pclose();
1574 }
1575 });
1576 self.pclose();
1577 }
1578
1579 fn print_local_decl(&mut self, loc: &ast::Local) {
1580 self.print_pat(&loc.pat);
1581 if let Some(ty) = &loc.ty {
1582 self.word_space(":");
1583 self.print_type(ty);
1584 }
1585 }
1586
1587 fn print_name(&mut self, name: Symbol) {
1588 self.word(name.to_string());
1589 self.ann.post(self, AnnNode::Name(&name))
1590 }
1591
1592 fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_params: bool) {
1593 self.word("<");
1594 self.print_type(&qself.ty);
1595 if qself.position > 0 {
1596 self.space();
1597 self.word_space("as");
1598 let depth = path.segments.len() - qself.position;
1599 self.print_path(path, false, depth);
1600 }
1601 self.word(">");
1602 for item_segment in &path.segments[qself.position..] {
1603 self.word("::");
1604 self.print_ident(item_segment.ident);
1605 if let Some(args) = &item_segment.args {
1606 self.print_generic_args(args, colons_before_params)
1607 }
1608 }
1609 }
1610
1611 fn print_pat(&mut self, pat: &ast::Pat) {
1612 self.maybe_print_comment(pat.span.lo());
1613 self.ann.pre(self, AnnNode::Pat(pat));
1614 match &pat.kind {
1617 PatKind::Wild => self.word("_"),
1618 PatKind::Never => self.word("!"),
1619 PatKind::Ident(BindingMode(by_ref, mutbl), ident, sub) => {
1620 if mutbl.is_mut() {
1621 self.word_nbsp("mut");
1622 }
1623 if let ByRef::Yes(rmutbl) = by_ref {
1624 self.word_nbsp("ref");
1625 if rmutbl.is_mut() {
1626 self.word_nbsp("mut");
1627 }
1628 }
1629 self.print_ident(*ident);
1630 if let Some(p) = sub {
1631 self.space();
1632 self.word_space("@");
1633 self.print_pat(p);
1634 }
1635 }
1636 PatKind::TupleStruct(qself, path, elts) => {
1637 if let Some(qself) = qself {
1638 self.print_qpath(path, qself, true);
1639 } else {
1640 self.print_path(path, true, 0);
1641 }
1642 self.popen();
1643 self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
1644 self.pclose();
1645 }
1646 PatKind::Or(pats) => {
1647 self.strsep("|", true, Inconsistent, pats, |s, p| s.print_pat(p));
1648 }
1649 PatKind::Path(None, path) => {
1650 self.print_path(path, true, 0);
1651 }
1652 PatKind::Path(Some(qself), path) => {
1653 self.print_qpath(path, qself, false);
1654 }
1655 PatKind::Struct(qself, path, fields, etc) => {
1656 if let Some(qself) = qself {
1657 self.print_qpath(path, qself, true);
1658 } else {
1659 self.print_path(path, true, 0);
1660 }
1661 self.nbsp();
1662 self.word("{");
1663 let empty = fields.is_empty() && *etc == ast::PatFieldsRest::None;
1664 if !empty {
1665 self.space();
1666 }
1667 self.commasep_cmnt(
1668 Consistent,
1669 fields,
1670 |s, f| {
1671 s.cbox(INDENT_UNIT);
1672 if !f.is_shorthand {
1673 s.print_ident(f.ident);
1674 s.word_nbsp(":");
1675 }
1676 s.print_pat(&f.pat);
1677 s.end();
1678 },
1679 |f| f.pat.span,
1680 );
1681 if let ast::PatFieldsRest::Rest | ast::PatFieldsRest::Recovered(_) = etc {
1682 if !fields.is_empty() {
1683 self.word_space(",");
1684 }
1685 self.word("..");
1686 if let ast::PatFieldsRest::Recovered(_) = etc {
1687 self.word("/* recovered parse error */");
1688 }
1689 }
1690 if !empty {
1691 self.space();
1692 }
1693 self.word("}");
1694 }
1695 PatKind::Tuple(elts) => {
1696 self.popen();
1697 self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
1698 if elts.len() == 1 {
1699 self.word(",");
1700 }
1701 self.pclose();
1702 }
1703 PatKind::Box(inner) => {
1704 self.word("box ");
1705 self.print_pat(inner);
1706 }
1707 PatKind::Deref(inner) => {
1708 self.word("deref!");
1709 self.popen();
1710 self.print_pat(inner);
1711 self.pclose();
1712 }
1713 PatKind::Ref(inner, mutbl) => {
1714 self.word("&");
1715 if mutbl.is_mut() {
1716 self.word("mut ");
1717 }
1718 if let PatKind::Ident(ast::BindingMode::MUT, ..) = inner.kind {
1719 self.popen();
1720 self.print_pat(inner);
1721 self.pclose();
1722 } else {
1723 self.print_pat(inner);
1724 }
1725 }
1726 PatKind::Expr(e) => self.print_expr(e, FixupContext::default()),
1727 PatKind::Range(begin, end, Spanned { node: end_kind, .. }) => {
1728 if let Some(e) = begin {
1729 self.print_expr(e, FixupContext::default());
1730 }
1731 match end_kind {
1732 RangeEnd::Included(RangeSyntax::DotDotDot) => self.word("..."),
1733 RangeEnd::Included(RangeSyntax::DotDotEq) => self.word("..="),
1734 RangeEnd::Excluded => self.word(".."),
1735 }
1736 if let Some(e) = end {
1737 self.print_expr(e, FixupContext::default());
1738 }
1739 }
1740 PatKind::Guard(subpat, condition) => {
1741 self.popen();
1742 self.print_pat(subpat);
1743 self.space();
1744 self.word_space("if");
1745 self.print_expr(condition, FixupContext::default());
1746 self.pclose();
1747 }
1748 PatKind::Slice(elts) => {
1749 self.word("[");
1750 self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
1751 self.word("]");
1752 }
1753 PatKind::Rest => self.word(".."),
1754 PatKind::Paren(inner) => {
1755 self.popen();
1756 self.print_pat(inner);
1757 self.pclose();
1758 }
1759 PatKind::MacCall(m) => self.print_mac(m),
1760 PatKind::Err(_) => {
1761 self.popen();
1762 self.word("/*ERROR*/");
1763 self.pclose();
1764 }
1765 }
1766 self.ann.post(self, AnnNode::Pat(pat))
1767 }
1768
1769 fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) {
1770 match &explicit_self.node {
1771 SelfKind::Value(m) => {
1772 self.print_mutability(*m, false);
1773 self.word("self")
1774 }
1775 SelfKind::Region(lt, m) => {
1776 self.word("&");
1777 self.print_opt_lifetime(lt);
1778 self.print_mutability(*m, false);
1779 self.word("self")
1780 }
1781 SelfKind::Explicit(typ, m) => {
1782 self.print_mutability(*m, false);
1783 self.word("self");
1784 self.word_space(":");
1785 self.print_type(typ)
1786 }
1787 }
1788 }
1789
1790 fn print_coroutine_kind(&mut self, coroutine_kind: ast::CoroutineKind) {
1791 match coroutine_kind {
1792 ast::CoroutineKind::Gen { .. } => {
1793 self.word_nbsp("gen");
1794 }
1795 ast::CoroutineKind::Async { .. } => {
1796 self.word_nbsp("async");
1797 }
1798 ast::CoroutineKind::AsyncGen { .. } => {
1799 self.word_nbsp("async");
1800 self.word_nbsp("gen");
1801 }
1802 }
1803 }
1804
1805 pub fn print_type_bounds(&mut self, bounds: &[ast::GenericBound]) {
1806 let mut first = true;
1807 for bound in bounds {
1808 if first {
1809 first = false;
1810 } else {
1811 self.nbsp();
1812 self.word_space("+");
1813 }
1814
1815 match bound {
1816 GenericBound::Trait(tref) => {
1817 self.print_poly_trait_ref(tref);
1818 }
1819 GenericBound::Outlives(lt) => self.print_lifetime(*lt),
1820 GenericBound::Use(args, _) => {
1821 self.word("use");
1822 self.word("<");
1823 self.commasep(Inconsistent, args, |s, arg| match arg {
1824 ast::PreciseCapturingArg::Arg(p, _) => s.print_path(p, false, 0),
1825 ast::PreciseCapturingArg::Lifetime(lt) => s.print_lifetime(*lt),
1826 });
1827 self.word(">")
1828 }
1829 }
1830 }
1831 }
1832
1833 fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
1834 self.print_name(lifetime.ident.name)
1835 }
1836
1837 fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) {
1838 for (i, bound) in bounds.iter().enumerate() {
1839 if i != 0 {
1840 self.word(" + ");
1841 }
1842 match bound {
1843 ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt),
1844 _ => {
1845 panic!("expected a lifetime bound, found a trait bound")
1846 }
1847 }
1848 }
1849 }
1850
1851 fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
1852 if generic_params.is_empty() {
1853 return;
1854 }
1855
1856 self.word("<");
1857
1858 self.commasep(Inconsistent, generic_params, |s, param| {
1859 s.print_outer_attributes_inline(¶m.attrs);
1860
1861 match ¶m.kind {
1862 ast::GenericParamKind::Lifetime => {
1863 let lt = ast::Lifetime { id: param.id, ident: param.ident };
1864 s.print_lifetime(lt);
1865 if !param.bounds.is_empty() {
1866 s.word_nbsp(":");
1867 s.print_lifetime_bounds(¶m.bounds)
1868 }
1869 }
1870 ast::GenericParamKind::Type { default } => {
1871 s.print_ident(param.ident);
1872 if !param.bounds.is_empty() {
1873 s.word_nbsp(":");
1874 s.print_type_bounds(¶m.bounds);
1875 }
1876 if let Some(default) = default {
1877 s.space();
1878 s.word_space("=");
1879 s.print_type(default)
1880 }
1881 }
1882 ast::GenericParamKind::Const { ty, default, .. } => {
1883 s.word_space("const");
1884 s.print_ident(param.ident);
1885 s.space();
1886 s.word_space(":");
1887 s.print_type(ty);
1888 if !param.bounds.is_empty() {
1889 s.word_nbsp(":");
1890 s.print_type_bounds(¶m.bounds);
1891 }
1892 if let Some(default) = default {
1893 s.space();
1894 s.word_space("=");
1895 s.print_expr(&default.value, FixupContext::default());
1896 }
1897 }
1898 }
1899 });
1900
1901 self.word(">");
1902 }
1903
1904 pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) {
1905 match mutbl {
1906 ast::Mutability::Mut => self.word_nbsp("mut"),
1907 ast::Mutability::Not => {
1908 if print_const {
1909 self.word_nbsp("const");
1910 }
1911 }
1912 }
1913 }
1914
1915 fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) {
1916 self.print_mutability(mt.mutbl, print_const);
1917 self.print_type(&mt.ty)
1918 }
1919
1920 fn print_param(&mut self, input: &ast::Param, is_closure: bool) {
1921 self.ibox(INDENT_UNIT);
1922
1923 self.print_outer_attributes_inline(&input.attrs);
1924
1925 match input.ty.kind {
1926 ast::TyKind::Infer if is_closure => self.print_pat(&input.pat),
1927 _ => {
1928 if let Some(eself) = input.to_self() {
1929 self.print_explicit_self(&eself);
1930 } else {
1931 let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind {
1932 ident.name == kw::Empty
1933 } else {
1934 false
1935 };
1936 if !invalid {
1937 self.print_pat(&input.pat);
1938 self.word(":");
1939 self.space();
1940 }
1941 self.print_type(&input.ty);
1942 }
1943 }
1944 }
1945 self.end();
1946 }
1947
1948 fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy) {
1949 if let ast::FnRetTy::Ty(ty) = fn_ret_ty {
1950 self.space_if_not_bol();
1951 self.ibox(INDENT_UNIT);
1952 self.word_space("->");
1953 self.print_type(ty);
1954 self.end();
1955 self.maybe_print_comment(ty.span.lo());
1956 }
1957 }
1958
1959 fn print_ty_fn(
1960 &mut self,
1961 ext: ast::Extern,
1962 safety: ast::Safety,
1963 decl: &ast::FnDecl,
1964 name: Option<Ident>,
1965 generic_params: &[ast::GenericParam],
1966 ) {
1967 self.ibox(INDENT_UNIT);
1968 self.print_formal_generic_params(generic_params);
1969 let generics = ast::Generics {
1970 params: ThinVec::new(),
1971 where_clause: ast::WhereClause {
1972 has_where_token: false,
1973 predicates: ThinVec::new(),
1974 span: DUMMY_SP,
1975 },
1976 span: DUMMY_SP,
1977 };
1978 let header = ast::FnHeader { safety, ext, ..ast::FnHeader::default() };
1979 self.print_fn(decl, header, name, &generics);
1980 self.end();
1981 }
1982
1983 fn print_fn_header_info(&mut self, header: ast::FnHeader) {
1984 self.print_constness(header.constness);
1985 header.coroutine_kind.map(|coroutine_kind| self.print_coroutine_kind(coroutine_kind));
1986 self.print_safety(header.safety);
1987
1988 match header.ext {
1989 ast::Extern::None => {}
1990 ast::Extern::Implicit(_) => {
1991 self.word_nbsp("extern");
1992 }
1993 ast::Extern::Explicit(abi, _) => {
1994 self.word_nbsp("extern");
1995 self.print_token_literal(abi.as_token_lit(), abi.span);
1996 self.nbsp();
1997 }
1998 }
1999
2000 self.word("fn")
2001 }
2002
2003 fn print_safety(&mut self, s: ast::Safety) {
2004 match s {
2005 ast::Safety::Default => {}
2006 ast::Safety::Safe(_) => self.word_nbsp("safe"),
2007 ast::Safety::Unsafe(_) => self.word_nbsp("unsafe"),
2008 }
2009 }
2010
2011 fn print_constness(&mut self, s: ast::Const) {
2012 match s {
2013 ast::Const::No => {}
2014 ast::Const::Yes(_) => self.word_nbsp("const"),
2015 }
2016 }
2017
2018 fn print_is_auto(&mut self, s: ast::IsAuto) {
2019 match s {
2020 ast::IsAuto::Yes => self.word_nbsp("auto"),
2021 ast::IsAuto::No => {}
2022 }
2023 }
2024
2025 fn print_meta_item_lit(&mut self, lit: &ast::MetaItemLit) {
2026 self.print_token_literal(lit.as_token_lit(), lit.span)
2027 }
2028
2029 fn print_token_literal(&mut self, token_lit: token::Lit, span: Span) {
2030 self.maybe_print_comment(span.lo());
2031 self.word(token_lit.to_string())
2032 }
2033
2034 fn print_symbol(&mut self, sym: Symbol, style: ast::StrStyle) {
2035 self.print_string(sym.as_str(), style);
2036 }
2037
2038 fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) -> bool {
2039 self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false)
2040 }
2041
2042 fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool {
2043 self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true)
2044 }
2045
2046 fn print_attribute(&mut self, attr: &ast::Attribute) {
2047 self.print_attribute_inline(attr, false)
2048 }
2049
2050 fn print_meta_list_item(&mut self, item: &ast::MetaItemInner) {
2051 match item {
2052 ast::MetaItemInner::MetaItem(mi) => self.print_meta_item(mi),
2053 ast::MetaItemInner::Lit(lit) => self.print_meta_item_lit(lit),
2054 }
2055 }
2056
2057 fn print_meta_item(&mut self, item: &ast::MetaItem) {
2058 self.ibox(INDENT_UNIT);
2059 match &item.kind {
2060 ast::MetaItemKind::Word => self.print_path(&item.path, false, 0),
2061 ast::MetaItemKind::NameValue(value) => {
2062 self.print_path(&item.path, false, 0);
2063 self.space();
2064 self.word_space("=");
2065 self.print_meta_item_lit(value);
2066 }
2067 ast::MetaItemKind::List(items) => {
2068 self.print_path(&item.path, false, 0);
2069 self.popen();
2070 self.commasep(Consistent, items, |s, i| s.print_meta_list_item(i));
2071 self.pclose();
2072 }
2073 }
2074 self.end();
2075 }
2076
2077 pub(crate) fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String {
2078 Self::to_string(|s| s.print_type_bounds(bounds))
2079 }
2080
2081 pub(crate) fn where_bound_predicate_to_string(
2082 &self,
2083 where_bound_predicate: &ast::WhereBoundPredicate,
2084 ) -> String {
2085 Self::to_string(|s| s.print_where_bound_predicate(where_bound_predicate))
2086 }
2087
2088 pub(crate) fn tt_to_string(&self, tt: &TokenTree) -> String {
2089 Self::to_string(|s| {
2090 s.print_tt(tt, false);
2091 })
2092 }
2093
2094 pub(crate) fn path_segment_to_string(&self, p: &ast::PathSegment) -> String {
2095 Self::to_string(|s| s.print_path_segment(p, false))
2096 }
2097
2098 pub(crate) fn meta_list_item_to_string(&self, li: &ast::MetaItemInner) -> String {
2099 Self::to_string(|s| s.print_meta_list_item(li))
2100 }
2101
2102 pub(crate) fn attribute_to_string(&self, attr: &ast::Attribute) -> String {
2103 Self::to_string(|s| s.print_attribute(attr))
2104 }
2105}