1fad3a1d3Sopenharmony_ci#![cfg(not(syn_disable_nightly_tests))] 2fad3a1d3Sopenharmony_ci#![cfg(not(miri))] 3fad3a1d3Sopenharmony_ci#![recursion_limit = "1024"] 4fad3a1d3Sopenharmony_ci#![feature(rustc_private)] 5fad3a1d3Sopenharmony_ci#![allow( 6fad3a1d3Sopenharmony_ci clippy::blocks_in_conditions, 7fad3a1d3Sopenharmony_ci clippy::manual_assert, 8fad3a1d3Sopenharmony_ci clippy::manual_let_else, 9fad3a1d3Sopenharmony_ci clippy::match_like_matches_macro, 10fad3a1d3Sopenharmony_ci clippy::uninlined_format_args 11fad3a1d3Sopenharmony_ci)] 12fad3a1d3Sopenharmony_ci 13fad3a1d3Sopenharmony_ciextern crate rustc_ast; 14fad3a1d3Sopenharmony_ciextern crate rustc_ast_pretty; 15fad3a1d3Sopenharmony_ciextern crate rustc_data_structures; 16fad3a1d3Sopenharmony_ciextern crate rustc_driver; 17fad3a1d3Sopenharmony_ciextern crate rustc_error_messages; 18fad3a1d3Sopenharmony_ciextern crate rustc_errors; 19fad3a1d3Sopenharmony_ciextern crate rustc_expand; 20fad3a1d3Sopenharmony_ciextern crate rustc_parse as parse; 21fad3a1d3Sopenharmony_ciextern crate rustc_session; 22fad3a1d3Sopenharmony_ciextern crate rustc_span; 23fad3a1d3Sopenharmony_ci 24fad3a1d3Sopenharmony_ciuse crate::common::eq::SpanlessEq; 25fad3a1d3Sopenharmony_ciuse quote::quote; 26fad3a1d3Sopenharmony_ciuse rustc_ast::ast::{ 27fad3a1d3Sopenharmony_ci AngleBracketedArg, AngleBracketedArgs, Crate, GenericArg, GenericParamKind, Generics, 28fad3a1d3Sopenharmony_ci WhereClause, 29fad3a1d3Sopenharmony_ci}; 30fad3a1d3Sopenharmony_ciuse rustc_ast::mut_visit::{self, MutVisitor}; 31fad3a1d3Sopenharmony_ciuse rustc_ast_pretty::pprust; 32fad3a1d3Sopenharmony_ciuse rustc_error_messages::{DiagnosticMessage, LazyFallbackBundle}; 33fad3a1d3Sopenharmony_ciuse rustc_errors::{translation, Diagnostic, PResult}; 34fad3a1d3Sopenharmony_ciuse rustc_session::parse::ParseSess; 35fad3a1d3Sopenharmony_ciuse rustc_span::source_map::FilePathMapping; 36fad3a1d3Sopenharmony_ciuse rustc_span::FileName; 37fad3a1d3Sopenharmony_ciuse std::borrow::Cow; 38fad3a1d3Sopenharmony_ciuse std::fs; 39fad3a1d3Sopenharmony_ciuse std::panic; 40fad3a1d3Sopenharmony_ciuse std::path::Path; 41fad3a1d3Sopenharmony_ciuse std::process; 42fad3a1d3Sopenharmony_ciuse std::sync::atomic::{AtomicUsize, Ordering}; 43fad3a1d3Sopenharmony_ciuse std::time::Instant; 44fad3a1d3Sopenharmony_ci 45fad3a1d3Sopenharmony_ci#[macro_use] 46fad3a1d3Sopenharmony_cimod macros; 47fad3a1d3Sopenharmony_ci 48fad3a1d3Sopenharmony_ci#[allow(dead_code)] 49fad3a1d3Sopenharmony_cimod common; 50fad3a1d3Sopenharmony_ci 51fad3a1d3Sopenharmony_cimod repo; 52fad3a1d3Sopenharmony_ci 53fad3a1d3Sopenharmony_ci#[test] 54fad3a1d3Sopenharmony_cifn test_round_trip() { 55fad3a1d3Sopenharmony_ci common::rayon_init(); 56fad3a1d3Sopenharmony_ci repo::clone_rust(); 57fad3a1d3Sopenharmony_ci let abort_after = common::abort_after(); 58fad3a1d3Sopenharmony_ci if abort_after == 0 { 59fad3a1d3Sopenharmony_ci panic!("Skipping all round_trip tests"); 60fad3a1d3Sopenharmony_ci } 61fad3a1d3Sopenharmony_ci 62fad3a1d3Sopenharmony_ci let failed = AtomicUsize::new(0); 63fad3a1d3Sopenharmony_ci 64fad3a1d3Sopenharmony_ci repo::for_each_rust_file(|path| test(path, &failed, abort_after)); 65fad3a1d3Sopenharmony_ci 66fad3a1d3Sopenharmony_ci let failed = failed.load(Ordering::Relaxed); 67fad3a1d3Sopenharmony_ci if failed > 0 { 68fad3a1d3Sopenharmony_ci panic!("{} failures", failed); 69fad3a1d3Sopenharmony_ci } 70fad3a1d3Sopenharmony_ci} 71fad3a1d3Sopenharmony_ci 72fad3a1d3Sopenharmony_cifn test(path: &Path, failed: &AtomicUsize, abort_after: usize) { 73fad3a1d3Sopenharmony_ci let content = fs::read_to_string(path).unwrap(); 74fad3a1d3Sopenharmony_ci 75fad3a1d3Sopenharmony_ci let start = Instant::now(); 76fad3a1d3Sopenharmony_ci let (krate, elapsed) = match syn::parse_file(&content) { 77fad3a1d3Sopenharmony_ci Ok(krate) => (krate, start.elapsed()), 78fad3a1d3Sopenharmony_ci Err(msg) => { 79fad3a1d3Sopenharmony_ci errorf!("=== {}: syn failed to parse\n{:?}\n", path.display(), msg); 80fad3a1d3Sopenharmony_ci let prev_failed = failed.fetch_add(1, Ordering::Relaxed); 81fad3a1d3Sopenharmony_ci if prev_failed + 1 >= abort_after { 82fad3a1d3Sopenharmony_ci process::exit(1); 83fad3a1d3Sopenharmony_ci } 84fad3a1d3Sopenharmony_ci return; 85fad3a1d3Sopenharmony_ci } 86fad3a1d3Sopenharmony_ci }; 87fad3a1d3Sopenharmony_ci let back = quote!(#krate).to_string(); 88fad3a1d3Sopenharmony_ci let edition = repo::edition(path).parse().unwrap(); 89fad3a1d3Sopenharmony_ci 90fad3a1d3Sopenharmony_ci rustc_span::create_session_if_not_set_then(edition, |_| { 91fad3a1d3Sopenharmony_ci let equal = match panic::catch_unwind(|| { 92fad3a1d3Sopenharmony_ci let locale_resources = rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(); 93fad3a1d3Sopenharmony_ci let file_path_mapping = FilePathMapping::empty(); 94fad3a1d3Sopenharmony_ci let sess = ParseSess::new(locale_resources, file_path_mapping); 95fad3a1d3Sopenharmony_ci let before = match librustc_parse(content, &sess) { 96fad3a1d3Sopenharmony_ci Ok(before) => before, 97fad3a1d3Sopenharmony_ci Err(diagnostic) => { 98fad3a1d3Sopenharmony_ci errorf!( 99fad3a1d3Sopenharmony_ci "=== {}: ignore - librustc failed to parse original content: {}\n", 100fad3a1d3Sopenharmony_ci path.display(), 101fad3a1d3Sopenharmony_ci translate_message(&diagnostic), 102fad3a1d3Sopenharmony_ci ); 103fad3a1d3Sopenharmony_ci diagnostic.cancel(); 104fad3a1d3Sopenharmony_ci return Err(true); 105fad3a1d3Sopenharmony_ci } 106fad3a1d3Sopenharmony_ci }; 107fad3a1d3Sopenharmony_ci let after = match librustc_parse(back, &sess) { 108fad3a1d3Sopenharmony_ci Ok(after) => after, 109fad3a1d3Sopenharmony_ci Err(mut diagnostic) => { 110fad3a1d3Sopenharmony_ci errorf!("=== {}: librustc failed to parse", path.display()); 111fad3a1d3Sopenharmony_ci diagnostic.emit(); 112fad3a1d3Sopenharmony_ci return Err(false); 113fad3a1d3Sopenharmony_ci } 114fad3a1d3Sopenharmony_ci }; 115fad3a1d3Sopenharmony_ci Ok((before, after)) 116fad3a1d3Sopenharmony_ci }) { 117fad3a1d3Sopenharmony_ci Err(_) => { 118fad3a1d3Sopenharmony_ci errorf!("=== {}: ignoring librustc panic\n", path.display()); 119fad3a1d3Sopenharmony_ci true 120fad3a1d3Sopenharmony_ci } 121fad3a1d3Sopenharmony_ci Ok(Err(equal)) => equal, 122fad3a1d3Sopenharmony_ci Ok(Ok((mut before, mut after))) => { 123fad3a1d3Sopenharmony_ci normalize(&mut before); 124fad3a1d3Sopenharmony_ci normalize(&mut after); 125fad3a1d3Sopenharmony_ci if SpanlessEq::eq(&before, &after) { 126fad3a1d3Sopenharmony_ci errorf!( 127fad3a1d3Sopenharmony_ci "=== {}: pass in {}ms\n", 128fad3a1d3Sopenharmony_ci path.display(), 129fad3a1d3Sopenharmony_ci elapsed.as_secs() * 1000 + u64::from(elapsed.subsec_nanos()) / 1_000_000 130fad3a1d3Sopenharmony_ci ); 131fad3a1d3Sopenharmony_ci true 132fad3a1d3Sopenharmony_ci } else { 133fad3a1d3Sopenharmony_ci errorf!( 134fad3a1d3Sopenharmony_ci "=== {}: FAIL\n{}\n!=\n{}\n", 135fad3a1d3Sopenharmony_ci path.display(), 136fad3a1d3Sopenharmony_ci pprust::crate_to_string_for_macros(&before), 137fad3a1d3Sopenharmony_ci pprust::crate_to_string_for_macros(&after), 138fad3a1d3Sopenharmony_ci ); 139fad3a1d3Sopenharmony_ci false 140fad3a1d3Sopenharmony_ci } 141fad3a1d3Sopenharmony_ci } 142fad3a1d3Sopenharmony_ci }; 143fad3a1d3Sopenharmony_ci if !equal { 144fad3a1d3Sopenharmony_ci let prev_failed = failed.fetch_add(1, Ordering::Relaxed); 145fad3a1d3Sopenharmony_ci if prev_failed + 1 >= abort_after { 146fad3a1d3Sopenharmony_ci process::exit(1); 147fad3a1d3Sopenharmony_ci } 148fad3a1d3Sopenharmony_ci } 149fad3a1d3Sopenharmony_ci }); 150fad3a1d3Sopenharmony_ci} 151fad3a1d3Sopenharmony_ci 152fad3a1d3Sopenharmony_cifn librustc_parse(content: String, sess: &ParseSess) -> PResult<Crate> { 153fad3a1d3Sopenharmony_ci static COUNTER: AtomicUsize = AtomicUsize::new(0); 154fad3a1d3Sopenharmony_ci let counter = COUNTER.fetch_add(1, Ordering::Relaxed); 155fad3a1d3Sopenharmony_ci let name = FileName::Custom(format!("test_round_trip{}", counter)); 156fad3a1d3Sopenharmony_ci parse::parse_crate_from_source_str(name, content, sess) 157fad3a1d3Sopenharmony_ci} 158fad3a1d3Sopenharmony_ci 159fad3a1d3Sopenharmony_cifn translate_message(diagnostic: &Diagnostic) -> Cow<'static, str> { 160fad3a1d3Sopenharmony_ci thread_local! { 161fad3a1d3Sopenharmony_ci static FLUENT_BUNDLE: LazyFallbackBundle = { 162fad3a1d3Sopenharmony_ci let locale_resources = rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(); 163fad3a1d3Sopenharmony_ci let with_directionality_markers = false; 164fad3a1d3Sopenharmony_ci rustc_error_messages::fallback_fluent_bundle(locale_resources, with_directionality_markers) 165fad3a1d3Sopenharmony_ci }; 166fad3a1d3Sopenharmony_ci } 167fad3a1d3Sopenharmony_ci 168fad3a1d3Sopenharmony_ci let message = &diagnostic.messages[0].0; 169fad3a1d3Sopenharmony_ci let args = translation::to_fluent_args(diagnostic.args()); 170fad3a1d3Sopenharmony_ci 171fad3a1d3Sopenharmony_ci let (identifier, attr) = match message { 172fad3a1d3Sopenharmony_ci DiagnosticMessage::Str(msg) | DiagnosticMessage::Eager(msg) => return msg.clone(), 173fad3a1d3Sopenharmony_ci DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr), 174fad3a1d3Sopenharmony_ci }; 175fad3a1d3Sopenharmony_ci 176fad3a1d3Sopenharmony_ci FLUENT_BUNDLE.with(|fluent_bundle| { 177fad3a1d3Sopenharmony_ci let message = fluent_bundle 178fad3a1d3Sopenharmony_ci .get_message(identifier) 179fad3a1d3Sopenharmony_ci .expect("missing diagnostic in fluent bundle"); 180fad3a1d3Sopenharmony_ci let value = match attr { 181fad3a1d3Sopenharmony_ci Some(attr) => message 182fad3a1d3Sopenharmony_ci .get_attribute(attr) 183fad3a1d3Sopenharmony_ci .expect("missing attribute in fluent message") 184fad3a1d3Sopenharmony_ci .value(), 185fad3a1d3Sopenharmony_ci None => message.value().expect("missing value in fluent message"), 186fad3a1d3Sopenharmony_ci }; 187fad3a1d3Sopenharmony_ci 188fad3a1d3Sopenharmony_ci let mut err = Vec::new(); 189fad3a1d3Sopenharmony_ci let translated = fluent_bundle.format_pattern(value, Some(&args), &mut err); 190fad3a1d3Sopenharmony_ci assert!(err.is_empty()); 191fad3a1d3Sopenharmony_ci Cow::Owned(translated.into_owned()) 192fad3a1d3Sopenharmony_ci }) 193fad3a1d3Sopenharmony_ci} 194fad3a1d3Sopenharmony_ci 195fad3a1d3Sopenharmony_cifn normalize(krate: &mut Crate) { 196fad3a1d3Sopenharmony_ci struct NormalizeVisitor; 197fad3a1d3Sopenharmony_ci 198fad3a1d3Sopenharmony_ci impl MutVisitor for NormalizeVisitor { 199fad3a1d3Sopenharmony_ci fn visit_angle_bracketed_parameter_data(&mut self, e: &mut AngleBracketedArgs) { 200fad3a1d3Sopenharmony_ci #[derive(Ord, PartialOrd, Eq, PartialEq)] 201fad3a1d3Sopenharmony_ci enum Group { 202fad3a1d3Sopenharmony_ci Lifetimes, 203fad3a1d3Sopenharmony_ci TypesAndConsts, 204fad3a1d3Sopenharmony_ci Constraints, 205fad3a1d3Sopenharmony_ci } 206fad3a1d3Sopenharmony_ci e.args.sort_by_key(|arg| match arg { 207fad3a1d3Sopenharmony_ci AngleBracketedArg::Arg(arg) => match arg { 208fad3a1d3Sopenharmony_ci GenericArg::Lifetime(_) => Group::Lifetimes, 209fad3a1d3Sopenharmony_ci GenericArg::Type(_) | GenericArg::Const(_) => Group::TypesAndConsts, 210fad3a1d3Sopenharmony_ci }, 211fad3a1d3Sopenharmony_ci AngleBracketedArg::Constraint(_) => Group::Constraints, 212fad3a1d3Sopenharmony_ci }); 213fad3a1d3Sopenharmony_ci mut_visit::noop_visit_angle_bracketed_parameter_data(e, self); 214fad3a1d3Sopenharmony_ci } 215fad3a1d3Sopenharmony_ci 216fad3a1d3Sopenharmony_ci fn visit_generics(&mut self, e: &mut Generics) { 217fad3a1d3Sopenharmony_ci #[derive(Ord, PartialOrd, Eq, PartialEq)] 218fad3a1d3Sopenharmony_ci enum Group { 219fad3a1d3Sopenharmony_ci Lifetimes, 220fad3a1d3Sopenharmony_ci TypesAndConsts, 221fad3a1d3Sopenharmony_ci } 222fad3a1d3Sopenharmony_ci e.params.sort_by_key(|param| match param.kind { 223fad3a1d3Sopenharmony_ci GenericParamKind::Lifetime => Group::Lifetimes, 224fad3a1d3Sopenharmony_ci GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { 225fad3a1d3Sopenharmony_ci Group::TypesAndConsts 226fad3a1d3Sopenharmony_ci } 227fad3a1d3Sopenharmony_ci }); 228fad3a1d3Sopenharmony_ci mut_visit::noop_visit_generics(e, self); 229fad3a1d3Sopenharmony_ci } 230fad3a1d3Sopenharmony_ci 231fad3a1d3Sopenharmony_ci fn visit_where_clause(&mut self, e: &mut WhereClause) { 232fad3a1d3Sopenharmony_ci if e.predicates.is_empty() { 233fad3a1d3Sopenharmony_ci e.has_where_token = false; 234fad3a1d3Sopenharmony_ci } 235fad3a1d3Sopenharmony_ci } 236fad3a1d3Sopenharmony_ci } 237fad3a1d3Sopenharmony_ci 238fad3a1d3Sopenharmony_ci NormalizeVisitor.visit_crate(krate); 239fad3a1d3Sopenharmony_ci} 240