about summary refs log tree commit diff
path: root/src/formatting.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/formatting.rs')
-rw-r--r--src/formatting.rs458
1 files changed, 39 insertions, 419 deletions
diff --git a/src/formatting.rs b/src/formatting.rs
index bed87748253..104e631f441 100644
--- a/src/formatting.rs
+++ b/src/formatting.rs
@@ -1,29 +1,20 @@
 // High level formatting functions.
 
-use std::cell::RefCell;
 use std::collections::HashMap;
 use std::io::{self, Write};
-use std::panic::{catch_unwind, AssertUnwindSafe};
-use std::rc::Rc;
 use std::time::{Duration, Instant};
 
-use rustc_data_structures::sync::{Lrc, Send};
-use rustc_errors::emitter::{Emitter, EmitterWriter};
-use rustc_errors::{ColorConfig, Diagnostic, DiagnosticBuilder, Handler, Level as DiagnosticLevel};
-use rustc_session::parse::ParseSess;
-use rustc_span::{
-    source_map::{FilePathMapping, SourceMap},
-    Span, DUMMY_SP,
-};
+use rustc_span::Span;
 use syntax::ast;
 
 use self::newline_style::apply_newline_style;
 use crate::comment::{CharClasses, FullCodeCharKind};
 use crate::config::{Config, FileName, Verbosity};
-use crate::ignore_path::IgnorePathSet;
 use crate::issues::BadIssueSeeker;
+use crate::syntux::parser::{DirectoryOwnership, Parser, ParserError};
+use crate::syntux::session::ParseSess;
 use crate::utils::count_newlines;
-use crate::visitor::{FmtVisitor, SnippetProvider};
+use crate::visitor::FmtVisitor;
 use crate::{modules, source_file, ErrorKind, FormatReport, Input, Session};
 
 mod newline_style;
