diff options
Diffstat (limited to 'vendor/syn/tests/test_precedence.rs')
-rw-r--r-- | vendor/syn/tests/test_precedence.rs | 548 |
1 files changed, 0 insertions, 548 deletions
diff --git a/vendor/syn/tests/test_precedence.rs b/vendor/syn/tests/test_precedence.rs deleted file mode 100644 index 026bece..0000000 --- a/vendor/syn/tests/test_precedence.rs +++ /dev/null @@ -1,548 +0,0 @@ -//! This test does the following for every file in the rust-lang/rust repo: -//! -//! 1. Parse the file using syn into a syn::File. -//! 2. Extract every syn::Expr from the file. -//! 3. Print each expr to a string of source code. -//! 4. Parse the source code using librustc_parse into a rustc_ast::Expr. -//! 5. For both the syn::Expr and rustc_ast::Expr, crawl the syntax tree to -//! insert parentheses surrounding every subexpression. -//! 6. Serialize the fully parenthesized syn::Expr to a string of source code. -//! 7. Parse the fully parenthesized source code using librustc_parse. -//! 8. Compare the rustc_ast::Expr resulting from parenthesizing using rustc -//! data structures vs syn data structures, ignoring spans. If they agree, -//! rustc's parser and syn's parser have identical handling of expression -//! precedence. - -#![cfg(not(syn_disable_nightly_tests))] -#![cfg(not(miri))] -#![recursion_limit = "1024"] -#![feature(rustc_private)] -#![allow( - clippy::blocks_in_conditions, - clippy::doc_markdown, - clippy::explicit_deref_methods, - clippy::let_underscore_untyped, - clippy::manual_assert, - clippy::manual_let_else, - clippy::match_like_matches_macro, - clippy::match_wildcard_for_single_variants, - clippy::too_many_lines, - clippy::uninlined_format_args -)] - -extern crate rustc_ast; -extern crate rustc_ast_pretty; -extern crate rustc_data_structures; -extern crate rustc_driver; -extern crate rustc_span; -extern crate smallvec; -extern crate thin_vec; - -use crate::common::eq::SpanlessEq; -use crate::common::parse; -use quote::ToTokens; -use rustc_ast::ast; -use rustc_ast::ptr::P; -use rustc_ast_pretty::pprust; -use rustc_span::edition::Edition; -use std::fs; -use std::path::Path; -use std::process; -use std::sync::atomic::{AtomicUsize, Ordering}; - -#[macro_use] -mod macros; - -#[allow(dead_code)] -mod common; - -mod repo; - -#[test] -fn test_rustc_precedence() { - common::rayon_init(); - repo::clone_rust(); - let abort_after = common::abort_after(); - if abort_after == 0 { - panic!("Skipping all precedence tests"); - } - - let passed = AtomicUsize::new(0); - let failed = AtomicUsize::new(0); - - repo::for_each_rust_file(|path| { - let content = fs::read_to_string(path).unwrap(); - - let (l_passed, l_failed) = match syn::parse_file(&content) { - Ok(file) => { - let edition = repo::edition(path).parse().unwrap(); - let exprs = collect_exprs(file); - let (l_passed, l_failed) = test_expressions(path, edition, exprs); - errorf!( - "=== {}: {} passed | {} failed\n", - path.display(), - l_passed, - l_failed, - ); - (l_passed, l_failed) - } - Err(msg) => { - errorf!("\nFAIL {} - syn failed to parse: {}\n", path.display(), msg); - (0, 1) - } - }; - - passed.fetch_add(l_passed, Ordering::Relaxed); - let prev_failed = failed.fetch_add(l_failed, Ordering::Relaxed); - - if prev_failed + l_failed >= abort_after { - process::exit(1); - } - }); - - let passed = passed.load(Ordering::Relaxed); - let failed = failed.load(Ordering::Relaxed); - - errorf!("\n===== Precedence Test Results =====\n"); - errorf!("{} passed | {} failed\n", passed, failed); - - if failed > 0 { - panic!("{} failures", failed); - } -} - -fn test_expressions(path: &Path, edition: Edition, exprs: Vec<syn::Expr>) -> (usize, usize) { - let mut passed = 0; - let mut failed = 0; - - rustc_span::create_session_if_not_set_then(edition, |_| { - for expr in exprs { - let source_code = expr.to_token_stream().to_string(); - let librustc_ast = if let Some(e) = librustc_parse_and_rewrite(&source_code) { - e - } else { - failed += 1; - errorf!( - "\nFAIL {} - librustc failed to parse original\n", - path.display(), - ); - continue; - }; - - let syn_parenthesized_code = - syn_parenthesize(expr.clone()).to_token_stream().to_string(); - let syn_ast = if let Some(e) = parse::librustc_expr(&syn_parenthesized_code) { - e - } else { - failed += 1; - errorf!( - "\nFAIL {} - librustc failed to parse parenthesized\n", - path.display(), - ); - continue; - }; - - if !SpanlessEq::eq(&syn_ast, &librustc_ast) { - failed += 1; - let syn_pretty = pprust::expr_to_string(&syn_ast); - let librustc_pretty = pprust::expr_to_string(&librustc_ast); - errorf!( - "\nFAIL {}\n{}\nsyn != rustc\n{}\n", - path.display(), - syn_pretty, - librustc_pretty, - ); - continue; - } - - let expr_invisible = make_parens_invisible(expr); - let Ok(reparsed_expr_invisible) = syn::parse2(expr_invisible.to_token_stream()) else { - failed += 1; - errorf!( - "\nFAIL {} - syn failed to parse invisible delimiters\n{}\n", - path.display(), - source_code, - ); - continue; - }; - if expr_invisible != reparsed_expr_invisible { - failed += 1; - errorf!( - "\nFAIL {} - mismatch after parsing invisible delimiters\n{}\n", - path.display(), - source_code, - ); - continue; - } - - passed += 1; - } - }); - - (passed, failed) -} - -fn librustc_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> { - parse::librustc_expr(input).map(librustc_parenthesize) -} - -fn librustc_parenthesize(mut librustc_expr: P<ast::Expr>) -> P<ast::Expr> { - use rustc_ast::ast::{ - AssocItem, AssocItemKind, Attribute, BinOpKind, Block, BorrowKind, BoundConstness, Expr, - ExprField, ExprKind, GenericArg, GenericBound, ItemKind, Local, LocalKind, Pat, Stmt, - StmtKind, StructExpr, StructRest, TraitBoundModifiers, Ty, - }; - use rustc_ast::mut_visit::{ - noop_flat_map_assoc_item, noop_visit_generic_arg, noop_visit_item_kind, noop_visit_local, - noop_visit_param_bound, MutVisitor, - }; - use rustc_data_structures::flat_map_in_place::FlatMapInPlace; - use rustc_span::DUMMY_SP; - use smallvec::SmallVec; - use std::mem; - use std::ops::DerefMut; - use thin_vec::ThinVec; - - struct FullyParenthesize; - - fn contains_let_chain(expr: &Expr) -> bool { - match &expr.kind { - ExprKind::Let(..) => true, - ExprKind::Binary(binop, left, right) => { - binop.node == BinOpKind::And - && (contains_let_chain(left) || contains_let_chain(right)) - } - _ => false, - } - } - - fn flat_map_field<T: MutVisitor>(mut f: ExprField, vis: &mut T) -> Vec<ExprField> { - if f.is_shorthand { - noop_visit_expr(&mut f.expr, vis); - } else { - vis.visit_expr(&mut f.expr); - } - vec![f] - } - - fn flat_map_stmt<T: MutVisitor>(stmt: Stmt, vis: &mut T) -> Vec<Stmt> { - let kind = match stmt.kind { - // Don't wrap toplevel expressions in statements. - StmtKind::Expr(mut e) => { - noop_visit_expr(&mut e, vis); - StmtKind::Expr(e) - } - StmtKind::Semi(mut e) => { - noop_visit_expr(&mut e, vis); - StmtKind::Semi(e) - } - s => s, - }; - - vec![Stmt { kind, ..stmt }] - } - - fn noop_visit_expr<T: MutVisitor>(e: &mut Expr, vis: &mut T) { - use rustc_ast::mut_visit::{noop_visit_expr, visit_attrs}; - match &mut e.kind { - ExprKind::AddrOf(BorrowKind::Raw, ..) => {} - ExprKind::Struct(expr) => { - let StructExpr { - qself, - path, - fields, - rest, - } = expr.deref_mut(); - vis.visit_qself(qself); - vis.visit_path(path); - fields.flat_map_in_place(|field| flat_map_field(field, vis)); - if let StructRest::Base(rest) = rest { - vis.visit_expr(rest); - } - vis.visit_id(&mut e.id); - vis.visit_span(&mut e.span); - visit_attrs(&mut e.attrs, vis); - } - _ => noop_visit_expr(e, vis), - } - } - - impl MutVisitor for FullyParenthesize { - fn visit_expr(&mut self, e: &mut P<Expr>) { - noop_visit_expr(e, self); - match e.kind { - ExprKind::Block(..) | ExprKind::If(..) | ExprKind::Let(..) => {} - ExprKind::Binary(..) if contains_let_chain(e) => {} - _ => { - let inner = mem::replace( - e, - P(Expr { - id: ast::DUMMY_NODE_ID, - kind: ExprKind::Err, - span: DUMMY_SP, - attrs: ThinVec::new(), - tokens: None, - }), - ); - e.kind = ExprKind::Paren(inner); - } - } - } - - fn visit_generic_arg(&mut self, arg: &mut GenericArg) { - match arg { - // Don't wrap unbraced const generic arg as that's invalid syntax. - GenericArg::Const(anon_const) => { - if let ExprKind::Block(..) = &mut anon_const.value.kind { - noop_visit_expr(&mut anon_const.value, self); - } - } - _ => noop_visit_generic_arg(arg, self), - } - } - - fn visit_param_bound(&mut self, bound: &mut GenericBound) { - match bound { - GenericBound::Trait( - _, - TraitBoundModifiers { - constness: BoundConstness::Maybe(_), - .. - }, - ) => {} - _ => noop_visit_param_bound(bound, self), - } - } - - fn visit_block(&mut self, block: &mut P<Block>) { - self.visit_id(&mut block.id); - block - .stmts - .flat_map_in_place(|stmt| flat_map_stmt(stmt, self)); - self.visit_span(&mut block.span); - } - - fn visit_local(&mut self, local: &mut P<Local>) { - match local.kind { - LocalKind::InitElse(..) => {} - _ => noop_visit_local(local, self), - } - } - - fn visit_item_kind(&mut self, item: &mut ItemKind) { - match item { - ItemKind::Const(const_item) - if !const_item.generics.params.is_empty() - || !const_item.generics.where_clause.predicates.is_empty() => {} - _ => noop_visit_item_kind(item, self), - } - } - - fn flat_map_trait_item(&mut self, item: P<AssocItem>) -> SmallVec<[P<AssocItem>; 1]> { - match &item.kind { - AssocItemKind::Const(const_item) - if !const_item.generics.params.is_empty() - || !const_item.generics.where_clause.predicates.is_empty() => - { - SmallVec::from([item]) - } - _ => noop_flat_map_assoc_item(item, self), - } - } - - fn flat_map_impl_item(&mut self, item: P<AssocItem>) -> SmallVec<[P<AssocItem>; 1]> { - match &item.kind { - AssocItemKind::Const(const_item) - if !const_item.generics.params.is_empty() - || !const_item.generics.where_clause.predicates.is_empty() => - { - SmallVec::from([item]) - } - _ => noop_flat_map_assoc_item(item, self), - } - } - - // We don't want to look at expressions that might appear in patterns or - // types yet. We'll look into comparing those in the future. For now - // focus on expressions appearing in other places. - fn visit_pat(&mut self, pat: &mut P<Pat>) { - let _ = pat; - } - - fn visit_ty(&mut self, ty: &mut P<Ty>) { - let _ = ty; - } - - fn visit_attribute(&mut self, attr: &mut Attribute) { - let _ = attr; - } - } - - let mut folder = FullyParenthesize; - folder.visit_expr(&mut librustc_expr); - librustc_expr -} - -fn syn_parenthesize(syn_expr: syn::Expr) -> syn::Expr { - use syn::fold::{fold_expr, fold_generic_argument, Fold}; - use syn::{token, BinOp, Expr, ExprParen, GenericArgument, MetaNameValue, Pat, Stmt, Type}; - - struct FullyParenthesize; - - fn parenthesize(expr: Expr) -> Expr { - Expr::Paren(ExprParen { - attrs: Vec::new(), - expr: Box::new(expr), - paren_token: token::Paren::default(), - }) - } - - fn needs_paren(expr: &Expr) -> bool { - match expr { - Expr::Group(_) => unreachable!(), - Expr::If(_) | Expr::Unsafe(_) | Expr::Block(_) | Expr::Let(_) => false, - Expr::Binary(_) => !contains_let_chain(expr), - _ => true, - } - } - - fn contains_let_chain(expr: &Expr) -> bool { - match expr { - Expr::Let(_) => true, - Expr::Binary(expr) => { - matches!(expr.op, BinOp::And(_)) - && (contains_let_chain(&expr.left) || contains_let_chain(&expr.right)) - } - _ => false, - } - } - - impl Fold for FullyParenthesize { - fn fold_expr(&mut self, expr: Expr) -> Expr { - let needs_paren = needs_paren(&expr); - let folded = fold_expr(self, expr); - if needs_paren { - parenthesize(folded) - } else { - folded - } - } - - fn fold_generic_argument(&mut self, arg: GenericArgument) -> GenericArgument { - match arg { - GenericArgument::Const(arg) => GenericArgument::Const(match arg { - Expr::Block(_) => fold_expr(self, arg), - // Don't wrap unbraced const generic arg as that's invalid syntax. - _ => arg, - }), - _ => fold_generic_argument(self, arg), - } - } - - fn fold_stmt(&mut self, stmt: Stmt) -> Stmt { - match stmt { - // Don't wrap toplevel expressions in statements. - Stmt::Expr(Expr::Verbatim(_), Some(_)) => stmt, - Stmt::Expr(e, semi) => Stmt::Expr(fold_expr(self, e), semi), - s => s, - } - } - - fn fold_meta_name_value(&mut self, meta: MetaNameValue) -> MetaNameValue { - // Don't turn #[p = "..."] into #[p = ("...")]. - meta - } - - // We don't want to look at expressions that might appear in patterns or - // types yet. We'll look into comparing those in the future. For now - // focus on expressions appearing in other places. - fn fold_pat(&mut self, pat: Pat) -> Pat { - pat - } - - fn fold_type(&mut self, ty: Type) -> Type { - ty - } - } - - let mut folder = FullyParenthesize; - folder.fold_expr(syn_expr) -} - -fn make_parens_invisible(expr: syn::Expr) -> syn::Expr { - use syn::fold::{fold_expr, fold_stmt, Fold}; - use syn::{token, Expr, ExprGroup, ExprParen, Stmt}; - - struct MakeParensInvisible; - - impl Fold for MakeParensInvisible { - fn fold_expr(&mut self, mut expr: Expr) -> Expr { - if let Expr::Paren(paren) = expr { - expr = Expr::Group(ExprGroup { - attrs: paren.attrs, - group_token: token::Group(paren.paren_token.span.join()), - expr: paren.expr, - }); - } - fold_expr(self, expr) - } - - fn fold_stmt(&mut self, stmt: Stmt) -> Stmt { - if let Stmt::Expr(expr @ (Expr::Binary(_) | Expr::Cast(_)), None) = stmt { - Stmt::Expr( - Expr::Paren(ExprParen { - attrs: Vec::new(), - paren_token: token::Paren::default(), - expr: Box::new(fold_expr(self, expr)), - }), - None, - ) - } else { - fold_stmt(self, stmt) - } - } - } - - let mut folder = MakeParensInvisible; - folder.fold_expr(expr) -} - -/// Walk through a crate collecting all expressions we can find in it. -fn collect_exprs(file: syn::File) -> Vec<syn::Expr> { - use syn::fold::Fold; - use syn::punctuated::Punctuated; - use syn::{token, ConstParam, Expr, ExprTuple, Pat, Path}; - - struct CollectExprs(Vec<Expr>); - impl Fold for CollectExprs { - fn fold_expr(&mut self, expr: Expr) -> Expr { - match expr { - Expr::Verbatim(_) => {} - _ => self.0.push(expr), - } - - Expr::Tuple(ExprTuple { - attrs: vec![], - elems: Punctuated::new(), - paren_token: token::Paren::default(), - }) - } - - fn fold_pat(&mut self, pat: Pat) -> Pat { - pat - } - - fn fold_path(&mut self, path: Path) -> Path { - // Skip traversing into const generic path arguments - path - } - - fn fold_const_param(&mut self, const_param: ConstParam) -> ConstParam { - const_param - } - } - - let mut folder = CollectExprs(vec![]); - folder.fold_file(file); - folder.0 -} |