aboutsummaryrefslogtreecommitdiff
path: root/vendor/syn/tests/test_precedence.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/syn/tests/test_precedence.rs')
-rw-r--r--vendor/syn/tests/test_precedence.rs548
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
-}