@@ -71,54 +62,41 @@ fn format_project<T: FormatHandler>(
     let main_file = input.file_name();
     let input_is_stdin = main_file == FileName::Stdin;
 
-    let ignore_path_set = match IgnorePathSet::from_ignore_list(&config.ignore()) {
-        Ok(set) => Rc::new(set),
-        Err(e) => return Err(ErrorKind::InvalidGlobPattern(e)),
-    };
-    if config.skip_children() && ignore_path_set.is_match(&main_file) {
+    let mut parse_session = ParseSess::new(config)?;
+    if config.skip_children() && parse_session.ignore_file(&main_file) {
         return Ok(FormatReport::new());
     }
 
     // Parse the crate.
-    let can_reset_parser_errors = Rc::new(RefCell::new(false));
-    let source_map = Rc::new(SourceMap::new(FilePathMapping::empty()));
-    let mut parse_session = make_parse_sess(
-        source_map.clone(),
-        config,
-        Rc::clone(&ignore_path_set),
-        can_reset_parser_errors.clone(),
-    );
     let mut report = FormatReport::new();
     let directory_ownership = input.to_directory_ownership();
-    let krate = match parse_crate(
-        input,
-        &parse_session,
-        config,
-        &mut report,
-        directory_ownership,
-        can_reset_parser_errors.clone(),
-    ) {
+    let krate = match Parser::parse_crate(config, input, directory_ownership, &parse_session) {
         Ok(krate) => krate,
         // Surface parse error via Session (errors are merged there from report)
-        Err(ErrorKind::ParseError) => return Ok(report),
-        Err(e) => return Err(e),
+        Err(e) => {
+            let forbid_verbose = input_is_stdin || e != ParserError::ParsePanicError;
+            should_emit_verbose(forbid_verbose, config, || {
+                eprintln!("The Rust parser panicked");
+            });
+            report.add_parsing_error();
+            return Ok(report);
+        }
     };
     timer = timer.done_parsing();
 
     // Suppress error output if we have to do any further parsing.
-    let silent_emitter = silent_emitter();
-    parse_session.span_diagnostic = Handler::with_emitter(true, None, silent_emitter);
+    parse_session.set_silent_emitter();
 
     let mut context = FormatContext::new(&krate, report, parse_session, config, handler);
     let files = modules::ModResolver::new(
         &context.parse_session,
-        directory_ownership.unwrap_or(rustc_parse::DirectoryOwnership::UnownedViaMod),
+        directory_ownership.unwrap_or(DirectoryOwnership::UnownedViaMod),
         !(input_is_stdin || config.skip_children()),
     )
     .visit_crate(&krate)
     .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
     for (path, module) in files {
-        let should_ignore = !input_is_stdin && ignore_path_set.is_match(&path);
+        let should_ignore = !input_is_stdin && context.ignore_file(&path);
         if (config.skip_children() && path != main_file) || should_ignore {
             continue;
         }
@@ -150,6 +128,10 @@ struct FormatContext<'a, T: FormatHandler> {
 }
 
 impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> {
+    fn ignore_file(&self, path: &FileName) -> bool {
+        self.parse_session.ignore_file(path)
+    }
+
     // Formats a single file/module.
     fn format_file(
         &mut self,
@@ -157,15 +139,8 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> {
         module: &ast::Mod,
         is_root: bool,
     ) -> Result<(), ErrorKind> {
-        let source_file = self
-            .parse_session
-            .source_map()
-            .lookup_char_pos(module.inner.lo())
-            .file;
-        let big_snippet = source_file.src.as_ref().unwrap();
-        let snippet_provider =
-            SnippetProvider::new(source_file.start_pos, source_file.end_pos, big_snippet);
-        let mut visitor = FmtVisitor::from_source_map(
+        let snippet_provider = self.parse_session.snippet_provider(module.inner);
+        let mut visitor = FmtVisitor::from_parse_sess(
             &self.parse_session,
             &self.config,
             &snippet_provider,
@@ -175,16 +150,16 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> {
 
         // Format inner attributes if available.
         if !self.krate.attrs.is_empty() && is_root {
-            visitor.skip_empty_lines(source_file.end_pos);
+            visitor.skip_empty_lines(snippet_provider.end_pos());
             if visitor.visit_attrs(&self.krate.attrs, ast::AttrStyle::Inner) {
                 visitor.push_rewrite(module.inner, None);
             } else {
-                visitor.format_separate_mod(module, &*source_file);
+                visitor.format_separate_mod(module, snippet_provider.end_pos());
             }
         } else {
-            visitor.last_pos = source_file.start_pos;
-            visitor.skip_empty_lines(source_file.end_pos);
-            visitor.format_separate_mod(module, &*source_file);
+            visitor.last_pos = snippet_provider.start_pos();
+            visitor.skip_empty_lines(snippet_provider.end_pos());
+            visitor.format_separate_mod(module, snippet_provider.end_pos());
         };
 
         debug_assert_eq!(
@@ -209,7 +184,7 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> {
         apply_newline_style(
             self.config.newline_style(),
             &mut visitor.buffer,
-            &big_snippet,
+            snippet_provider.entire_snippet(),
         );
 
         if visitor.macro_rewrite_failure {
@@ -219,7 +194,7 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> {
             .add_non_formatted_ranges(visitor.skipped_range.borrow().clone());
 
         self.handler.handle_formatted_file(
-            self.parse_session.source_map(),
+            &self.parse_session,
             path,
             visitor.buffer.to_owned(),
             &mut self.report,
@@ -231,7 +206,7 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> {
 trait FormatHandler {
     fn handle_formatted_file(
         &mut self,
-        source_map: &SourceMap,
+        parse_session: &ParseSess,
         path: FileName,
         result: String,
         report: &mut FormatReport,
@@ -242,14 +217,14 @@ impl<'b, T: Write + 'b> FormatHandler for Session<'b, T> {
     // Called for each formatted file.
     fn handle_formatted_file(
         &mut self,
-        source_map: &SourceMap,
+        parse_session: &ParseSess,
         path: FileName,
         result: String,
         report: &mut FormatReport,
     ) -> Result<(), ErrorKind> {
         if let Some(ref mut out) = self.out {
             match source_file::write_file(
-                Some(source_map),
+                Some(parse_session),
                 &path,
                 &result,
                 out,
@@ -282,23 +257,15 @@ pub(crate) struct FormattingError {
 impl FormattingError {
     pub(crate) fn from_span(
         span: Span,
-        source_map: &SourceMap,
+        parse_sess: &ParseSess,
         kind: ErrorKind,
     ) -> FormattingError {
         FormattingError {
-            line: source_map.lookup_char_pos(span.lo()).line,
+            line: parse_sess.line_of_byte_pos(span.lo()),
             is_comment: kind.is_comment(),
             kind,
             is_string: false,
-            line_buffer: source_map
-                .span_to_lines(span)
-                .ok()
-                .and_then(|fl| {
-                    fl.file
-                        .get_line(fl.lines[0].line_index)
-                        .map(std::borrow::Cow::into_owned)
-                })
-                .unwrap_or_else(String::new),
+            line_buffer: parse_sess.span_to_first_line_string(span),
         }
     }
 
@@ -633,358 +600,11 @@ impl<'a> FormatLines<'a> {
     }
 }
 
-fn parse_crate(
-    input: Input,
-    parse_session: &ParseSess,
-    config: &Config,
-    report: &mut FormatReport,
-    directory_ownership: Option<rustc_parse::DirectoryOwnership>,
-    can_reset_parser_errors: Rc<RefCell<bool>>,
-) -> Result<ast::Crate, ErrorKind> {
-    let input_is_stdin = input.is_text();
-
-    let parser = match input {
-        Input::File(ref file) => {
-            // Use `new_sub_parser_from_file` when we the input is a submodule.
-            Ok(if let Some(dir_own) = directory_ownership {
-                rustc_parse::new_sub_parser_from_file(parse_session, file, dir_own, None, DUMMY_SP)
-            } else {
-                rustc_parse::new_parser_from_file(parse_session, file)
-            })
-        }
-        Input::Text(text) => rustc_parse::maybe_new_parser_from_source_str(
-            parse_session,
-            rustc_span::FileName::Custom("stdin".to_owned()),
-            text,
-        )
-        .map(|mut parser| {
-            parser.recurse_into_file_modules = false;
-            parser
-        }),
-    };
-
-    let result = match parser {
-        Ok(mut parser) => {
-            parser.cfg_mods = false;
-            if config.skip_children() {
-                parser.recurse_into_file_modules = false;
-            }
-
-            let mut parser = AssertUnwindSafe(parser);
-            catch_unwind(move || parser.0.parse_crate_mod().map_err(|d| vec![d]))
-        }
-        Err(diagnostics) => {
-            for diagnostic in diagnostics {
-                parse_session.span_diagnostic.emit_diagnostic(&diagnostic);
-            }
-            report.add_parsing_error();
-            return Err(ErrorKind::ParseError);
-        }
-    };
-
-    match result {
-        Ok(Ok(c)) => {
-            if !parse_session.span_diagnostic.has_errors() {
-                return Ok(c);
-            }
-            // This scenario occurs when the parser encountered errors
-            // but was still able to recover. If all of the parser errors
-            // occurred in files that are ignored, then reset
-            // the error count and continue.
-            // https://github.com/rust-lang/rustfmt/issues/3779
-            if *can_reset_parser_errors.borrow() {
-                parse_session.span_diagnostic.reset_err_count();
-                return Ok(c);
-            }
-        }
-        Ok(Err(mut diagnostics)) => diagnostics.iter_mut().for_each(DiagnosticBuilder::emit),
-        Err(_) => {
-            // Note that if you see this message and want more information,
-            // then run the `parse_crate_mod` function above without
-            // `catch_unwind` so rustfmt panics and you can get a backtrace.
-            should_emit_verbose(input_is_stdin, config, || {
-                println!("The Rust parser panicked")
-            });
-        }
-    }
-
-    report.add_parsing_error();
-    Err(ErrorKind::ParseError)
-}
-
-struct SilentOnIgnoredFilesEmitter {
-    ignore_path_set: Rc<IgnorePathSet>,
-    source_map: Rc<SourceMap>,
-    emitter: Box<dyn Emitter + Send>,
-    has_non_ignorable_parser_errors: bool,
-    can_reset: Rc<RefCell<bool>>,
-}
-
-impl SilentOnIgnoredFilesEmitter {
-    fn handle_non_ignoreable_error(&mut self, db: &Diagnostic) {
-        self.has_non_ignorable_parser_errors = true;
-        *self.can_reset.borrow_mut() = false;
-        self.emitter.emit_diagnostic(db);
-    }
-}
-
-impl Emitter for SilentOnIgnoredFilesEmitter {
-    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
-        None
-    }
-
-    fn emit_diagnostic(&mut self, db: &Diagnostic) {
-        if db.level == DiagnosticLevel::Fatal {
-            return self.handle_non_ignoreable_error(db);
-        }
-        if let Some(primary_span) = &db.span.primary_span() {
-            let file_name = self.source_map.span_to_filename(*primary_span);
-            if let rustc_span::FileName::Real(ref path) = file_name {
-                if self
-                    .ignore_path_set
-                    .is_match(&FileName::Real(path.to_path_buf()))
-                {
-                    if !self.has_non_ignorable_parser_errors {
-                        *self.can_reset.borrow_mut() = true;
-                    }
-                    return;
-                }
-            };
-        }
-        self.handle_non_ignoreable_error(db);
-    }
-}
-
-/// Emitter which discards every error.
-struct SilentEmitter;
-
-impl Emitter for SilentEmitter {
-    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
-        None
-    }
-    fn emit_diagnostic(&mut self, _db: &Diagnostic) {}
-}
-
-fn silent_emitter() -> Box<dyn Emitter + Send> {
-    Box::new(SilentEmitter {})
-}
-
-fn make_parse_sess(
-    source_map: Rc<SourceMap>,
-    config: &Config,
-    ignore_path_set: Rc<IgnorePathSet>,
-    can_reset: Rc<RefCell<bool>>,
-) -> ParseSess {
-    let supports_color = term::stderr().map_or(false, |term| term.supports_color());
-    let color_cfg = if supports_color {
-        ColorConfig::Auto
-    } else {
-        ColorConfig::Never
-    };
-
-    let emitter = if config.hide_parse_errors() {
-        silent_emitter()
-    } else {
-        Box::new(EmitterWriter::stderr(
-            color_cfg,
-            Some(source_map.clone()),
-            false,
-            false,
-            None,
-            false,
-        ))
-    };
-    let handler = Handler::with_emitter(
-        true,
-        None,
-        Box::new(SilentOnIgnoredFilesEmitter {
-            has_non_ignorable_parser_errors: false,
-            source_map: source_map.clone(),
-            emitter,
-            ignore_path_set,
-            can_reset,
-        }),
-    );
-
-    ParseSess::with_span_handler(handler, source_map)
-}
-
-fn should_emit_verbose<F>(is_stdin: bool, config: &Config, f: F)
+fn should_emit_verbose<F>(forbid_verbose_output: bool, config: &Config, f: F)
 where
     F: Fn(),
 {
-    if config.verbose() == Verbosity::Verbose && !is_stdin {
+    if config.verbose() == Verbosity::Verbose && !forbid_verbose_output {
         f();
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    mod emitter {
-        use super::*;
-        use crate::config::IgnoreList;
-        use crate::is_nightly_channel;
-        use crate::utils::mk_sp;
-        use rustc_span::{BytePos, FileName as SourceMapFileName, MultiSpan, DUMMY_SP};
-        use std::path::{Path, PathBuf};
-
-        struct TestEmitter {
-            num_emitted_errors: Rc<RefCell<u32>>,
-        }
-
-        impl Emitter for TestEmitter {
-            fn source_map(&self) -> Option<&Lrc<SourceMap>> {
-                None
-            }
-            fn emit_diagnostic(&mut self, _db: &Diagnostic) {
-                *self.num_emitted_errors.borrow_mut() += 1;
-            }
-        }
-
-        fn build_diagnostic(level: DiagnosticLevel, span: Option<MultiSpan>) -> Diagnostic {
-            Diagnostic {
-                level,
-                code: None,
-                message: vec![],
-                children: vec![],
-                suggestions: vec![],
-                span: span.unwrap_or_else(MultiSpan::new),
-                sort_span: DUMMY_SP,
-            }
-        }
-
-        fn build_emitter(
-            num_emitted_errors: Rc<RefCell<u32>>,
-            can_reset: Rc<RefCell<bool>>,
-            source_map: Option<Rc<SourceMap>>,
-            ignore_list: Option<IgnoreList>,
-        ) -> SilentOnIgnoredFilesEmitter {
-            let emitter_writer = TestEmitter { num_emitted_errors };
-            let source_map =
-                source_map.unwrap_or_else(|| Rc::new(SourceMap::new(FilePathMapping::empty())));
-            let ignore_path_set =
-                Rc::new(IgnorePathSet::from_ignore_list(&ignore_list.unwrap_or_default()).unwrap());
-            SilentOnIgnoredFilesEmitter {
-                has_non_ignorable_parser_errors: false,
-                source_map,
-                emitter: Box::new(emitter_writer),
-                ignore_path_set,
-                can_reset,
-            }
-        }
-
-        fn get_ignore_list(config: &str) -> IgnoreList {
-            Config::from_toml(config, Path::new("")).unwrap().ignore()
-        }
-
-        #[test]
-        fn handles_fatal_parse_error_in_ignored_file() {
-            let num_emitted_errors = Rc::new(RefCell::new(0));
-            let can_reset_errors = Rc::new(RefCell::new(false));
-            let ignore_list = get_ignore_list(r#"ignore = ["foo.rs"]"#);
-            let source_map = Rc::new(SourceMap::new(FilePathMapping::empty()));
-            let source =
-                String::from(r#"extern "system" fn jni_symbol!( funcName ) ( ... ) -> {} "#);
-            source_map.new_source_file(SourceMapFileName::Real(PathBuf::from("foo.rs")), source);
-            let mut emitter = build_emitter(
-                Rc::clone(&num_emitted_errors),
-                Rc::clone(&can_reset_errors),
-                Some(Rc::clone(&source_map)),
-                Some(ignore_list),
-            );
-            let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
-            let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, Some(span));
-            emitter.emit_diagnostic(&fatal_diagnostic);
-            assert_eq!(*num_emitted_errors.borrow(), 1);
-            assert_eq!(*can_reset_errors.borrow(), false);
-        }
-
-        #[test]
-        fn handles_recoverable_parse_error_in_ignored_file() {
-            if !is_nightly_channel!() {
-                return;
-            }
-            let num_emitted_errors = Rc::new(RefCell::new(0));
-            let can_reset_errors = Rc::new(RefCell::new(false));
-            let ignore_list = get_ignore_list(r#"ignore = ["foo.rs"]"#);
-            let source_map = Rc::new(SourceMap::new(FilePathMapping::empty()));
-            let source = String::from(r#"pub fn bar() { 1x; }"#);
-            source_map.new_source_file(SourceMapFileName::Real(PathBuf::from("foo.rs")), source);
-            let mut emitter = build_emitter(
-                Rc::clone(&num_emitted_errors),
-                Rc::clone(&can_reset_errors),
-                Some(Rc::clone(&source_map)),
-                Some(ignore_list),
-            );
-            let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
-            let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span));
-            emitter.emit_diagnostic(&non_fatal_diagnostic);
-            assert_eq!(*num_emitted_errors.borrow(), 0);
-            assert_eq!(*can_reset_errors.borrow(), true);
-        }
-
-        #[test]
-        fn handles_recoverable_parse_error_in_non_ignored_file() {
-            if !is_nightly_channel!() {
-                return;
-            }
-            let num_emitted_errors = Rc::new(RefCell::new(0));
-            let can_reset_errors = Rc::new(RefCell::new(false));
-            let source_map = Rc::new(SourceMap::new(FilePathMapping::empty()));
-            let source = String::from(r#"pub fn bar() { 1x; }"#);
-            source_map.new_source_file(SourceMapFileName::Real(PathBuf::from("foo.rs")), source);
-            let mut emitter = build_emitter(
-                Rc::clone(&num_emitted_errors),
-                Rc::clone(&can_reset_errors),
-                Some(Rc::clone(&source_map)),
-                None,
-            );
-            let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
-            let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span));
-            emitter.emit_diagnostic(&non_fatal_diagnostic);
-            assert_eq!(*num_emitted_errors.borrow(), 1);
-            assert_eq!(*can_reset_errors.borrow(), false);
-        }
-
-        #[test]
-        fn handles_mix_of_recoverable_parse_error() {
-            if !is_nightly_channel!() {
-                return;
-            }
-            let num_emitted_errors = Rc::new(RefCell::new(0));
-            let can_reset_errors = Rc::new(RefCell::new(false));
-            let source_map = Rc::new(SourceMap::new(FilePathMapping::empty()));
-            let ignore_list = get_ignore_list(r#"ignore = ["foo.rs"]"#);
-            let bar_source = String::from(r#"pub fn bar() { 1x; }"#);
-            let foo_source = String::from(r#"pub fn foo() { 1x; }"#);
-            let fatal_source =
-                String::from(r#"extern "system" fn jni_symbol!( funcName ) ( ... ) -> {} "#);
-            source_map
-                .new_source_file(SourceMapFileName::Real(PathBuf::from("bar.rs")), bar_source);
-            source_map
-                .new_source_file(SourceMapFileName::Real(PathBuf::from("foo.rs")), foo_source);
-            source_map.new_source_file(
-                SourceMapFileName::Real(PathBuf::from("fatal.rs")),
-                fatal_source,
-            );
-            let mut emitter = build_emitter(
-                Rc::clone(&num_emitted_errors),
-                Rc::clone(&can_reset_errors),
-                Some(Rc::clone(&source_map)),
-                Some(ignore_list),
-            );
-            let bar_span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
-            let foo_span = MultiSpan::from_span(mk_sp(BytePos(21), BytePos(22)));
-            let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(bar_span));
-            let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(foo_span));
-            let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, None);
-            emitter.emit_diagnostic(&bar_diagnostic);
-            emitter.emit_diagnostic(&foo_diagnostic);
-            emitter.emit_diagnostic(&fatal_diagnostic);
-            assert_eq!(*num_emitted_errors.borrow(), 2);
-            assert_eq!(*can_reset_errors.borrow(), false);
-        }
-    }
-}