"rustc-rayon",
"rustc-rayon-core",
"rustc_apfloat",
+ "rustc_ast_pretty",
"rustc_attr",
"rustc_data_structures",
"rustc_errors",
dependencies = [
"log",
"rustc",
+ "rustc_ast_pretty",
"rustc_data_structures",
"rustc_errors",
"rustc_hir",
version = "0.0.0"
dependencies = [
"log",
+ "rustc_ast_pretty",
"rustc_attr",
"rustc_data_structures",
"rustc_errors",
"syntax",
]
+[[package]]
+name = "rustc_ast_pretty"
+version = "0.0.0"
+dependencies = [
+ "log",
+ "rustc_data_structures",
+ "rustc_span",
+ "syntax",
+]
+
[[package]]
name = "rustc_attr"
version = "0.0.0"
dependencies = [
+ "rustc_ast_pretty",
"rustc_data_structures",
"rustc_errors",
"rustc_feature",
dependencies = [
"fmt_macros",
"log",
+ "rustc_ast_pretty",
"rustc_attr",
"rustc_data_structures",
"rustc_errors",
"lazy_static 1.4.0",
"log",
"rustc",
+ "rustc_ast_pretty",
"rustc_codegen_utils",
"rustc_data_structures",
"rustc_error_codes",
dependencies = [
"log",
"rustc_ast_passes",
+ "rustc_ast_pretty",
"rustc_attr",
"rustc_data_structures",
"rustc_errors",
name = "rustc_hir"
version = "0.0.0"
dependencies = [
+ "rustc_ast_pretty",
"rustc_data_structures",
"rustc_errors",
"rustc_index",
dependencies = [
"log",
"rustc",
+ "rustc_ast_pretty",
"rustc_attr",
"rustc_data_structures",
"rustc_errors",
"log",
"memmap",
"rustc",
+ "rustc_ast_pretty",
"rustc_attr",
"rustc_data_structures",
"rustc_errors",
"polonius-engine",
"rustc",
"rustc_apfloat",
+ "rustc_ast_pretty",
"rustc_attr",
"rustc_data_structures",
"rustc_errors",
dependencies = [
"bitflags",
"log",
+ "rustc_ast_pretty",
"rustc_attr",
"rustc_data_structures",
"rustc_errors",
"log",
"rustc",
"rustc_ast_lowering",
+ "rustc_ast_pretty",
"rustc_attr",
"rustc_data_structures",
"rustc_errors",
"rls-data",
"rls-span",
"rustc",
+ "rustc_ast_pretty",
"rustc_codegen_utils",
"rustc_data_structures",
"rustc_hir",
rustc-rayon-core = "0.3.0"
polonius-engine = "0.11.0"
rustc_apfloat = { path = "../librustc_apfloat" }
+# FIXME(Centril): remove this dependency when stuff is moved to rustc_lint.
+rustc_ast_pretty = { path = "../librustc_ast_pretty" }
rustc_attr = { path = "../librustc_attr" }
rustc_feature = { path = "../librustc_feature" }
rustc_hir = { path = "../librustc_hir" }
[dependencies]
log = { version = "0.4", features = ["release_max_level_info", "std"] }
rustc = { path = "../librustc" }
+rustc_ast_pretty = { path = "../librustc_ast_pretty" }
rustc_hir = { path = "../librustc_hir" }
rustc_target = { path = "../librustc_target" }
rustc_data_structures = { path = "../librustc_data_structures" }
use rustc::hir::map::definitions::{DefKey, DefPathData, Definitions};
use rustc::hir::map::Map;
use rustc::{bug, span_bug};
+use rustc_ast_pretty::pprust;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use syntax::ast::*;
use syntax::attr;
use syntax::node_id::NodeMap;
-use syntax::print::pprust;
use syntax::token::{self, Nonterminal, Token};
use syntax::tokenstream::{TokenStream, TokenTree};
use syntax::visit::{self, Visitor};
[dependencies]
log = "0.4"
+rustc_ast_pretty = { path = "../librustc_ast_pretty" }
rustc_attr = { path = "../librustc_attr" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_errors = { path = "../librustc_errors" }
// This pass is supposed to perform only simple checks not requiring name resolution
// or type checking or some other kind of complex analysis.
+use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{struct_span_err, Applicability, FatalError};
use rustc_parse::validate_attr;
use syntax::ast::*;
use syntax::attr;
use syntax::expand::is_proc_macro_attr;
-use syntax::print::pprust;
use syntax::visit::{self, Visitor};
use syntax::walk_list;
--- /dev/null
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_ast_pretty"
+version = "0.0.0"
+edition = "2018"
+
+[lib]
+name = "rustc_ast_pretty"
+path = "lib.rs"
+doctest = false
+
+[dependencies]
+log = "0.4"
+rustc_span = { path = "../librustc_span" }
+rustc_data_structures = { path = "../librustc_data_structures" }
+syntax = { path = "../libsyntax" }
--- /dev/null
+use crate::pp::Printer;
+use std::borrow::Cow;
+
+impl Printer {
+ pub fn word_space<W: Into<Cow<'static, str>>>(&mut self, w: W) {
+ self.word(w);
+ self.space();
+ }
+
+ pub fn popen(&mut self) {
+ self.word("(");
+ }
+
+ pub fn pclose(&mut self) {
+ self.word(")");
+ }
+
+ pub fn hardbreak_if_not_bol(&mut self) {
+ if !self.is_beginning_of_line() {
+ self.hardbreak()
+ }
+ }
+
+ pub fn space_if_not_bol(&mut self) {
+ if !self.is_beginning_of_line() {
+ self.space();
+ }
+ }
+
+ pub fn nbsp(&mut self) {
+ self.word(" ")
+ }
+
+ pub fn word_nbsp<S: Into<Cow<'static, str>>>(&mut self, w: S) {
+ self.word(w);
+ self.nbsp()
+ }
+}
--- /dev/null
+#![feature(bool_to_option)]
+#![feature(crate_visibility_modifier)]
+
+mod helpers;
+pub mod pp;
+pub mod pprust;
--- /dev/null
+//! This pretty-printer is a direct reimplementation of Philip Karlton's
+//! Mesa pretty-printer, as described in appendix A of
+//!
+//! ```text
+//! STAN-CS-79-770: "Pretty Printing", by Derek C. Oppen.
+//! Stanford Department of Computer Science, 1979.
+//! ```
+//!
+//! The algorithm's aim is to break a stream into as few lines as possible
+//! while respecting the indentation-consistency requirements of the enclosing
+//! block, and avoiding breaking at silly places on block boundaries, for
+//! example, between "x" and ")" in "x)".
+//!
+//! I am implementing this algorithm because it comes with 20 pages of
+//! documentation explaining its theory, and because it addresses the set of
+//! concerns I've seen other pretty-printers fall down on. Weirdly. Even though
+//! it's 32 years old. What can I say?
+//!
+//! Despite some redundancies and quirks in the way it's implemented in that
+//! paper, I've opted to keep the implementation here as similar as I can,
+//! changing only what was blatantly wrong, a typo, or sufficiently
+//! non-idiomatic rust that it really stuck out.
+//!
+//! In particular you'll see a certain amount of churn related to INTEGER vs.
+//! CARDINAL in the Mesa implementation. Mesa apparently interconverts the two
+//! somewhat readily? In any case, I've used usize for indices-in-buffers and
+//! ints for character-sizes-and-indentation-offsets. This respects the need
+//! for ints to "go negative" while carrying a pending-calculation balance, and
+//! helps differentiate all the numbers flying around internally (slightly).
+//!
+//! I also inverted the indentation arithmetic used in the print stack, since
+//! the Mesa implementation (somewhat randomly) stores the offset on the print
+//! stack in terms of margin-col rather than col itself. I store col.
+//!
+//! I also implemented a small change in the String token, in that I store an
+//! explicit length for the string. For most tokens this is just the length of
+//! the accompanying string. But it's necessary to permit it to differ, for
+//! encoding things that are supposed to "go on their own line" -- certain
+//! classes of comment and blank-line -- where relying on adjacent
+//! hardbreak-like Break tokens with long blankness indication doesn't actually
+//! work. To see why, consider when there is a "thing that should be on its own
+//! line" between two long blocks, say functions. If you put a hardbreak after
+//! each function (or before each) and the breaking algorithm decides to break
+//! there anyways (because the functions themselves are long) you wind up with
+//! extra blank lines. If you don't put hardbreaks you can wind up with the
+//! "thing which should be on its own line" not getting its own line in the
+//! rare case of "really small functions" or such. This re-occurs with comments
+//! and explicit blank lines. So in those cases we use a string with a payload
+//! we want isolated to a line and an explicit length that's huge, surrounded
+//! by two zero-length breaks. The algorithm will try its best to fit it on a
+//! line (which it can't) and so naturally place the content on its own line to
+//! avoid combining it with other lines and making matters even worse.
+//!
+//! # Explanation
+//!
+//! In case you do not have the paper, here is an explanation of what's going
+//! on.
+//!
+//! There is a stream of input tokens flowing through this printer.
+//!
+//! The printer buffers up to 3N tokens inside itself, where N is linewidth.
+//! Yes, linewidth is chars and tokens are multi-char, but in the worst
+//! case every token worth buffering is 1 char long, so it's ok.
+//!
+//! Tokens are String, Break, and Begin/End to delimit blocks.
+//!
+//! Begin tokens can carry an offset, saying "how far to indent when you break
+//! inside here", as well as a flag indicating "consistent" or "inconsistent"
+//! breaking. Consistent breaking means that after the first break, no attempt
+//! will be made to flow subsequent breaks together onto lines. Inconsistent
+//! is the opposite. Inconsistent breaking example would be, say:
+//!
+//! ```
+//! foo(hello, there, good, friends)
+//! ```
+//!
+//! breaking inconsistently to become
+//!
+//! ```
+//! foo(hello, there
+//! good, friends);
+//! ```
+//!
+//! whereas a consistent breaking would yield:
+//!
+//! ```
+//! foo(hello,
+//! there
+//! good,
+//! friends);
+//! ```
+//!
+//! That is, in the consistent-break blocks we value vertical alignment
+//! more than the ability to cram stuff onto a line. But in all cases if it
+//! can make a block a one-liner, it'll do so.
+//!
+//! Carrying on with high-level logic:
+//!
+//! The buffered tokens go through a ring-buffer, 'tokens'. The 'left' and
+//! 'right' indices denote the active portion of the ring buffer as well as
+//! describing hypothetical points-in-the-infinite-stream at most 3N tokens
+//! apart (i.e., "not wrapped to ring-buffer boundaries"). The paper will switch
+//! between using 'left' and 'right' terms to denote the wrapped-to-ring-buffer
+//! and point-in-infinite-stream senses freely.
+//!
+//! There is a parallel ring buffer, `size`, that holds the calculated size of
+//! each token. Why calculated? Because for Begin/End pairs, the "size"
+//! includes everything between the pair. That is, the "size" of Begin is
+//! actually the sum of the sizes of everything between Begin and the paired
+//! End that follows. Since that is arbitrarily far in the future, `size` is
+//! being rewritten regularly while the printer runs; in fact most of the
+//! machinery is here to work out `size` entries on the fly (and give up when
+//! they're so obviously over-long that "infinity" is a good enough
+//! approximation for purposes of line breaking).
+//!
+//! The "input side" of the printer is managed as an abstract process called
+//! SCAN, which uses `scan_stack`, to manage calculating `size`. SCAN is, in
+//! other words, the process of calculating 'size' entries.
+//!
+//! The "output side" of the printer is managed by an abstract process called
+//! PRINT, which uses `print_stack`, `margin` and `space` to figure out what to
+//! do with each token/size pair it consumes as it goes. It's trying to consume
+//! the entire buffered window, but can't output anything until the size is >=
+//! 0 (sizes are set to negative while they're pending calculation).
+//!
+//! So SCAN takes input and buffers tokens and pending calculations, while
+//! PRINT gobbles up completed calculations and tokens from the buffer. The
+//! theory is that the two can never get more than 3N tokens apart, because
+//! once there's "obviously" too much data to fit on a line, in a size
+//! calculation, SCAN will write "infinity" to the size and let PRINT consume
+//! it.
+//!
+//! In this implementation (following the paper, again) the SCAN process is the
+//! methods called `Printer::scan_*`, and the 'PRINT' process is the
+//! method called `Printer::print`.
+
+use log::debug;
+use std::borrow::Cow;
+use std::collections::VecDeque;
+use std::fmt;
+
+/// How to break. Described in more detail in the module docs.
+#[derive(Clone, Copy, PartialEq)]
+pub enum Breaks {
+ Consistent,
+ Inconsistent,
+}
+
+#[derive(Clone, Copy)]
+pub struct BreakToken {
+ offset: isize,
+ blank_space: isize,
+}
+
+#[derive(Clone, Copy)]
+pub struct BeginToken {
+ offset: isize,
+ breaks: Breaks,
+}
+
+#[derive(Clone)]
+pub enum Token {
+ // In practice a string token contains either a `&'static str` or a
+ // `String`. `Cow` is overkill for this because we never modify the data,
+ // but it's more convenient than rolling our own more specialized type.
+ String(Cow<'static, str>),
+ Break(BreakToken),
+ Begin(BeginToken),
+ End,
+ Eof,
+}
+
+impl Token {
+ crate fn is_eof(&self) -> bool {
+ match *self {
+ Token::Eof => true,
+ _ => false,
+ }
+ }
+
+ pub fn is_hardbreak_tok(&self) -> bool {
+ match *self {
+ Token::Break(BreakToken { offset: 0, blank_space: bs }) if bs == SIZE_INFINITY => true,
+ _ => false,
+ }
+ }
+}
+
+impl fmt::Display for Token {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ Token::String(ref s) => write!(f, "STR({},{})", s, s.len()),
+ Token::Break(_) => f.write_str("BREAK"),
+ Token::Begin(_) => f.write_str("BEGIN"),
+ Token::End => f.write_str("END"),
+ Token::Eof => f.write_str("EOF"),
+ }
+ }
+}
+
+fn buf_str(buf: &[BufEntry], left: usize, right: usize, lim: usize) -> String {
+ let n = buf.len();
+ let mut i = left;
+ let mut l = lim;
+ let mut s = String::from("[");
+ while i != right && l != 0 {
+ l -= 1;
+ if i != left {
+ s.push_str(", ");
+ }
+ s.push_str(&format!("{}={}", buf[i].size, &buf[i].token));
+ i += 1;
+ i %= n;
+ }
+ s.push(']');
+ s
+}
+
+#[derive(Copy, Clone)]
+enum PrintStackBreak {
+ Fits,
+ Broken(Breaks),
+}
+
+#[derive(Copy, Clone)]
+struct PrintStackElem {
+ offset: isize,
+ pbreak: PrintStackBreak,
+}
+
+const SIZE_INFINITY: isize = 0xffff;
+
+pub fn mk_printer() -> Printer {
+ let linewidth = 78;
+ // Yes 55, it makes the ring buffers big enough to never fall behind.
+ let n: usize = 55 * linewidth;
+ debug!("mk_printer {}", linewidth);
+ Printer {
+ out: String::new(),
+ buf_max_len: n,
+ margin: linewidth as isize,
+ space: linewidth as isize,
+ left: 0,
+ right: 0,
+ // Initialize a single entry; advance_right() will extend it on demand
+ // up to `buf_max_len` elements.
+ buf: vec![BufEntry::default()],
+ left_total: 0,
+ right_total: 0,
+ scan_stack: VecDeque::new(),
+ print_stack: Vec::new(),
+ pending_indentation: 0,
+ }
+}
+
+pub struct Printer {
+ out: String,
+ buf_max_len: usize,
+ /// Width of lines we're constrained to
+ margin: isize,
+ /// Number of spaces left on line
+ space: isize,
+ /// Index of left side of input stream
+ left: usize,
+ /// Index of right side of input stream
+ right: usize,
+ /// Ring-buffer of tokens and calculated sizes
+ buf: Vec<BufEntry>,
+ /// Running size of stream "...left"
+ left_total: isize,
+ /// Running size of stream "...right"
+ right_total: isize,
+ /// Pseudo-stack, really a ring too. Holds the
+ /// primary-ring-buffers index of the Begin that started the
+ /// current block, possibly with the most recent Break after that
+ /// Begin (if there is any) on top of it. Stuff is flushed off the
+ /// bottom as it becomes irrelevant due to the primary ring-buffer
+ /// advancing.
+ scan_stack: VecDeque<usize>,
+ /// Stack of blocks-in-progress being flushed by print
+ print_stack: Vec<PrintStackElem>,
+ /// Buffered indentation to avoid writing trailing whitespace
+ pending_indentation: isize,
+}
+
+#[derive(Clone)]
+struct BufEntry {
+ token: Token,
+ size: isize,
+}
+
+impl Default for BufEntry {
+ fn default() -> Self {
+ BufEntry { token: Token::Eof, size: 0 }
+ }
+}
+
+impl Printer {
+ pub fn last_token(&self) -> Token {
+ self.buf[self.right].token.clone()
+ }
+
+ /// Be very careful with this!
+ pub fn replace_last_token(&mut self, t: Token) {
+ self.buf[self.right].token = t;
+ }
+
+ fn scan_eof(&mut self) {
+ if !self.scan_stack.is_empty() {
+ self.check_stack(0);
+ self.advance_left();
+ }
+ }
+
+ fn scan_begin(&mut self, b: BeginToken) {
+ if self.scan_stack.is_empty() {
+ self.left_total = 1;
+ self.right_total = 1;
+ self.left = 0;
+ self.right = 0;
+ } else {
+ self.advance_right();
+ }
+ debug!("pp Begin({})/buffer Vec<{},{}>", b.offset, self.left, self.right);
+ self.scan_push(BufEntry { token: Token::Begin(b), size: -self.right_total });
+ }
+
+ fn scan_end(&mut self) {
+ if self.scan_stack.is_empty() {
+ debug!("pp End/print Vec<{},{}>", self.left, self.right);
+ self.print_end();
+ } else {
+ debug!("pp End/buffer Vec<{},{}>", self.left, self.right);
+ self.advance_right();
+ self.scan_push(BufEntry { token: Token::End, size: -1 });
+ }
+ }
+
+ fn scan_break(&mut self, b: BreakToken) {
+ if self.scan_stack.is_empty() {
+ self.left_total = 1;
+ self.right_total = 1;
+ self.left = 0;
+ self.right = 0;
+ } else {
+ self.advance_right();
+ }
+ debug!("pp Break({})/buffer Vec<{},{}>", b.offset, self.left, self.right);
+ self.check_stack(0);
+ self.scan_push(BufEntry { token: Token::Break(b), size: -self.right_total });
+ self.right_total += b.blank_space;
+ }
+
+ fn scan_string(&mut self, s: Cow<'static, str>) {
+ if self.scan_stack.is_empty() {
+ debug!("pp String('{}')/print Vec<{},{}>", s, self.left, self.right);
+ self.print_string(s);
+ } else {
+ debug!("pp String('{}')/buffer Vec<{},{}>", s, self.left, self.right);
+ self.advance_right();
+ let len = s.len() as isize;
+ self.buf[self.right] = BufEntry { token: Token::String(s), size: len };
+ self.right_total += len;
+ self.check_stream();
+ }
+ }
+
+ fn check_stream(&mut self) {
+ debug!(
+ "check_stream Vec<{}, {}> with left_total={}, right_total={}",
+ self.left, self.right, self.left_total, self.right_total
+ );
+ if self.right_total - self.left_total > self.space {
+ debug!(
+ "scan window is {}, longer than space on line ({})",
+ self.right_total - self.left_total,
+ self.space
+ );
+ if Some(&self.left) == self.scan_stack.back() {
+ debug!("setting {} to infinity and popping", self.left);
+ let scanned = self.scan_pop_bottom();
+ self.buf[scanned].size = SIZE_INFINITY;
+ }
+ self.advance_left();
+ if self.left != self.right {
+ self.check_stream();
+ }
+ }
+ }
+
+ fn scan_push(&mut self, entry: BufEntry) {
+ debug!("scan_push {}", self.right);
+ self.buf[self.right] = entry;
+ self.scan_stack.push_front(self.right);
+ }
+
+ fn scan_pop(&mut self) -> usize {
+ self.scan_stack.pop_front().unwrap()
+ }
+
+ fn scan_top(&mut self) -> usize {
+ *self.scan_stack.front().unwrap()
+ }
+
+ fn scan_pop_bottom(&mut self) -> usize {
+ self.scan_stack.pop_back().unwrap()
+ }
+
+ fn advance_right(&mut self) {
+ self.right += 1;
+ self.right %= self.buf_max_len;
+ // Extend the buf if necessary.
+ if self.right == self.buf.len() {
+ self.buf.push(BufEntry::default());
+ }
+ assert_ne!(self.right, self.left);
+ }
+
+ fn advance_left(&mut self) {
+ debug!(
+ "advance_left Vec<{},{}>, sizeof({})={}",
+ self.left, self.right, self.left, self.buf[self.left].size
+ );
+
+ let mut left_size = self.buf[self.left].size;
+
+ while left_size >= 0 {
+ let left = self.buf[self.left].token.clone();
+
+ let len = match left {
+ Token::Break(b) => b.blank_space,
+ Token::String(ref s) => {
+ let len = s.len() as isize;
+ assert_eq!(len, left_size);
+ len
+ }
+ _ => 0,
+ };
+
+ self.print(left, left_size);
+
+ self.left_total += len;
+
+ if self.left == self.right {
+ break;
+ }
+
+ self.left += 1;
+ self.left %= self.buf_max_len;
+
+ left_size = self.buf[self.left].size;
+ }
+ }
+
+ fn check_stack(&mut self, k: usize) {
+ if !self.scan_stack.is_empty() {
+ let x = self.scan_top();
+ match self.buf[x].token {
+ Token::Begin(_) => {
+ if k > 0 {
+ self.scan_pop();
+ self.buf[x].size += self.right_total;
+ self.check_stack(k - 1);
+ }
+ }
+ Token::End => {
+ // paper says + not =, but that makes no sense.
+ self.scan_pop();
+ self.buf[x].size = 1;
+ self.check_stack(k + 1);
+ }
+ _ => {
+ self.scan_pop();
+ self.buf[x].size += self.right_total;
+ if k > 0 {
+ self.check_stack(k);
+ }
+ }
+ }
+ }
+ }
+
+ fn print_newline(&mut self, amount: isize) {
+ debug!("NEWLINE {}", amount);
+ self.out.push('\n');
+ self.pending_indentation = 0;
+ self.indent(amount);
+ }
+
+ fn indent(&mut self, amount: isize) {
+ debug!("INDENT {}", amount);
+ self.pending_indentation += amount;
+ }
+
+ fn get_top(&mut self) -> PrintStackElem {
+ match self.print_stack.last() {
+ Some(el) => *el,
+ None => {
+ PrintStackElem { offset: 0, pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) }
+ }
+ }
+ }
+
+ fn print_begin(&mut self, b: BeginToken, l: isize) {
+ if l > self.space {
+ let col = self.margin - self.space + b.offset;
+ debug!("print Begin -> push broken block at col {}", col);
+ self.print_stack
+ .push(PrintStackElem { offset: col, pbreak: PrintStackBreak::Broken(b.breaks) });
+ } else {
+ debug!("print Begin -> push fitting block");
+ self.print_stack.push(PrintStackElem { offset: 0, pbreak: PrintStackBreak::Fits });
+ }
+ }
+
+ fn print_end(&mut self) {
+ debug!("print End -> pop End");
+ self.print_stack.pop().unwrap();
+ }
+
+ fn print_break(&mut self, b: BreakToken, l: isize) {
+ let top = self.get_top();
+ match top.pbreak {
+ PrintStackBreak::Fits => {
+ debug!("print Break({}) in fitting block", b.blank_space);
+ self.space -= b.blank_space;
+ self.indent(b.blank_space);
+ }
+ PrintStackBreak::Broken(Breaks::Consistent) => {
+ debug!("print Break({}+{}) in consistent block", top.offset, b.offset);
+ self.print_newline(top.offset + b.offset);
+ self.space = self.margin - (top.offset + b.offset);
+ }
+ PrintStackBreak::Broken(Breaks::Inconsistent) => {
+ if l > self.space {
+ debug!("print Break({}+{}) w/ newline in inconsistent", top.offset, b.offset);
+ self.print_newline(top.offset + b.offset);
+ self.space = self.margin - (top.offset + b.offset);
+ } else {
+ debug!("print Break({}) w/o newline in inconsistent", b.blank_space);
+ self.indent(b.blank_space);
+ self.space -= b.blank_space;
+ }
+ }
+ }
+ }
+
+ fn print_string(&mut self, s: Cow<'static, str>) {
+ let len = s.len() as isize;
+ debug!("print String({})", s);
+ // assert!(len <= space);
+ self.space -= len;
+
+ // Write the pending indent. A more concise way of doing this would be:
+ //
+ // write!(self.out, "{: >n$}", "", n = self.pending_indentation as usize)?;
+ //
+ // But that is significantly slower. This code is sufficiently hot, and indents can get
+ // sufficiently large, that the difference is significant on some workloads.
+ self.out.reserve(self.pending_indentation as usize);
+ self.out.extend(std::iter::repeat(' ').take(self.pending_indentation as usize));
+ self.pending_indentation = 0;
+ self.out.push_str(&s);
+ }
+
+ fn print(&mut self, token: Token, l: isize) {
+ debug!("print {} {} (remaining line space={})", token, l, self.space);
+ debug!("{}", buf_str(&self.buf, self.left, self.right, 6));
+ match token {
+ Token::Begin(b) => self.print_begin(b, l),
+ Token::End => self.print_end(),
+ Token::Break(b) => self.print_break(b, l),
+ Token::String(s) => {
+ let len = s.len() as isize;
+ assert_eq!(len, l);
+ self.print_string(s);
+ }
+ Token::Eof => panic!(), // Eof should never get here.
+ }
+ }
+
+ // Convenience functions to talk to the printer.
+
+ /// "raw box"
+ pub fn rbox(&mut self, indent: usize, b: Breaks) {
+ self.scan_begin(BeginToken { offset: indent as isize, breaks: b })
+ }
+
+ /// Inconsistent breaking box
+ pub fn ibox(&mut self, indent: usize) {
+ self.rbox(indent, Breaks::Inconsistent)
+ }
+
+ /// Consistent breaking box
+ pub fn cbox(&mut self, indent: usize) {
+ self.rbox(indent, Breaks::Consistent)
+ }
+
+ pub fn break_offset(&mut self, n: usize, off: isize) {
+ self.scan_break(BreakToken { offset: off, blank_space: n as isize })
+ }
+
+ pub fn end(&mut self) {
+ self.scan_end()
+ }
+
+ pub fn eof(mut self) -> String {
+ self.scan_eof();
+ self.out
+ }
+
+ pub fn word<S: Into<Cow<'static, str>>>(&mut self, wrd: S) {
+ let s = wrd.into();
+ self.scan_string(s)
+ }
+
+ fn spaces(&mut self, n: usize) {
+ self.break_offset(n, 0)
+ }
+
+ crate fn zerobreak(&mut self) {
+ self.spaces(0)
+ }
+
+ pub fn space(&mut self) {
+ self.spaces(1)
+ }
+
+ pub fn hardbreak(&mut self) {
+ self.spaces(SIZE_INFINITY as usize)
+ }
+
+ pub fn is_beginning_of_line(&self) -> bool {
+ self.last_token().is_eof() || self.last_token().is_hardbreak_tok()
+ }
+
+ pub fn hardbreak_tok_offset(off: isize) -> Token {
+ Token::Break(BreakToken { offset: off, blank_space: SIZE_INFINITY })
+ }
+}
--- /dev/null
+use crate::pp::Breaks::{Consistent, Inconsistent};
+use crate::pp::{self, Breaks};
+
+use rustc_data_structures::sync::Once;
+use rustc_span::edition::Edition;
+use rustc_span::source_map::{dummy_spanned, SourceMap, Spanned};
+use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::{BytePos, FileName, Span};
+use syntax::ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
+use syntax::ast::{Attribute, GenericArg, MacArgs};
+use syntax::ast::{GenericBound, SelfKind, TraitBoundModifier};
+use syntax::attr;
+use syntax::ptr::P;
+use syntax::token::{self, BinOpToken, DelimToken, Nonterminal, Token, TokenKind};
+use syntax::tokenstream::{self, TokenStream, TokenTree};
+use syntax::util::parser::{self, AssocOp, Fixity};
+use syntax::util::{classify, comments};
+
+use std::borrow::Cow;
+
+#[cfg(test)]
+mod tests;
+
+pub enum MacHeader<'a> {
+ Path(&'a ast::Path),
+ Keyword(&'static str),
+}
+
+pub enum AnnNode<'a> {
+ Ident(&'a ast::Ident),
+ Name(&'a ast::Name),
+ Block(&'a ast::Block),
+ Item(&'a ast::Item),
+ SubItem(ast::NodeId),
+ Expr(&'a ast::Expr),
+ Pat(&'a ast::Pat),
+ Crate(&'a ast::Crate),
+}
+
+pub trait PpAnn {
+ fn pre(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
+ fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
+}
+
+#[derive(Copy, Clone)]
+pub struct NoAnn;
+
+impl PpAnn for NoAnn {}
+
+pub struct Comments<'a> {
+ cm: &'a SourceMap,
+ comments: Vec<comments::Comment>,
+ current: usize,
+}
+
+impl<'a> Comments<'a> {
+ pub fn new(cm: &'a SourceMap, filename: FileName, input: String) -> Comments<'a> {
+ let comments = comments::gather_comments(cm, filename, input);
+ Comments { cm, comments, current: 0 }
+ }
+
+ pub fn next(&self) -> Option<comments::Comment> {
+ self.comments.get(self.current).cloned()
+ }
+
+ pub fn trailing_comment(
+ &mut self,
+ span: rustc_span::Span,
+ next_pos: Option<BytePos>,
+ ) -> Option<comments::Comment> {
+ if let Some(cmnt) = self.next() {
+ if cmnt.style != comments::Trailing {
+ return None;
+ }
+ let span_line = self.cm.lookup_char_pos(span.hi());
+ let comment_line = self.cm.lookup_char_pos(cmnt.pos);
+ let next = next_pos.unwrap_or_else(|| cmnt.pos + BytePos(1));
+ if span.hi() < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line {
+ return Some(cmnt);
+ }
+ }
+
+ None
+ }
+}
+
+pub struct State<'a> {
+ pub s: pp::Printer,
+ comments: Option<Comments<'a>>,
+ ann: &'a (dyn PpAnn + 'a),
+ is_expanded: bool,
+}
+
+crate const INDENT_UNIT: usize = 4;
+
+/// Requires you to pass an input filename and reader so that
+/// it can scan the input text for comments to copy forward.
+pub fn print_crate<'a>(
+ cm: &'a SourceMap,
+ krate: &ast::Crate,
+ filename: FileName,
+ input: String,
+ ann: &'a dyn PpAnn,
+ is_expanded: bool,
+ edition: Edition,
+ injected_crate_name: &Once<Symbol>,
+) -> String {
+ let mut s = State {
+ s: pp::mk_printer(),
+ comments: Some(Comments::new(cm, filename, input)),
+ ann,
+ is_expanded,
+ };
+
+ if is_expanded && injected_crate_name.try_get().is_some() {
+ // We need to print `#![no_std]` (and its feature gate) so that
+ // compiling pretty-printed source won't inject libstd again.
+ // However, we don't want these attributes in the AST because
+ // of the feature gate, so we fake them up here.
+
+ // `#![feature(prelude_import)]`
+ let pi_nested = attr::mk_nested_word_item(ast::Ident::with_dummy_span(sym::prelude_import));
+ let list = attr::mk_list_item(ast::Ident::with_dummy_span(sym::feature), vec![pi_nested]);
+ let fake_attr = attr::mk_attr_inner(list);
+ s.print_attribute(&fake_attr);
+
+ // Currently, in Rust 2018 we don't have `extern crate std;` at the crate
+ // root, so this is not needed, and actually breaks things.
+ if edition == Edition::Edition2015 {
+ // `#![no_std]`
+ let no_std_meta = attr::mk_word_item(ast::Ident::with_dummy_span(sym::no_std));
+ let fake_attr = attr::mk_attr_inner(no_std_meta);
+ s.print_attribute(&fake_attr);
+ }
+ }
+
+ s.print_mod(&krate.module, &krate.attrs);
+ s.print_remaining_comments();
+ s.ann.post(&mut s, AnnNode::Crate(krate));
+ s.s.eof()
+}
+
+pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
+ let mut printer =
+ State { s: pp::mk_printer(), comments: None, ann: &NoAnn, is_expanded: false };
+ f(&mut printer);
+ printer.s.eof()
+}
+
+// This makes comma-separated lists look slightly nicer,
+// and also addresses a specific regression described in issue #63896.
+fn tt_prepend_space(tt: &TokenTree) -> bool {
+ match tt {
+ TokenTree::Token(token) => match token.kind {
+ token::Comma => false,
+ _ => true,
+ },
+ _ => true,
+ }
+}
+
+fn binop_to_string(op: BinOpToken) -> &'static str {
+ match op {
+ token::Plus => "+",
+ token::Minus => "-",
+ token::Star => "*",
+ token::Slash => "/",
+ token::Percent => "%",
+ token::Caret => "^",
+ token::And => "&",
+ token::Or => "|",
+ token::Shl => "<<",
+ token::Shr => ">>",
+ }
+}
+
+pub fn literal_to_string(lit: token::Lit) -> String {
+ let token::Lit { kind, symbol, suffix } = lit;
+ let mut out = match kind {
+ token::Byte => format!("b'{}'", symbol),
+ token::Char => format!("'{}'", symbol),
+ token::Str => format!("\"{}\"", symbol),
+ token::StrRaw(n) => {
+ format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
+ }
+ token::ByteStr => format!("b\"{}\"", symbol),
+ token::ByteStrRaw(n) => {
+ format!("br{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
+ }
+ token::Integer | token::Float | token::Bool | token::Err => symbol.to_string(),
+ };
+
+ if let Some(suffix) = suffix {
+ out.push_str(&suffix.as_str())
+ }
+
+ out
+}
+
+/// Print an ident from AST, `$crate` is converted into its respective crate name.
+pub fn ast_ident_to_string(ident: ast::Ident, is_raw: bool) -> String {
+ ident_to_string(ident.name, is_raw, Some(ident.span))
+}
+
+// AST pretty-printer is used as a fallback for turning AST structures into token streams for
+// proc macros. Additionally, proc macros may stringify their input and expect it survive the
+// stringification (especially true for proc macro derives written between Rust 1.15 and 1.30).
+// So we need to somehow pretty-print `$crate` in a way preserving at least some of its
+// hygiene data, most importantly name of the crate it refers to.
+// As a result we print `$crate` as `crate` if it refers to the local crate
+// and as `::other_crate_name` if it refers to some other crate.
+// Note, that this is only done if the ident token is printed from inside of AST pretty-pringing,
+// but not otherwise. Pretty-printing is the only way for proc macros to discover token contents,
+// so we should not perform this lossy conversion if the top level call to the pretty-printer was
+// done for a token stream or a single token.
+fn ident_to_string(name: ast::Name, is_raw: bool, convert_dollar_crate: Option<Span>) -> String {
+ if is_raw {
+ format!("r#{}", name)
+ } else {
+ if name == kw::DollarCrate {
+ if let Some(span) = convert_dollar_crate {
+ let converted = span.ctxt().dollar_crate_name();
+ return if converted.is_path_segment_keyword() {
+ converted.to_string()
+ } else {
+ format!("::{}", converted)
+ };
+ }
+ }
+ name.to_string()
+ }
+}
+
+/// Print the token kind precisely, without converting `$crate` into its respective crate name.
+pub fn token_kind_to_string(tok: &TokenKind) -> String {
+ token_kind_to_string_ext(tok, None)
+}
+
+fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option<Span>) -> String {
+ match *tok {
+ token::Eq => "=".to_string(),
+ token::Lt => "<".to_string(),
+ token::Le => "<=".to_string(),
+ token::EqEq => "==".to_string(),
+ token::Ne => "!=".to_string(),
+ token::Ge => ">=".to_string(),
+ token::Gt => ">".to_string(),
+ token::Not => "!".to_string(),
+ token::Tilde => "~".to_string(),
+ token::OrOr => "||".to_string(),
+ token::AndAnd => "&&".to_string(),
+ token::BinOp(op) => binop_to_string(op).to_string(),
+ token::BinOpEq(op) => format!("{}=", binop_to_string(op)),
+
+ /* Structural symbols */
+ token::At => "@".to_string(),
+ token::Dot => ".".to_string(),
+ token::DotDot => "..".to_string(),
+ token::DotDotDot => "...".to_string(),
+ token::DotDotEq => "..=".to_string(),
+ token::Comma => ",".to_string(),
+ token::Semi => ";".to_string(),
+ token::Colon => ":".to_string(),
+ token::ModSep => "::".to_string(),
+ token::RArrow => "->".to_string(),
+ token::LArrow => "<-".to_string(),
+ token::FatArrow => "=>".to_string(),
+ token::OpenDelim(token::Paren) => "(".to_string(),
+ token::CloseDelim(token::Paren) => ")".to_string(),
+ token::OpenDelim(token::Bracket) => "[".to_string(),
+ token::CloseDelim(token::Bracket) => "]".to_string(),
+ token::OpenDelim(token::Brace) => "{".to_string(),
+ token::CloseDelim(token::Brace) => "}".to_string(),
+ token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) => " ".to_string(),
+ token::Pound => "#".to_string(),
+ token::Dollar => "$".to_string(),
+ token::Question => "?".to_string(),
+ token::SingleQuote => "'".to_string(),
+
+ /* Literals */
+ token::Literal(lit) => literal_to_string(lit),
+
+ /* Name components */
+ token::Ident(s, is_raw) => ident_to_string(s, is_raw, convert_dollar_crate),
+ token::Lifetime(s) => s.to_string(),
+
+ /* Other */
+ token::DocComment(s) => s.to_string(),
+ token::Eof => "<eof>".to_string(),
+ token::Whitespace => " ".to_string(),
+ token::Comment => "/* */".to_string(),
+ token::Shebang(s) => format!("/* shebang: {}*/", s),
+ token::Unknown(s) => s.to_string(),
+
+ token::Interpolated(ref nt) => nonterminal_to_string(nt),
+ }
+}
+
+/// Print the token precisely, without converting `$crate` into its respective crate name.
+pub fn token_to_string(token: &Token) -> String {
+ token_to_string_ext(token, false)
+}
+
+fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String {
+ let convert_dollar_crate = convert_dollar_crate.then_some(token.span);
+ token_kind_to_string_ext(&token.kind, convert_dollar_crate)
+}
+
+pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
+ match *nt {
+ token::NtExpr(ref e) => expr_to_string(e),
+ token::NtMeta(ref e) => attr_item_to_string(e),
+ token::NtTy(ref e) => ty_to_string(e),
+ token::NtPath(ref e) => path_to_string(e),
+ token::NtItem(ref e) => item_to_string(e),
+ token::NtBlock(ref e) => block_to_string(e),
+ token::NtStmt(ref e) => stmt_to_string(e),
+ token::NtPat(ref e) => pat_to_string(e),
+ token::NtIdent(e, is_raw) => ast_ident_to_string(e, is_raw),
+ token::NtLifetime(e) => e.to_string(),
+ token::NtLiteral(ref e) => expr_to_string(e),
+ token::NtTT(ref tree) => tt_to_string(tree.clone()),
+ // FIXME(Centril): merge these variants.
+ token::NtImplItem(ref e) | token::NtTraitItem(ref e) => assoc_item_to_string(e),
+ token::NtVis(ref e) => vis_to_string(e),
+ token::NtForeignItem(ref e) => foreign_item_to_string(e),
+ }
+}
+
+pub fn ty_to_string(ty: &ast::Ty) -> String {
+ to_string(|s| s.print_type(ty))
+}
+
+pub fn bounds_to_string(bounds: &[ast::GenericBound]) -> String {
+ to_string(|s| s.print_type_bounds("", bounds))
+}
+
+pub fn pat_to_string(pat: &ast::Pat) -> String {
+ to_string(|s| s.print_pat(pat))
+}
+
+pub fn expr_to_string(e: &ast::Expr) -> String {
+ to_string(|s| s.print_expr(e))
+}
+
+pub fn tt_to_string(tt: tokenstream::TokenTree) -> String {
+ to_string(|s| s.print_tt(tt, false))
+}
+
+pub fn tts_to_string(tokens: TokenStream) -> String {
+ to_string(|s| s.print_tts(tokens, false))
+}
+
+pub fn stmt_to_string(stmt: &ast::Stmt) -> String {
+ to_string(|s| s.print_stmt(stmt))
+}
+
+pub fn item_to_string(i: &ast::Item) -> String {
+ to_string(|s| s.print_item(i))
+}
+
+fn assoc_item_to_string(i: &ast::AssocItem) -> String {
+ to_string(|s| s.print_assoc_item(i))
+}
+
+pub fn generic_params_to_string(generic_params: &[ast::GenericParam]) -> String {
+ to_string(|s| s.print_generic_params(generic_params))
+}
+
+pub fn path_to_string(p: &ast::Path) -> String {
+ to_string(|s| s.print_path(p, false, 0))
+}
+
+pub fn path_segment_to_string(p: &ast::PathSegment) -> String {
+ to_string(|s| s.print_path_segment(p, false))
+}
+
+pub fn vis_to_string(v: &ast::Visibility) -> String {
+ to_string(|s| s.print_visibility(v))
+}
+
+fn block_to_string(blk: &ast::Block) -> String {
+ to_string(|s| {
+ // Containing cbox, will be closed by `print_block` at `}`.
+ s.cbox(INDENT_UNIT);
+ // Head-ibox, will be closed by `print_block` after `{`.
+ s.ibox(0);
+ s.print_block(blk)
+ })
+}
+
+pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String {
+ to_string(|s| s.print_meta_list_item(li))
+}
+
+fn attr_item_to_string(ai: &ast::AttrItem) -> String {
+ to_string(|s| s.print_attr_item(ai, ai.path.span))
+}
+
+pub fn attribute_to_string(attr: &ast::Attribute) -> String {
+ to_string(|s| s.print_attribute(attr))
+}
+
+pub fn param_to_string(arg: &ast::Param) -> String {
+ to_string(|s| s.print_param(arg, false))
+}
+
+fn foreign_item_to_string(arg: &ast::ForeignItem) -> String {
+ to_string(|s| s.print_foreign_item(arg))
+}
+
+fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
+ format!("{}{}", to_string(|s| s.print_visibility(vis)), s)
+}
+
+impl std::ops::Deref for State<'_> {
+ type Target = pp::Printer;
+ fn deref(&self) -> &Self::Target {
+ &self.s
+ }
+}
+
+impl std::ops::DerefMut for State<'_> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.s
+ }
+}
+
+pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::DerefMut {
+ fn comments(&mut self) -> &mut Option<Comments<'a>>;
+ fn print_ident(&mut self, ident: ast::Ident);
+ fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
+
+ fn strsep<T, F>(
+ &mut self,
+ sep: &'static str,
+ space_before: bool,
+ b: Breaks,
+ elts: &[T],
+ mut op: F,
+ ) where
+ F: FnMut(&mut Self, &T),
+ {
+ self.rbox(0, b);
+ if let Some((first, rest)) = elts.split_first() {
+ op(self, first);
+ for elt in rest {
+ if space_before {
+ self.space();
+ }
+ self.word_space(sep);
+ op(self, elt);
+ }
+ }
+ self.end();
+ }
+
+ fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], op: F)
+ where
+ F: FnMut(&mut Self, &T),
+ {
+ self.strsep(",", false, b, elts, op)
+ }
+
+ fn maybe_print_comment(&mut self, pos: BytePos) {
+ while let Some(ref cmnt) = self.next_comment() {
+ if cmnt.pos < pos {
+ self.print_comment(cmnt);
+ } else {
+ break;
+ }
+ }
+ }
+
+ fn print_comment(&mut self, cmnt: &comments::Comment) {
+ match cmnt.style {
+ comments::Mixed => {
+ assert_eq!(cmnt.lines.len(), 1);
+ self.zerobreak();
+ self.word(cmnt.lines[0].clone());
+ self.zerobreak()
+ }
+ comments::Isolated => {
+ self.hardbreak_if_not_bol();
+ for line in &cmnt.lines {
+ // Don't print empty lines because they will end up as trailing
+ // whitespace.
+ if !line.is_empty() {
+ self.word(line.clone());
+ }
+ self.hardbreak();
+ }
+ }
+ comments::Trailing => {
+ if !self.is_beginning_of_line() {
+ self.word(" ");
+ }
+ if cmnt.lines.len() == 1 {
+ self.word(cmnt.lines[0].clone());
+ self.hardbreak()
+ } else {
+ self.ibox(0);
+ for line in &cmnt.lines {
+ if !line.is_empty() {
+ self.word(line.clone());
+ }
+ self.hardbreak();
+ }
+ self.end();
+ }
+ }
+ comments::BlankLine => {
+ // We need to do at least one, possibly two hardbreaks.
+ let twice = match self.last_token() {
+ pp::Token::String(s) => ";" == s,
+ pp::Token::Begin(_) => true,
+ pp::Token::End => true,
+ _ => false,
+ };
+ if twice {
+ self.hardbreak();
+ }
+ self.hardbreak();
+ }
+ }
+ if let Some(cm) = self.comments() {
+ cm.current += 1;
+ }
+ }
+
+ fn next_comment(&mut self) -> Option<comments::Comment> {
+ self.comments().as_mut().and_then(|c| c.next())
+ }
+
+ fn print_literal(&mut self, lit: &ast::Lit) {
+ self.maybe_print_comment(lit.span.lo());
+ self.word(lit.token.to_string())
+ }
+
+ fn print_string(&mut self, st: &str, style: ast::StrStyle) {
+ let st = match style {
+ ast::StrStyle::Cooked => (format!("\"{}\"", st.escape_debug())),
+ ast::StrStyle::Raw(n) => {
+ format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = st)
+ }
+ };
+ self.word(st)
+ }
+
+ fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) {
+ self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
+ }
+
+ fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) {
+ self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false)
+ }
+
+ fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) {
+ self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
+ }
+
+ fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) {
+ self.print_either_attributes(attrs, ast::AttrStyle::Inner, true, true)
+ }
+
+ fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) {
+ self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true)
+ }
+
+ fn print_either_attributes(
+ &mut self,
+ attrs: &[ast::Attribute],
+ kind: ast::AttrStyle,
+ is_inline: bool,
+ trailing_hardbreak: bool,
+ ) {
+ let mut count = 0;
+ for attr in attrs {
+ if attr.style == kind {
+ self.print_attribute_inline(attr, is_inline);
+ if is_inline {
+ self.nbsp();
+ }
+ count += 1;
+ }
+ }
+ if count > 0 && trailing_hardbreak && !is_inline {
+ self.hardbreak_if_not_bol();
+ }
+ }
+
+ fn print_attribute(&mut self, attr: &ast::Attribute) {
+ self.print_attribute_inline(attr, false)
+ }
+
+ fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) {
+ if !is_inline {
+ self.hardbreak_if_not_bol();
+ }
+ self.maybe_print_comment(attr.span.lo());
+ match attr.kind {
+ ast::AttrKind::Normal(ref item) => {
+ match attr.style {
+ ast::AttrStyle::Inner => self.word("#!["),
+ ast::AttrStyle::Outer => self.word("#["),
+ }
+ self.print_attr_item(&item, attr.span);
+ self.word("]");
+ }
+ ast::AttrKind::DocComment(comment) => {
+ self.word(comment.to_string());
+ self.hardbreak()
+ }
+ }
+ }
+
+ fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
+ self.ibox(0);
+ match &item.args {
+ MacArgs::Delimited(_, delim, tokens) => self.print_mac_common(
+ Some(MacHeader::Path(&item.path)),
+ false,
+ None,
+ delim.to_token(),
+ tokens.clone(),
+ true,
+ span,
+ ),
+ MacArgs::Empty | MacArgs::Eq(..) => {
+ self.print_path(&item.path, false, 0);
+ if let MacArgs::Eq(_, tokens) = &item.args {
+ self.space();
+ self.word_space("=");
+ self.print_tts(tokens.clone(), true);
+ }
+ }
+ }
+ self.end();
+ }
+
+ fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) {
+ match item {
+ ast::NestedMetaItem::MetaItem(ref mi) => self.print_meta_item(mi),
+ ast::NestedMetaItem::Literal(ref lit) => self.print_literal(lit),
+ }
+ }
+
+ fn print_meta_item(&mut self, item: &ast::MetaItem) {
+ self.ibox(INDENT_UNIT);
+ match item.kind {
+ ast::MetaItemKind::Word => self.print_path(&item.path, false, 0),
+ ast::MetaItemKind::NameValue(ref value) => {
+ self.print_path(&item.path, false, 0);
+ self.space();
+ self.word_space("=");
+ self.print_literal(value);
+ }
+ ast::MetaItemKind::List(ref items) => {
+ self.print_path(&item.path, false, 0);
+ self.popen();
+ self.commasep(Consistent, &items[..], |s, i| s.print_meta_list_item(i));
+ self.pclose();
+ }
+ }
+ self.end();
+ }
+
+ /// This doesn't deserve to be called "pretty" printing, but it should be
+ /// meaning-preserving. A quick hack that might help would be to look at the
+ /// spans embedded in the TTs to decide where to put spaces and newlines.
+ /// But it'd be better to parse these according to the grammar of the
+ /// appropriate macro, transcribe back into the grammar we just parsed from,
+ /// and then pretty-print the resulting AST nodes (so, e.g., we print
+ /// expression arguments as expressions). It can be done! I think.
+ fn print_tt(&mut self, tt: tokenstream::TokenTree, convert_dollar_crate: bool) {
+ match tt {
+ TokenTree::Token(ref token) => {
+ self.word(token_to_string_ext(&token, convert_dollar_crate));
+ match token.kind {
+ token::DocComment(..) => self.hardbreak(),
+ _ => {}
+ }
+ }
+ TokenTree::Delimited(dspan, delim, tts) => {
+ self.print_mac_common(
+ None,
+ false,
+ None,
+ delim,
+ tts,
+ convert_dollar_crate,
+ dspan.entire(),
+ );
+ }
+ }
+ }
+
+ fn print_tts(&mut self, tts: tokenstream::TokenStream, convert_dollar_crate: bool) {
+ for (i, tt) in tts.into_trees().enumerate() {
+ if i != 0 && tt_prepend_space(&tt) {
+ self.space();
+ }
+ self.print_tt(tt, convert_dollar_crate);
+ }
+ }
+
+ fn print_mac_common(
+ &mut self,
+ header: Option<MacHeader<'_>>,
+ has_bang: bool,
+ ident: Option<ast::Ident>,
+ delim: DelimToken,
+ tts: TokenStream,
+ convert_dollar_crate: bool,
+ span: Span,
+ ) {
+ if delim == DelimToken::Brace {
+ self.cbox(INDENT_UNIT);
+ }
+ match header {
+ Some(MacHeader::Path(path)) => self.print_path(path, false, 0),
+ Some(MacHeader::Keyword(kw)) => self.word(kw),
+ None => {}
+ }
+ if has_bang {
+ self.word("!");
+ }
+ if let Some(ident) = ident {
+ self.nbsp();
+ self.print_ident(ident);
+ }
+ match delim {
+ DelimToken::Brace => {
+ if header.is_some() || has_bang || ident.is_some() {
+ self.nbsp();
+ }
+ self.word("{");
+ if !tts.is_empty() {
+ self.space();
+ }
+ }
+ _ => self.word(token_kind_to_string(&token::OpenDelim(delim))),
+ }
+ self.ibox(0);
+ self.print_tts(tts, convert_dollar_crate);
+ self.end();
+ match delim {
+ DelimToken::Brace => self.bclose(span),
+ _ => self.word(token_kind_to_string(&token::CloseDelim(delim))),
+ }
+ }
+
+ fn print_path(&mut self, path: &ast::Path, colons_before_params: bool, depth: usize) {
+ self.maybe_print_comment(path.span.lo());
+
+ for (i, segment) in path.segments[..path.segments.len() - depth].iter().enumerate() {
+ if i > 0 {
+ self.word("::")
+ }
+ self.print_path_segment(segment, colons_before_params);
+ }
+ }
+
+ fn print_path_segment(&mut self, segment: &ast::PathSegment, colons_before_params: bool) {
+ if segment.ident.name != kw::PathRoot {
+ self.print_ident(segment.ident);
+ if let Some(ref args) = segment.args {
+ self.print_generic_args(args, colons_before_params);
+ }
+ }
+ }
+
+ fn head<S: Into<Cow<'static, str>>>(&mut self, w: S) {
+ let w = w.into();
+ // Outer-box is consistent.
+ self.cbox(INDENT_UNIT);
+ // Head-box is inconsistent.
+ self.ibox(w.len() + 1);
+ // Keyword that starts the head.
+ if !w.is_empty() {
+ self.word_nbsp(w);
+ }
+ }
+
+ fn bopen(&mut self) {
+ self.word("{");
+ self.end(); // Close the head-box.
+ }
+
+ fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) {
+ self.maybe_print_comment(span.hi());
+ self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize));
+ self.word("}");
+ if close_box {
+ self.end(); // Close the outer-box.
+ }
+ }
+
+ fn bclose(&mut self, span: rustc_span::Span) {
+ self.bclose_maybe_open(span, true)
+ }
+
+ fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
+ if !self.is_beginning_of_line() {
+ self.break_offset(n, off)
+ } else {
+ if off != 0 && self.last_token().is_hardbreak_tok() {
+ // We do something pretty sketchy here: tuck the nonzero
+ // offset-adjustment we were going to deposit along with the
+ // break into the previous hardbreak.
+ self.replace_last_token(pp::Printer::hardbreak_tok_offset(off));
+ }
+ }
+ }
+}
+
+impl<'a> PrintState<'a> for State<'a> {
+ fn comments(&mut self) -> &mut Option<Comments<'a>> {
+ &mut self.comments
+ }
+
+ fn print_ident(&mut self, ident: ast::Ident) {
+ self.s.word(ast_ident_to_string(ident, ident.is_raw_guess()));
+ self.ann.post(self, AnnNode::Ident(&ident))
+ }
+
+ fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool) {
+ if colons_before_params {
+ self.s.word("::")
+ }
+
+ match *args {
+ ast::GenericArgs::AngleBracketed(ref data) => {
+ self.s.word("<");
+
+ self.commasep(Inconsistent, &data.args, |s, generic_arg| {
+ s.print_generic_arg(generic_arg)
+ });
+
+ let mut comma = data.args.len() != 0;
+
+ for constraint in data.constraints.iter() {
+ if comma {
+ self.word_space(",")
+ }
+ self.print_ident(constraint.ident);
+ self.s.space();
+ match constraint.kind {
+ ast::AssocTyConstraintKind::Equality { ref ty } => {
+ self.word_space("=");
+ self.print_type(ty);
+ }
+ ast::AssocTyConstraintKind::Bound { ref bounds } => {
+ self.print_type_bounds(":", &*bounds);
+ }
+ }
+ comma = true;
+ }
+
+ self.s.word(">")
+ }
+
+ ast::GenericArgs::Parenthesized(ref data) => {
+ self.s.word("(");
+ self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(ty));
+ self.s.word(")");
+ self.print_fn_ret_ty(&data.output);
+ }
+ }
+ }
+}
+
+impl<'a> State<'a> {
+ // Synthesizes a comment that was not textually present in the original source
+ // file.
+ pub fn synth_comment(&mut self, text: String) {
+ self.s.word("/*");
+ self.s.space();
+ self.s.word(text);
+ self.s.space();
+ self.s.word("*/")
+ }
+
+ crate fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
+ where
+ F: FnMut(&mut State<'_>, &T),
+ G: FnMut(&T) -> rustc_span::Span,
+ {
+ self.rbox(0, b);
+ let len = elts.len();
+ let mut i = 0;
+ for elt in elts {
+ self.maybe_print_comment(get_span(elt).hi());
+ op(self, elt);
+ i += 1;
+ if i < len {
+ self.s.word(",");
+ self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi()));
+ self.space_if_not_bol();
+ }
+ }
+ self.end();
+ }
+
+ crate fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) {
+ self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
+ }
+
+ pub fn print_mod(&mut self, _mod: &ast::Mod, attrs: &[ast::Attribute]) {
+ self.print_inner_attributes(attrs);
+ for item in &_mod.items {
+ self.print_item(item);
+ }
+ }
+
+ crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) {
+ self.print_inner_attributes(attrs);
+ for item in &nmod.items {
+ self.print_foreign_item(item);
+ }
+ }
+
+ pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) {
+ if let Some(lt) = *lifetime {
+ self.print_lifetime(lt);
+ self.nbsp();
+ }
+ }
+
+ crate fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
+ match generic_arg {
+ GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
+ GenericArg::Type(ty) => self.print_type(ty),
+ GenericArg::Const(ct) => self.print_expr(&ct.value),
+ }
+ }
+
+ pub fn print_type(&mut self, ty: &ast::Ty) {
+ self.maybe_print_comment(ty.span.lo());
+ self.ibox(0);
+ match ty.kind {
+ ast::TyKind::Slice(ref ty) => {
+ self.s.word("[");
+ self.print_type(ty);
+ self.s.word("]");
+ }
+ ast::TyKind::Ptr(ref mt) => {
+ self.s.word("*");
+ self.print_mt(mt, true);
+ }
+ ast::TyKind::Rptr(ref lifetime, ref mt) => {
+ self.s.word("&");
+ self.print_opt_lifetime(lifetime);
+ self.print_mt(mt, false);
+ }
+ ast::TyKind::Never => {
+ self.s.word("!");
+ }
+ ast::TyKind::Tup(ref elts) => {
+ self.popen();
+ self.commasep(Inconsistent, &elts[..], |s, ty| s.print_type(ty));
+ if elts.len() == 1 {
+ self.s.word(",");
+ }
+ self.pclose();
+ }
+ ast::TyKind::Paren(ref typ) => {
+ self.popen();
+ self.print_type(typ);
+ self.pclose();
+ }
+ ast::TyKind::BareFn(ref f) => {
+ self.print_ty_fn(f.ext, f.unsafety, &f.decl, None, &f.generic_params);
+ }
+ ast::TyKind::Path(None, ref path) => {
+ self.print_path(path, false, 0);
+ }
+ ast::TyKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, false),
+ ast::TyKind::TraitObject(ref bounds, syntax) => {
+ let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn" } else { "" };
+ self.print_type_bounds(prefix, &bounds[..]);
+ }
+ ast::TyKind::ImplTrait(_, ref bounds) => {
+ self.print_type_bounds("impl", &bounds[..]);
+ }
+ ast::TyKind::Array(ref ty, ref length) => {
+ self.s.word("[");
+ self.print_type(ty);
+ self.s.word("; ");
+ self.print_expr(&length.value);
+ self.s.word("]");
+ }
+ ast::TyKind::Typeof(ref e) => {
+ self.s.word("typeof(");
+ self.print_expr(&e.value);
+ self.s.word(")");
+ }
+ ast::TyKind::Infer => {
+ self.s.word("_");
+ }
+ ast::TyKind::Err => {
+ self.popen();
+ self.s.word("/*ERROR*/");
+ self.pclose();
+ }
+ ast::TyKind::ImplicitSelf => {
+ self.s.word("Self");
+ }
+ ast::TyKind::Mac(ref m) => {
+ self.print_mac(m);
+ }
+ ast::TyKind::CVarArgs => {
+ self.s.word("...");
+ }
+ }
+ self.end();
+ }
+
+ crate fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
+ self.hardbreak_if_not_bol();
+ self.maybe_print_comment(item.span.lo());
+ self.print_outer_attributes(&item.attrs);
+ match item.kind {
+ ast::ForeignItemKind::Fn(ref decl, ref generics) => {
+ self.head("");
+ self.print_fn(
+ decl,
+ ast::FnHeader::default(),
+ Some(item.ident),
+ generics,
+ &item.vis,
+ );
+ self.end(); // end head-ibox
+ self.s.word(";");
+ self.end(); // end the outer fn box
+ }
+ ast::ForeignItemKind::Static(ref t, m) => {
+ self.head(visibility_qualified(&item.vis, "static"));
+ if m == ast::Mutability::Mut {
+ self.word_space("mut");
+ }
+ self.print_ident(item.ident);
+ self.word_space(":");
+ self.print_type(t);
+ self.s.word(";");
+ self.end(); // end the head-ibox
+ self.end(); // end the outer cbox
+ }
+ ast::ForeignItemKind::Ty => {
+ self.head(visibility_qualified(&item.vis, "type"));
+ self.print_ident(item.ident);
+ self.s.word(";");
+ self.end(); // end the head-ibox
+ self.end(); // end the outer cbox
+ }
+ ast::ForeignItemKind::Macro(ref m) => {
+ self.print_mac(m);
+ if m.args.need_semicolon() {
+ self.s.word(";");
+ }
+ }
+ }
+ }
+
+ fn print_associated_const(
+ &mut self,
+ ident: ast::Ident,
+ ty: &ast::Ty,
+ default: Option<&ast::Expr>,
+ vis: &ast::Visibility,
+ ) {
+ self.s.word(visibility_qualified(vis, ""));
+ self.word_space("const");
+ self.print_ident(ident);
+ self.word_space(":");
+ self.print_type(ty);
+ if let Some(expr) = default {
+ self.s.space();
+ self.word_space("=");
+ self.print_expr(expr);
+ }
+ self.s.word(";")
+ }
+
+ fn print_associated_type(
+ &mut self,
+ ident: ast::Ident,
+ bounds: &ast::GenericBounds,
+ ty: Option<&ast::Ty>,
+ ) {
+ self.word_space("type");
+ self.print_ident(ident);
+ self.print_type_bounds(":", bounds);
+ if let Some(ty) = ty {
+ self.s.space();
+ self.word_space("=");
+ self.print_type(ty);
+ }
+ self.s.word(";")
+ }
+
+ /// Pretty-prints an item.
+ crate fn print_item(&mut self, item: &ast::Item) {
+ self.hardbreak_if_not_bol();
+ self.maybe_print_comment(item.span.lo());
+ self.print_outer_attributes(&item.attrs);
+ self.ann.pre(self, AnnNode::Item(item));
+ match item.kind {
+ ast::ItemKind::ExternCrate(orig_name) => {
+ self.head(visibility_qualified(&item.vis, "extern crate"));
+ if let Some(orig_name) = orig_name {
+ self.print_name(orig_name);
+ self.s.space();
+ self.s.word("as");
+ self.s.space();
+ }
+ self.print_ident(item.ident);
+ self.s.word(";");
+ self.end(); // end inner head-block
+ self.end(); // end outer head-block
+ }
+ ast::ItemKind::Use(ref tree) => {
+ self.head(visibility_qualified(&item.vis, "use"));
+ self.print_use_tree(tree);
+ self.s.word(";");
+ self.end(); // end inner head-block
+ self.end(); // end outer head-block
+ }
+ ast::ItemKind::Static(ref ty, m, ref expr) => {
+ self.head(visibility_qualified(&item.vis, "static"));
+ if m == ast::Mutability::Mut {
+ self.word_space("mut");
+ }
+ self.print_ident(item.ident);
+ self.word_space(":");
+ self.print_type(ty);
+ self.s.space();
+ self.end(); // end the head-ibox
+
+ self.word_space("=");
+ self.print_expr(expr);
+ self.s.word(";");
+ self.end(); // end the outer cbox
+ }
+ ast::ItemKind::Const(ref ty, ref expr) => {
+ self.head(visibility_qualified(&item.vis, "const"));
+ self.print_ident(item.ident);
+ self.word_space(":");
+ self.print_type(ty);
+ self.s.space();
+ self.end(); // end the head-ibox
+
+ self.word_space("=");
+ self.print_expr(expr);
+ self.s.word(";");
+ self.end(); // end the outer cbox
+ }
+ ast::ItemKind::Fn(ref sig, ref param_names, ref body) => {
+ self.head("");
+ self.print_fn(&sig.decl, sig.header, Some(item.ident), param_names, &item.vis);
+ self.s.word(" ");
+ self.print_block_with_attrs(body, &item.attrs);
+ }
+ ast::ItemKind::Mod(ref _mod) => {
+ self.head(visibility_qualified(&item.vis, "mod"));
+ self.print_ident(item.ident);
+
+ if _mod.inline || self.is_expanded {
+ self.nbsp();
+ self.bopen();
+ self.print_mod(_mod, &item.attrs);
+ self.bclose(item.span);
+ } else {
+ self.s.word(";");
+ self.end(); // end inner head-block
+ self.end(); // end outer head-block
+ }
+ }
+ ast::ItemKind::ForeignMod(ref nmod) => {
+ self.head("extern");
+ if let Some(abi) = nmod.abi {
+ self.print_literal(&abi.as_lit());
+ self.nbsp();
+ }
+ self.bopen();
+ self.print_foreign_mod(nmod, &item.attrs);
+ self.bclose(item.span);
+ }
+ ast::ItemKind::GlobalAsm(ref ga) => {
+ self.head(visibility_qualified(&item.vis, "global_asm!"));
+ self.s.word(ga.asm.to_string());
+ self.end();
+ }
+ ast::ItemKind::TyAlias(ref ty, ref generics) => {
+ self.head(visibility_qualified(&item.vis, "type"));
+ self.print_ident(item.ident);
+ self.print_generic_params(&generics.params);
+ self.end(); // end the inner ibox
+
+ self.print_where_clause(&generics.where_clause);
+ self.s.space();
+ self.word_space("=");
+ self.print_type(ty);
+ self.s.word(";");
+ self.end(); // end the outer ibox
+ }
+ ast::ItemKind::Enum(ref enum_definition, ref params) => {
+ self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis);
+ }
+ ast::ItemKind::Struct(ref struct_def, ref generics) => {
+ self.head(visibility_qualified(&item.vis, "struct"));
+ self.print_struct(struct_def, generics, item.ident, item.span, true);
+ }
+ ast::ItemKind::Union(ref struct_def, ref generics) => {
+ self.head(visibility_qualified(&item.vis, "union"));
+ self.print_struct(struct_def, generics, item.ident, item.span, true);
+ }
+ ast::ItemKind::Impl {
+ unsafety,
+ polarity,
+ defaultness,
+ constness,
+ ref generics,
+ ref of_trait,
+ ref self_ty,
+ ref items,
+ } => {
+ self.head("");
+ self.print_visibility(&item.vis);
+ self.print_defaultness(defaultness);
+ self.print_unsafety(unsafety);
+ self.word_nbsp("impl");
+ self.print_constness(constness);
+
+ if !generics.params.is_empty() {
+ self.print_generic_params(&generics.params);
+ self.s.space();
+ }
+
+ if polarity == ast::ImplPolarity::Negative {
+ self.s.word("!");
+ }
+
+ if let Some(ref t) = *of_trait {
+ self.print_trait_ref(t);
+ self.s.space();
+ self.word_space("for");
+ }
+
+ self.print_type(self_ty);
+ self.print_where_clause(&generics.where_clause);
+
+ self.s.space();
+ self.bopen();
+ self.print_inner_attributes(&item.attrs);
+ for impl_item in items {
+ self.print_assoc_item(impl_item);
+ }
+ self.bclose(item.span);
+ }
+ ast::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref trait_items) => {
+ self.head("");
+ self.print_visibility(&item.vis);
+ self.print_unsafety(unsafety);
+ self.print_is_auto(is_auto);
+ self.word_nbsp("trait");
+ self.print_ident(item.ident);
+ self.print_generic_params(&generics.params);
+ let mut real_bounds = Vec::with_capacity(bounds.len());
+ for b in bounds.iter() {
+ if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
+ self.s.space();
+ self.word_space("for ?");
+ self.print_trait_ref(&ptr.trait_ref);
+ } else {
+ real_bounds.push(b.clone());
+ }
+ }
+ self.print_type_bounds(":", &real_bounds[..]);
+ self.print_where_clause(&generics.where_clause);
+ self.s.word(" ");
+ self.bopen();
+ for trait_item in trait_items {
+ self.print_assoc_item(trait_item);
+ }
+ self.bclose(item.span);
+ }
+ ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
+ self.head("");
+ self.print_visibility(&item.vis);
+ self.word_nbsp("trait");
+ self.print_ident(item.ident);
+ self.print_generic_params(&generics.params);
+ let mut real_bounds = Vec::with_capacity(bounds.len());
+ // FIXME(durka) this seems to be some quite outdated syntax
+ for b in bounds.iter() {
+ if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
+ self.s.space();
+ self.word_space("for ?");
+ self.print_trait_ref(&ptr.trait_ref);
+ } else {
+ real_bounds.push(b.clone());
+ }
+ }
+ self.nbsp();
+ self.print_type_bounds("=", &real_bounds[..]);
+ self.print_where_clause(&generics.where_clause);
+ self.s.word(";");
+ }
+ ast::ItemKind::Mac(ref mac) => {
+ self.print_mac(mac);
+ if mac.args.need_semicolon() {
+ self.s.word(";");
+ }
+ }
+ ast::ItemKind::MacroDef(ref macro_def) => {
+ let (kw, has_bang) = if macro_def.legacy {
+ ("macro_rules", true)
+ } else {
+ self.print_visibility(&item.vis);
+ ("macro", false)
+ };
+ self.print_mac_common(
+ Some(MacHeader::Keyword(kw)),
+ has_bang,
+ Some(item.ident),
+ macro_def.body.delim(),
+ macro_def.body.inner_tokens(),
+ true,
+ item.span,
+ );
+ }
+ }
+ self.ann.post(self, AnnNode::Item(item))
+ }
+
+ fn print_trait_ref(&mut self, t: &ast::TraitRef) {
+ self.print_path(&t.path, false, 0)
+ }
+
+ fn print_formal_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
+ if !generic_params.is_empty() {
+ self.s.word("for");
+ self.print_generic_params(generic_params);
+ self.nbsp();
+ }
+ }
+
+ fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) {
+ self.print_formal_generic_params(&t.bound_generic_params);
+ self.print_trait_ref(&t.trait_ref)
+ }
+
+ crate fn print_enum_def(
+ &mut self,
+ enum_definition: &ast::EnumDef,
+ generics: &ast::Generics,
+ ident: ast::Ident,
+ span: rustc_span::Span,
+ visibility: &ast::Visibility,
+ ) {
+ self.head(visibility_qualified(visibility, "enum"));
+ self.print_ident(ident);
+ self.print_generic_params(&generics.params);
+ self.print_where_clause(&generics.where_clause);
+ self.s.space();
+ self.print_variants(&enum_definition.variants, span)
+ }
+
+ crate fn print_variants(&mut self, variants: &[ast::Variant], span: rustc_span::Span) {
+ self.bopen();
+ for v in variants {
+ self.space_if_not_bol();
+ self.maybe_print_comment(v.span.lo());
+ self.print_outer_attributes(&v.attrs);
+ self.ibox(INDENT_UNIT);
+ self.print_variant(v);
+ self.s.word(",");
+ self.end();
+ self.maybe_print_trailing_comment(v.span, None);
+ }
+ self.bclose(span)
+ }
+
+ crate fn print_visibility(&mut self, vis: &ast::Visibility) {
+ match vis.node {
+ ast::VisibilityKind::Public => self.word_nbsp("pub"),
+ ast::VisibilityKind::Crate(sugar) => match sugar {
+ ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"),
+ ast::CrateSugar::JustCrate => self.word_nbsp("crate"),
+ },
+ ast::VisibilityKind::Restricted { ref path, .. } => {
+ let path = to_string(|s| s.print_path(path, false, 0));
+ if path == "self" || path == "super" {
+ self.word_nbsp(format!("pub({})", path))
+ } else {
+ self.word_nbsp(format!("pub(in {})", path))
+ }
+ }
+ ast::VisibilityKind::Inherited => {}
+ }
+ }
+
+ crate fn print_defaultness(&mut self, defaultness: ast::Defaultness) {
+ if let ast::Defaultness::Default = defaultness {
+ self.word_nbsp("default");
+ }
+ }
+
+ crate fn print_struct(
+ &mut self,
+ struct_def: &ast::VariantData,
+ generics: &ast::Generics,
+ ident: ast::Ident,
+ span: rustc_span::Span,
+ print_finalizer: bool,
+ ) {
+ self.print_ident(ident);
+ self.print_generic_params(&generics.params);
+ match struct_def {
+ ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
+ if let ast::VariantData::Tuple(..) = struct_def {
+ self.popen();
+ self.commasep(Inconsistent, struct_def.fields(), |s, field| {
+ s.maybe_print_comment(field.span.lo());
+ s.print_outer_attributes(&field.attrs);
+ s.print_visibility(&field.vis);
+ s.print_type(&field.ty)
+ });
+ self.pclose();
+ }
+ self.print_where_clause(&generics.where_clause);
+ if print_finalizer {
+ self.s.word(";");
+ }
+ self.end();
+ self.end(); // Close the outer-box.
+ }
+ ast::VariantData::Struct(..) => {
+ self.print_where_clause(&generics.where_clause);
+ self.nbsp();
+ self.bopen();
+ self.hardbreak_if_not_bol();
+
+ for field in struct_def.fields() {
+ self.hardbreak_if_not_bol();
+ self.maybe_print_comment(field.span.lo());
+ self.print_outer_attributes(&field.attrs);
+ self.print_visibility(&field.vis);
+ self.print_ident(field.ident.unwrap());
+ self.word_nbsp(":");
+ self.print_type(&field.ty);
+ self.s.word(",");
+ }
+
+ self.bclose(span)
+ }
+ }
+ }
+
+ crate fn print_variant(&mut self, v: &ast::Variant) {
+ self.head("");
+ self.print_visibility(&v.vis);
+ let generics = ast::Generics::default();
+ self.print_struct(&v.data, &generics, v.ident, v.span, false);
+ match v.disr_expr {
+ Some(ref d) => {
+ self.s.space();
+ self.word_space("=");
+ self.print_expr(&d.value)
+ }
+ _ => {}
+ }
+ }
+
+ crate fn print_assoc_item(&mut self, item: &ast::AssocItem) {
+ self.ann.pre(self, AnnNode::SubItem(item.id));
+ self.hardbreak_if_not_bol();
+ self.maybe_print_comment(item.span.lo());
+ self.print_outer_attributes(&item.attrs);
+ self.print_defaultness(item.defaultness);
+ match &item.kind {
+ ast::AssocItemKind::Const(ty, expr) => {
+ self.print_associated_const(item.ident, ty, expr.as_deref(), &item.vis);
+ }
+ ast::AssocItemKind::Fn(sig, body) => {
+ if body.is_some() {
+ self.head("");
+ }
+ self.print_fn(&sig.decl, sig.header, Some(item.ident), &item.generics, &item.vis);
+ if let Some(body) = body {
+ self.nbsp();
+ self.print_block_with_attrs(body, &item.attrs);
+ } else {
+ self.s.word(";");
+ }
+ }
+ ast::AssocItemKind::TyAlias(bounds, ty) => {
+ self.print_associated_type(item.ident, bounds, ty.as_deref());
+ }
+ ast::AssocItemKind::Macro(mac) => {
+ self.print_mac(mac);
+ if mac.args.need_semicolon() {
+ self.s.word(";");
+ }
+ }
+ }
+ self.ann.post(self, AnnNode::SubItem(item.id))
+ }
+
+ crate fn print_stmt(&mut self, st: &ast::Stmt) {
+ self.maybe_print_comment(st.span.lo());
+ match st.kind {
+ ast::StmtKind::Local(ref loc) => {
+ self.print_outer_attributes(&loc.attrs);
+ self.space_if_not_bol();
+ self.ibox(INDENT_UNIT);
+ self.word_nbsp("let");
+
+ self.ibox(INDENT_UNIT);
+ self.print_local_decl(loc);
+ self.end();
+ if let Some(ref init) = loc.init {
+ self.nbsp();
+ self.word_space("=");
+ self.print_expr(init);
+ }
+ self.s.word(";");
+ self.end();
+ }
+ ast::StmtKind::Item(ref item) => self.print_item(item),
+ ast::StmtKind::Expr(ref expr) => {
+ self.space_if_not_bol();
+ self.print_expr_outer_attr_style(expr, false);
+ if classify::expr_requires_semi_to_be_stmt(expr) {
+ self.s.word(";");
+ }
+ }
+ ast::StmtKind::Semi(ref expr) => {
+ match expr.kind {
+ // Filter out empty `Tup` exprs created for the `redundant_semicolon`
+ // lint, as they shouldn't be visible and interact poorly
+ // with proc macros.
+ ast::ExprKind::Tup(ref exprs) if exprs.is_empty() && expr.attrs.is_empty() => {
+ ()
+ }
+ _ => {
+ self.space_if_not_bol();
+ self.print_expr_outer_attr_style(expr, false);
+ self.s.word(";");
+ }
+ }
+ }
+ ast::StmtKind::Mac(ref mac) => {
+ let (ref mac, style, ref attrs) = **mac;
+ self.space_if_not_bol();
+ self.print_outer_attributes(attrs);
+ self.print_mac(mac);
+ if style == ast::MacStmtStyle::Semicolon {
+ self.s.word(";");
+ }
+ }
+ }
+ self.maybe_print_trailing_comment(st.span, None)
+ }
+
+ crate fn print_block(&mut self, blk: &ast::Block) {
+ self.print_block_with_attrs(blk, &[])
+ }
+
+ crate fn print_block_unclosed_indent(&mut self, blk: &ast::Block) {
+ self.print_block_maybe_unclosed(blk, &[], false)
+ }
+
+ crate fn print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute]) {
+ self.print_block_maybe_unclosed(blk, attrs, true)
+ }
+
+ crate fn print_block_maybe_unclosed(
+ &mut self,
+ blk: &ast::Block,
+ attrs: &[ast::Attribute],
+ close_box: bool,
+ ) {
+ match blk.rules {
+ BlockCheckMode::Unsafe(..) => self.word_space("unsafe"),
+ BlockCheckMode::Default => (),
+ }
+ self.maybe_print_comment(blk.span.lo());
+ self.ann.pre(self, AnnNode::Block(blk));
+ self.bopen();
+
+ self.print_inner_attributes(attrs);
+
+ for (i, st) in blk.stmts.iter().enumerate() {
+ match st.kind {
+ ast::StmtKind::Expr(ref expr) if i == blk.stmts.len() - 1 => {
+ self.maybe_print_comment(st.span.lo());
+ self.space_if_not_bol();
+ self.print_expr_outer_attr_style(expr, false);
+ self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
+ }
+ _ => self.print_stmt(st),
+ }
+ }
+
+ self.bclose_maybe_open(blk.span, close_box);
+ self.ann.post(self, AnnNode::Block(blk))
+ }
+
+ /// Print a `let pat = scrutinee` expression.
+ crate fn print_let(&mut self, pat: &ast::Pat, scrutinee: &ast::Expr) {
+ self.s.word("let ");
+
+ self.print_pat(pat);
+ self.s.space();
+
+ self.word_space("=");
+ self.print_expr_cond_paren(
+ scrutinee,
+ Self::cond_needs_par(scrutinee)
+ || parser::needs_par_as_let_scrutinee(scrutinee.precedence().order()),
+ )
+ }
+
+ fn print_else(&mut self, els: Option<&ast::Expr>) {
+ if let Some(_else) = els {
+ match _else.kind {
+ // Another `else if` block.
+ ast::ExprKind::If(ref i, ref then, ref e) => {
+ self.cbox(INDENT_UNIT - 1);
+ self.ibox(0);
+ self.s.word(" else if ");
+ self.print_expr_as_cond(i);
+ self.s.space();
+ self.print_block(then);
+ self.print_else(e.as_deref())
+ }
+ // Final `else` block.
+ ast::ExprKind::Block(ref b, _) => {
+ self.cbox(INDENT_UNIT - 1);
+ self.ibox(0);
+ self.s.word(" else ");
+ self.print_block(b)
+ }
+ // Constraints would be great here!
+ _ => {
+ panic!("print_if saw if with weird alternative");
+ }
+ }
+ }
+ }
+
+ crate fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) {
+ self.head("if");
+
+ self.print_expr_as_cond(test);
+ self.s.space();
+
+ self.print_block(blk);
+ self.print_else(elseopt)
+ }
+
+ crate fn print_mac(&mut self, m: &ast::Mac) {
+ self.print_mac_common(
+ Some(MacHeader::Path(&m.path)),
+ true,
+ None,
+ m.args.delim(),
+ m.args.inner_tokens(),
+ true,
+ m.span(),
+ );
+ }
+
+ fn print_call_post(&mut self, args: &[P<ast::Expr>]) {
+ self.popen();
+ self.commasep_exprs(Inconsistent, args);
+ self.pclose()
+ }
+
+ crate fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) {
+ self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
+ }
+
+ /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
+ /// `if cond { ... }`.
+ crate fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
+ self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
+ }
+
+ /// Does `expr` need parenthesis when printed in a condition position?
+ fn cond_needs_par(expr: &ast::Expr) -> bool {
+ match expr.kind {
+ // These cases need parens due to the parse error observed in #26461: `if return {}`
+ // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
+ ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) | ast::ExprKind::Break(..) => true,
+
+ _ => parser::contains_exterior_struct_lit(expr),
+ }
+ }
+
+ /// Prints `expr` or `(expr)` when `needs_par` holds.
+ fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) {
+ if needs_par {
+ self.popen();
+ }
+ self.print_expr(expr);
+ if needs_par {
+ self.pclose();
+ }
+ }
+
+ fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>], attrs: &[Attribute]) {
+ self.ibox(INDENT_UNIT);
+ self.s.word("[");
+ self.print_inner_attributes_inline(attrs);
+ self.commasep_exprs(Inconsistent, &exprs[..]);
+ self.s.word("]");
+ self.end();
+ }
+
+ fn print_expr_repeat(
+ &mut self,
+ element: &ast::Expr,
+ count: &ast::AnonConst,
+ attrs: &[Attribute],
+ ) {
+ self.ibox(INDENT_UNIT);
+ self.s.word("[");
+ self.print_inner_attributes_inline(attrs);
+ self.print_expr(element);
+ self.word_space(";");
+ self.print_expr(&count.value);
+ self.s.word("]");
+ self.end();
+ }
+
+ fn print_expr_struct(
+ &mut self,
+ path: &ast::Path,
+ fields: &[ast::Field],
+ wth: &Option<P<ast::Expr>>,
+ attrs: &[Attribute],
+ ) {
+ self.print_path(path, true, 0);
+ self.s.word("{");
+ self.print_inner_attributes_inline(attrs);
+ self.commasep_cmnt(
+ Consistent,
+ &fields[..],
+ |s, field| {
+ s.ibox(INDENT_UNIT);
+ if !field.is_shorthand {
+ s.print_ident(field.ident);
+ s.word_space(":");
+ }
+ s.print_expr(&field.expr);
+ s.end();
+ },
+ |f| f.span,
+ );
+ match *wth {
+ Some(ref expr) => {
+ self.ibox(INDENT_UNIT);
+ if !fields.is_empty() {
+ self.s.word(",");
+ self.s.space();
+ }
+ self.s.word("..");
+ self.print_expr(expr);
+ self.end();
+ }
+ _ => {
+ if !fields.is_empty() {
+ self.s.word(",")
+ }
+ }
+ }
+ self.s.word("}");
+ }
+
+ fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>], attrs: &[Attribute]) {
+ self.popen();
+ self.print_inner_attributes_inline(attrs);
+ self.commasep_exprs(Inconsistent, &exprs[..]);
+ if exprs.len() == 1 {
+ self.s.word(",");
+ }
+ self.pclose()
+ }
+
+ fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>]) {
+ let prec = match func.kind {
+ ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
+ _ => parser::PREC_POSTFIX,
+ };
+
+ self.print_expr_maybe_paren(func, prec);
+ self.print_call_post(args)
+ }
+
+ fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
+ let base_args = &args[1..];
+ self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
+ self.s.word(".");
+ self.print_ident(segment.ident);
+ if let Some(ref args) = segment.args {
+ self.print_generic_args(args, true);
+ }
+ self.print_call_post(base_args)
+ }
+
+ fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) {
+ let assoc_op = AssocOp::from_ast_binop(op.node);
+ let prec = assoc_op.precedence() as i8;
+ let fixity = assoc_op.fixity();
+
+ let (left_prec, right_prec) = match fixity {
+ Fixity::Left => (prec, prec + 1),
+ Fixity::Right => (prec + 1, prec),
+ Fixity::None => (prec + 1, prec + 1),
+ };
+
+ let left_prec = match (&lhs.kind, op.node) {
+ // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
+ // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
+ // of `(x as i32) < ...`. We need to convince it _not_ to do that.
+ (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt)
+ | (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Shl) => parser::PREC_FORCE_PAREN,
+ // We are given `(let _ = a) OP b`.
+ //
+ // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens
+ // as the parser will interpret this as `(let _ = a) OP b`.
+ //
+ // - Otherwise, e.g. when we have `(let a = b) < c` in AST,
+ // parens are required since the parser would interpret `let a = b < c` as
+ // `let a = (b < c)`. To achieve this, we force parens.
+ (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
+ parser::PREC_FORCE_PAREN
+ }
+ _ => left_prec,
+ };
+
+ self.print_expr_maybe_paren(lhs, left_prec);
+ self.s.space();
+ self.word_space(op.node.to_string());
+ self.print_expr_maybe_paren(rhs, right_prec)
+ }
+
+ fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) {
+ self.s.word(ast::UnOp::to_string(op));
+ self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
+ }
+
+ fn print_expr_addr_of(
+ &mut self,
+ kind: ast::BorrowKind,
+ mutability: ast::Mutability,
+ expr: &ast::Expr,
+ ) {
+ self.s.word("&");
+ match kind {
+ ast::BorrowKind::Ref => self.print_mutability(mutability, false),
+ ast::BorrowKind::Raw => {
+ self.word_nbsp("raw");
+ self.print_mutability(mutability, true);
+ }
+ }
+ self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
+ }
+
+ pub fn print_expr(&mut self, expr: &ast::Expr) {
+ self.print_expr_outer_attr_style(expr, true)
+ }
+
+ fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
+ self.maybe_print_comment(expr.span.lo());
+
+ let attrs = &expr.attrs;
+ if is_inline {
+ self.print_outer_attributes_inline(attrs);
+ } else {
+ self.print_outer_attributes(attrs);
+ }
+
+ self.ibox(INDENT_UNIT);
+ self.ann.pre(self, AnnNode::Expr(expr));
+ match expr.kind {
+ ast::ExprKind::Box(ref expr) => {
+ self.word_space("box");
+ self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
+ }
+ ast::ExprKind::Array(ref exprs) => {
+ self.print_expr_vec(&exprs[..], attrs);
+ }
+ ast::ExprKind::Repeat(ref element, ref count) => {
+ self.print_expr_repeat(element, count, attrs);
+ }
+ ast::ExprKind::Struct(ref path, ref fields, ref wth) => {
+ self.print_expr_struct(path, &fields[..], wth, attrs);
+ }
+ ast::ExprKind::Tup(ref exprs) => {
+ self.print_expr_tup(&exprs[..], attrs);
+ }
+ ast::ExprKind::Call(ref func, ref args) => {
+ self.print_expr_call(func, &args[..]);
+ }
+ ast::ExprKind::MethodCall(ref segment, ref args) => {
+ self.print_expr_method_call(segment, &args[..]);
+ }
+ ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
+ self.print_expr_binary(op, lhs, rhs);
+ }
+ ast::ExprKind::Unary(op, ref expr) => {
+ self.print_expr_unary(op, expr);
+ }
+ ast::ExprKind::AddrOf(k, m, ref expr) => {
+ self.print_expr_addr_of(k, m, expr);
+ }
+ ast::ExprKind::Lit(ref lit) => {
+ self.print_literal(lit);
+ }
+ ast::ExprKind::Cast(ref expr, ref ty) => {
+ let prec = AssocOp::As.precedence() as i8;
+ self.print_expr_maybe_paren(expr, prec);
+ self.s.space();
+ self.word_space("as");
+ self.print_type(ty);
+ }
+ ast::ExprKind::Type(ref expr, ref ty) => {
+ let prec = AssocOp::Colon.precedence() as i8;
+ self.print_expr_maybe_paren(expr, prec);
+ self.word_space(":");
+ self.print_type(ty);
+ }
+ ast::ExprKind::Let(ref pat, ref scrutinee) => {
+ self.print_let(pat, scrutinee);
+ }
+ ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
+ self.print_if(test, blk, elseopt.as_deref())
+ }
+ ast::ExprKind::While(ref test, ref blk, opt_label) => {
+ if let Some(label) = opt_label {
+ self.print_ident(label.ident);
+ self.word_space(":");
+ }
+ self.head("while");
+ self.print_expr_as_cond(test);
+ self.s.space();
+ self.print_block_with_attrs(blk, attrs);
+ }
+ ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
+ if let Some(label) = opt_label {
+ self.print_ident(label.ident);
+ self.word_space(":");
+ }
+ self.head("for");
+ self.print_pat(pat);
+ self.s.space();
+ self.word_space("in");
+ self.print_expr_as_cond(iter);
+ self.s.space();
+ self.print_block_with_attrs(blk, attrs);
+ }
+ ast::ExprKind::Loop(ref blk, opt_label) => {
+ if let Some(label) = opt_label {
+ self.print_ident(label.ident);
+ self.word_space(":");
+ }
+ self.head("loop");
+ self.s.space();
+ self.print_block_with_attrs(blk, attrs);
+ }
+ ast::ExprKind::Match(ref expr, ref arms) => {
+ self.cbox(INDENT_UNIT);
+ self.ibox(INDENT_UNIT);
+ self.word_nbsp("match");
+ self.print_expr_as_cond(expr);
+ self.s.space();
+ self.bopen();
+ self.print_inner_attributes_no_trailing_hardbreak(attrs);
+ for arm in arms {
+ self.print_arm(arm);
+ }
+ self.bclose(expr.span);
+ }
+ ast::ExprKind::Closure(
+ capture_clause,
+ asyncness,
+ movability,
+ ref decl,
+ ref body,
+ _,
+ ) => {
+ self.print_movability(movability);
+ self.print_asyncness(asyncness);
+ self.print_capture_clause(capture_clause);
+
+ self.print_fn_params_and_ret(decl, true);
+ self.s.space();
+ self.print_expr(body);
+ self.end(); // need to close a box
+
+ // a box will be closed by print_expr, but we didn't want an overall
+ // wrapper so we closed the corresponding opening. so create an
+ // empty box to satisfy the close.
+ self.ibox(0);
+ }
+ ast::ExprKind::Block(ref blk, opt_label) => {
+ if let Some(label) = opt_label {
+ self.print_ident(label.ident);
+ self.word_space(":");
+ }
+ // containing cbox, will be closed by print-block at }
+ self.cbox(INDENT_UNIT);
+ // head-box, will be closed by print-block after {
+ self.ibox(0);
+ self.print_block_with_attrs(blk, attrs);
+ }
+ ast::ExprKind::Async(capture_clause, _, ref blk) => {
+ self.word_nbsp("async");
+ self.print_capture_clause(capture_clause);
+ self.s.space();
+ // cbox/ibox in analogy to the `ExprKind::Block` arm above
+ self.cbox(INDENT_UNIT);
+ self.ibox(0);
+ self.print_block_with_attrs(blk, attrs);
+ }
+ ast::ExprKind::Await(ref expr) => {
+ self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+ self.s.word(".await");
+ }
+ ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
+ let prec = AssocOp::Assign.precedence() as i8;
+ self.print_expr_maybe_paren(lhs, prec + 1);
+ self.s.space();
+ self.word_space("=");
+ self.print_expr_maybe_paren(rhs, prec);
+ }
+ ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
+ let prec = AssocOp::Assign.precedence() as i8;
+ self.print_expr_maybe_paren(lhs, prec + 1);
+ self.s.space();
+ self.s.word(op.node.to_string());
+ self.word_space("=");
+ self.print_expr_maybe_paren(rhs, prec);
+ }
+ ast::ExprKind::Field(ref expr, ident) => {
+ self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+ self.s.word(".");
+ self.print_ident(ident);
+ }
+ ast::ExprKind::Index(ref expr, ref index) => {
+ self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+ self.s.word("[");
+ self.print_expr(index);
+ self.s.word("]");
+ }
+ ast::ExprKind::Range(ref start, ref end, limits) => {
+ // Special case for `Range`. `AssocOp` claims that `Range` has higher precedence
+ // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.
+ // Here we use a fake precedence value so that any child with lower precedence than
+ // a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
+ let fake_prec = AssocOp::LOr.precedence() as i8;
+ if let Some(ref e) = *start {
+ self.print_expr_maybe_paren(e, fake_prec);
+ }
+ if limits == ast::RangeLimits::HalfOpen {
+ self.s.word("..");
+ } else {
+ self.s.word("..=");
+ }
+ if let Some(ref e) = *end {
+ self.print_expr_maybe_paren(e, fake_prec);
+ }
+ }
+ ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0),
+ ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
+ ast::ExprKind::Break(opt_label, ref opt_expr) => {
+ self.s.word("break");
+ self.s.space();
+ if let Some(label) = opt_label {
+ self.print_ident(label.ident);
+ self.s.space();
+ }
+ if let Some(ref expr) = *opt_expr {
+ self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+ self.s.space();
+ }
+ }
+ ast::ExprKind::Continue(opt_label) => {
+ self.s.word("continue");
+ self.s.space();
+ if let Some(label) = opt_label {
+ self.print_ident(label.ident);
+ self.s.space()
+ }
+ }
+ ast::ExprKind::Ret(ref result) => {
+ self.s.word("return");
+ if let Some(ref expr) = *result {
+ self.s.word(" ");
+ self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+ }
+ }
+ ast::ExprKind::InlineAsm(ref a) => {
+ self.s.word("asm!");
+ self.popen();
+ self.print_string(&a.asm.as_str(), a.asm_str_style);
+ self.word_space(":");
+
+ self.commasep(Inconsistent, &a.outputs, |s, out| {
+ let constraint = out.constraint.as_str();
+ let mut ch = constraint.chars();
+ match ch.next() {
+ Some('=') if out.is_rw => {
+ s.print_string(&format!("+{}", ch.as_str()), ast::StrStyle::Cooked)
+ }
+ _ => s.print_string(&constraint, ast::StrStyle::Cooked),
+ }
+ s.popen();
+ s.print_expr(&out.expr);
+ s.pclose();
+ });
+ self.s.space();
+ self.word_space(":");
+
+ self.commasep(Inconsistent, &a.inputs, |s, &(co, ref o)| {
+ s.print_string(&co.as_str(), ast::StrStyle::Cooked);
+ s.popen();
+ s.print_expr(o);
+ s.pclose();
+ });
+ self.s.space();
+ self.word_space(":");
+
+ self.commasep(Inconsistent, &a.clobbers, |s, co| {
+ s.print_string(&co.as_str(), ast::StrStyle::Cooked);
+ });
+
+ let mut options = vec![];
+ if a.volatile {
+ options.push("volatile");
+ }
+ if a.alignstack {
+ options.push("alignstack");
+ }
+ if a.dialect == ast::AsmDialect::Intel {
+ options.push("intel");
+ }
+
+ if !options.is_empty() {
+ self.s.space();
+ self.word_space(":");
+ self.commasep(Inconsistent, &options, |s, &co| {
+ s.print_string(co, ast::StrStyle::Cooked);
+ });
+ }
+
+ self.pclose();
+ }
+ ast::ExprKind::Mac(ref m) => self.print_mac(m),
+ ast::ExprKind::Paren(ref e) => {
+ self.popen();
+ self.print_inner_attributes_inline(attrs);
+ self.print_expr(e);
+ self.pclose();
+ }
+ ast::ExprKind::Yield(ref e) => {
+ self.s.word("yield");
+ match *e {
+ Some(ref expr) => {
+ self.s.space();
+ self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+ }
+ _ => (),
+ }
+ }
+ ast::ExprKind::Try(ref e) => {
+ self.print_expr_maybe_paren(e, parser::PREC_POSTFIX);
+ self.s.word("?")
+ }
+ ast::ExprKind::TryBlock(ref blk) => {
+ self.head("try");
+ self.s.space();
+ self.print_block_with_attrs(blk, attrs)
+ }
+ ast::ExprKind::Err => {
+ self.popen();
+ self.s.word("/*ERROR*/");
+ self.pclose()
+ }
+ }
+ self.ann.post(self, AnnNode::Expr(expr));
+ self.end();
+ }
+
+ crate fn print_local_decl(&mut self, loc: &ast::Local) {
+ self.print_pat(&loc.pat);
+ if let Some(ref ty) = loc.ty {
+ self.word_space(":");
+ self.print_type(ty);
+ }
+ }
+
+ pub fn print_usize(&mut self, i: usize) {
+ self.s.word(i.to_string())
+ }
+
+ crate fn print_name(&mut self, name: ast::Name) {
+ self.s.word(name.to_string());
+ self.ann.post(self, AnnNode::Name(&name))
+ }
+
+ fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_params: bool) {
+ self.s.word("<");
+ self.print_type(&qself.ty);
+ if qself.position > 0 {
+ self.s.space();
+ self.word_space("as");
+ let depth = path.segments.len() - qself.position;
+ self.print_path(path, false, depth);
+ }
+ self.s.word(">");
+ self.s.word("::");
+ let item_segment = path.segments.last().unwrap();
+ self.print_ident(item_segment.ident);
+ match item_segment.args {
+ Some(ref args) => self.print_generic_args(args, colons_before_params),
+ None => {}
+ }
+ }
+
+ crate fn print_pat(&mut self, pat: &ast::Pat) {
+ self.maybe_print_comment(pat.span.lo());
+ self.ann.pre(self, AnnNode::Pat(pat));
+ /* Pat isn't normalized, but the beauty of it
+ is that it doesn't matter */
+ match pat.kind {
+ PatKind::Wild => self.s.word("_"),
+ PatKind::Ident(binding_mode, ident, ref sub) => {
+ match binding_mode {
+ ast::BindingMode::ByRef(mutbl) => {
+ self.word_nbsp("ref");
+ self.print_mutability(mutbl, false);
+ }
+ ast::BindingMode::ByValue(ast::Mutability::Not) => {}
+ ast::BindingMode::ByValue(ast::Mutability::Mut) => {
+ self.word_nbsp("mut");
+ }
+ }
+ self.print_ident(ident);
+ if let Some(ref p) = *sub {
+ self.s.space();
+ self.s.word_space("@");
+ self.print_pat(p);
+ }
+ }
+ PatKind::TupleStruct(ref path, ref elts) => {
+ self.print_path(path, true, 0);
+ self.popen();
+ self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
+ self.pclose();
+ }
+ PatKind::Or(ref pats) => {
+ self.strsep("|", true, Inconsistent, &pats[..], |s, p| s.print_pat(p));
+ }
+ PatKind::Path(None, ref path) => {
+ self.print_path(path, true, 0);
+ }
+ PatKind::Path(Some(ref qself), ref path) => {
+ self.print_qpath(path, qself, false);
+ }
+ PatKind::Struct(ref path, ref fields, etc) => {
+ self.print_path(path, true, 0);
+ self.nbsp();
+ self.word_space("{");
+ self.commasep_cmnt(
+ Consistent,
+ &fields[..],
+ |s, f| {
+ s.cbox(INDENT_UNIT);
+ if !f.is_shorthand {
+ s.print_ident(f.ident);
+ s.word_nbsp(":");
+ }
+ s.print_pat(&f.pat);
+ s.end();
+ },
+ |f| f.pat.span,
+ );
+ if etc {
+ if !fields.is_empty() {
+ self.word_space(",");
+ }
+ self.s.word("..");
+ }
+ self.s.space();
+ self.s.word("}");
+ }
+ PatKind::Tuple(ref elts) => {
+ self.popen();
+ self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
+ if elts.len() == 1 {
+ self.s.word(",");
+ }
+ self.pclose();
+ }
+ PatKind::Box(ref inner) => {
+ self.s.word("box ");
+ self.print_pat(inner);
+ }
+ PatKind::Ref(ref inner, mutbl) => {
+ self.s.word("&");
+ if mutbl == ast::Mutability::Mut {
+ self.s.word("mut ");
+ }
+ self.print_pat(inner);
+ }
+ PatKind::Lit(ref e) => self.print_expr(&**e),
+ PatKind::Range(ref begin, ref end, Spanned { node: ref end_kind, .. }) => {
+ if let Some(e) = begin {
+ self.print_expr(e);
+ self.s.space();
+ }
+ match *end_kind {
+ RangeEnd::Included(RangeSyntax::DotDotDot) => self.s.word("..."),
+ RangeEnd::Included(RangeSyntax::DotDotEq) => self.s.word("..="),
+ RangeEnd::Excluded => self.s.word(".."),
+ }
+ if let Some(e) = end {
+ self.print_expr(e);
+ }
+ }
+ PatKind::Slice(ref elts) => {
+ self.s.word("[");
+ self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
+ self.s.word("]");
+ }
+ PatKind::Rest => self.s.word(".."),
+ PatKind::Paren(ref inner) => {
+ self.popen();
+ self.print_pat(inner);
+ self.pclose();
+ }
+ PatKind::Mac(ref m) => self.print_mac(m),
+ }
+ self.ann.post(self, AnnNode::Pat(pat))
+ }
+
+ fn print_arm(&mut self, arm: &ast::Arm) {
+ // Note, I have no idea why this check is necessary, but here it is.
+ if arm.attrs.is_empty() {
+ self.s.space();
+ }
+ self.cbox(INDENT_UNIT);
+ self.ibox(0);
+ self.maybe_print_comment(arm.pat.span.lo());
+ self.print_outer_attributes(&arm.attrs);
+ self.print_pat(&arm.pat);
+ self.s.space();
+ if let Some(ref e) = arm.guard {
+ self.word_space("if");
+ self.print_expr(e);
+ self.s.space();
+ }
+ self.word_space("=>");
+
+ match arm.body.kind {
+ ast::ExprKind::Block(ref blk, opt_label) => {
+ if let Some(label) = opt_label {
+ self.print_ident(label.ident);
+ self.word_space(":");
+ }
+
+ // The block will close the pattern's ibox.
+ self.print_block_unclosed_indent(blk);
+
+ // If it is a user-provided unsafe block, print a comma after it.
+ if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
+ self.s.word(",");
+ }
+ }
+ _ => {
+ self.end(); // Close the ibox for the pattern.
+ self.print_expr(&arm.body);
+ self.s.word(",");
+ }
+ }
+ self.end(); // Close enclosing cbox.
+ }
+
+ fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) {
+ match explicit_self.node {
+ SelfKind::Value(m) => {
+ self.print_mutability(m, false);
+ self.s.word("self")
+ }
+ SelfKind::Region(ref lt, m) => {
+ self.s.word("&");
+ self.print_opt_lifetime(lt);
+ self.print_mutability(m, false);
+ self.s.word("self")
+ }
+ SelfKind::Explicit(ref typ, m) => {
+ self.print_mutability(m, false);
+ self.s.word("self");
+ self.word_space(":");
+ self.print_type(typ)
+ }
+ }
+ }
+
+ crate fn print_fn(
+ &mut self,
+ decl: &ast::FnDecl,
+ header: ast::FnHeader,
+ name: Option<ast::Ident>,
+ generics: &ast::Generics,
+ vis: &ast::Visibility,
+ ) {
+ self.print_fn_header_info(header, vis);
+
+ if let Some(name) = name {
+ self.nbsp();
+ self.print_ident(name);
+ }
+ self.print_generic_params(&generics.params);
+ self.print_fn_params_and_ret(decl, false);
+ self.print_where_clause(&generics.where_clause)
+ }
+
+ crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
+ let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") };
+ self.word(open);
+ self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure));
+ self.word(close);
+ self.print_fn_ret_ty(&decl.output)
+ }
+
+ crate fn print_movability(&mut self, movability: ast::Movability) {
+ match movability {
+ ast::Movability::Static => self.word_space("static"),
+ ast::Movability::Movable => {}
+ }
+ }
+
+ crate fn print_asyncness(&mut self, asyncness: ast::IsAsync) {
+ if asyncness.is_async() {
+ self.word_nbsp("async");
+ }
+ }
+
+ crate fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
+ match capture_clause {
+ ast::CaptureBy::Value => self.word_space("move"),
+ ast::CaptureBy::Ref => {}
+ }
+ }
+
+ pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::GenericBound]) {
+ if !bounds.is_empty() {
+ self.s.word(prefix);
+ let mut first = true;
+ for bound in bounds {
+ if !(first && prefix.is_empty()) {
+ self.nbsp();
+ }
+ if first {
+ first = false;
+ } else {
+ self.word_space("+");
+ }
+
+ match bound {
+ GenericBound::Trait(tref, modifier) => {
+ if modifier == &TraitBoundModifier::Maybe {
+ self.s.word("?");
+ }
+ self.print_poly_trait_ref(tref);
+ }
+ GenericBound::Outlives(lt) => self.print_lifetime(*lt),
+ }
+ }
+ }
+ }
+
+ crate fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
+ self.print_name(lifetime.ident.name)
+ }
+
+ crate fn print_lifetime_bounds(
+ &mut self,
+ lifetime: ast::Lifetime,
+ bounds: &ast::GenericBounds,
+ ) {
+ self.print_lifetime(lifetime);
+ if !bounds.is_empty() {
+ self.s.word(": ");
+ for (i, bound) in bounds.iter().enumerate() {
+ if i != 0 {
+ self.s.word(" + ");
+ }
+ match bound {
+ ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt),
+ _ => panic!(),
+ }
+ }
+ }
+ }
+
+ crate fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
+ if generic_params.is_empty() {
+ return;
+ }
+
+ self.s.word("<");
+
+ self.commasep(Inconsistent, &generic_params, |s, param| {
+ s.print_outer_attributes_inline(¶m.attrs);
+
+ match param.kind {
+ ast::GenericParamKind::Lifetime => {
+ let lt = ast::Lifetime { id: param.id, ident: param.ident };
+ s.print_lifetime_bounds(lt, ¶m.bounds)
+ }
+ ast::GenericParamKind::Type { ref default } => {
+ s.print_ident(param.ident);
+ s.print_type_bounds(":", ¶m.bounds);
+ if let Some(ref default) = default {
+ s.s.space();
+ s.word_space("=");
+ s.print_type(default)
+ }
+ }
+ ast::GenericParamKind::Const { ref ty } => {
+ s.word_space("const");
+ s.print_ident(param.ident);
+ s.s.space();
+ s.word_space(":");
+ s.print_type(ty);
+ s.print_type_bounds(":", ¶m.bounds)
+ }
+ }
+ });
+
+ self.s.word(">");
+ }
+
+ crate fn print_where_clause(&mut self, where_clause: &ast::WhereClause) {
+ if where_clause.predicates.is_empty() {
+ return;
+ }
+
+ self.s.space();
+ self.word_space("where");
+
+ for (i, predicate) in where_clause.predicates.iter().enumerate() {
+ if i != 0 {
+ self.word_space(",");
+ }
+
+ match *predicate {
+ ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
+ ref bound_generic_params,
+ ref bounded_ty,
+ ref bounds,
+ ..
+ }) => {
+ self.print_formal_generic_params(bound_generic_params);
+ self.print_type(bounded_ty);
+ self.print_type_bounds(":", bounds);
+ }
+ ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
+ ref lifetime,
+ ref bounds,
+ ..
+ }) => {
+ self.print_lifetime_bounds(*lifetime, bounds);
+ }
+ ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
+ ref lhs_ty,
+ ref rhs_ty,
+ ..
+ }) => {
+ self.print_type(lhs_ty);
+ self.s.space();
+ self.word_space("=");
+ self.print_type(rhs_ty);
+ }
+ }
+ }
+ }
+
+ crate fn print_use_tree(&mut self, tree: &ast::UseTree) {
+ match tree.kind {
+ ast::UseTreeKind::Simple(rename, ..) => {
+ self.print_path(&tree.prefix, false, 0);
+ if let Some(rename) = rename {
+ self.s.space();
+ self.word_space("as");
+ self.print_ident(rename);
+ }
+ }
+ ast::UseTreeKind::Glob => {
+ if !tree.prefix.segments.is_empty() {
+ self.print_path(&tree.prefix, false, 0);
+ self.s.word("::");
+ }
+ self.s.word("*");
+ }
+ ast::UseTreeKind::Nested(ref items) => {
+ if tree.prefix.segments.is_empty() {
+ self.s.word("{");
+ } else {
+ self.print_path(&tree.prefix, false, 0);
+ self.s.word("::{");
+ }
+ self.commasep(Inconsistent, &items[..], |this, &(ref tree, _)| {
+ this.print_use_tree(tree)
+ });
+ self.s.word("}");
+ }
+ }
+ }
+
+ pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) {
+ match mutbl {
+ ast::Mutability::Mut => self.word_nbsp("mut"),
+ ast::Mutability::Not => {
+ if print_const {
+ self.word_nbsp("const");
+ }
+ }
+ }
+ }
+
+ crate fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) {
+ self.print_mutability(mt.mutbl, print_const);
+ self.print_type(&mt.ty)
+ }
+
+ crate fn print_param(&mut self, input: &ast::Param, is_closure: bool) {
+ self.ibox(INDENT_UNIT);
+
+ self.print_outer_attributes_inline(&input.attrs);
+
+ match input.ty.kind {
+ ast::TyKind::Infer if is_closure => self.print_pat(&input.pat),
+ _ => {
+ if let Some(eself) = input.to_self() {
+ self.print_explicit_self(&eself);
+ } else {
+ let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind {
+ ident.name == kw::Invalid
+ } else {
+ false
+ };
+ if !invalid {
+ self.print_pat(&input.pat);
+ self.s.word(":");
+ self.s.space();
+ }
+ self.print_type(&input.ty);
+ }
+ }
+ }
+ self.end();
+ }
+
+ crate fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FunctionRetTy) {
+ if let ast::FunctionRetTy::Ty(ty) = fn_ret_ty {
+ self.space_if_not_bol();
+ self.ibox(INDENT_UNIT);
+ self.word_space("->");
+ self.print_type(ty);
+ self.end();
+ self.maybe_print_comment(ty.span.lo());
+ }
+ }
+
+ crate fn print_ty_fn(
+ &mut self,
+ ext: ast::Extern,
+ unsafety: ast::Unsafety,
+ decl: &ast::FnDecl,
+ name: Option<ast::Ident>,
+ generic_params: &[ast::GenericParam],
+ ) {
+ self.ibox(INDENT_UNIT);
+ if !generic_params.is_empty() {
+ self.s.word("for");
+ self.print_generic_params(generic_params);
+ }
+ let generics = ast::Generics {
+ params: Vec::new(),
+ where_clause: ast::WhereClause { predicates: Vec::new(), span: rustc_span::DUMMY_SP },
+ span: rustc_span::DUMMY_SP,
+ };
+ self.print_fn(
+ decl,
+ ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() },
+ name,
+ &generics,
+ &dummy_spanned(ast::VisibilityKind::Inherited),
+ );
+ self.end();
+ }
+
+ crate fn maybe_print_trailing_comment(
+ &mut self,
+ span: rustc_span::Span,
+ next_pos: Option<BytePos>,
+ ) {
+ if let Some(cmnts) = self.comments() {
+ if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
+ self.print_comment(&cmnt);
+ }
+ }
+ }
+
+ crate fn print_remaining_comments(&mut self) {
+ // If there aren't any remaining comments, then we need to manually
+ // make sure there is a line break at the end.
+ if self.next_comment().is_none() {
+ self.s.hardbreak();
+ }
+ while let Some(ref cmnt) = self.next_comment() {
+ self.print_comment(cmnt);
+ }
+ }
+
+ crate fn print_fn_header_info(&mut self, header: ast::FnHeader, vis: &ast::Visibility) {
+ self.s.word(visibility_qualified(vis, ""));
+
+ match header.constness.node {
+ ast::Constness::NotConst => {}
+ ast::Constness::Const => self.word_nbsp("const"),
+ }
+
+ self.print_asyncness(header.asyncness.node);
+ self.print_unsafety(header.unsafety);
+
+ match header.ext {
+ ast::Extern::None => {}
+ ast::Extern::Implicit => {
+ self.word_nbsp("extern");
+ }
+ ast::Extern::Explicit(abi) => {
+ self.word_nbsp("extern");
+ self.print_literal(&abi.as_lit());
+ self.nbsp();
+ }
+ }
+
+ self.s.word("fn")
+ }
+
+ crate fn print_unsafety(&mut self, s: ast::Unsafety) {
+ match s {
+ ast::Unsafety::Normal => {}
+ ast::Unsafety::Unsafe => self.word_nbsp("unsafe"),
+ }
+ }
+
+ crate fn print_constness(&mut self, s: ast::Constness) {
+ match s {
+ ast::Constness::Const => self.word_nbsp("const"),
+ ast::Constness::NotConst => {}
+ }
+ }
+
+ crate fn print_is_auto(&mut self, s: ast::IsAuto) {
+ match s {
+ ast::IsAuto::Yes => self.word_nbsp("auto"),
+ ast::IsAuto::No => {}
+ }
+ }
+}
--- /dev/null
+use super::*;
+
+use rustc_span;
+use rustc_span::source_map::{dummy_spanned, respan};
+use syntax::ast;
+use syntax::attr::with_default_globals;
+
+fn fun_to_string(
+ decl: &ast::FnDecl,
+ header: ast::FnHeader,
+ name: ast::Ident,
+ generics: &ast::Generics,
+) -> String {
+ to_string(|s| {
+ s.head("");
+ s.print_fn(
+ decl,
+ header,
+ Some(name),
+ generics,
+ &dummy_spanned(ast::VisibilityKind::Inherited),
+ );
+ s.end(); // Close the head box.
+ s.end(); // Close the outer box.
+ })
+}
+
+fn variant_to_string(var: &ast::Variant) -> String {
+ to_string(|s| s.print_variant(var))
+}
+
+#[test]
+fn test_fun_to_string() {
+ with_default_globals(|| {
+ let abba_ident = ast::Ident::from_str("abba");
+
+ let decl = ast::FnDecl {
+ inputs: Vec::new(),
+ output: ast::FunctionRetTy::Default(rustc_span::DUMMY_SP),
+ };
+ let generics = ast::Generics::default();
+ assert_eq!(
+ fun_to_string(&decl, ast::FnHeader::default(), abba_ident, &generics),
+ "fn abba()"
+ );
+ })
+}
+
+#[test]
+fn test_variant_to_string() {
+ with_default_globals(|| {
+ let ident = ast::Ident::from_str("principal_skinner");
+
+ let var = ast::Variant {
+ ident,
+ vis: respan(rustc_span::DUMMY_SP, ast::VisibilityKind::Inherited),
+ attrs: Vec::new(),
+ id: ast::DUMMY_NODE_ID,
+ data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
+ disr_expr: None,
+ span: rustc_span::DUMMY_SP,
+ is_placeholder: false,
+ };
+
+ let varstr = variant_to_string(&var);
+ assert_eq!(varstr, "principal_skinner");
+ })
+}
doctest = false
[dependencies]
+rustc_ast_pretty = { path = "../librustc_ast_pretty" }
rustc_serialize = { path = "../libserialize", package = "serialize" }
rustc_errors = { path = "../librustc_errors" }
rustc_span = { path = "../librustc_span" }
use super::{find_by_name, mark_used};
+use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability, Handler};
use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
use rustc_macros::HashStable_Generic;
use rustc_span::{symbol::sym, symbol::Symbol, Span};
use std::num::NonZeroU32;
use syntax::ast::{self, Attribute, MetaItem, MetaItemKind, NestedMetaItem};
-use syntax::print::pprust;
pub fn is_builtin_attr(attr: &Attribute) -> bool {
attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some()
[dependencies]
fmt_macros = { path = "../libfmt_macros" }
log = "0.4"
+rustc_ast_pretty = { path = "../librustc_ast_pretty" }
rustc_attr = { path = "../librustc_attr" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_errors = { path = "../librustc_errors" }
use rustc_errors::{Applicability, DiagnosticBuilder};
+use rustc_ast_pretty::pprust;
use rustc_expand::base::*;
use rustc_parse::parser::Parser;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
use syntax::ast::{self, *};
-use syntax::print::pprust;
use syntax::ptr::P;
use syntax::token::{self, TokenKind};
use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree};
+use rustc_ast_pretty::pprust;
use rustc_expand::base;
use rustc_span;
-use syntax::print;
use syntax::tokenstream::TokenStream;
pub fn expand_log_syntax<'cx>(
sp: rustc_span::Span,
tts: TokenStream,
) -> Box<dyn base::MacResult + 'cx> {
- println!("{}", print::pprust::tts_to_string(tts));
+ println!("{}", pprust::tts_to_string(tts));
// any so that `log_syntax` can be invoked as an expression and item.
base::DummyResult::any_valid(sp)
use std::mem;
+use rustc_ast_pretty::pprust;
use rustc_expand::base::{ExtCtxt, Resolver};
use rustc_expand::expand::{AstFragment, ExpansionConfig};
use rustc_session::parse::ParseSess;
use syntax::ast::{self, Ident};
use syntax::attr;
use syntax::expand::is_proc_macro_attr;
-use syntax::print::pprust;
use syntax::ptr::P;
use syntax::visit::{self, Visitor};
+use rustc_ast_pretty::pprust;
use rustc_expand::base::{self, *};
use rustc_expand::panictry;
use rustc_parse::{self, new_sub_parser_from_file, parser::Parser, DirectoryOwnership};
use rustc_span::symbol::Symbol;
use rustc_span::{self, Pos, Span};
use syntax::ast;
-use syntax::print::pprust;
use syntax::ptr::P;
use syntax::token;
use syntax::tokenstream::TokenStream;
/// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
use crate::util::check_builtin_macro_attribute;
+use rustc_ast_pretty::pprust;
use rustc_expand::base::*;
use rustc_span::source_map::respan;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use syntax::ast;
use syntax::attr;
-use syntax::print::pprust;
use std::iter;
log = "0.4"
env_logger = { version = "0.7", default-features = false }
rustc = { path = "../librustc" }
+rustc_ast_pretty = { path = "../librustc_ast_pretty" }
rustc_target = { path = "../librustc_target" }
rustc_lint = { path = "../librustc_lint" }
rustc_data_structures = { path = "../librustc_data_structures" }
use rustc::session::Session;
use rustc::ty::{self, TyCtxt};
use rustc::util::common::ErrorReported;
+use rustc_ast_pretty::pprust;
use rustc_hir as hir;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_hir::print as pprust_hir;
use rustc_mir::util::{write_mir_graphviz, write_mir_pretty};
-
use rustc_span::FileName;
use syntax::ast;
-use syntax::print::pprust;
use std::cell::Cell;
use std::fs::File;
rustc_serialize = { path = "../libserialize", package = "serialize" }
log = "0.4"
rustc_span = { path = "../librustc_span" }
+rustc_ast_pretty = { path = "../librustc_ast_pretty" }
rustc_ast_passes = { path = "../librustc_ast_passes" }
rustc_attr = { path = "../librustc_attr" }
rustc_data_structures = { path = "../librustc_data_structures" }
use crate::placeholders::{placeholder, PlaceholderExpander};
use crate::proc_macro::collect_derives;
+use rustc_ast_pretty::pprust;
use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, FatalError, PResult};
use syntax::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path};
use syntax::ast::{ItemKind, MacArgs, MacStmtStyle, StmtKind};
use syntax::mut_visit::*;
-use syntax::print::pprust;
use syntax::ptr::P;
use syntax::token;
use syntax::tokenstream::{TokenStream, TokenTree};
use crate::mbe::{self, TokenTree};
+use rustc_ast_pretty::pprust;
use rustc_parse::parser::{FollowedByType, Parser, PathStyle};
use rustc_parse::Directory;
use rustc_session::parse::ParseSess;
use rustc_span::symbol::{kw, sym, Symbol};
use syntax::ast::{Ident, Name};
-use syntax::print::pprust;
use syntax::ptr::P;
use syntax::token::{self, DocComment, Nonterminal, Token};
use syntax::tokenstream::TokenStream;
use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedParseResult};
use crate::mbe::transcribe::transcribe;
+use rustc_ast_pretty::pprust;
use rustc_attr::{self as attr, TransparencyError};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;
use syntax::ast;
-use syntax::print::pprust;
use syntax::token::{self, NtTT, Token, TokenKind::*};
use syntax::tokenstream::{DelimSpan, TokenStream};
use crate::mbe::macro_parser;
use crate::mbe::{Delimited, KleeneOp, KleeneToken, SequenceRepetition, TokenTree};
+use rustc_ast_pretty::pprust;
use rustc_session::parse::ParseSess;
use rustc_span::symbol::kw;
use syntax::ast;
-use syntax::print::pprust;
use syntax::token::{self, Token};
use syntax::tokenstream;
use crate::base::ExtCtxt;
+use rustc_ast_pretty::pprust;
use rustc_data_structures::sync::Lrc;
use rustc_errors::Diagnostic;
use rustc_parse::lexer::nfc_normalize;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
use syntax::ast;
-use syntax::print::pprust;
use syntax::token;
use syntax::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
use syntax::util::comments;
doctest = false
[dependencies]
+rustc_ast_pretty = { path = "../librustc_ast_pretty" }
rustc_target = { path = "../librustc_target" }
rustc_macros = { path = "../librustc_macros" }
rustc_data_structures = { path = "../librustc_data_structures" }
+use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
+use rustc_ast_pretty::pp::{self, Breaks};
+use rustc_ast_pretty::pprust::{self, Comments, PrintState};
use rustc_span::source_map::{SourceMap, Spanned};
use rustc_span::symbol::kw;
use rustc_span::{self, BytePos, FileName};
use rustc_target::spec::abi::Abi;
use syntax::ast;
-use syntax::print::pp::Breaks::{Consistent, Inconsistent};
-use syntax::print::pp::{self, Breaks};
-use syntax::print::pprust::{self, Comments, PrintState};
use syntax::util::parser::{self, AssocOp, Fixity};
use crate::hir;
log = "0.4"
unicode-security = "0.0.2"
rustc = { path = "../librustc" }
+rustc_ast_pretty = { path = "../librustc_ast_pretty" }
rustc_attr = { path = "../librustc_attr" }
rustc_errors = { path = "../librustc_errors" }
rustc_hir = { path = "../librustc_hir" }
use rustc::hir::map::Map;
use rustc::traits::misc::can_type_implement_copy;
use rustc::ty::{self, layout::VariantIdx, Ty, TyCtxt};
+use rustc_ast_pretty::pprust::{self, expr_to_string};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_feature::Stability;
use rustc_span::{BytePos, Span};
use syntax::ast::{self, Expr};
use syntax::attr::{self, HasAttrs};
-use syntax::print::pprust::{self, expr_to_string};
use syntax::tokenstream::{TokenStream, TokenTree};
use syntax::visit::FnKind;
use crate::context::{CheckLintNameResult, LintStore};
use crate::late::unerased_lint_store;
use rustc::hir::map::Map;
-use rustc::lint::struct_lint_level;
-use rustc::lint::{LintLevelMap, LintLevelSets, LintSet, LintSource};
+use rustc::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource};
use rustc::ty::query::Providers;
use rustc::ty::TyCtxt;
+use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_span::symbol::{sym, Symbol};
use syntax::ast;
use syntax::attr;
-use syntax::print::pprust;
use syntax::unwrap_or;
use std::cmp;
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc::ty::adjustment;
use rustc::ty::{self, Ty};
+use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, Applicability};
use rustc_feature::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_span::{BytePos, Span};
use syntax::ast;
use syntax::attr;
-use syntax::print::pprust;
use syntax::util::parser;
use log::debug;
memmap = "0.7"
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
rustc = { path = "../librustc" }
+rustc_ast_pretty = { path = "../librustc_ast_pretty" }
rustc_attr = { path = "../librustc_attr" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_errors = { path = "../librustc_errors" }
/// Serialize the text of exported macros
fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef<'_>) {
- use syntax::print::pprust;
+ use rustc_ast_pretty::pprust;
let def_id = self.tcx.hir().local_def_id(macro_def.hir_id);
record!(self.per_def.kind[def_id] <- EntryKind::MacroDef(self.lazy(MacroDef {
body: pprust::tts_to_string(macro_def.body.clone()),
log_settings = "0.1.1"
polonius-engine = "0.11.0"
rustc = { path = "../librustc" }
+rustc_ast_pretty = { path = "../librustc_ast_pretty" }
rustc_attr = { path = "../librustc_attr" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_errors = { path = "../librustc_errors" }
+use rustc_ast_pretty::pprust;
use rustc_span::symbol::{sym, Symbol};
use syntax::ast::{self, MetaItem};
-use syntax::print::pprust;
use rustc_data_structures::work_queue::WorkQueue;
use rustc_index::bit_set::{BitSet, HybridBitSet};
[dependencies]
bitflags = "1.0"
log = "0.4"
+rustc_ast_pretty = { path = "../librustc_ast_pretty" }
rustc_attr = { path = "../librustc_attr" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_feature = { path = "../librustc_feature" }
use super::{StringReader, UnmatchedBrace};
+use rustc_ast_pretty::pprust::token_to_string;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::PResult;
use rustc_span::Span;
-use syntax::print::pprust::token_to_string;
use syntax::token::{self, Token};
use syntax::tokenstream::{
DelimSpan,
#![feature(crate_visibility_modifier)]
#![cfg_attr(bootstrap, feature(slice_patterns))]
+use rustc_ast_pretty::pprust;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Diagnostic, FatalError, Level, PResult};
use rustc_session::parse::ParseSess;
use rustc_span::{FileName, SourceFile, Span};
use syntax::ast;
-use syntax::print::pprust;
use syntax::token::{self, Nonterminal};
use syntax::tokenstream::{self, TokenStream, TokenTree};
use super::{Parser, PathStyle, TokenType};
+use rustc_ast_pretty::pprust;
use rustc_errors::PResult;
use rustc_span::{Span, Symbol};
use syntax::ast;
use syntax::attr;
-use syntax::print::pprust;
use syntax::token::{self, Nonterminal};
use syntax::util::comments;
use super::{BlockMode, Parser, PathStyle, SemiColonMode, SeqSep, TokenExpectType, TokenType};
+use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, struct_span_err};
use rustc_errors::{Applicability, DiagnosticBuilder, Handler, PResult};
self, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, Param,
};
use syntax::ast::{AttrVec, ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind};
-use syntax::print::pprust;
use syntax::ptr::P;
use syntax::token::{self, token_can_begin_expr, TokenKind};
use syntax::util::parser::AssocOp;
use super::{SemiColonMode, SeqSep, TokenExpectType};
use crate::maybe_recover_from_interpolated_ty_qpath;
+use rustc_ast_pretty::pprust;
use rustc_errors::{Applicability, PResult};
use rustc_span::source_map::{self, Span, Spanned};
use rustc_span::symbol::{kw, sym, Symbol};
AnonConst, BinOp, BinOpKind, FnDecl, FunctionRetTy, Mac, Param, Ty, TyKind, UnOp,
};
use syntax::ast::{Arm, BlockCheckMode, Expr, ExprKind, IsAsync, Label, Movability, RangeLimits};
-use syntax::print::pprust;
use syntax::ptr::P;
use syntax::token::{self, Token, TokenKind};
use syntax::util::classify;
use crate::maybe_whole;
+use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult, StashKey};
use rustc_span::source_map::{self, respan, Span};
use rustc_span::symbol::{kw, sym, Symbol};
use syntax::ast::{Constness, Defaultness, Extern, IsAsync, IsAuto, PathSegment, StrLit, Unsafety};
use syntax::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData};
use syntax::ast::{FnHeader, ForeignItem, ForeignItemKind, Mutability, Visibility, VisibilityKind};
-use syntax::print::pprust;
use syntax::ptr::P;
use syntax::token;
use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree};
use crate::{Directory, DirectoryOwnership};
use log::debug;
+use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError, PResult};
use rustc_session::parse::ParseSess;
use rustc_span::source_map::respan;
use rustc_span::{BytePos, FileName, Span, DUMMY_SP};
use syntax::ast::{self, AttrStyle, AttrVec, CrateSugar, Extern, Ident, Unsafety, DUMMY_NODE_ID};
use syntax::ast::{IsAsync, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind};
-use syntax::print::pprust;
use syntax::ptr::P;
use syntax::token::{self, DelimToken, Token, TokenKind};
use syntax::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndJoint};
use super::{Parser, PathStyle};
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
+use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult};
use rustc_span::source_map::{respan, Span, Spanned};
use rustc_span::symbol::{kw, sym};
use syntax::ast::{self, AttrVec, Attribute, FieldPat, Mac, Pat, PatKind, RangeEnd, RangeSyntax};
use syntax::ast::{BindingMode, Expr, ExprKind, Ident, Mutability, Path, QSelf};
use syntax::mut_visit::{noop_visit_mac, noop_visit_pat, MutVisitor};
-use syntax::print::pprust;
use syntax::ptr::P;
use syntax::token;
arena = { path = "../libarena" }
rustc = { path = "../librustc" }
rustc_ast_lowering = { path = "../librustc_ast_lowering" }
+rustc_ast_pretty = { path = "../librustc_ast_pretty" }
rustc_attr = { path = "../librustc_attr" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_errors = { path = "../librustc_errors" }
use rustc::bug;
use rustc::session::Session;
use rustc::ty::{self, DefIdTree};
+use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
use rustc_feature::BUILTIN_ATTRIBUTES;
use rustc_span::symbol::{kw, Symbol};
use rustc_span::{BytePos, MultiSpan, Span};
use syntax::ast::{self, Ident, Path};
-use syntax::print::pprust;
use syntax::util::lev_distance::find_best_match_for_name;
use crate::imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
use rustc::span_bug;
use rustc::ty::query::Providers;
use rustc::ty::{self, DefIdTree, ResolverOutputs};
+use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_data_structures::ptr_key::PtrKey;
use rustc_data_structures::sync::Lrc;
use syntax::ast::{ItemKind, Path};
use syntax::attr;
use syntax::node_id::{NodeMap, NodeSet};
-use syntax::print::pprust;
use syntax::unwrap_or;
use syntax::visit::{self, Visitor};
use rustc::session::parse::feature_err;
use rustc::session::Session;
use rustc::{lint, span_bug, ty};
+use rustc_ast_pretty::pprust;
use rustc_attr::{self as attr, StabilityLevel};
use rustc_data_structures::fx::FxHashSet;
use rustc_expand::base::SyntaxExtension;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
use syntax::ast::{self, Ident, NodeId};
-use syntax::print::pprust;
use rustc_data_structures::sync::Lrc;
use rustc_span::hygiene::{AstPass, MacroKind};
[dependencies]
log = "0.4"
rustc = { path = "../librustc" }
+rustc_ast_pretty = { path = "../librustc_ast_pretty" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_codegen_utils = { path = "../librustc_codegen_utils" }
rustc_hir = { path = "../librustc_hir" }
use rustc::session::config::Input;
use rustc::span_bug;
use rustc::ty::{self, DefIdTree, TyCtxt};
+use rustc_ast_pretty::pprust::{bounds_to_string, generic_params_to_string, ty_to_string};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::{DefKind as HirDefKind, Res};
use rustc_hir::def_id::DefId;
-
-use std::env;
-use std::path::Path;
-
use rustc_span::source_map::{respan, DUMMY_SP};
use rustc_span::*;
use syntax::ast::{self, Attribute, NodeId, PatKind};
-use syntax::print::pprust::{bounds_to_string, generic_params_to_string, ty_to_string};
use syntax::ptr::P;
use syntax::token;
use syntax::visit::{self, Visitor};
use syntax::walk_list;
+use std::env;
+use std::path::Path;
+
use crate::dumper::{Access, Dumper};
use crate::sig;
use crate::span_utils::SpanUtils;
use rustc::session::config::{CrateType, Input, OutputType};
use rustc::ty::{self, DefIdTree, TyCtxt};
use rustc::{bug, span_bug};
+use rustc_ast_pretty::pprust::{self, param_to_string, ty_to_string};
use rustc_codegen_utils::link::{filename_for_metadata, out_filename};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind as HirDefKind, Res};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::Node;
+use rustc_span::source_map::Spanned;
+use rustc_span::*;
+use syntax::ast::{self, Attribute, NodeId, PatKind, DUMMY_NODE_ID};
+use syntax::util::comments::strip_doc_comment_decoration;
+use syntax::visit::{self, Visitor};
use std::cell::Cell;
use std::default::Default;
use std::io::BufWriter;
use std::path::{Path, PathBuf};
-use rustc_span::source_map::Spanned;
-use rustc_span::*;
-use syntax::ast::{self, Attribute, NodeId, PatKind, DUMMY_NODE_ID};
-use syntax::print::pprust;
-use syntax::print::pprust::{param_to_string, ty_to_string};
-use syntax::util::comments::strip_doc_comment_decoration;
-use syntax::visit::{self, Visitor};
-
use dump_visitor::DumpVisitor;
use span_utils::SpanUtils;
use rls_data::{SigElement, Signature};
+use rustc_ast_pretty::pprust;
use rustc_hir::def::{DefKind, Res};
use syntax::ast::{self, Extern, NodeId};
-use syntax::print::pprust;
pub fn item_signature(item: &ast::Item, scx: &SaveContext<'_, '_>) -> Option<Signature> {
if !scx.config.signatures {
use rustc::middle::privacy::AccessLevels;
use rustc::middle::stability;
+use rustc_ast_pretty::pprust;
use rustc_data_structures::flock;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_feature::UnstableFeatures;
use serde::ser::SerializeSeq;
use serde::{Serialize, Serializer};
use syntax::ast;
-use syntax::print::pprust;
use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy};
use crate::config::RenderOptions;
extern crate env_logger;
extern crate getopts;
extern crate rustc;
+extern crate rustc_ast_pretty;
extern crate rustc_attr;
extern crate rustc_data_structures;
extern crate rustc_driver;
// Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade.
fn scrape_test_config(krate: &::rustc_hir::Crate) -> TestOptions {
- use syntax::print::pprust;
+ use rustc_ast_pretty::pprust;
let mut opts =
TestOptions { no_crate_inject: false, display_warnings: false, attrs: Vec::new() };
}
impl MacDelimiter {
- crate fn to_token(self) -> DelimToken {
+ pub fn to_token(self) -> DelimToken {
match self {
MacDelimiter::Parenthesis => DelimToken::Paren,
MacDelimiter::Bracket => DelimToken::Bracket,
}
impl StrLit {
- crate fn as_lit(&self) -> Lit {
+ pub fn as_lit(&self) -> Lit {
let token_kind = match self.style {
StrStyle::Cooked => token::Str,
StrStyle::Raw(n) => token::StrRaw(n),
pub mod tokenstream;
pub mod visit;
-pub mod print {
- mod helpers;
- pub mod pp;
- pub mod pprust;
-}
-
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
/// Requirements for a `StableHashingContext` to be used in this crate.
+++ /dev/null
-use crate::print::pp::Printer;
-use std::borrow::Cow;
-
-impl Printer {
- pub fn word_space<W: Into<Cow<'static, str>>>(&mut self, w: W) {
- self.word(w);
- self.space();
- }
-
- pub fn popen(&mut self) {
- self.word("(");
- }
-
- pub fn pclose(&mut self) {
- self.word(")");
- }
-
- pub fn hardbreak_if_not_bol(&mut self) {
- if !self.is_beginning_of_line() {
- self.hardbreak()
- }
- }
-
- pub fn space_if_not_bol(&mut self) {
- if !self.is_beginning_of_line() {
- self.space();
- }
- }
-
- pub fn nbsp(&mut self) {
- self.word(" ")
- }
-
- pub fn word_nbsp<S: Into<Cow<'static, str>>>(&mut self, w: S) {
- self.word(w);
- self.nbsp()
- }
-}
+++ /dev/null
-//! This pretty-printer is a direct reimplementation of Philip Karlton's
-//! Mesa pretty-printer, as described in appendix A of
-//!
-//! ```text
-//! STAN-CS-79-770: "Pretty Printing", by Derek C. Oppen.
-//! Stanford Department of Computer Science, 1979.
-//! ```
-//!
-//! The algorithm's aim is to break a stream into as few lines as possible
-//! while respecting the indentation-consistency requirements of the enclosing
-//! block, and avoiding breaking at silly places on block boundaries, for
-//! example, between "x" and ")" in "x)".
-//!
-//! I am implementing this algorithm because it comes with 20 pages of
-//! documentation explaining its theory, and because it addresses the set of
-//! concerns I've seen other pretty-printers fall down on. Weirdly. Even though
-//! it's 32 years old. What can I say?
-//!
-//! Despite some redundancies and quirks in the way it's implemented in that
-//! paper, I've opted to keep the implementation here as similar as I can,
-//! changing only what was blatantly wrong, a typo, or sufficiently
-//! non-idiomatic rust that it really stuck out.
-//!
-//! In particular you'll see a certain amount of churn related to INTEGER vs.
-//! CARDINAL in the Mesa implementation. Mesa apparently interconverts the two
-//! somewhat readily? In any case, I've used usize for indices-in-buffers and
-//! ints for character-sizes-and-indentation-offsets. This respects the need
-//! for ints to "go negative" while carrying a pending-calculation balance, and
-//! helps differentiate all the numbers flying around internally (slightly).
-//!
-//! I also inverted the indentation arithmetic used in the print stack, since
-//! the Mesa implementation (somewhat randomly) stores the offset on the print
-//! stack in terms of margin-col rather than col itself. I store col.
-//!
-//! I also implemented a small change in the String token, in that I store an
-//! explicit length for the string. For most tokens this is just the length of
-//! the accompanying string. But it's necessary to permit it to differ, for
-//! encoding things that are supposed to "go on their own line" -- certain
-//! classes of comment and blank-line -- where relying on adjacent
-//! hardbreak-like Break tokens with long blankness indication doesn't actually
-//! work. To see why, consider when there is a "thing that should be on its own
-//! line" between two long blocks, say functions. If you put a hardbreak after
-//! each function (or before each) and the breaking algorithm decides to break
-//! there anyways (because the functions themselves are long) you wind up with
-//! extra blank lines. If you don't put hardbreaks you can wind up with the
-//! "thing which should be on its own line" not getting its own line in the
-//! rare case of "really small functions" or such. This re-occurs with comments
-//! and explicit blank lines. So in those cases we use a string with a payload
-//! we want isolated to a line and an explicit length that's huge, surrounded
-//! by two zero-length breaks. The algorithm will try its best to fit it on a
-//! line (which it can't) and so naturally place the content on its own line to
-//! avoid combining it with other lines and making matters even worse.
-//!
-//! # Explanation
-//!
-//! In case you do not have the paper, here is an explanation of what's going
-//! on.
-//!
-//! There is a stream of input tokens flowing through this printer.
-//!
-//! The printer buffers up to 3N tokens inside itself, where N is linewidth.
-//! Yes, linewidth is chars and tokens are multi-char, but in the worst
-//! case every token worth buffering is 1 char long, so it's ok.
-//!
-//! Tokens are String, Break, and Begin/End to delimit blocks.
-//!
-//! Begin tokens can carry an offset, saying "how far to indent when you break
-//! inside here", as well as a flag indicating "consistent" or "inconsistent"
-//! breaking. Consistent breaking means that after the first break, no attempt
-//! will be made to flow subsequent breaks together onto lines. Inconsistent
-//! is the opposite. Inconsistent breaking example would be, say:
-//!
-//! ```
-//! foo(hello, there, good, friends)
-//! ```
-//!
-//! breaking inconsistently to become
-//!
-//! ```
-//! foo(hello, there
-//! good, friends);
-//! ```
-//!
-//! whereas a consistent breaking would yield:
-//!
-//! ```
-//! foo(hello,
-//! there
-//! good,
-//! friends);
-//! ```
-//!
-//! That is, in the consistent-break blocks we value vertical alignment
-//! more than the ability to cram stuff onto a line. But in all cases if it
-//! can make a block a one-liner, it'll do so.
-//!
-//! Carrying on with high-level logic:
-//!
-//! The buffered tokens go through a ring-buffer, 'tokens'. The 'left' and
-//! 'right' indices denote the active portion of the ring buffer as well as
-//! describing hypothetical points-in-the-infinite-stream at most 3N tokens
-//! apart (i.e., "not wrapped to ring-buffer boundaries"). The paper will switch
-//! between using 'left' and 'right' terms to denote the wrapped-to-ring-buffer
-//! and point-in-infinite-stream senses freely.
-//!
-//! There is a parallel ring buffer, `size`, that holds the calculated size of
-//! each token. Why calculated? Because for Begin/End pairs, the "size"
-//! includes everything between the pair. That is, the "size" of Begin is
-//! actually the sum of the sizes of everything between Begin and the paired
-//! End that follows. Since that is arbitrarily far in the future, `size` is
-//! being rewritten regularly while the printer runs; in fact most of the
-//! machinery is here to work out `size` entries on the fly (and give up when
-//! they're so obviously over-long that "infinity" is a good enough
-//! approximation for purposes of line breaking).
-//!
-//! The "input side" of the printer is managed as an abstract process called
-//! SCAN, which uses `scan_stack`, to manage calculating `size`. SCAN is, in
-//! other words, the process of calculating 'size' entries.
-//!
-//! The "output side" of the printer is managed by an abstract process called
-//! PRINT, which uses `print_stack`, `margin` and `space` to figure out what to
-//! do with each token/size pair it consumes as it goes. It's trying to consume
-//! the entire buffered window, but can't output anything until the size is >=
-//! 0 (sizes are set to negative while they're pending calculation).
-//!
-//! So SCAN takes input and buffers tokens and pending calculations, while
-//! PRINT gobbles up completed calculations and tokens from the buffer. The
-//! theory is that the two can never get more than 3N tokens apart, because
-//! once there's "obviously" too much data to fit on a line, in a size
-//! calculation, SCAN will write "infinity" to the size and let PRINT consume
-//! it.
-//!
-//! In this implementation (following the paper, again) the SCAN process is the
-//! methods called `Printer::scan_*`, and the 'PRINT' process is the
-//! method called `Printer::print`.
-
-use log::debug;
-use std::borrow::Cow;
-use std::collections::VecDeque;
-use std::fmt;
-
-/// How to break. Described in more detail in the module docs.
-#[derive(Clone, Copy, PartialEq)]
-pub enum Breaks {
- Consistent,
- Inconsistent,
-}
-
-#[derive(Clone, Copy)]
-pub struct BreakToken {
- offset: isize,
- blank_space: isize,
-}
-
-#[derive(Clone, Copy)]
-pub struct BeginToken {
- offset: isize,
- breaks: Breaks,
-}
-
-#[derive(Clone)]
-pub enum Token {
- // In practice a string token contains either a `&'static str` or a
- // `String`. `Cow` is overkill for this because we never modify the data,
- // but it's more convenient than rolling our own more specialized type.
- String(Cow<'static, str>),
- Break(BreakToken),
- Begin(BeginToken),
- End,
- Eof,
-}
-
-impl Token {
- crate fn is_eof(&self) -> bool {
- match *self {
- Token::Eof => true,
- _ => false,
- }
- }
-
- pub fn is_hardbreak_tok(&self) -> bool {
- match *self {
- Token::Break(BreakToken { offset: 0, blank_space: bs }) if bs == SIZE_INFINITY => true,
- _ => false,
- }
- }
-}
-
-impl fmt::Display for Token {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match *self {
- Token::String(ref s) => write!(f, "STR({},{})", s, s.len()),
- Token::Break(_) => f.write_str("BREAK"),
- Token::Begin(_) => f.write_str("BEGIN"),
- Token::End => f.write_str("END"),
- Token::Eof => f.write_str("EOF"),
- }
- }
-}
-
-fn buf_str(buf: &[BufEntry], left: usize, right: usize, lim: usize) -> String {
- let n = buf.len();
- let mut i = left;
- let mut l = lim;
- let mut s = String::from("[");
- while i != right && l != 0 {
- l -= 1;
- if i != left {
- s.push_str(", ");
- }
- s.push_str(&format!("{}={}", buf[i].size, &buf[i].token));
- i += 1;
- i %= n;
- }
- s.push(']');
- s
-}
-
-#[derive(Copy, Clone)]
-enum PrintStackBreak {
- Fits,
- Broken(Breaks),
-}
-
-#[derive(Copy, Clone)]
-struct PrintStackElem {
- offset: isize,
- pbreak: PrintStackBreak,
-}
-
-const SIZE_INFINITY: isize = 0xffff;
-
-pub fn mk_printer() -> Printer {
- let linewidth = 78;
- // Yes 55, it makes the ring buffers big enough to never fall behind.
- let n: usize = 55 * linewidth;
- debug!("mk_printer {}", linewidth);
- Printer {
- out: String::new(),
- buf_max_len: n,
- margin: linewidth as isize,
- space: linewidth as isize,
- left: 0,
- right: 0,
- // Initialize a single entry; advance_right() will extend it on demand
- // up to `buf_max_len` elements.
- buf: vec![BufEntry::default()],
- left_total: 0,
- right_total: 0,
- scan_stack: VecDeque::new(),
- print_stack: Vec::new(),
- pending_indentation: 0,
- }
-}
-
-pub struct Printer {
- out: String,
- buf_max_len: usize,
- /// Width of lines we're constrained to
- margin: isize,
- /// Number of spaces left on line
- space: isize,
- /// Index of left side of input stream
- left: usize,
- /// Index of right side of input stream
- right: usize,
- /// Ring-buffer of tokens and calculated sizes
- buf: Vec<BufEntry>,
- /// Running size of stream "...left"
- left_total: isize,
- /// Running size of stream "...right"
- right_total: isize,
- /// Pseudo-stack, really a ring too. Holds the
- /// primary-ring-buffers index of the Begin that started the
- /// current block, possibly with the most recent Break after that
- /// Begin (if there is any) on top of it. Stuff is flushed off the
- /// bottom as it becomes irrelevant due to the primary ring-buffer
- /// advancing.
- scan_stack: VecDeque<usize>,
- /// Stack of blocks-in-progress being flushed by print
- print_stack: Vec<PrintStackElem>,
- /// Buffered indentation to avoid writing trailing whitespace
- pending_indentation: isize,
-}
-
-#[derive(Clone)]
-struct BufEntry {
- token: Token,
- size: isize,
-}
-
-impl Default for BufEntry {
- fn default() -> Self {
- BufEntry { token: Token::Eof, size: 0 }
- }
-}
-
-impl Printer {
- pub fn last_token(&self) -> Token {
- self.buf[self.right].token.clone()
- }
-
- /// Be very careful with this!
- pub fn replace_last_token(&mut self, t: Token) {
- self.buf[self.right].token = t;
- }
-
- fn scan_eof(&mut self) {
- if !self.scan_stack.is_empty() {
- self.check_stack(0);
- self.advance_left();
- }
- }
-
- fn scan_begin(&mut self, b: BeginToken) {
- if self.scan_stack.is_empty() {
- self.left_total = 1;
- self.right_total = 1;
- self.left = 0;
- self.right = 0;
- } else {
- self.advance_right();
- }
- debug!("pp Begin({})/buffer Vec<{},{}>", b.offset, self.left, self.right);
- self.scan_push(BufEntry { token: Token::Begin(b), size: -self.right_total });
- }
-
- fn scan_end(&mut self) {
- if self.scan_stack.is_empty() {
- debug!("pp End/print Vec<{},{}>", self.left, self.right);
- self.print_end();
- } else {
- debug!("pp End/buffer Vec<{},{}>", self.left, self.right);
- self.advance_right();
- self.scan_push(BufEntry { token: Token::End, size: -1 });
- }
- }
-
- fn scan_break(&mut self, b: BreakToken) {
- if self.scan_stack.is_empty() {
- self.left_total = 1;
- self.right_total = 1;
- self.left = 0;
- self.right = 0;
- } else {
- self.advance_right();
- }
- debug!("pp Break({})/buffer Vec<{},{}>", b.offset, self.left, self.right);
- self.check_stack(0);
- self.scan_push(BufEntry { token: Token::Break(b), size: -self.right_total });
- self.right_total += b.blank_space;
- }
-
- fn scan_string(&mut self, s: Cow<'static, str>) {
- if self.scan_stack.is_empty() {
- debug!("pp String('{}')/print Vec<{},{}>", s, self.left, self.right);
- self.print_string(s);
- } else {
- debug!("pp String('{}')/buffer Vec<{},{}>", s, self.left, self.right);
- self.advance_right();
- let len = s.len() as isize;
- self.buf[self.right] = BufEntry { token: Token::String(s), size: len };
- self.right_total += len;
- self.check_stream();
- }
- }
-
- fn check_stream(&mut self) {
- debug!(
- "check_stream Vec<{}, {}> with left_total={}, right_total={}",
- self.left, self.right, self.left_total, self.right_total
- );
- if self.right_total - self.left_total > self.space {
- debug!(
- "scan window is {}, longer than space on line ({})",
- self.right_total - self.left_total,
- self.space
- );
- if Some(&self.left) == self.scan_stack.back() {
- debug!("setting {} to infinity and popping", self.left);
- let scanned = self.scan_pop_bottom();
- self.buf[scanned].size = SIZE_INFINITY;
- }
- self.advance_left();
- if self.left != self.right {
- self.check_stream();
- }
- }
- }
-
- fn scan_push(&mut self, entry: BufEntry) {
- debug!("scan_push {}", self.right);
- self.buf[self.right] = entry;
- self.scan_stack.push_front(self.right);
- }
-
- fn scan_pop(&mut self) -> usize {
- self.scan_stack.pop_front().unwrap()
- }
-
- fn scan_top(&mut self) -> usize {
- *self.scan_stack.front().unwrap()
- }
-
- fn scan_pop_bottom(&mut self) -> usize {
- self.scan_stack.pop_back().unwrap()
- }
-
- fn advance_right(&mut self) {
- self.right += 1;
- self.right %= self.buf_max_len;
- // Extend the buf if necessary.
- if self.right == self.buf.len() {
- self.buf.push(BufEntry::default());
- }
- assert_ne!(self.right, self.left);
- }
-
- fn advance_left(&mut self) {
- debug!(
- "advance_left Vec<{},{}>, sizeof({})={}",
- self.left, self.right, self.left, self.buf[self.left].size
- );
-
- let mut left_size = self.buf[self.left].size;
-
- while left_size >= 0 {
- let left = self.buf[self.left].token.clone();
-
- let len = match left {
- Token::Break(b) => b.blank_space,
- Token::String(ref s) => {
- let len = s.len() as isize;
- assert_eq!(len, left_size);
- len
- }
- _ => 0,
- };
-
- self.print(left, left_size);
-
- self.left_total += len;
-
- if self.left == self.right {
- break;
- }
-
- self.left += 1;
- self.left %= self.buf_max_len;
-
- left_size = self.buf[self.left].size;
- }
- }
-
- fn check_stack(&mut self, k: usize) {
- if !self.scan_stack.is_empty() {
- let x = self.scan_top();
- match self.buf[x].token {
- Token::Begin(_) => {
- if k > 0 {
- self.scan_pop();
- self.buf[x].size += self.right_total;
- self.check_stack(k - 1);
- }
- }
- Token::End => {
- // paper says + not =, but that makes no sense.
- self.scan_pop();
- self.buf[x].size = 1;
- self.check_stack(k + 1);
- }
- _ => {
- self.scan_pop();
- self.buf[x].size += self.right_total;
- if k > 0 {
- self.check_stack(k);
- }
- }
- }
- }
- }
-
- fn print_newline(&mut self, amount: isize) {
- debug!("NEWLINE {}", amount);
- self.out.push('\n');
- self.pending_indentation = 0;
- self.indent(amount);
- }
-
- fn indent(&mut self, amount: isize) {
- debug!("INDENT {}", amount);
- self.pending_indentation += amount;
- }
-
- fn get_top(&mut self) -> PrintStackElem {
- match self.print_stack.last() {
- Some(el) => *el,
- None => {
- PrintStackElem { offset: 0, pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) }
- }
- }
- }
-
- fn print_begin(&mut self, b: BeginToken, l: isize) {
- if l > self.space {
- let col = self.margin - self.space + b.offset;
- debug!("print Begin -> push broken block at col {}", col);
- self.print_stack
- .push(PrintStackElem { offset: col, pbreak: PrintStackBreak::Broken(b.breaks) });
- } else {
- debug!("print Begin -> push fitting block");
- self.print_stack.push(PrintStackElem { offset: 0, pbreak: PrintStackBreak::Fits });
- }
- }
-
- fn print_end(&mut self) {
- debug!("print End -> pop End");
- self.print_stack.pop().unwrap();
- }
-
- fn print_break(&mut self, b: BreakToken, l: isize) {
- let top = self.get_top();
- match top.pbreak {
- PrintStackBreak::Fits => {
- debug!("print Break({}) in fitting block", b.blank_space);
- self.space -= b.blank_space;
- self.indent(b.blank_space);
- }
- PrintStackBreak::Broken(Breaks::Consistent) => {
- debug!("print Break({}+{}) in consistent block", top.offset, b.offset);
- self.print_newline(top.offset + b.offset);
- self.space = self.margin - (top.offset + b.offset);
- }
- PrintStackBreak::Broken(Breaks::Inconsistent) => {
- if l > self.space {
- debug!("print Break({}+{}) w/ newline in inconsistent", top.offset, b.offset);
- self.print_newline(top.offset + b.offset);
- self.space = self.margin - (top.offset + b.offset);
- } else {
- debug!("print Break({}) w/o newline in inconsistent", b.blank_space);
- self.indent(b.blank_space);
- self.space -= b.blank_space;
- }
- }
- }
- }
-
- fn print_string(&mut self, s: Cow<'static, str>) {
- let len = s.len() as isize;
- debug!("print String({})", s);
- // assert!(len <= space);
- self.space -= len;
-
- // Write the pending indent. A more concise way of doing this would be:
- //
- // write!(self.out, "{: >n$}", "", n = self.pending_indentation as usize)?;
- //
- // But that is significantly slower. This code is sufficiently hot, and indents can get
- // sufficiently large, that the difference is significant on some workloads.
- self.out.reserve(self.pending_indentation as usize);
- self.out.extend(std::iter::repeat(' ').take(self.pending_indentation as usize));
- self.pending_indentation = 0;
- self.out.push_str(&s);
- }
-
- fn print(&mut self, token: Token, l: isize) {
- debug!("print {} {} (remaining line space={})", token, l, self.space);
- debug!("{}", buf_str(&self.buf, self.left, self.right, 6));
- match token {
- Token::Begin(b) => self.print_begin(b, l),
- Token::End => self.print_end(),
- Token::Break(b) => self.print_break(b, l),
- Token::String(s) => {
- let len = s.len() as isize;
- assert_eq!(len, l);
- self.print_string(s);
- }
- Token::Eof => panic!(), // Eof should never get here.
- }
- }
-
- // Convenience functions to talk to the printer.
-
- /// "raw box"
- pub fn rbox(&mut self, indent: usize, b: Breaks) {
- self.scan_begin(BeginToken { offset: indent as isize, breaks: b })
- }
-
- /// Inconsistent breaking box
- pub fn ibox(&mut self, indent: usize) {
- self.rbox(indent, Breaks::Inconsistent)
- }
-
- /// Consistent breaking box
- pub fn cbox(&mut self, indent: usize) {
- self.rbox(indent, Breaks::Consistent)
- }
-
- pub fn break_offset(&mut self, n: usize, off: isize) {
- self.scan_break(BreakToken { offset: off, blank_space: n as isize })
- }
-
- pub fn end(&mut self) {
- self.scan_end()
- }
-
- pub fn eof(mut self) -> String {
- self.scan_eof();
- self.out
- }
-
- pub fn word<S: Into<Cow<'static, str>>>(&mut self, wrd: S) {
- let s = wrd.into();
- self.scan_string(s)
- }
-
- fn spaces(&mut self, n: usize) {
- self.break_offset(n, 0)
- }
-
- crate fn zerobreak(&mut self) {
- self.spaces(0)
- }
-
- pub fn space(&mut self) {
- self.spaces(1)
- }
-
- pub fn hardbreak(&mut self) {
- self.spaces(SIZE_INFINITY as usize)
- }
-
- pub fn is_beginning_of_line(&self) -> bool {
- self.last_token().is_eof() || self.last_token().is_hardbreak_tok()
- }
-
- pub fn hardbreak_tok_offset(off: isize) -> Token {
- Token::Break(BreakToken { offset: off, blank_space: SIZE_INFINITY })
- }
-}
+++ /dev/null
-use crate::ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
-use crate::ast::{Attribute, GenericArg, MacArgs};
-use crate::ast::{GenericBound, SelfKind, TraitBoundModifier};
-use crate::attr;
-use crate::print::pp::Breaks::{Consistent, Inconsistent};
-use crate::print::pp::{self, Breaks};
-use crate::ptr::P;
-use crate::token::{self, BinOpToken, DelimToken, Nonterminal, Token, TokenKind};
-use crate::tokenstream::{self, TokenStream, TokenTree};
-use crate::util::classify;
-use crate::util::comments;
-use crate::util::parser::{self, AssocOp, Fixity};
-
-use rustc_data_structures::sync::Once;
-use rustc_span::edition::Edition;
-use rustc_span::source_map::{dummy_spanned, SourceMap, Spanned};
-use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::{BytePos, FileName, Span};
-
-use std::borrow::Cow;
-
-#[cfg(test)]
-mod tests;
-
-pub enum MacHeader<'a> {
- Path(&'a ast::Path),
- Keyword(&'static str),
-}
-
-pub enum AnnNode<'a> {
- Ident(&'a ast::Ident),
- Name(&'a ast::Name),
- Block(&'a ast::Block),
- Item(&'a ast::Item),
- SubItem(ast::NodeId),
- Expr(&'a ast::Expr),
- Pat(&'a ast::Pat),
- Crate(&'a ast::Crate),
-}
-
-pub trait PpAnn {
- fn pre(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
- fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
-}
-
-#[derive(Copy, Clone)]
-pub struct NoAnn;
-
-impl PpAnn for NoAnn {}
-
-pub struct Comments<'a> {
- cm: &'a SourceMap,
- comments: Vec<comments::Comment>,
- current: usize,
-}
-
-impl<'a> Comments<'a> {
- pub fn new(cm: &'a SourceMap, filename: FileName, input: String) -> Comments<'a> {
- let comments = comments::gather_comments(cm, filename, input);
- Comments { cm, comments, current: 0 }
- }
-
- pub fn next(&self) -> Option<comments::Comment> {
- self.comments.get(self.current).cloned()
- }
-
- pub fn trailing_comment(
- &mut self,
- span: rustc_span::Span,
- next_pos: Option<BytePos>,
- ) -> Option<comments::Comment> {
- if let Some(cmnt) = self.next() {
- if cmnt.style != comments::Trailing {
- return None;
- }
- let span_line = self.cm.lookup_char_pos(span.hi());
- let comment_line = self.cm.lookup_char_pos(cmnt.pos);
- let next = next_pos.unwrap_or_else(|| cmnt.pos + BytePos(1));
- if span.hi() < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line {
- return Some(cmnt);
- }
- }
-
- None
- }
-}
-
-pub struct State<'a> {
- pub s: pp::Printer,
- comments: Option<Comments<'a>>,
- ann: &'a (dyn PpAnn + 'a),
- is_expanded: bool,
-}
-
-crate const INDENT_UNIT: usize = 4;
-
-/// Requires you to pass an input filename and reader so that
-/// it can scan the input text for comments to copy forward.
-pub fn print_crate<'a>(
- cm: &'a SourceMap,
- krate: &ast::Crate,
- filename: FileName,
- input: String,
- ann: &'a dyn PpAnn,
- is_expanded: bool,
- edition: Edition,
- injected_crate_name: &Once<Symbol>,
-) -> String {
- let mut s = State {
- s: pp::mk_printer(),
- comments: Some(Comments::new(cm, filename, input)),
- ann,
- is_expanded,
- };
-
- if is_expanded && injected_crate_name.try_get().is_some() {
- // We need to print `#![no_std]` (and its feature gate) so that
- // compiling pretty-printed source won't inject libstd again.
- // However, we don't want these attributes in the AST because
- // of the feature gate, so we fake them up here.
-
- // `#![feature(prelude_import)]`
- let pi_nested = attr::mk_nested_word_item(ast::Ident::with_dummy_span(sym::prelude_import));
- let list = attr::mk_list_item(ast::Ident::with_dummy_span(sym::feature), vec![pi_nested]);
- let fake_attr = attr::mk_attr_inner(list);
- s.print_attribute(&fake_attr);
-
- // Currently, in Rust 2018 we don't have `extern crate std;` at the crate
- // root, so this is not needed, and actually breaks things.
- if edition == Edition::Edition2015 {
- // `#![no_std]`
- let no_std_meta = attr::mk_word_item(ast::Ident::with_dummy_span(sym::no_std));
- let fake_attr = attr::mk_attr_inner(no_std_meta);
- s.print_attribute(&fake_attr);
- }
- }
-
- s.print_mod(&krate.module, &krate.attrs);
- s.print_remaining_comments();
- s.ann.post(&mut s, AnnNode::Crate(krate));
- s.s.eof()
-}
-
-pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
- let mut printer =
- State { s: pp::mk_printer(), comments: None, ann: &NoAnn, is_expanded: false };
- f(&mut printer);
- printer.s.eof()
-}
-
-// This makes comma-separated lists look slightly nicer,
-// and also addresses a specific regression described in issue #63896.
-fn tt_prepend_space(tt: &TokenTree) -> bool {
- match tt {
- TokenTree::Token(token) => match token.kind {
- token::Comma => false,
- _ => true,
- },
- _ => true,
- }
-}
-
-fn binop_to_string(op: BinOpToken) -> &'static str {
- match op {
- token::Plus => "+",
- token::Minus => "-",
- token::Star => "*",
- token::Slash => "/",
- token::Percent => "%",
- token::Caret => "^",
- token::And => "&",
- token::Or => "|",
- token::Shl => "<<",
- token::Shr => ">>",
- }
-}
-
-pub fn literal_to_string(lit: token::Lit) -> String {
- let token::Lit { kind, symbol, suffix } = lit;
- let mut out = match kind {
- token::Byte => format!("b'{}'", symbol),
- token::Char => format!("'{}'", symbol),
- token::Str => format!("\"{}\"", symbol),
- token::StrRaw(n) => {
- format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
- }
- token::ByteStr => format!("b\"{}\"", symbol),
- token::ByteStrRaw(n) => {
- format!("br{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
- }
- token::Integer | token::Float | token::Bool | token::Err => symbol.to_string(),
- };
-
- if let Some(suffix) = suffix {
- out.push_str(&suffix.as_str())
- }
-
- out
-}
-
-/// Print an ident from AST, `$crate` is converted into its respective crate name.
-pub fn ast_ident_to_string(ident: ast::Ident, is_raw: bool) -> String {
- ident_to_string(ident.name, is_raw, Some(ident.span))
-}
-
-// AST pretty-printer is used as a fallback for turning AST structures into token streams for
-// proc macros. Additionally, proc macros may stringify their input and expect it survive the
-// stringification (especially true for proc macro derives written between Rust 1.15 and 1.30).
-// So we need to somehow pretty-print `$crate` in a way preserving at least some of its
-// hygiene data, most importantly name of the crate it refers to.
-// As a result we print `$crate` as `crate` if it refers to the local crate
-// and as `::other_crate_name` if it refers to some other crate.
-// Note, that this is only done if the ident token is printed from inside of AST pretty-pringing,
-// but not otherwise. Pretty-printing is the only way for proc macros to discover token contents,
-// so we should not perform this lossy conversion if the top level call to the pretty-printer was
-// done for a token stream or a single token.
-fn ident_to_string(name: ast::Name, is_raw: bool, convert_dollar_crate: Option<Span>) -> String {
- if is_raw {
- format!("r#{}", name)
- } else {
- if name == kw::DollarCrate {
- if let Some(span) = convert_dollar_crate {
- let converted = span.ctxt().dollar_crate_name();
- return if converted.is_path_segment_keyword() {
- converted.to_string()
- } else {
- format!("::{}", converted)
- };
- }
- }
- name.to_string()
- }
-}
-
-/// Print the token kind precisely, without converting `$crate` into its respective crate name.
-pub fn token_kind_to_string(tok: &TokenKind) -> String {
- token_kind_to_string_ext(tok, None)
-}
-
-fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option<Span>) -> String {
- match *tok {
- token::Eq => "=".to_string(),
- token::Lt => "<".to_string(),
- token::Le => "<=".to_string(),
- token::EqEq => "==".to_string(),
- token::Ne => "!=".to_string(),
- token::Ge => ">=".to_string(),
- token::Gt => ">".to_string(),
- token::Not => "!".to_string(),
- token::Tilde => "~".to_string(),
- token::OrOr => "||".to_string(),
- token::AndAnd => "&&".to_string(),
- token::BinOp(op) => binop_to_string(op).to_string(),
- token::BinOpEq(op) => format!("{}=", binop_to_string(op)),
-
- /* Structural symbols */
- token::At => "@".to_string(),
- token::Dot => ".".to_string(),
- token::DotDot => "..".to_string(),
- token::DotDotDot => "...".to_string(),
- token::DotDotEq => "..=".to_string(),
- token::Comma => ",".to_string(),
- token::Semi => ";".to_string(),
- token::Colon => ":".to_string(),
- token::ModSep => "::".to_string(),
- token::RArrow => "->".to_string(),
- token::LArrow => "<-".to_string(),
- token::FatArrow => "=>".to_string(),
- token::OpenDelim(token::Paren) => "(".to_string(),
- token::CloseDelim(token::Paren) => ")".to_string(),
- token::OpenDelim(token::Bracket) => "[".to_string(),
- token::CloseDelim(token::Bracket) => "]".to_string(),
- token::OpenDelim(token::Brace) => "{".to_string(),
- token::CloseDelim(token::Brace) => "}".to_string(),
- token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) => " ".to_string(),
- token::Pound => "#".to_string(),
- token::Dollar => "$".to_string(),
- token::Question => "?".to_string(),
- token::SingleQuote => "'".to_string(),
-
- /* Literals */
- token::Literal(lit) => literal_to_string(lit),
-
- /* Name components */
- token::Ident(s, is_raw) => ident_to_string(s, is_raw, convert_dollar_crate),
- token::Lifetime(s) => s.to_string(),
-
- /* Other */
- token::DocComment(s) => s.to_string(),
- token::Eof => "<eof>".to_string(),
- token::Whitespace => " ".to_string(),
- token::Comment => "/* */".to_string(),
- token::Shebang(s) => format!("/* shebang: {}*/", s),
- token::Unknown(s) => s.to_string(),
-
- token::Interpolated(ref nt) => nonterminal_to_string(nt),
- }
-}
-
-/// Print the token precisely, without converting `$crate` into its respective crate name.
-pub fn token_to_string(token: &Token) -> String {
- token_to_string_ext(token, false)
-}
-
-fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String {
- let convert_dollar_crate = convert_dollar_crate.then_some(token.span);
- token_kind_to_string_ext(&token.kind, convert_dollar_crate)
-}
-
-pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
- match *nt {
- token::NtExpr(ref e) => expr_to_string(e),
- token::NtMeta(ref e) => attr_item_to_string(e),
- token::NtTy(ref e) => ty_to_string(e),
- token::NtPath(ref e) => path_to_string(e),
- token::NtItem(ref e) => item_to_string(e),
- token::NtBlock(ref e) => block_to_string(e),
- token::NtStmt(ref e) => stmt_to_string(e),
- token::NtPat(ref e) => pat_to_string(e),
- token::NtIdent(e, is_raw) => ast_ident_to_string(e, is_raw),
- token::NtLifetime(e) => e.to_string(),
- token::NtLiteral(ref e) => expr_to_string(e),
- token::NtTT(ref tree) => tt_to_string(tree.clone()),
- // FIXME(Centril): merge these variants.
- token::NtImplItem(ref e) | token::NtTraitItem(ref e) => assoc_item_to_string(e),
- token::NtVis(ref e) => vis_to_string(e),
- token::NtForeignItem(ref e) => foreign_item_to_string(e),
- }
-}
-
-pub fn ty_to_string(ty: &ast::Ty) -> String {
- to_string(|s| s.print_type(ty))
-}
-
-pub fn bounds_to_string(bounds: &[ast::GenericBound]) -> String {
- to_string(|s| s.print_type_bounds("", bounds))
-}
-
-pub fn pat_to_string(pat: &ast::Pat) -> String {
- to_string(|s| s.print_pat(pat))
-}
-
-pub fn expr_to_string(e: &ast::Expr) -> String {
- to_string(|s| s.print_expr(e))
-}
-
-pub fn tt_to_string(tt: tokenstream::TokenTree) -> String {
- to_string(|s| s.print_tt(tt, false))
-}
-
-pub fn tts_to_string(tokens: TokenStream) -> String {
- to_string(|s| s.print_tts(tokens, false))
-}
-
-pub fn stmt_to_string(stmt: &ast::Stmt) -> String {
- to_string(|s| s.print_stmt(stmt))
-}
-
-pub fn item_to_string(i: &ast::Item) -> String {
- to_string(|s| s.print_item(i))
-}
-
-fn assoc_item_to_string(i: &ast::AssocItem) -> String {
- to_string(|s| s.print_assoc_item(i))
-}
-
-pub fn generic_params_to_string(generic_params: &[ast::GenericParam]) -> String {
- to_string(|s| s.print_generic_params(generic_params))
-}
-
-pub fn path_to_string(p: &ast::Path) -> String {
- to_string(|s| s.print_path(p, false, 0))
-}
-
-pub fn path_segment_to_string(p: &ast::PathSegment) -> String {
- to_string(|s| s.print_path_segment(p, false))
-}
-
-pub fn vis_to_string(v: &ast::Visibility) -> String {
- to_string(|s| s.print_visibility(v))
-}
-
-fn block_to_string(blk: &ast::Block) -> String {
- to_string(|s| {
- // Containing cbox, will be closed by `print_block` at `}`.
- s.cbox(INDENT_UNIT);
- // Head-ibox, will be closed by `print_block` after `{`.
- s.ibox(0);
- s.print_block(blk)
- })
-}
-
-pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String {
- to_string(|s| s.print_meta_list_item(li))
-}
-
-fn attr_item_to_string(ai: &ast::AttrItem) -> String {
- to_string(|s| s.print_attr_item(ai, ai.path.span))
-}
-
-pub fn attribute_to_string(attr: &ast::Attribute) -> String {
- to_string(|s| s.print_attribute(attr))
-}
-
-pub fn param_to_string(arg: &ast::Param) -> String {
- to_string(|s| s.print_param(arg, false))
-}
-
-fn foreign_item_to_string(arg: &ast::ForeignItem) -> String {
- to_string(|s| s.print_foreign_item(arg))
-}
-
-fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
- format!("{}{}", to_string(|s| s.print_visibility(vis)), s)
-}
-
-impl std::ops::Deref for State<'_> {
- type Target = pp::Printer;
- fn deref(&self) -> &Self::Target {
- &self.s
- }
-}
-
-impl std::ops::DerefMut for State<'_> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.s
- }
-}
-
-pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::DerefMut {
- fn comments(&mut self) -> &mut Option<Comments<'a>>;
- fn print_ident(&mut self, ident: ast::Ident);
- fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
-
- fn strsep<T, F>(
- &mut self,
- sep: &'static str,
- space_before: bool,
- b: Breaks,
- elts: &[T],
- mut op: F,
- ) where
- F: FnMut(&mut Self, &T),
- {
- self.rbox(0, b);
- if let Some((first, rest)) = elts.split_first() {
- op(self, first);
- for elt in rest {
- if space_before {
- self.space();
- }
- self.word_space(sep);
- op(self, elt);
- }
- }
- self.end();
- }
-
- fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], op: F)
- where
- F: FnMut(&mut Self, &T),
- {
- self.strsep(",", false, b, elts, op)
- }
-
- fn maybe_print_comment(&mut self, pos: BytePos) {
- while let Some(ref cmnt) = self.next_comment() {
- if cmnt.pos < pos {
- self.print_comment(cmnt);
- } else {
- break;
- }
- }
- }
-
- fn print_comment(&mut self, cmnt: &comments::Comment) {
- match cmnt.style {
- comments::Mixed => {
- assert_eq!(cmnt.lines.len(), 1);
- self.zerobreak();
- self.word(cmnt.lines[0].clone());
- self.zerobreak()
- }
- comments::Isolated => {
- self.hardbreak_if_not_bol();
- for line in &cmnt.lines {
- // Don't print empty lines because they will end up as trailing
- // whitespace.
- if !line.is_empty() {
- self.word(line.clone());
- }
- self.hardbreak();
- }
- }
- comments::Trailing => {
- if !self.is_beginning_of_line() {
- self.word(" ");
- }
- if cmnt.lines.len() == 1 {
- self.word(cmnt.lines[0].clone());
- self.hardbreak()
- } else {
- self.ibox(0);
- for line in &cmnt.lines {
- if !line.is_empty() {
- self.word(line.clone());
- }
- self.hardbreak();
- }
- self.end();
- }
- }
- comments::BlankLine => {
- // We need to do at least one, possibly two hardbreaks.
- let twice = match self.last_token() {
- pp::Token::String(s) => ";" == s,
- pp::Token::Begin(_) => true,
- pp::Token::End => true,
- _ => false,
- };
- if twice {
- self.hardbreak();
- }
- self.hardbreak();
- }
- }
- if let Some(cm) = self.comments() {
- cm.current += 1;
- }
- }
-
- fn next_comment(&mut self) -> Option<comments::Comment> {
- self.comments().as_mut().and_then(|c| c.next())
- }
-
- fn print_literal(&mut self, lit: &ast::Lit) {
- self.maybe_print_comment(lit.span.lo());
- self.word(lit.token.to_string())
- }
-
- fn print_string(&mut self, st: &str, style: ast::StrStyle) {
- let st = match style {
- ast::StrStyle::Cooked => (format!("\"{}\"", st.escape_debug())),
- ast::StrStyle::Raw(n) => {
- format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = st)
- }
- };
- self.word(st)
- }
-
- fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) {
- self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
- }
-
- fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) {
- self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false)
- }
-
- fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) {
- self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
- }
-
- fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) {
- self.print_either_attributes(attrs, ast::AttrStyle::Inner, true, true)
- }
-
- fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) {
- self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true)
- }
-
- fn print_either_attributes(
- &mut self,
- attrs: &[ast::Attribute],
- kind: ast::AttrStyle,
- is_inline: bool,
- trailing_hardbreak: bool,
- ) {
- let mut count = 0;
- for attr in attrs {
- if attr.style == kind {
- self.print_attribute_inline(attr, is_inline);
- if is_inline {
- self.nbsp();
- }
- count += 1;
- }
- }
- if count > 0 && trailing_hardbreak && !is_inline {
- self.hardbreak_if_not_bol();
- }
- }
-
- fn print_attribute(&mut self, attr: &ast::Attribute) {
- self.print_attribute_inline(attr, false)
- }
-
- fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) {
- if !is_inline {
- self.hardbreak_if_not_bol();
- }
- self.maybe_print_comment(attr.span.lo());
- match attr.kind {
- ast::AttrKind::Normal(ref item) => {
- match attr.style {
- ast::AttrStyle::Inner => self.word("#!["),
- ast::AttrStyle::Outer => self.word("#["),
- }
- self.print_attr_item(&item, attr.span);
- self.word("]");
- }
- ast::AttrKind::DocComment(comment) => {
- self.word(comment.to_string());
- self.hardbreak()
- }
- }
- }
-
- fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
- self.ibox(0);
- match &item.args {
- MacArgs::Delimited(_, delim, tokens) => self.print_mac_common(
- Some(MacHeader::Path(&item.path)),
- false,
- None,
- delim.to_token(),
- tokens.clone(),
- true,
- span,
- ),
- MacArgs::Empty | MacArgs::Eq(..) => {
- self.print_path(&item.path, false, 0);
- if let MacArgs::Eq(_, tokens) = &item.args {
- self.space();
- self.word_space("=");
- self.print_tts(tokens.clone(), true);
- }
- }
- }
- self.end();
- }
-
- fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) {
- match item {
- ast::NestedMetaItem::MetaItem(ref mi) => self.print_meta_item(mi),
- ast::NestedMetaItem::Literal(ref lit) => self.print_literal(lit),
- }
- }
-
- fn print_meta_item(&mut self, item: &ast::MetaItem) {
- self.ibox(INDENT_UNIT);
- match item.kind {
- ast::MetaItemKind::Word => self.print_path(&item.path, false, 0),
- ast::MetaItemKind::NameValue(ref value) => {
- self.print_path(&item.path, false, 0);
- self.space();
- self.word_space("=");
- self.print_literal(value);
- }
- ast::MetaItemKind::List(ref items) => {
- self.print_path(&item.path, false, 0);
- self.popen();
- self.commasep(Consistent, &items[..], |s, i| s.print_meta_list_item(i));
- self.pclose();
- }
- }
- self.end();
- }
-
- /// This doesn't deserve to be called "pretty" printing, but it should be
- /// meaning-preserving. A quick hack that might help would be to look at the
- /// spans embedded in the TTs to decide where to put spaces and newlines.
- /// But it'd be better to parse these according to the grammar of the
- /// appropriate macro, transcribe back into the grammar we just parsed from,
- /// and then pretty-print the resulting AST nodes (so, e.g., we print
- /// expression arguments as expressions). It can be done! I think.
- fn print_tt(&mut self, tt: tokenstream::TokenTree, convert_dollar_crate: bool) {
- match tt {
- TokenTree::Token(ref token) => {
- self.word(token_to_string_ext(&token, convert_dollar_crate));
- match token.kind {
- token::DocComment(..) => self.hardbreak(),
- _ => {}
- }
- }
- TokenTree::Delimited(dspan, delim, tts) => {
- self.print_mac_common(
- None,
- false,
- None,
- delim,
- tts,
- convert_dollar_crate,
- dspan.entire(),
- );
- }
- }
- }
-
- fn print_tts(&mut self, tts: tokenstream::TokenStream, convert_dollar_crate: bool) {
- for (i, tt) in tts.into_trees().enumerate() {
- if i != 0 && tt_prepend_space(&tt) {
- self.space();
- }
- self.print_tt(tt, convert_dollar_crate);
- }
- }
-
- fn print_mac_common(
- &mut self,
- header: Option<MacHeader<'_>>,
- has_bang: bool,
- ident: Option<ast::Ident>,
- delim: DelimToken,
- tts: TokenStream,
- convert_dollar_crate: bool,
- span: Span,
- ) {
- if delim == DelimToken::Brace {
- self.cbox(INDENT_UNIT);
- }
- match header {
- Some(MacHeader::Path(path)) => self.print_path(path, false, 0),
- Some(MacHeader::Keyword(kw)) => self.word(kw),
- None => {}
- }
- if has_bang {
- self.word("!");
- }
- if let Some(ident) = ident {
- self.nbsp();
- self.print_ident(ident);
- }
- match delim {
- DelimToken::Brace => {
- if header.is_some() || has_bang || ident.is_some() {
- self.nbsp();
- }
- self.word("{");
- if !tts.is_empty() {
- self.space();
- }
- }
- _ => self.word(token_kind_to_string(&token::OpenDelim(delim))),
- }
- self.ibox(0);
- self.print_tts(tts, convert_dollar_crate);
- self.end();
- match delim {
- DelimToken::Brace => self.bclose(span),
- _ => self.word(token_kind_to_string(&token::CloseDelim(delim))),
- }
- }
-
- fn print_path(&mut self, path: &ast::Path, colons_before_params: bool, depth: usize) {
- self.maybe_print_comment(path.span.lo());
-
- for (i, segment) in path.segments[..path.segments.len() - depth].iter().enumerate() {
- if i > 0 {
- self.word("::")
- }
- self.print_path_segment(segment, colons_before_params);
- }
- }
-
- fn print_path_segment(&mut self, segment: &ast::PathSegment, colons_before_params: bool) {
- if segment.ident.name != kw::PathRoot {
- self.print_ident(segment.ident);
- if let Some(ref args) = segment.args {
- self.print_generic_args(args, colons_before_params);
- }
- }
- }
-
- fn head<S: Into<Cow<'static, str>>>(&mut self, w: S) {
- let w = w.into();
- // Outer-box is consistent.
- self.cbox(INDENT_UNIT);
- // Head-box is inconsistent.
- self.ibox(w.len() + 1);
- // Keyword that starts the head.
- if !w.is_empty() {
- self.word_nbsp(w);
- }
- }
-
- fn bopen(&mut self) {
- self.word("{");
- self.end(); // Close the head-box.
- }
-
- fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) {
- self.maybe_print_comment(span.hi());
- self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize));
- self.word("}");
- if close_box {
- self.end(); // Close the outer-box.
- }
- }
-
- fn bclose(&mut self, span: rustc_span::Span) {
- self.bclose_maybe_open(span, true)
- }
-
- fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
- if !self.is_beginning_of_line() {
- self.break_offset(n, off)
- } else {
- if off != 0 && self.last_token().is_hardbreak_tok() {
- // We do something pretty sketchy here: tuck the nonzero
- // offset-adjustment we were going to deposit along with the
- // break into the previous hardbreak.
- self.replace_last_token(pp::Printer::hardbreak_tok_offset(off));
- }
- }
- }
-}
-
-impl<'a> PrintState<'a> for State<'a> {
- fn comments(&mut self) -> &mut Option<Comments<'a>> {
- &mut self.comments
- }
-
- fn print_ident(&mut self, ident: ast::Ident) {
- self.s.word(ast_ident_to_string(ident, ident.is_raw_guess()));
- self.ann.post(self, AnnNode::Ident(&ident))
- }
-
- fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool) {
- if colons_before_params {
- self.s.word("::")
- }
-
- match *args {
- ast::GenericArgs::AngleBracketed(ref data) => {
- self.s.word("<");
-
- self.commasep(Inconsistent, &data.args, |s, generic_arg| {
- s.print_generic_arg(generic_arg)
- });
-
- let mut comma = data.args.len() != 0;
-
- for constraint in data.constraints.iter() {
- if comma {
- self.word_space(",")
- }
- self.print_ident(constraint.ident);
- self.s.space();
- match constraint.kind {
- ast::AssocTyConstraintKind::Equality { ref ty } => {
- self.word_space("=");
- self.print_type(ty);
- }
- ast::AssocTyConstraintKind::Bound { ref bounds } => {
- self.print_type_bounds(":", &*bounds);
- }
- }
- comma = true;
- }
-
- self.s.word(">")
- }
-
- ast::GenericArgs::Parenthesized(ref data) => {
- self.s.word("(");
- self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(ty));
- self.s.word(")");
- self.print_fn_ret_ty(&data.output);
- }
- }
- }
-}
-
-impl<'a> State<'a> {
- // Synthesizes a comment that was not textually present in the original source
- // file.
- pub fn synth_comment(&mut self, text: String) {
- self.s.word("/*");
- self.s.space();
- self.s.word(text);
- self.s.space();
- self.s.word("*/")
- }
-
- crate fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
- where
- F: FnMut(&mut State<'_>, &T),
- G: FnMut(&T) -> rustc_span::Span,
- {
- self.rbox(0, b);
- let len = elts.len();
- let mut i = 0;
- for elt in elts {
- self.maybe_print_comment(get_span(elt).hi());
- op(self, elt);
- i += 1;
- if i < len {
- self.s.word(",");
- self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi()));
- self.space_if_not_bol();
- }
- }
- self.end();
- }
-
- crate fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) {
- self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
- }
-
- pub fn print_mod(&mut self, _mod: &ast::Mod, attrs: &[ast::Attribute]) {
- self.print_inner_attributes(attrs);
- for item in &_mod.items {
- self.print_item(item);
- }
- }
-
- crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) {
- self.print_inner_attributes(attrs);
- for item in &nmod.items {
- self.print_foreign_item(item);
- }
- }
-
- pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) {
- if let Some(lt) = *lifetime {
- self.print_lifetime(lt);
- self.nbsp();
- }
- }
-
- crate fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
- match generic_arg {
- GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
- GenericArg::Type(ty) => self.print_type(ty),
- GenericArg::Const(ct) => self.print_expr(&ct.value),
- }
- }
-
- pub fn print_type(&mut self, ty: &ast::Ty) {
- self.maybe_print_comment(ty.span.lo());
- self.ibox(0);
- match ty.kind {
- ast::TyKind::Slice(ref ty) => {
- self.s.word("[");
- self.print_type(ty);
- self.s.word("]");
- }
- ast::TyKind::Ptr(ref mt) => {
- self.s.word("*");
- self.print_mt(mt, true);
- }
- ast::TyKind::Rptr(ref lifetime, ref mt) => {
- self.s.word("&");
- self.print_opt_lifetime(lifetime);
- self.print_mt(mt, false);
- }
- ast::TyKind::Never => {
- self.s.word("!");
- }
- ast::TyKind::Tup(ref elts) => {
- self.popen();
- self.commasep(Inconsistent, &elts[..], |s, ty| s.print_type(ty));
- if elts.len() == 1 {
- self.s.word(",");
- }
- self.pclose();
- }
- ast::TyKind::Paren(ref typ) => {
- self.popen();
- self.print_type(typ);
- self.pclose();
- }
- ast::TyKind::BareFn(ref f) => {
- self.print_ty_fn(f.ext, f.unsafety, &f.decl, None, &f.generic_params);
- }
- ast::TyKind::Path(None, ref path) => {
- self.print_path(path, false, 0);
- }
- ast::TyKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, false),
- ast::TyKind::TraitObject(ref bounds, syntax) => {
- let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn" } else { "" };
- self.print_type_bounds(prefix, &bounds[..]);
- }
- ast::TyKind::ImplTrait(_, ref bounds) => {
- self.print_type_bounds("impl", &bounds[..]);
- }
- ast::TyKind::Array(ref ty, ref length) => {
- self.s.word("[");
- self.print_type(ty);
- self.s.word("; ");
- self.print_expr(&length.value);
- self.s.word("]");
- }
- ast::TyKind::Typeof(ref e) => {
- self.s.word("typeof(");
- self.print_expr(&e.value);
- self.s.word(")");
- }
- ast::TyKind::Infer => {
- self.s.word("_");
- }
- ast::TyKind::Err => {
- self.popen();
- self.s.word("/*ERROR*/");
- self.pclose();
- }
- ast::TyKind::ImplicitSelf => {
- self.s.word("Self");
- }
- ast::TyKind::Mac(ref m) => {
- self.print_mac(m);
- }
- ast::TyKind::CVarArgs => {
- self.s.word("...");
- }
- }
- self.end();
- }
-
- crate fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
- self.hardbreak_if_not_bol();
- self.maybe_print_comment(item.span.lo());
- self.print_outer_attributes(&item.attrs);
- match item.kind {
- ast::ForeignItemKind::Fn(ref decl, ref generics) => {
- self.head("");
- self.print_fn(
- decl,
- ast::FnHeader::default(),
- Some(item.ident),
- generics,
- &item.vis,
- );
- self.end(); // end head-ibox
- self.s.word(";");
- self.end(); // end the outer fn box
- }
- ast::ForeignItemKind::Static(ref t, m) => {
- self.head(visibility_qualified(&item.vis, "static"));
- if m == ast::Mutability::Mut {
- self.word_space("mut");
- }
- self.print_ident(item.ident);
- self.word_space(":");
- self.print_type(t);
- self.s.word(";");
- self.end(); // end the head-ibox
- self.end(); // end the outer cbox
- }
- ast::ForeignItemKind::Ty => {
- self.head(visibility_qualified(&item.vis, "type"));
- self.print_ident(item.ident);
- self.s.word(";");
- self.end(); // end the head-ibox
- self.end(); // end the outer cbox
- }
- ast::ForeignItemKind::Macro(ref m) => {
- self.print_mac(m);
- if m.args.need_semicolon() {
- self.s.word(";");
- }
- }
- }
- }
-
- fn print_associated_const(
- &mut self,
- ident: ast::Ident,
- ty: &ast::Ty,
- default: Option<&ast::Expr>,
- vis: &ast::Visibility,
- ) {
- self.s.word(visibility_qualified(vis, ""));
- self.word_space("const");
- self.print_ident(ident);
- self.word_space(":");
- self.print_type(ty);
- if let Some(expr) = default {
- self.s.space();
- self.word_space("=");
- self.print_expr(expr);
- }
- self.s.word(";")
- }
-
- fn print_associated_type(
- &mut self,
- ident: ast::Ident,
- bounds: &ast::GenericBounds,
- ty: Option<&ast::Ty>,
- ) {
- self.word_space("type");
- self.print_ident(ident);
- self.print_type_bounds(":", bounds);
- if let Some(ty) = ty {
- self.s.space();
- self.word_space("=");
- self.print_type(ty);
- }
- self.s.word(";")
- }
-
- /// Pretty-prints an item.
- crate fn print_item(&mut self, item: &ast::Item) {
- self.hardbreak_if_not_bol();
- self.maybe_print_comment(item.span.lo());
- self.print_outer_attributes(&item.attrs);
- self.ann.pre(self, AnnNode::Item(item));
- match item.kind {
- ast::ItemKind::ExternCrate(orig_name) => {
- self.head(visibility_qualified(&item.vis, "extern crate"));
- if let Some(orig_name) = orig_name {
- self.print_name(orig_name);
- self.s.space();
- self.s.word("as");
- self.s.space();
- }
- self.print_ident(item.ident);
- self.s.word(";");
- self.end(); // end inner head-block
- self.end(); // end outer head-block
- }
- ast::ItemKind::Use(ref tree) => {
- self.head(visibility_qualified(&item.vis, "use"));
- self.print_use_tree(tree);
- self.s.word(";");
- self.end(); // end inner head-block
- self.end(); // end outer head-block
- }
- ast::ItemKind::Static(ref ty, m, ref expr) => {
- self.head(visibility_qualified(&item.vis, "static"));
- if m == ast::Mutability::Mut {
- self.word_space("mut");
- }
- self.print_ident(item.ident);
- self.word_space(":");
- self.print_type(ty);
- self.s.space();
- self.end(); // end the head-ibox
-
- self.word_space("=");
- self.print_expr(expr);
- self.s.word(";");
- self.end(); // end the outer cbox
- }
- ast::ItemKind::Const(ref ty, ref expr) => {
- self.head(visibility_qualified(&item.vis, "const"));
- self.print_ident(item.ident);
- self.word_space(":");
- self.print_type(ty);
- self.s.space();
- self.end(); // end the head-ibox
-
- self.word_space("=");
- self.print_expr(expr);
- self.s.word(";");
- self.end(); // end the outer cbox
- }
- ast::ItemKind::Fn(ref sig, ref param_names, ref body) => {
- self.head("");
- self.print_fn(&sig.decl, sig.header, Some(item.ident), param_names, &item.vis);
- self.s.word(" ");
- self.print_block_with_attrs(body, &item.attrs);
- }
- ast::ItemKind::Mod(ref _mod) => {
- self.head(visibility_qualified(&item.vis, "mod"));
- self.print_ident(item.ident);
-
- if _mod.inline || self.is_expanded {
- self.nbsp();
- self.bopen();
- self.print_mod(_mod, &item.attrs);
- self.bclose(item.span);
- } else {
- self.s.word(";");
- self.end(); // end inner head-block
- self.end(); // end outer head-block
- }
- }
- ast::ItemKind::ForeignMod(ref nmod) => {
- self.head("extern");
- if let Some(abi) = nmod.abi {
- self.print_literal(&abi.as_lit());
- self.nbsp();
- }
- self.bopen();
- self.print_foreign_mod(nmod, &item.attrs);
- self.bclose(item.span);
- }
- ast::ItemKind::GlobalAsm(ref ga) => {
- self.head(visibility_qualified(&item.vis, "global_asm!"));
- self.s.word(ga.asm.to_string());
- self.end();
- }
- ast::ItemKind::TyAlias(ref ty, ref generics) => {
- self.head(visibility_qualified(&item.vis, "type"));
- self.print_ident(item.ident);
- self.print_generic_params(&generics.params);
- self.end(); // end the inner ibox
-
- self.print_where_clause(&generics.where_clause);
- self.s.space();
- self.word_space("=");
- self.print_type(ty);
- self.s.word(";");
- self.end(); // end the outer ibox
- }
- ast::ItemKind::Enum(ref enum_definition, ref params) => {
- self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis);
- }
- ast::ItemKind::Struct(ref struct_def, ref generics) => {
- self.head(visibility_qualified(&item.vis, "struct"));
- self.print_struct(struct_def, generics, item.ident, item.span, true);
- }
- ast::ItemKind::Union(ref struct_def, ref generics) => {
- self.head(visibility_qualified(&item.vis, "union"));
- self.print_struct(struct_def, generics, item.ident, item.span, true);
- }
- ast::ItemKind::Impl {
- unsafety,
- polarity,
- defaultness,
- constness,
- ref generics,
- ref of_trait,
- ref self_ty,
- ref items,
- } => {
- self.head("");
- self.print_visibility(&item.vis);
- self.print_defaultness(defaultness);
- self.print_unsafety(unsafety);
- self.word_nbsp("impl");
- self.print_constness(constness);
-
- if !generics.params.is_empty() {
- self.print_generic_params(&generics.params);
- self.s.space();
- }
-
- if polarity == ast::ImplPolarity::Negative {
- self.s.word("!");
- }
-
- if let Some(ref t) = *of_trait {
- self.print_trait_ref(t);
- self.s.space();
- self.word_space("for");
- }
-
- self.print_type(self_ty);
- self.print_where_clause(&generics.where_clause);
-
- self.s.space();
- self.bopen();
- self.print_inner_attributes(&item.attrs);
- for impl_item in items {
- self.print_assoc_item(impl_item);
- }
- self.bclose(item.span);
- }
- ast::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref trait_items) => {
- self.head("");
- self.print_visibility(&item.vis);
- self.print_unsafety(unsafety);
- self.print_is_auto(is_auto);
- self.word_nbsp("trait");
- self.print_ident(item.ident);
- self.print_generic_params(&generics.params);
- let mut real_bounds = Vec::with_capacity(bounds.len());
- for b in bounds.iter() {
- if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
- self.s.space();
- self.word_space("for ?");
- self.print_trait_ref(&ptr.trait_ref);
- } else {
- real_bounds.push(b.clone());
- }
- }
- self.print_type_bounds(":", &real_bounds[..]);
- self.print_where_clause(&generics.where_clause);
- self.s.word(" ");
- self.bopen();
- for trait_item in trait_items {
- self.print_assoc_item(trait_item);
- }
- self.bclose(item.span);
- }
- ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
- self.head("");
- self.print_visibility(&item.vis);
- self.word_nbsp("trait");
- self.print_ident(item.ident);
- self.print_generic_params(&generics.params);
- let mut real_bounds = Vec::with_capacity(bounds.len());
- // FIXME(durka) this seems to be some quite outdated syntax
- for b in bounds.iter() {
- if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
- self.s.space();
- self.word_space("for ?");
- self.print_trait_ref(&ptr.trait_ref);
- } else {
- real_bounds.push(b.clone());
- }
- }
- self.nbsp();
- self.print_type_bounds("=", &real_bounds[..]);
- self.print_where_clause(&generics.where_clause);
- self.s.word(";");
- }
- ast::ItemKind::Mac(ref mac) => {
- self.print_mac(mac);
- if mac.args.need_semicolon() {
- self.s.word(";");
- }
- }
- ast::ItemKind::MacroDef(ref macro_def) => {
- let (kw, has_bang) = if macro_def.legacy {
- ("macro_rules", true)
- } else {
- self.print_visibility(&item.vis);
- ("macro", false)
- };
- self.print_mac_common(
- Some(MacHeader::Keyword(kw)),
- has_bang,
- Some(item.ident),
- macro_def.body.delim(),
- macro_def.body.inner_tokens(),
- true,
- item.span,
- );
- }
- }
- self.ann.post(self, AnnNode::Item(item))
- }
-
- fn print_trait_ref(&mut self, t: &ast::TraitRef) {
- self.print_path(&t.path, false, 0)
- }
-
- fn print_formal_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
- if !generic_params.is_empty() {
- self.s.word("for");
- self.print_generic_params(generic_params);
- self.nbsp();
- }
- }
-
- fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) {
- self.print_formal_generic_params(&t.bound_generic_params);
- self.print_trait_ref(&t.trait_ref)
- }
-
- crate fn print_enum_def(
- &mut self,
- enum_definition: &ast::EnumDef,
- generics: &ast::Generics,
- ident: ast::Ident,
- span: rustc_span::Span,
- visibility: &ast::Visibility,
- ) {
- self.head(visibility_qualified(visibility, "enum"));
- self.print_ident(ident);
- self.print_generic_params(&generics.params);
- self.print_where_clause(&generics.where_clause);
- self.s.space();
- self.print_variants(&enum_definition.variants, span)
- }
-
- crate fn print_variants(&mut self, variants: &[ast::Variant], span: rustc_span::Span) {
- self.bopen();
- for v in variants {
- self.space_if_not_bol();
- self.maybe_print_comment(v.span.lo());
- self.print_outer_attributes(&v.attrs);
- self.ibox(INDENT_UNIT);
- self.print_variant(v);
- self.s.word(",");
- self.end();
- self.maybe_print_trailing_comment(v.span, None);
- }
- self.bclose(span)
- }
-
- crate fn print_visibility(&mut self, vis: &ast::Visibility) {
- match vis.node {
- ast::VisibilityKind::Public => self.word_nbsp("pub"),
- ast::VisibilityKind::Crate(sugar) => match sugar {
- ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"),
- ast::CrateSugar::JustCrate => self.word_nbsp("crate"),
- },
- ast::VisibilityKind::Restricted { ref path, .. } => {
- let path = to_string(|s| s.print_path(path, false, 0));
- if path == "self" || path == "super" {
- self.word_nbsp(format!("pub({})", path))
- } else {
- self.word_nbsp(format!("pub(in {})", path))
- }
- }
- ast::VisibilityKind::Inherited => {}
- }
- }
-
- crate fn print_defaultness(&mut self, defaultness: ast::Defaultness) {
- if let ast::Defaultness::Default = defaultness {
- self.word_nbsp("default");
- }
- }
-
- crate fn print_struct(
- &mut self,
- struct_def: &ast::VariantData,
- generics: &ast::Generics,
- ident: ast::Ident,
- span: rustc_span::Span,
- print_finalizer: bool,
- ) {
- self.print_ident(ident);
- self.print_generic_params(&generics.params);
- match struct_def {
- ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
- if let ast::VariantData::Tuple(..) = struct_def {
- self.popen();
- self.commasep(Inconsistent, struct_def.fields(), |s, field| {
- s.maybe_print_comment(field.span.lo());
- s.print_outer_attributes(&field.attrs);
- s.print_visibility(&field.vis);
- s.print_type(&field.ty)
- });
- self.pclose();
- }
- self.print_where_clause(&generics.where_clause);
- if print_finalizer {
- self.s.word(";");
- }
- self.end();
- self.end(); // Close the outer-box.
- }
- ast::VariantData::Struct(..) => {
- self.print_where_clause(&generics.where_clause);
- self.nbsp();
- self.bopen();
- self.hardbreak_if_not_bol();
-
- for field in struct_def.fields() {
- self.hardbreak_if_not_bol();
- self.maybe_print_comment(field.span.lo());
- self.print_outer_attributes(&field.attrs);
- self.print_visibility(&field.vis);
- self.print_ident(field.ident.unwrap());
- self.word_nbsp(":");
- self.print_type(&field.ty);
- self.s.word(",");
- }
-
- self.bclose(span)
- }
- }
- }
-
- crate fn print_variant(&mut self, v: &ast::Variant) {
- self.head("");
- self.print_visibility(&v.vis);
- let generics = ast::Generics::default();
- self.print_struct(&v.data, &generics, v.ident, v.span, false);
- match v.disr_expr {
- Some(ref d) => {
- self.s.space();
- self.word_space("=");
- self.print_expr(&d.value)
- }
- _ => {}
- }
- }
-
- crate fn print_assoc_item(&mut self, item: &ast::AssocItem) {
- self.ann.pre(self, AnnNode::SubItem(item.id));
- self.hardbreak_if_not_bol();
- self.maybe_print_comment(item.span.lo());
- self.print_outer_attributes(&item.attrs);
- self.print_defaultness(item.defaultness);
- match &item.kind {
- ast::AssocItemKind::Const(ty, expr) => {
- self.print_associated_const(item.ident, ty, expr.as_deref(), &item.vis);
- }
- ast::AssocItemKind::Fn(sig, body) => {
- if body.is_some() {
- self.head("");
- }
- self.print_fn(&sig.decl, sig.header, Some(item.ident), &item.generics, &item.vis);
- if let Some(body) = body {
- self.nbsp();
- self.print_block_with_attrs(body, &item.attrs);
- } else {
- self.s.word(";");
- }
- }
- ast::AssocItemKind::TyAlias(bounds, ty) => {
- self.print_associated_type(item.ident, bounds, ty.as_deref());
- }
- ast::AssocItemKind::Macro(mac) => {
- self.print_mac(mac);
- if mac.args.need_semicolon() {
- self.s.word(";");
- }
- }
- }
- self.ann.post(self, AnnNode::SubItem(item.id))
- }
-
- crate fn print_stmt(&mut self, st: &ast::Stmt) {
- self.maybe_print_comment(st.span.lo());
- match st.kind {
- ast::StmtKind::Local(ref loc) => {
- self.print_outer_attributes(&loc.attrs);
- self.space_if_not_bol();
- self.ibox(INDENT_UNIT);
- self.word_nbsp("let");
-
- self.ibox(INDENT_UNIT);
- self.print_local_decl(loc);
- self.end();
- if let Some(ref init) = loc.init {
- self.nbsp();
- self.word_space("=");
- self.print_expr(init);
- }
- self.s.word(";");
- self.end();
- }
- ast::StmtKind::Item(ref item) => self.print_item(item),
- ast::StmtKind::Expr(ref expr) => {
- self.space_if_not_bol();
- self.print_expr_outer_attr_style(expr, false);
- if classify::expr_requires_semi_to_be_stmt(expr) {
- self.s.word(";");
- }
- }
- ast::StmtKind::Semi(ref expr) => {
- match expr.kind {
- // Filter out empty `Tup` exprs created for the `redundant_semicolon`
- // lint, as they shouldn't be visible and interact poorly
- // with proc macros.
- ast::ExprKind::Tup(ref exprs) if exprs.is_empty() && expr.attrs.is_empty() => {
- ()
- }
- _ => {
- self.space_if_not_bol();
- self.print_expr_outer_attr_style(expr, false);
- self.s.word(";");
- }
- }
- }
- ast::StmtKind::Mac(ref mac) => {
- let (ref mac, style, ref attrs) = **mac;
- self.space_if_not_bol();
- self.print_outer_attributes(attrs);
- self.print_mac(mac);
- if style == ast::MacStmtStyle::Semicolon {
- self.s.word(";");
- }
- }
- }
- self.maybe_print_trailing_comment(st.span, None)
- }
-
- crate fn print_block(&mut self, blk: &ast::Block) {
- self.print_block_with_attrs(blk, &[])
- }
-
- crate fn print_block_unclosed_indent(&mut self, blk: &ast::Block) {
- self.print_block_maybe_unclosed(blk, &[], false)
- }
-
- crate fn print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute]) {
- self.print_block_maybe_unclosed(blk, attrs, true)
- }
-
- crate fn print_block_maybe_unclosed(
- &mut self,
- blk: &ast::Block,
- attrs: &[ast::Attribute],
- close_box: bool,
- ) {
- match blk.rules {
- BlockCheckMode::Unsafe(..) => self.word_space("unsafe"),
- BlockCheckMode::Default => (),
- }
- self.maybe_print_comment(blk.span.lo());
- self.ann.pre(self, AnnNode::Block(blk));
- self.bopen();
-
- self.print_inner_attributes(attrs);
-
- for (i, st) in blk.stmts.iter().enumerate() {
- match st.kind {
- ast::StmtKind::Expr(ref expr) if i == blk.stmts.len() - 1 => {
- self.maybe_print_comment(st.span.lo());
- self.space_if_not_bol();
- self.print_expr_outer_attr_style(expr, false);
- self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
- }
- _ => self.print_stmt(st),
- }
- }
-
- self.bclose_maybe_open(blk.span, close_box);
- self.ann.post(self, AnnNode::Block(blk))
- }
-
- /// Print a `let pat = scrutinee` expression.
- crate fn print_let(&mut self, pat: &ast::Pat, scrutinee: &ast::Expr) {
- self.s.word("let ");
-
- self.print_pat(pat);
- self.s.space();
-
- self.word_space("=");
- self.print_expr_cond_paren(
- scrutinee,
- Self::cond_needs_par(scrutinee)
- || parser::needs_par_as_let_scrutinee(scrutinee.precedence().order()),
- )
- }
-
- fn print_else(&mut self, els: Option<&ast::Expr>) {
- if let Some(_else) = els {
- match _else.kind {
- // Another `else if` block.
- ast::ExprKind::If(ref i, ref then, ref e) => {
- self.cbox(INDENT_UNIT - 1);
- self.ibox(0);
- self.s.word(" else if ");
- self.print_expr_as_cond(i);
- self.s.space();
- self.print_block(then);
- self.print_else(e.as_deref())
- }
- // Final `else` block.
- ast::ExprKind::Block(ref b, _) => {
- self.cbox(INDENT_UNIT - 1);
- self.ibox(0);
- self.s.word(" else ");
- self.print_block(b)
- }
- // Constraints would be great here!
- _ => {
- panic!("print_if saw if with weird alternative");
- }
- }
- }
- }
-
- crate fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) {
- self.head("if");
-
- self.print_expr_as_cond(test);
- self.s.space();
-
- self.print_block(blk);
- self.print_else(elseopt)
- }
-
- crate fn print_mac(&mut self, m: &ast::Mac) {
- self.print_mac_common(
- Some(MacHeader::Path(&m.path)),
- true,
- None,
- m.args.delim(),
- m.args.inner_tokens(),
- true,
- m.span(),
- );
- }
-
- fn print_call_post(&mut self, args: &[P<ast::Expr>]) {
- self.popen();
- self.commasep_exprs(Inconsistent, args);
- self.pclose()
- }
-
- crate fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) {
- self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
- }
-
- /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
- /// `if cond { ... }`.
- crate fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
- self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
- }
-
- /// Does `expr` need parenthesis when printed in a condition position?
- fn cond_needs_par(expr: &ast::Expr) -> bool {
- match expr.kind {
- // These cases need parens due to the parse error observed in #26461: `if return {}`
- // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
- ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) | ast::ExprKind::Break(..) => true,
-
- _ => parser::contains_exterior_struct_lit(expr),
- }
- }
-
- /// Prints `expr` or `(expr)` when `needs_par` holds.
- fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) {
- if needs_par {
- self.popen();
- }
- self.print_expr(expr);
- if needs_par {
- self.pclose();
- }
- }
-
- fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>], attrs: &[Attribute]) {
- self.ibox(INDENT_UNIT);
- self.s.word("[");
- self.print_inner_attributes_inline(attrs);
- self.commasep_exprs(Inconsistent, &exprs[..]);
- self.s.word("]");
- self.end();
- }
-
- fn print_expr_repeat(
- &mut self,
- element: &ast::Expr,
- count: &ast::AnonConst,
- attrs: &[Attribute],
- ) {
- self.ibox(INDENT_UNIT);
- self.s.word("[");
- self.print_inner_attributes_inline(attrs);
- self.print_expr(element);
- self.word_space(";");
- self.print_expr(&count.value);
- self.s.word("]");
- self.end();
- }
-
- fn print_expr_struct(
- &mut self,
- path: &ast::Path,
- fields: &[ast::Field],
- wth: &Option<P<ast::Expr>>,
- attrs: &[Attribute],
- ) {
- self.print_path(path, true, 0);
- self.s.word("{");
- self.print_inner_attributes_inline(attrs);
- self.commasep_cmnt(
- Consistent,
- &fields[..],
- |s, field| {
- s.ibox(INDENT_UNIT);
- if !field.is_shorthand {
- s.print_ident(field.ident);
- s.word_space(":");
- }
- s.print_expr(&field.expr);
- s.end();
- },
- |f| f.span,
- );
- match *wth {
- Some(ref expr) => {
- self.ibox(INDENT_UNIT);
- if !fields.is_empty() {
- self.s.word(",");
- self.s.space();
- }
- self.s.word("..");
- self.print_expr(expr);
- self.end();
- }
- _ => {
- if !fields.is_empty() {
- self.s.word(",")
- }
- }
- }
- self.s.word("}");
- }
-
- fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>], attrs: &[Attribute]) {
- self.popen();
- self.print_inner_attributes_inline(attrs);
- self.commasep_exprs(Inconsistent, &exprs[..]);
- if exprs.len() == 1 {
- self.s.word(",");
- }
- self.pclose()
- }
-
- fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>]) {
- let prec = match func.kind {
- ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
- _ => parser::PREC_POSTFIX,
- };
-
- self.print_expr_maybe_paren(func, prec);
- self.print_call_post(args)
- }
-
- fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
- let base_args = &args[1..];
- self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
- self.s.word(".");
- self.print_ident(segment.ident);
- if let Some(ref args) = segment.args {
- self.print_generic_args(args, true);
- }
- self.print_call_post(base_args)
- }
-
- fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) {
- let assoc_op = AssocOp::from_ast_binop(op.node);
- let prec = assoc_op.precedence() as i8;
- let fixity = assoc_op.fixity();
-
- let (left_prec, right_prec) = match fixity {
- Fixity::Left => (prec, prec + 1),
- Fixity::Right => (prec + 1, prec),
- Fixity::None => (prec + 1, prec + 1),
- };
-
- let left_prec = match (&lhs.kind, op.node) {
- // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
- // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
- // of `(x as i32) < ...`. We need to convince it _not_ to do that.
- (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt)
- | (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Shl) => parser::PREC_FORCE_PAREN,
- // We are given `(let _ = a) OP b`.
- //
- // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens
- // as the parser will interpret this as `(let _ = a) OP b`.
- //
- // - Otherwise, e.g. when we have `(let a = b) < c` in AST,
- // parens are required since the parser would interpret `let a = b < c` as
- // `let a = (b < c)`. To achieve this, we force parens.
- (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
- parser::PREC_FORCE_PAREN
- }
- _ => left_prec,
- };
-
- self.print_expr_maybe_paren(lhs, left_prec);
- self.s.space();
- self.word_space(op.node.to_string());
- self.print_expr_maybe_paren(rhs, right_prec)
- }
-
- fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) {
- self.s.word(ast::UnOp::to_string(op));
- self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
- }
-
- fn print_expr_addr_of(
- &mut self,
- kind: ast::BorrowKind,
- mutability: ast::Mutability,
- expr: &ast::Expr,
- ) {
- self.s.word("&");
- match kind {
- ast::BorrowKind::Ref => self.print_mutability(mutability, false),
- ast::BorrowKind::Raw => {
- self.word_nbsp("raw");
- self.print_mutability(mutability, true);
- }
- }
- self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
- }
-
- pub fn print_expr(&mut self, expr: &ast::Expr) {
- self.print_expr_outer_attr_style(expr, true)
- }
-
- fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
- self.maybe_print_comment(expr.span.lo());
-
- let attrs = &expr.attrs;
- if is_inline {
- self.print_outer_attributes_inline(attrs);
- } else {
- self.print_outer_attributes(attrs);
- }
-
- self.ibox(INDENT_UNIT);
- self.ann.pre(self, AnnNode::Expr(expr));
- match expr.kind {
- ast::ExprKind::Box(ref expr) => {
- self.word_space("box");
- self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
- }
- ast::ExprKind::Array(ref exprs) => {
- self.print_expr_vec(&exprs[..], attrs);
- }
- ast::ExprKind::Repeat(ref element, ref count) => {
- self.print_expr_repeat(element, count, attrs);
- }
- ast::ExprKind::Struct(ref path, ref fields, ref wth) => {
- self.print_expr_struct(path, &fields[..], wth, attrs);
- }
- ast::ExprKind::Tup(ref exprs) => {
- self.print_expr_tup(&exprs[..], attrs);
- }
- ast::ExprKind::Call(ref func, ref args) => {
- self.print_expr_call(func, &args[..]);
- }
- ast::ExprKind::MethodCall(ref segment, ref args) => {
- self.print_expr_method_call(segment, &args[..]);
- }
- ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
- self.print_expr_binary(op, lhs, rhs);
- }
- ast::ExprKind::Unary(op, ref expr) => {
- self.print_expr_unary(op, expr);
- }
- ast::ExprKind::AddrOf(k, m, ref expr) => {
- self.print_expr_addr_of(k, m, expr);
- }
- ast::ExprKind::Lit(ref lit) => {
- self.print_literal(lit);
- }
- ast::ExprKind::Cast(ref expr, ref ty) => {
- let prec = AssocOp::As.precedence() as i8;
- self.print_expr_maybe_paren(expr, prec);
- self.s.space();
- self.word_space("as");
- self.print_type(ty);
- }
- ast::ExprKind::Type(ref expr, ref ty) => {
- let prec = AssocOp::Colon.precedence() as i8;
- self.print_expr_maybe_paren(expr, prec);
- self.word_space(":");
- self.print_type(ty);
- }
- ast::ExprKind::Let(ref pat, ref scrutinee) => {
- self.print_let(pat, scrutinee);
- }
- ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
- self.print_if(test, blk, elseopt.as_deref())
- }
- ast::ExprKind::While(ref test, ref blk, opt_label) => {
- if let Some(label) = opt_label {
- self.print_ident(label.ident);
- self.word_space(":");
- }
- self.head("while");
- self.print_expr_as_cond(test);
- self.s.space();
- self.print_block_with_attrs(blk, attrs);
- }
- ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
- if let Some(label) = opt_label {
- self.print_ident(label.ident);
- self.word_space(":");
- }
- self.head("for");
- self.print_pat(pat);
- self.s.space();
- self.word_space("in");
- self.print_expr_as_cond(iter);
- self.s.space();
- self.print_block_with_attrs(blk, attrs);
- }
- ast::ExprKind::Loop(ref blk, opt_label) => {
- if let Some(label) = opt_label {
- self.print_ident(label.ident);
- self.word_space(":");
- }
- self.head("loop");
- self.s.space();
- self.print_block_with_attrs(blk, attrs);
- }
- ast::ExprKind::Match(ref expr, ref arms) => {
- self.cbox(INDENT_UNIT);
- self.ibox(INDENT_UNIT);
- self.word_nbsp("match");
- self.print_expr_as_cond(expr);
- self.s.space();
- self.bopen();
- self.print_inner_attributes_no_trailing_hardbreak(attrs);
- for arm in arms {
- self.print_arm(arm);
- }
- self.bclose(expr.span);
- }
- ast::ExprKind::Closure(
- capture_clause,
- asyncness,
- movability,
- ref decl,
- ref body,
- _,
- ) => {
- self.print_movability(movability);
- self.print_asyncness(asyncness);
- self.print_capture_clause(capture_clause);
-
- self.print_fn_params_and_ret(decl, true);
- self.s.space();
- self.print_expr(body);
- self.end(); // need to close a box
-
- // a box will be closed by print_expr, but we didn't want an overall
- // wrapper so we closed the corresponding opening. so create an
- // empty box to satisfy the close.
- self.ibox(0);
- }
- ast::ExprKind::Block(ref blk, opt_label) => {
- if let Some(label) = opt_label {
- self.print_ident(label.ident);
- self.word_space(":");
- }
- // containing cbox, will be closed by print-block at }
- self.cbox(INDENT_UNIT);
- // head-box, will be closed by print-block after {
- self.ibox(0);
- self.print_block_with_attrs(blk, attrs);
- }
- ast::ExprKind::Async(capture_clause, _, ref blk) => {
- self.word_nbsp("async");
- self.print_capture_clause(capture_clause);
- self.s.space();
- // cbox/ibox in analogy to the `ExprKind::Block` arm above
- self.cbox(INDENT_UNIT);
- self.ibox(0);
- self.print_block_with_attrs(blk, attrs);
- }
- ast::ExprKind::Await(ref expr) => {
- self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
- self.s.word(".await");
- }
- ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
- let prec = AssocOp::Assign.precedence() as i8;
- self.print_expr_maybe_paren(lhs, prec + 1);
- self.s.space();
- self.word_space("=");
- self.print_expr_maybe_paren(rhs, prec);
- }
- ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
- let prec = AssocOp::Assign.precedence() as i8;
- self.print_expr_maybe_paren(lhs, prec + 1);
- self.s.space();
- self.s.word(op.node.to_string());
- self.word_space("=");
- self.print_expr_maybe_paren(rhs, prec);
- }
- ast::ExprKind::Field(ref expr, ident) => {
- self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
- self.s.word(".");
- self.print_ident(ident);
- }
- ast::ExprKind::Index(ref expr, ref index) => {
- self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
- self.s.word("[");
- self.print_expr(index);
- self.s.word("]");
- }
- ast::ExprKind::Range(ref start, ref end, limits) => {
- // Special case for `Range`. `AssocOp` claims that `Range` has higher precedence
- // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.
- // Here we use a fake precedence value so that any child with lower precedence than
- // a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
- let fake_prec = AssocOp::LOr.precedence() as i8;
- if let Some(ref e) = *start {
- self.print_expr_maybe_paren(e, fake_prec);
- }
- if limits == ast::RangeLimits::HalfOpen {
- self.s.word("..");
- } else {
- self.s.word("..=");
- }
- if let Some(ref e) = *end {
- self.print_expr_maybe_paren(e, fake_prec);
- }
- }
- ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0),
- ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
- ast::ExprKind::Break(opt_label, ref opt_expr) => {
- self.s.word("break");
- self.s.space();
- if let Some(label) = opt_label {
- self.print_ident(label.ident);
- self.s.space();
- }
- if let Some(ref expr) = *opt_expr {
- self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
- self.s.space();
- }
- }
- ast::ExprKind::Continue(opt_label) => {
- self.s.word("continue");
- self.s.space();
- if let Some(label) = opt_label {
- self.print_ident(label.ident);
- self.s.space()
- }
- }
- ast::ExprKind::Ret(ref result) => {
- self.s.word("return");
- if let Some(ref expr) = *result {
- self.s.word(" ");
- self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
- }
- }
- ast::ExprKind::InlineAsm(ref a) => {
- self.s.word("asm!");
- self.popen();
- self.print_string(&a.asm.as_str(), a.asm_str_style);
- self.word_space(":");
-
- self.commasep(Inconsistent, &a.outputs, |s, out| {
- let constraint = out.constraint.as_str();
- let mut ch = constraint.chars();
- match ch.next() {
- Some('=') if out.is_rw => {
- s.print_string(&format!("+{}", ch.as_str()), ast::StrStyle::Cooked)
- }
- _ => s.print_string(&constraint, ast::StrStyle::Cooked),
- }
- s.popen();
- s.print_expr(&out.expr);
- s.pclose();
- });
- self.s.space();
- self.word_space(":");
-
- self.commasep(Inconsistent, &a.inputs, |s, &(co, ref o)| {
- s.print_string(&co.as_str(), ast::StrStyle::Cooked);
- s.popen();
- s.print_expr(o);
- s.pclose();
- });
- self.s.space();
- self.word_space(":");
-
- self.commasep(Inconsistent, &a.clobbers, |s, co| {
- s.print_string(&co.as_str(), ast::StrStyle::Cooked);
- });
-
- let mut options = vec![];
- if a.volatile {
- options.push("volatile");
- }
- if a.alignstack {
- options.push("alignstack");
- }
- if a.dialect == ast::AsmDialect::Intel {
- options.push("intel");
- }
-
- if !options.is_empty() {
- self.s.space();
- self.word_space(":");
- self.commasep(Inconsistent, &options, |s, &co| {
- s.print_string(co, ast::StrStyle::Cooked);
- });
- }
-
- self.pclose();
- }
- ast::ExprKind::Mac(ref m) => self.print_mac(m),
- ast::ExprKind::Paren(ref e) => {
- self.popen();
- self.print_inner_attributes_inline(attrs);
- self.print_expr(e);
- self.pclose();
- }
- ast::ExprKind::Yield(ref e) => {
- self.s.word("yield");
- match *e {
- Some(ref expr) => {
- self.s.space();
- self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
- }
- _ => (),
- }
- }
- ast::ExprKind::Try(ref e) => {
- self.print_expr_maybe_paren(e, parser::PREC_POSTFIX);
- self.s.word("?")
- }
- ast::ExprKind::TryBlock(ref blk) => {
- self.head("try");
- self.s.space();
- self.print_block_with_attrs(blk, attrs)
- }
- ast::ExprKind::Err => {
- self.popen();
- self.s.word("/*ERROR*/");
- self.pclose()
- }
- }
- self.ann.post(self, AnnNode::Expr(expr));
- self.end();
- }
-
- crate fn print_local_decl(&mut self, loc: &ast::Local) {
- self.print_pat(&loc.pat);
- if let Some(ref ty) = loc.ty {
- self.word_space(":");
- self.print_type(ty);
- }
- }
-
- pub fn print_usize(&mut self, i: usize) {
- self.s.word(i.to_string())
- }
-
- crate fn print_name(&mut self, name: ast::Name) {
- self.s.word(name.to_string());
- self.ann.post(self, AnnNode::Name(&name))
- }
-
- fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_params: bool) {
- self.s.word("<");
- self.print_type(&qself.ty);
- if qself.position > 0 {
- self.s.space();
- self.word_space("as");
- let depth = path.segments.len() - qself.position;
- self.print_path(path, false, depth);
- }
- self.s.word(">");
- self.s.word("::");
- let item_segment = path.segments.last().unwrap();
- self.print_ident(item_segment.ident);
- match item_segment.args {
- Some(ref args) => self.print_generic_args(args, colons_before_params),
- None => {}
- }
- }
-
- crate fn print_pat(&mut self, pat: &ast::Pat) {
- self.maybe_print_comment(pat.span.lo());
- self.ann.pre(self, AnnNode::Pat(pat));
- /* Pat isn't normalized, but the beauty of it
- is that it doesn't matter */
- match pat.kind {
- PatKind::Wild => self.s.word("_"),
- PatKind::Ident(binding_mode, ident, ref sub) => {
- match binding_mode {
- ast::BindingMode::ByRef(mutbl) => {
- self.word_nbsp("ref");
- self.print_mutability(mutbl, false);
- }
- ast::BindingMode::ByValue(ast::Mutability::Not) => {}
- ast::BindingMode::ByValue(ast::Mutability::Mut) => {
- self.word_nbsp("mut");
- }
- }
- self.print_ident(ident);
- if let Some(ref p) = *sub {
- self.s.space();
- self.s.word_space("@");
- self.print_pat(p);
- }
- }
- PatKind::TupleStruct(ref path, ref elts) => {
- self.print_path(path, true, 0);
- self.popen();
- self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
- self.pclose();
- }
- PatKind::Or(ref pats) => {
- self.strsep("|", true, Inconsistent, &pats[..], |s, p| s.print_pat(p));
- }
- PatKind::Path(None, ref path) => {
- self.print_path(path, true, 0);
- }
- PatKind::Path(Some(ref qself), ref path) => {
- self.print_qpath(path, qself, false);
- }
- PatKind::Struct(ref path, ref fields, etc) => {
- self.print_path(path, true, 0);
- self.nbsp();
- self.word_space("{");
- self.commasep_cmnt(
- Consistent,
- &fields[..],
- |s, f| {
- s.cbox(INDENT_UNIT);
- if !f.is_shorthand {
- s.print_ident(f.ident);
- s.word_nbsp(":");
- }
- s.print_pat(&f.pat);
- s.end();
- },
- |f| f.pat.span,
- );
- if etc {
- if !fields.is_empty() {
- self.word_space(",");
- }
- self.s.word("..");
- }
- self.s.space();
- self.s.word("}");
- }
- PatKind::Tuple(ref elts) => {
- self.popen();
- self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
- if elts.len() == 1 {
- self.s.word(",");
- }
- self.pclose();
- }
- PatKind::Box(ref inner) => {
- self.s.word("box ");
- self.print_pat(inner);
- }
- PatKind::Ref(ref inner, mutbl) => {
- self.s.word("&");
- if mutbl == ast::Mutability::Mut {
- self.s.word("mut ");
- }
- self.print_pat(inner);
- }
- PatKind::Lit(ref e) => self.print_expr(&**e),
- PatKind::Range(ref begin, ref end, Spanned { node: ref end_kind, .. }) => {
- if let Some(e) = begin {
- self.print_expr(e);
- self.s.space();
- }
- match *end_kind {
- RangeEnd::Included(RangeSyntax::DotDotDot) => self.s.word("..."),
- RangeEnd::Included(RangeSyntax::DotDotEq) => self.s.word("..="),
- RangeEnd::Excluded => self.s.word(".."),
- }
- if let Some(e) = end {
- self.print_expr(e);
- }
- }
- PatKind::Slice(ref elts) => {
- self.s.word("[");
- self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
- self.s.word("]");
- }
- PatKind::Rest => self.s.word(".."),
- PatKind::Paren(ref inner) => {
- self.popen();
- self.print_pat(inner);
- self.pclose();
- }
- PatKind::Mac(ref m) => self.print_mac(m),
- }
- self.ann.post(self, AnnNode::Pat(pat))
- }
-
- fn print_arm(&mut self, arm: &ast::Arm) {
- // Note, I have no idea why this check is necessary, but here it is.
- if arm.attrs.is_empty() {
- self.s.space();
- }
- self.cbox(INDENT_UNIT);
- self.ibox(0);
- self.maybe_print_comment(arm.pat.span.lo());
- self.print_outer_attributes(&arm.attrs);
- self.print_pat(&arm.pat);
- self.s.space();
- if let Some(ref e) = arm.guard {
- self.word_space("if");
- self.print_expr(e);
- self.s.space();
- }
- self.word_space("=>");
-
- match arm.body.kind {
- ast::ExprKind::Block(ref blk, opt_label) => {
- if let Some(label) = opt_label {
- self.print_ident(label.ident);
- self.word_space(":");
- }
-
- // The block will close the pattern's ibox.
- self.print_block_unclosed_indent(blk);
-
- // If it is a user-provided unsafe block, print a comma after it.
- if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
- self.s.word(",");
- }
- }
- _ => {
- self.end(); // Close the ibox for the pattern.
- self.print_expr(&arm.body);
- self.s.word(",");
- }
- }
- self.end(); // Close enclosing cbox.
- }
-
- fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) {
- match explicit_self.node {
- SelfKind::Value(m) => {
- self.print_mutability(m, false);
- self.s.word("self")
- }
- SelfKind::Region(ref lt, m) => {
- self.s.word("&");
- self.print_opt_lifetime(lt);
- self.print_mutability(m, false);
- self.s.word("self")
- }
- SelfKind::Explicit(ref typ, m) => {
- self.print_mutability(m, false);
- self.s.word("self");
- self.word_space(":");
- self.print_type(typ)
- }
- }
- }
-
- crate fn print_fn(
- &mut self,
- decl: &ast::FnDecl,
- header: ast::FnHeader,
- name: Option<ast::Ident>,
- generics: &ast::Generics,
- vis: &ast::Visibility,
- ) {
- self.print_fn_header_info(header, vis);
-
- if let Some(name) = name {
- self.nbsp();
- self.print_ident(name);
- }
- self.print_generic_params(&generics.params);
- self.print_fn_params_and_ret(decl, false);
- self.print_where_clause(&generics.where_clause)
- }
-
- crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
- let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") };
- self.word(open);
- self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure));
- self.word(close);
- self.print_fn_ret_ty(&decl.output)
- }
-
- crate fn print_movability(&mut self, movability: ast::Movability) {
- match movability {
- ast::Movability::Static => self.word_space("static"),
- ast::Movability::Movable => {}
- }
- }
-
- crate fn print_asyncness(&mut self, asyncness: ast::IsAsync) {
- if asyncness.is_async() {
- self.word_nbsp("async");
- }
- }
-
- crate fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
- match capture_clause {
- ast::CaptureBy::Value => self.word_space("move"),
- ast::CaptureBy::Ref => {}
- }
- }
-
- pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::GenericBound]) {
- if !bounds.is_empty() {
- self.s.word(prefix);
- let mut first = true;
- for bound in bounds {
- if !(first && prefix.is_empty()) {
- self.nbsp();
- }
- if first {
- first = false;
- } else {
- self.word_space("+");
- }
-
- match bound {
- GenericBound::Trait(tref, modifier) => {
- if modifier == &TraitBoundModifier::Maybe {
- self.s.word("?");
- }
- self.print_poly_trait_ref(tref);
- }
- GenericBound::Outlives(lt) => self.print_lifetime(*lt),
- }
- }
- }
- }
-
- crate fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
- self.print_name(lifetime.ident.name)
- }
-
- crate fn print_lifetime_bounds(
- &mut self,
- lifetime: ast::Lifetime,
- bounds: &ast::GenericBounds,
- ) {
- self.print_lifetime(lifetime);
- if !bounds.is_empty() {
- self.s.word(": ");
- for (i, bound) in bounds.iter().enumerate() {
- if i != 0 {
- self.s.word(" + ");
- }
- match bound {
- ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt),
- _ => panic!(),
- }
- }
- }
- }
-
- crate fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
- if generic_params.is_empty() {
- return;
- }
-
- self.s.word("<");
-
- self.commasep(Inconsistent, &generic_params, |s, param| {
- s.print_outer_attributes_inline(¶m.attrs);
-
- match param.kind {
- ast::GenericParamKind::Lifetime => {
- let lt = ast::Lifetime { id: param.id, ident: param.ident };
- s.print_lifetime_bounds(lt, ¶m.bounds)
- }
- ast::GenericParamKind::Type { ref default } => {
- s.print_ident(param.ident);
- s.print_type_bounds(":", ¶m.bounds);
- if let Some(ref default) = default {
- s.s.space();
- s.word_space("=");
- s.print_type(default)
- }
- }
- ast::GenericParamKind::Const { ref ty } => {
- s.word_space("const");
- s.print_ident(param.ident);
- s.s.space();
- s.word_space(":");
- s.print_type(ty);
- s.print_type_bounds(":", ¶m.bounds)
- }
- }
- });
-
- self.s.word(">");
- }
-
- crate fn print_where_clause(&mut self, where_clause: &ast::WhereClause) {
- if where_clause.predicates.is_empty() {
- return;
- }
-
- self.s.space();
- self.word_space("where");
-
- for (i, predicate) in where_clause.predicates.iter().enumerate() {
- if i != 0 {
- self.word_space(",");
- }
-
- match *predicate {
- ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
- ref bound_generic_params,
- ref bounded_ty,
- ref bounds,
- ..
- }) => {
- self.print_formal_generic_params(bound_generic_params);
- self.print_type(bounded_ty);
- self.print_type_bounds(":", bounds);
- }
- ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
- ref lifetime,
- ref bounds,
- ..
- }) => {
- self.print_lifetime_bounds(*lifetime, bounds);
- }
- ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
- ref lhs_ty,
- ref rhs_ty,
- ..
- }) => {
- self.print_type(lhs_ty);
- self.s.space();
- self.word_space("=");
- self.print_type(rhs_ty);
- }
- }
- }
- }
-
- crate fn print_use_tree(&mut self, tree: &ast::UseTree) {
- match tree.kind {
- ast::UseTreeKind::Simple(rename, ..) => {
- self.print_path(&tree.prefix, false, 0);
- if let Some(rename) = rename {
- self.s.space();
- self.word_space("as");
- self.print_ident(rename);
- }
- }
- ast::UseTreeKind::Glob => {
- if !tree.prefix.segments.is_empty() {
- self.print_path(&tree.prefix, false, 0);
- self.s.word("::");
- }
- self.s.word("*");
- }
- ast::UseTreeKind::Nested(ref items) => {
- if tree.prefix.segments.is_empty() {
- self.s.word("{");
- } else {
- self.print_path(&tree.prefix, false, 0);
- self.s.word("::{");
- }
- self.commasep(Inconsistent, &items[..], |this, &(ref tree, _)| {
- this.print_use_tree(tree)
- });
- self.s.word("}");
- }
- }
- }
-
- pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) {
- match mutbl {
- ast::Mutability::Mut => self.word_nbsp("mut"),
- ast::Mutability::Not => {
- if print_const {
- self.word_nbsp("const");
- }
- }
- }
- }
-
- crate fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) {
- self.print_mutability(mt.mutbl, print_const);
- self.print_type(&mt.ty)
- }
-
- crate fn print_param(&mut self, input: &ast::Param, is_closure: bool) {
- self.ibox(INDENT_UNIT);
-
- self.print_outer_attributes_inline(&input.attrs);
-
- match input.ty.kind {
- ast::TyKind::Infer if is_closure => self.print_pat(&input.pat),
- _ => {
- if let Some(eself) = input.to_self() {
- self.print_explicit_self(&eself);
- } else {
- let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind {
- ident.name == kw::Invalid
- } else {
- false
- };
- if !invalid {
- self.print_pat(&input.pat);
- self.s.word(":");
- self.s.space();
- }
- self.print_type(&input.ty);
- }
- }
- }
- self.end();
- }
-
- crate fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FunctionRetTy) {
- if let ast::FunctionRetTy::Ty(ty) = fn_ret_ty {
- self.space_if_not_bol();
- self.ibox(INDENT_UNIT);
- self.word_space("->");
- self.print_type(ty);
- self.end();
- self.maybe_print_comment(ty.span.lo());
- }
- }
-
- crate fn print_ty_fn(
- &mut self,
- ext: ast::Extern,
- unsafety: ast::Unsafety,
- decl: &ast::FnDecl,
- name: Option<ast::Ident>,
- generic_params: &[ast::GenericParam],
- ) {
- self.ibox(INDENT_UNIT);
- if !generic_params.is_empty() {
- self.s.word("for");
- self.print_generic_params(generic_params);
- }
- let generics = ast::Generics {
- params: Vec::new(),
- where_clause: ast::WhereClause { predicates: Vec::new(), span: rustc_span::DUMMY_SP },
- span: rustc_span::DUMMY_SP,
- };
- self.print_fn(
- decl,
- ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() },
- name,
- &generics,
- &dummy_spanned(ast::VisibilityKind::Inherited),
- );
- self.end();
- }
-
- crate fn maybe_print_trailing_comment(
- &mut self,
- span: rustc_span::Span,
- next_pos: Option<BytePos>,
- ) {
- if let Some(cmnts) = self.comments() {
- if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
- self.print_comment(&cmnt);
- }
- }
- }
-
- crate fn print_remaining_comments(&mut self) {
- // If there aren't any remaining comments, then we need to manually
- // make sure there is a line break at the end.
- if self.next_comment().is_none() {
- self.s.hardbreak();
- }
- while let Some(ref cmnt) = self.next_comment() {
- self.print_comment(cmnt);
- }
- }
-
- crate fn print_fn_header_info(&mut self, header: ast::FnHeader, vis: &ast::Visibility) {
- self.s.word(visibility_qualified(vis, ""));
-
- match header.constness.node {
- ast::Constness::NotConst => {}
- ast::Constness::Const => self.word_nbsp("const"),
- }
-
- self.print_asyncness(header.asyncness.node);
- self.print_unsafety(header.unsafety);
-
- match header.ext {
- ast::Extern::None => {}
- ast::Extern::Implicit => {
- self.word_nbsp("extern");
- }
- ast::Extern::Explicit(abi) => {
- self.word_nbsp("extern");
- self.print_literal(&abi.as_lit());
- self.nbsp();
- }
- }
-
- self.s.word("fn")
- }
-
- crate fn print_unsafety(&mut self, s: ast::Unsafety) {
- match s {
- ast::Unsafety::Normal => {}
- ast::Unsafety::Unsafe => self.word_nbsp("unsafe"),
- }
- }
-
- crate fn print_constness(&mut self, s: ast::Constness) {
- match s {
- ast::Constness::Const => self.word_nbsp("const"),
- ast::Constness::NotConst => {}
- }
- }
-
- crate fn print_is_auto(&mut self, s: ast::IsAuto) {
- match s {
- ast::IsAuto::Yes => self.word_nbsp("auto"),
- ast::IsAuto::No => {}
- }
- }
-}
+++ /dev/null
-use super::*;
-
-use crate::ast;
-use crate::with_default_globals;
-use rustc_span;
-use rustc_span::source_map::{dummy_spanned, respan};
-
-fn fun_to_string(
- decl: &ast::FnDecl,
- header: ast::FnHeader,
- name: ast::Ident,
- generics: &ast::Generics,
-) -> String {
- to_string(|s| {
- s.head("");
- s.print_fn(
- decl,
- header,
- Some(name),
- generics,
- &dummy_spanned(ast::VisibilityKind::Inherited),
- );
- s.end(); // Close the head box.
- s.end(); // Close the outer box.
- })
-}
-
-fn variant_to_string(var: &ast::Variant) -> String {
- to_string(|s| s.print_variant(var))
-}
-
-#[test]
-fn test_fun_to_string() {
- with_default_globals(|| {
- let abba_ident = ast::Ident::from_str("abba");
-
- let decl = ast::FnDecl {
- inputs: Vec::new(),
- output: ast::FunctionRetTy::Default(rustc_span::DUMMY_SP),
- };
- let generics = ast::Generics::default();
- assert_eq!(
- fun_to_string(&decl, ast::FnHeader::default(), abba_ident, &generics),
- "fn abba()"
- );
- })
-}
-
-#[test]
-fn test_variant_to_string() {
- with_default_globals(|| {
- let ident = ast::Ident::from_str("principal_skinner");
-
- let var = ast::Variant {
- ident,
- vis: respan(rustc_span::DUMMY_SP, ast::VisibilityKind::Inherited),
- attrs: Vec::new(),
- id: ast::DUMMY_NODE_ID,
- data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
- disr_expr: None,
- span: rustc_span::DUMMY_SP,
- is_placeholder: false,
- };
-
- let varstr = variant_to_string(&var);
- assert_eq!(varstr, "principal_skinner");
- })
-}
pub use CommentStyle::*;
use crate::ast;
-
use rustc_span::source_map::SourceMap;
use rustc_span::{BytePos, CharPos, FileName, Pos};
-use std::usize;
-
use log::debug;
+use std::usize;
#[cfg(test)]
mod tests;
// it appears this function is called only from pprust... that's
// probably not a good thing.
-crate fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comment> {
+pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comment> {
let cm = SourceMap::new(sm.path_mapping().clone());
let source_file = cm.new_source_file(path, src);
let text = (*source_file.src.as_ref().unwrap()).clone();
///
/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
/// Can we print this as `let _ = a OP b`?
-crate fn needs_par_as_let_scrutinee(order: i8) -> bool {
+pub fn needs_par_as_let_scrutinee(order: i8) -> bool {
order <= prec_let_scrutinee_needs_par() as i8
}