]> git.lizzy.rs Git - rust.git/blobdiff - src/lib.rs
fix: don't force a newline after an empty where clause
[rust.git] / src / lib.rs
index efd88357088bafb6ca0404e468b17a89a456f1a0..753840e065c968ff496c3d6dfba141e1e6e578cd 100644 (file)
@@ -3,7 +3,6 @@
 
 #[macro_use]
 extern crate derive_new;
-#[cfg(test)]
 #[macro_use]
 extern crate lazy_static;
 #[macro_use]
 use std::path::PathBuf;
 use std::rc::Rc;
 
-use failure::Fail;
 use ignore;
-use syntax::{ast, parse::DirectoryOwnership};
+use rustc_ast::ast;
+use rustc_span::symbol;
+use thiserror::Error;
 
 use crate::comment::LineClasses;
+use crate::emitter::Emitter;
 use crate::formatting::{FormatErrorMap, FormattingError, ReportedErrors, SourceFile};
 use crate::issues::Issue;
+use crate::modules::ModuleResolutionError;
 use crate::shape::Indent;
+use crate::syntux::parser::DirectoryOwnership;
 use crate::utils::indent_next_line;
 
 pub use crate::config::{
 
 mod attr;
 mod chains;
-pub(crate) mod checkstyle;
 mod closures;
 mod comment;
 pub(crate) mod config;
+mod coverage;
+mod emitter;
 mod expr;
 mod format_report_formatter;
 pub(crate) mod formatting;
 mod overflow;
 mod pairs;
 mod patterns;
+mod release_channel;
 mod reorder;
 mod rewrite;
 pub(crate) mod rustfmt_diff;
 mod shape;
+mod skip;
 pub(crate) mod source_file;
 pub(crate) mod source_map;
 mod spanned;
+mod stmt;
 mod string;
+mod syntux;
 #[cfg(test)]
 mod test;
 mod types;
 
 /// The various errors that can occur during formatting. Note that not all of
 /// these can currently be propagated to clients.
-#[derive(Fail, Debug)]
+#[derive(Error, Debug)]
 pub enum ErrorKind {
     /// Line has exceeded character limit (found, maximum).
-    #[fail(
-        display = "line formatted, but exceeded maximum width \
-                   (maximum: {} (see `max_width` option), found: {})",
-        _1, _0
+    #[error(
+        "line formatted, but exceeded maximum width \
+         (maximum: {1} (see `max_width` option), found: {0})"
     )]
     LineOverflow(usize, usize),
     /// Line ends in whitespace.
-    #[fail(display = "left behind trailing whitespace")]
+    #[error("left behind trailing whitespace")]
     TrailingWhitespace,
     /// TODO or FIXME item without an issue number.
-    #[fail(display = "found {}", _0)]
+    #[error("found {0}")]
     BadIssue(Issue),
     /// License check has failed.
-    #[fail(display = "license check failed")]
+    #[error("license check failed")]
     LicenseCheck,
     /// Used deprecated skip attribute.
-    #[fail(display = "`rustfmt_skip` is deprecated; use `rustfmt::skip`")]
+    #[error("`rustfmt_skip` is deprecated; use `rustfmt::skip`")]
     DeprecatedAttr,
     /// Used a rustfmt:: attribute other than skip or skip::macros.
-    #[fail(display = "invalid attribute")]
+    #[error("invalid attribute")]
     BadAttr,
     /// An io error during reading or writing.
-    #[fail(display = "io error: {}", _0)]
+    #[error("io error: {0}")]
     IoError(io::Error),
+    /// Error during module resolution.
+    #[error("{0}")]
+    ModuleResolutionError(#[from] ModuleResolutionError),
     /// Parse error occurred when parsing the input.
-    #[fail(display = "parse error")]
+    #[error("parse error")]
     ParseError,
     /// The user mandated a version and the current version of Rustfmt does not
     /// satisfy that requirement.
-    #[fail(display = "version mismatch")]
+    #[error("version mismatch")]
     VersionMismatch,
     /// If we had formatted the given node, then we would have lost a comment.
-    #[fail(display = "not formatted because a comment would be lost")]
+    #[error("not formatted because a comment would be lost")]
     LostComment,
     /// Invalid glob pattern in `ignore` configuration option.
-    #[fail(display = "Invalid glob pattern found in ignore list: {}", _0)]
+    #[error("Invalid glob pattern found in ignore list: {0}")]
     InvalidGlobPattern(ignore::Error),
 }
 
