use rustc::session::Session;
use rustc_target::spec::abi::Abi;
use std::fmt::Debug;
use std::rc::Rc;
use syntax::ast::*;
use syntax::attr;
use syntax::ext::hygiene::SyntaxContext;
use syntax::parse::token::{DelimToken, Nonterminal, Token};
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::source_map::{BytePos, FileName, Span, Spanned};
use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree};
use syntax::util::parser;
use syntax::ThinVec;
use crate::ast_manip::ast_map::NodeTable;
use crate::ast_manip::util::extended_span;
use crate::ast_manip::{AstDeref, GetNodeId, GetSpan};
use crate::driver;
use crate::rewrite::base::{binop_left_prec, binop_right_prec};
use crate::rewrite::base::{describe, is_rewritable};
use crate::rewrite::{ExprPrec, Rewrite, RewriteCtxt, RewriteCtxtRef, TextAdjust, TextRewrite};
use crate::util::Lone;
pub trait PrintParse {
fn to_string(&self) -> String;
type Parsed: AstDeref<Target = Self>;
fn parse(sess: &Session, src: &str) -> Self::Parsed;
}
impl PrintParse for Expr {
fn to_string(&self) -> String {
pprust::expr_to_string(self)
}
type Parsed = P<Expr>;
fn parse(sess: &Session, src: &str) -> Self::Parsed {
driver::parse_expr(sess, src)
}
}
impl PrintParse for Pat {
fn to_string(&self) -> String {
pprust::pat_to_string(self)
}
type Parsed = P<Pat>;
fn parse(sess: &Session, src: &str) -> Self::Parsed {
driver::parse_pat(sess, src)
}
}
impl PrintParse for Ty {
fn to_string(&self) -> String {
pprust::ty_to_string(self)
}
type Parsed = P<Ty>;
fn parse(sess: &Session, src: &str) -> Self::Parsed {
driver::parse_ty(sess, src)
}
}
impl PrintParse for Stmt {
fn to_string(&self) -> String {
match self.node {
StmtKind::Expr(ref expr) => pprust::expr_to_string(expr),
_ => pprust::stmt_to_string(self),
}
}
type Parsed = Stmt;
fn parse(sess: &Session, src: &str) -> Self::Parsed {
driver::parse_stmts(sess, src).lone()
}
}
impl PrintParse for Item {
fn to_string(&self) -> String {
match self.node {
ItemKind::Mod(ref m) if !m.inline => {
let mut tmp = self.clone();
expect!([tmp.node] ItemKind::Mod(ref mut m) => m.inline = true);
warn!(
"printing non-inline module {:?} as inline for rewriting purposes",
self.ident
);
pprust::item_to_string(&tmp)
}
_ => pprust::item_to_string(self),
}
}
type Parsed = P<Item>;
fn parse(sess: &Session, src: &str) -> Self::Parsed {
driver::parse_items(sess, src).lone()
}
}
impl PrintParse for ForeignItem {
fn to_string(&self) -> String {
pprust::to_string(|s| s.print_foreign_item(self))
}
type Parsed = ForeignItem;
fn parse(sess: &Session, src: &str) -> Self::Parsed {
driver::parse_foreign_items(sess, src).lone()
}
}
impl PrintParse for Block {
fn to_string(&self) -> String {
pprust::block_to_string(self)
}
type Parsed = P<Block>;
fn parse(sess: &Session, src: &str) -> Self::Parsed {
driver::parse_block(sess, src)
}
}
impl PrintParse for Arg {
fn to_string(&self) -> String {
pprust::arg_to_string(self)
}
type Parsed = Arg;
fn parse(sess: &Session, src: &str) -> Self::Parsed {
driver::parse_arg(sess, src)
}
}
impl PrintParse for Attribute {
fn to_string(&self) -> String {
pprust::attr_to_string(self)
}
type Parsed = Attribute;
fn parse(sess: &Session, src: &str) -> Self::Parsed {
driver::run_parser(sess, src, |p| {
match p.token {
Token::DocComment(s) => {
assert!(src.ends_with('\n'));
let span = p.span.with_hi(p.span.hi() + BytePos(1));
let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, span);
p.bump();
return Ok(attr);
}
_ => p.parse_attribute(true),
}
})
}
}
pub trait Splice {
fn splice_span(&self) -> Span;
fn get_adjustment(&self, _rcx: &RewriteCtxt) -> TextAdjust {
TextAdjust::None
}
}
impl Splice for Expr {
fn splice_span(&self) -> Span {
extended_span(self.span, &self.attrs)
}
fn get_adjustment(&self, rcx: &RewriteCtxt) -> TextAdjust {
let prec = self.precedence();
let need_parens = match rcx.expr_prec() {
ExprPrec::Normal(min_prec) => prec.order() < min_prec,
ExprPrec::Cond(min_prec) => {
prec.order() < min_prec || parser::contains_exterior_struct_lit(self)
}
ExprPrec::Callee(min_prec) => match self.node {
ExprKind::Field(..) => true,
_ => prec.order() < min_prec,
},
ExprPrec::LeftLess(min_prec) => match self.node {
ExprKind::Cast(..) | ExprKind::Type(..) => true,
_ => prec.order() < min_prec,
},
};
if need_parens {
TextAdjust::Parenthesize
} else {
TextAdjust::None
}
}
}
impl Splice for Pat {
fn splice_span(&self) -> Span {
self.span
}
}
impl Splice for Ty {
fn splice_span(&self) -> Span {
self.span
}
}
impl Splice for Stmt {
fn splice_span(&self) -> Span {
self.span
}
}
impl Splice for Item {
fn splice_span(&self) -> Span {
extended_span(self.span, &self.attrs)
}
}
impl Splice for ForeignItem {
fn splice_span(&self) -> Span {
extended_span(self.span, &self.attrs)
}
}
impl Splice for Block {
fn splice_span(&self) -> Span {
self.span
}
}
impl Splice for Arg {
fn splice_span(&self) -> Span {
self.pat.span.to(self.ty.span)
}
}
impl Splice for Attribute {
fn splice_span(&self) -> Span {
self.span
}
}
pub trait Recover {
fn node_table<'a, 's>(rcx: &'a RewriteCtxt<'s>) -> &'a NodeTable<'s, Self>;
}
impl Recover for Expr {
fn node_table<'a, 's>(rcx: &'a RewriteCtxt<'s>) -> &'a NodeTable<'s, Self> {
&rcx.old_nodes().exprs
}
}
impl Recover for Pat {
fn node_table<'a, 's>(rcx: &'a RewriteCtxt<'s>) -> &'a NodeTable<'s, Self> {
&rcx.old_nodes().pats
}
}
impl Recover for Ty {
fn node_table<'a, 's>(rcx: &'a RewriteCtxt<'s>) -> &'a NodeTable<'s, Self> {
&rcx.old_nodes().tys
}
}
impl Recover for Stmt {
fn node_table<'a, 's>(rcx: &'a RewriteCtxt<'s>) -> &'a NodeTable<'s, Self> {
&rcx.old_nodes().stmts
}
}
impl Recover for Item {
fn node_table<'a, 's>(rcx: &'a RewriteCtxt<'s>) -> &'a NodeTable<'s, Self> {
&rcx.old_nodes().items
}
}
impl Recover for ForeignItem {
fn node_table<'a, 's>(rcx: &'a RewriteCtxt<'s>) -> &'a NodeTable<'s, Self> {
&rcx.old_nodes().foreign_items
}
}
impl Recover for Block {
fn node_table<'a, 's>(rcx: &'a RewriteCtxt<'s>) -> &'a NodeTable<'s, Self> {
&rcx.old_nodes().blocks
}
}
pub trait RecoverChildren {
fn recover_children(reparsed: &Self, new: &Self, rcx: RewriteCtxtRef);
fn recover_node_and_children(reparsed: &Self, new: &Self, rcx: RewriteCtxtRef);
fn recover_node_restricted(old_span: Span, reparsed: &Self, new: &Self, rcx: RewriteCtxtRef);
}
impl<T: RecoverChildren> RecoverChildren for P<T> {
fn recover_children(reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
<T as RecoverChildren>::recover_children(reparsed, new, rcx)
}
fn recover_node_and_children(reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
<T as RecoverChildren>::recover_node_and_children(reparsed, new, rcx)
}
fn recover_node_restricted(old_span: Span, reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
<T as RecoverChildren>::recover_node_restricted(old_span, reparsed, new, rcx)
}
}
impl<T: RecoverChildren> RecoverChildren for Rc<T> {
fn recover_children(reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
<T as RecoverChildren>::recover_children(reparsed, new, rcx)
}
fn recover_node_and_children(reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
<T as RecoverChildren>::recover_node_and_children(reparsed, new, rcx)
}
fn recover_node_restricted(old_span: Span, reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
<T as RecoverChildren>::recover_node_restricted(old_span, reparsed, new, rcx)
}
}
impl<T: RecoverChildren> RecoverChildren for Spanned<T> {
fn recover_children(reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
<T as RecoverChildren>::recover_children(&reparsed.node, &new.node, rcx)
}
fn recover_node_and_children(reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
<T as RecoverChildren>::recover_node_and_children(&reparsed.node, &new.node, rcx)
}
fn recover_node_restricted(old_span: Span, reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
<T as RecoverChildren>::recover_node_restricted(old_span, &reparsed.node, &new.node, rcx)
}
}
impl<T: RecoverChildren> RecoverChildren for Option<T> {
fn recover_children(reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
match (reparsed, new) {
(&Some(ref x1), &Some(ref x2)) => {
RecoverChildren::recover_children(x1, x2, rcx);
}
(_, _) => {}
}
}
fn recover_node_and_children(reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
match (reparsed, new) {
(&Some(ref x1), &Some(ref x2)) => {
RecoverChildren::recover_node_and_children(x1, x2, rcx);
}
(_, _) => {}
}
}
fn recover_node_restricted(_old_span: Span, reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
RecoverChildren::recover_children(reparsed, new, rcx);
}
}
impl<A: RecoverChildren, B: RecoverChildren> RecoverChildren for (A, B) {
fn recover_children(reparsed: &Self, new: &Self, mut rcx: RewriteCtxtRef) {
<A as RecoverChildren>::recover_children(&reparsed.0, &new.0, rcx.borrow());
<B as RecoverChildren>::recover_children(&reparsed.1, &new.1, rcx.borrow());
}
fn recover_node_and_children(reparsed: &Self, new: &Self, mut rcx: RewriteCtxtRef) {
<A as RecoverChildren>::recover_node_and_children(&reparsed.0, &new.0, rcx.borrow());
<B as RecoverChildren>::recover_node_and_children(&reparsed.1, &new.1, rcx.borrow());
}
fn recover_node_restricted(_old_span: Span, reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
RecoverChildren::recover_children(reparsed, new, rcx);
}
}
impl<A: RecoverChildren, B: RecoverChildren, C: RecoverChildren> RecoverChildren for (A, B, C) {
fn recover_children(reparsed: &Self, new: &Self, mut rcx: RewriteCtxtRef) {
<A as RecoverChildren>::recover_children(&reparsed.0, &new.0, rcx.borrow());
<B as RecoverChildren>::recover_children(&reparsed.1, &new.1, rcx.borrow());
<C as RecoverChildren>::recover_children(&reparsed.2, &new.2, rcx.borrow());
}
fn recover_node_and_children(reparsed: &Self, new: &Self, mut rcx: RewriteCtxtRef) {
<A as RecoverChildren>::recover_node_and_children(&reparsed.0, &new.0, rcx.borrow());
<B as RecoverChildren>::recover_node_and_children(&reparsed.1, &new.1, rcx.borrow());
<C as RecoverChildren>::recover_node_and_children(&reparsed.2, &new.2, rcx.borrow());
}
fn recover_node_restricted(_old_span: Span, reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
RecoverChildren::recover_children(reparsed, new, rcx);
}
}
impl<T: RecoverChildren> RecoverChildren for [T] {
fn recover_children(reparsed: &Self, new: &Self, mut rcx: RewriteCtxtRef) {
assert!(
reparsed.len() == new.len(),
"new and reprinted ASTs don't match"
);
for i in 0..reparsed.len() {
RecoverChildren::recover_children(&reparsed[i], &new[i], rcx.borrow());
}
}
fn recover_node_and_children(reparsed: &Self, new: &Self, mut rcx: RewriteCtxtRef) {
assert!(
reparsed.len() == new.len(),
"new and reprinted ASTs don't match"
);
for i in 0..reparsed.len() {
RecoverChildren::recover_node_and_children(&reparsed[i], &new[i], rcx.borrow());
}
}
fn recover_node_restricted(_old_span: Span, reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
RecoverChildren::recover_children(reparsed, new, rcx);
}
}
impl<T: RecoverChildren> RecoverChildren for Vec<T> {
fn recover_children(reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
<[T] as RecoverChildren>::recover_children(&reparsed, &new, rcx)
}
fn recover_node_and_children(reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
<[T] as RecoverChildren>::recover_node_and_children(&reparsed, &new, rcx)
}
fn recover_node_restricted(old_span: Span, reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
<[T] as RecoverChildren>::recover_node_restricted(old_span, &reparsed, &new, rcx)
}
}
impl<T: RecoverChildren> RecoverChildren for ThinVec<T> {
fn recover_children(reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
<[T] as RecoverChildren>::recover_children(&reparsed, &new, rcx)
}
fn recover_node_and_children(reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
<[T] as RecoverChildren>::recover_node_and_children(&reparsed, &new, rcx)
}
fn recover_node_restricted(old_span: Span, reparsed: &Self, new: &Self, rcx: RewriteCtxtRef) {
<[T] as RecoverChildren>::recover_node_restricted(old_span, &reparsed, &new, rcx)
}
}
include!(concat!(
env!("OUT_DIR"),
"/rewrite_recover_children_gen.inc.rs"
));
fn recover<'s, T>(
maybe_restricted_span: Option<Span>,
reparsed: &T,
new: &T,
mut rcx: RewriteCtxtRef<'s, '_>,
) -> bool
where
T: GetNodeId + Recover + Rewrite + Splice + 's,
{
let old_id = rcx.new_to_old_id(new.get_node_id());
let old = match <T as Recover>::node_table(&mut rcx).get(old_id) {
Some(x) => x,
None => {
return false;
}
};
if !is_rewritable(old.splice_span()) {
return false;
}
let sf = rcx
.session()
.source_map()
.lookup_byte_offset(old.splice_span().lo())
.sf;
if let FileName::Macros(..) = sf.name {
return false;
}
if let Some(restricted_span) = maybe_restricted_span {
if old.splice_span() == restricted_span {
return false;
}
}
info!("REVERT {}", describe(rcx.session(), reparsed.splice_span()));
info!(" TO {}", describe(rcx.session(), old.splice_span()));
let mut rw = TextRewrite::adjusted(
reparsed.splice_span(),
old.splice_span(),
new.get_adjustment(&rcx),
);
let mark = rcx.mark();
let ok = Rewrite::rewrite(old, new, rcx.enter(&mut rw));
if !ok {
rcx.rewind(mark);
return false;
}
rcx.record(rw);
true
}
pub fn rewrite<T>(old: &T, new: &T, rcx: RewriteCtxtRef) -> bool
where
T: PrintParse + RecoverChildren + Splice + Debug,
{
if !is_rewritable(old.splice_span()) {
warn!("can't splice in fresh text for a non-rewritable node");
return true;
}
rewrite_at(old.splice_span(), new, rcx)
}
pub fn rewrite_at<T>(old_span: Span, new: &T, mut rcx: RewriteCtxtRef) -> bool
where
T: PrintParse + RecoverChildren + Splice + Debug,
{
let printed = new.to_string();
let reparsed = T::parse(rcx.session(), &printed);
let reparsed = reparsed.ast_deref();
if old_span.lo() != old_span.hi() {
info!("REWRITE {}", describe(rcx.session(), old_span));
info!(
" INTO {}",
describe(rcx.session(), reparsed.splice_span())
);
} else {
info!("INSERT AT {}", describe(rcx.session(), old_span));
info!(
" TEXT {}",
describe(rcx.session(), reparsed.splice_span())
);
}
let mut rw = TextRewrite::adjusted(old_span, reparsed.splice_span(), new.get_adjustment(&rcx));
RecoverChildren::recover_node_restricted(old_span, reparsed, new, rcx.enter(&mut rw));
rcx.record(rw);
true
}