]> git.proxmox.com Git - rustc.git/blobdiff - src/tools/rustfmt/src/emitter/diff.rs
Update upstream source from tag 'upstream/1.52.1+dfsg1'
[rustc.git] / src / tools / rustfmt / src / emitter / diff.rs
diff --git a/src/tools/rustfmt/src/emitter/diff.rs b/src/tools/rustfmt/src/emitter/diff.rs
new file mode 100644 (file)
index 0000000..9be4fb2
--- /dev/null
@@ -0,0 +1,138 @@
+use super::*;
+use crate::config::Config;
+use crate::rustfmt_diff::{make_diff, print_diff};
+
+pub(crate) struct DiffEmitter {
+    config: Config,
+}
+
+impl DiffEmitter {
+    pub(crate) fn new(config: Config) -> Self {
+        Self { config }
+    }
+}
+
+impl Emitter for DiffEmitter {
+    fn emit_formatted_file(
+        &mut self,
+        output: &mut dyn Write,
+        FormattedFile {
+            filename,
+            original_text,
+            formatted_text,
+        }: FormattedFile<'_>,
+    ) -> Result<EmitterResult, io::Error> {
+        const CONTEXT_SIZE: usize = 3;
+        let mismatch = make_diff(&original_text, formatted_text, CONTEXT_SIZE);
+        let has_diff = !mismatch.is_empty();
+
+        if has_diff {
+            if self.config.print_misformatted_file_names() {
+                writeln!(output, "{}", ensure_real_path(filename).display())?;
+            } else {
+                print_diff(
+                    mismatch,
+                    |line_num| format!("Diff in {} at line {}:", filename, line_num),
+                    &self.config,
+                );
+            }
+        } else if original_text != formatted_text {
+            // This occurs when the only difference between the original and formatted values
+            // is the newline style. This happens because The make_diff function compares the
+            // original and formatted values line by line, independent of line endings.
+            let file_path = ensure_real_path(filename);
+            writeln!(output, "Incorrect newline style in {}", file_path.display())?;
+            return Ok(EmitterResult { has_diff: true });
+        }
+
+        return Ok(EmitterResult { has_diff });
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::config::Config;
+    use crate::FileName;
+    use std::path::PathBuf;
+
+    #[test]
+    fn does_not_print_when_no_files_reformatted() {
+        let mut writer = Vec::new();
+        let config = Config::default();
+        let mut emitter = DiffEmitter::new(config);
+        let result = emitter
+            .emit_formatted_file(
+                &mut writer,
+                FormattedFile {
+                    filename: &FileName::Real(PathBuf::from("src/lib.rs")),
+                    original_text: "fn empty() {}\n",
+                    formatted_text: "fn empty() {}\n",
+                },
+            )
+            .unwrap();
+        assert_eq!(result.has_diff, false);
+        assert_eq!(writer.len(), 0);
+    }
+
+    #[test]
+    fn prints_file_names_when_config_is_enabled() {
+        let bin_file = "src/bin.rs";
+        let bin_original = "fn main() {\nprintln!(\"Hello, world!\");\n}";
+        let bin_formatted = "fn main() {\n    println!(\"Hello, world!\");\n}";
+        let lib_file = "src/lib.rs";
+        let lib_original = "fn greet() {\nprintln!(\"Greetings!\");\n}";
+        let lib_formatted = "fn greet() {\n    println!(\"Greetings!\");\n}";
+
+        let mut writer = Vec::new();
+        let mut config = Config::default();
+        config.set().print_misformatted_file_names(true);
+        let mut emitter = DiffEmitter::new(config);
+        let _ = emitter
+            .emit_formatted_file(
+                &mut writer,
+                FormattedFile {
+                    filename: &FileName::Real(PathBuf::from(bin_file)),
+                    original_text: bin_original,
+                    formatted_text: bin_formatted,
+                },
+            )
+            .unwrap();
+        let _ = emitter
+            .emit_formatted_file(
+                &mut writer,
+                FormattedFile {
+                    filename: &FileName::Real(PathBuf::from(lib_file)),
+                    original_text: lib_original,
+                    formatted_text: lib_formatted,
+                },
+            )
+            .unwrap();
+
+        assert_eq!(
+            String::from_utf8(writer).unwrap(),
+            format!("{}\n{}\n", bin_file, lib_file),
+        )
+    }
+
+    #[test]
+    fn prints_newline_message_with_only_newline_style_diff() {
+        let mut writer = Vec::new();
+        let config = Config::default();
+        let mut emitter = DiffEmitter::new(config);
+        let _ = emitter
+            .emit_formatted_file(
+                &mut writer,
+                FormattedFile {
+                    filename: &FileName::Real(PathBuf::from("src/lib.rs")),
+                    original_text: "fn empty() {}\n",
+                    formatted_text: "fn empty() {}\r\n",
+                },
+            )
+            .unwrap();
+        assert_eq!(
+            String::from_utf8(writer).unwrap(),
+            String::from("Incorrect newline style in src/lib.rs\n")
+        );
+    }
+}