@@ -263,7 +273,9 @@ pub fn fancy_print(
     }
 }
 
-#[deprecated(note = "Use FormatReportFormatter instead")]
+/// Deprecated - Use FormatReportFormatter instead
+// https://github.com/rust-lang/rust/issues/78625
+// https://github.com/rust-lang/rust/issues/39935
 impl fmt::Display for FormatReport {
     // Prints all the formatting errors.
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
@@ -274,7 +286,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
 
 /// Format the given snippet. The snippet is expected to be *complete* code.
 /// When we cannot parse the given snippet, this function returns `None`.
-fn format_snippet(snippet: &str, config: &Config) -> Option<FormattedSnippet> {
+fn format_snippet(snippet: &str, config: &Config, is_macro_def: bool) -> Option<FormattedSnippet> {
     let mut config = config.clone();
     panic::catch_unwind(|| {
         let mut out: Vec<u8> = Vec::with_capacity(snippet.len() * 2);
@@ -285,7 +297,7 @@ fn format_snippet(snippet: &str, config: &Config) -> Option<FormattedSnippet> {
         let (formatting_error, result) = {
             let input = Input::Text(snippet.into());
             let mut session = Session::new(config, Some(&mut out));
-            let result = session.format(input);
+            let result = session.format_input_inner(input, is_macro_def);
             (
                 session.errors.has_macro_format_failure
                     || session.out.as_ref().unwrap().is_empty() && !snippet.is_empty()
@@ -311,7 +323,11 @@ fn format_snippet(snippet: &str, config: &Config) -> Option<FormattedSnippet> {
 /// The code block may be incomplete (i.e., parser may be unable to parse it).
 /// To avoid panic in parser, we wrap the code block with a dummy function.
 /// The returned code block does **not** end with newline.
-fn format_code_block(code_snippet: &str, config: &Config) -> Option<FormattedSnippet> {
+fn format_code_block(
+    code_snippet: &str,
+    config: &Config,
+    is_macro_def: bool,
+) -> Option<FormattedSnippet> {
     const FN_MAIN_PREFIX: &str = "fn main() {\n";
 
     fn enclose_in_main_block(s: &str, config: &Config) -> String {
@@ -344,7 +360,7 @@ fn enclose_in_main_block(s: &str, config: &Config) -> String {
     config_with_unix_newline
         .set()
         .newline_style(NewlineStyle::Unix);
-    let mut formatted = format_snippet(&snippet, &config_with_unix_newline)?;
+    let mut formatted = format_snippet(&snippet, &config_with_unix_newline, is_macro_def)?;
     // Remove wrapping main block
     formatted.unwrap_code_block();
 
@@ -400,17 +416,21 @@ pub struct Session<'b, T: Write> {
     pub out: Option<&'b mut T>,
     pub(crate) errors: ReportedErrors,
     source_file: SourceFile,
+    emitter: Box<dyn Emitter + 'b>,
 }
 
 impl<'b, T: Write + 'b> Session<'b, T> {
-    pub fn new(config: Config, out: Option<&'b mut T>) -> Session<'b, T> {
-        if config.emit_mode() == EmitMode::Checkstyle {
-            println!("{}", checkstyle::header());
+    pub fn new(config: Config, mut out: Option<&'b mut T>) -> Session<'b, T> {
+        let emitter = create_emitter(&config);
+
+        if let Some(ref mut out) = out {
+            let _ = emitter.emit_header(out);
         }
 
         Session {
             config,
             out,
+            emitter,
             errors: ReportedErrors::default(),
             source_file: SourceFile::new(),
         }
@@ -419,7 +439,7 @@ pub fn new(config: Config, out: Option<&'b mut T>) -> Session<'b, T> {
     /// The main entry point for Rustfmt. Formats the given input according to the
     /// given config. `out` is only necessary if required by the configuration.
     pub fn format(&mut self, input: Input) -> Result<FormatReport, ErrorKind> {
-        self.format_input_inner(input)
+        self.format_input_inner(input, false)
     }
 
     pub fn override_config<F, U>(&mut self, mut config: Config, f: F) -> U
@@ -466,10 +486,28 @@ pub fn has_no_errors(&self) -> bool {
     }
 }
 
+pub(crate) fn create_emitter<'a>(config: &Config) -> Box<dyn Emitter + 'a> {
+    match config.emit_mode() {
+        EmitMode::Files if config.make_backup() => {
+            Box::new(emitter::FilesWithBackupEmitter::default())
+        }
+        EmitMode::Files => Box::new(emitter::FilesEmitter::new(
+            config.print_misformatted_file_names(),
+        )),
+        EmitMode::Stdout | EmitMode::Coverage => {
+            Box::new(emitter::StdoutEmitter::new(config.verbose()))
+        }
+        EmitMode::Json => Box::new(emitter::JsonEmitter::default()),
+        EmitMode::ModifiedLines => Box::new(emitter::ModifiedLinesEmitter::default()),
+        EmitMode::Checkstyle => Box::new(emitter::CheckstyleEmitter::default()),
+        EmitMode::Diff => Box::new(emitter::DiffEmitter::new(config.clone())),
+    }
+}
+
 impl<'b, T: Write + 'b> Drop for Session<'b, T> {
     fn drop(&mut self) {
-        if self.config.emit_mode() == EmitMode::Checkstyle {
-            println!("{}", checkstyle::footer());
+        if let Some(ref mut out) = self.out {
+            let _ = self.emitter.emit_footer(out);
         }
     }
 }
@@ -481,13 +519,6 @@ pub enum Input {
 }
 
 impl Input {
-    fn is_text(&self) -> bool {
-        match *self {
-            Input::File(_) => false,
-            Input::Text(_) => true,
-        }
-    }
-
     fn file_name(&self) -> FileName {
         match *self {
             Input::File(ref file) => FileName::Real(file.clone()),
@@ -503,7 +534,7 @@ fn to_directory_ownership(&self) -> Option<DirectoryOwnership> {
                 let file_stem = file.file_stem()?;
                 if file.parent()?.to_path_buf().join(file_stem).is_dir() {
                     Some(DirectoryOwnership::Owned {
-                        relative: file_stem.to_str().map(ast::Ident::from_str),
+                        relative: file_stem.to_str().map(symbol::Ident::from_str),
                     })
                 } else {
                     None
@@ -523,15 +554,15 @@ fn test_no_panic_on_format_snippet_and_format_code_block() {
         // `format_snippet()` and `format_code_block()` should not panic
         // even when we cannot parse the given snippet.
         let snippet = "let";
-        assert!(format_snippet(snippet, &Config::default()).is_none());
-        assert!(format_code_block(snippet, &Config::default()).is_none());
+        assert!(format_snippet(snippet, &Config::default(), false).is_none());
+        assert!(format_code_block(snippet, &Config::default(), false).is_none());
     }
 
     fn test_format_inner<F>(formatter: F, input: &str, expected: &str) -> bool
     where
-        F: Fn(&str, &Config) -> Option<FormattedSnippet>,
+        F: Fn(&str, &Config, bool) -> Option<FormattedSnippet>,
     {
-        let output = formatter(input, &Config::default());
+        let output = formatter(input, &Config::default(), false);
         output.is_some() && output.unwrap().snippet == expected
     }
 
@@ -553,7 +584,7 @@ fn test_format_snippet() {
     fn test_format_code_block_fail() {
         #[rustfmt::skip]
         let code_block = "this_line_is_100_characters_long_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(x, y, z);";
-        assert!(format_code_block(code_block, &Config::default()).is_none());
+        assert!(format_code_block(code_block, &Config::default(), false).is_none());
     }
 
     #[test]