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