]> git.lizzy.rs Git - rust.git/blob - src/source_file.rs
Enable unreachable_pub lint
[rust.git] / src / source_file.rs
1 use std::fs;
2 use std::io::{self, Write};
3 use std::path::Path;
4
5 use syntax::source_map::SourceMap;
6
7 use crate::checkstyle::output_checkstyle_file;
8 use crate::config::{Config, EmitMode, FileName, Verbosity};
9 use crate::rustfmt_diff::{make_diff, print_diff, ModifiedLines};
10
11 #[cfg(test)]
12 use crate::formatting::FileRecord;
13
14 // Append a newline to the end of each file.
15 pub(crate) fn append_newline(s: &mut String) {
16     s.push_str("\n");
17 }
18
19 #[cfg(test)]
20 pub(crate) fn write_all_files<T>(
21     source_file: &[FileRecord],
22     out: &mut T,
23     config: &Config,
24 ) -> Result<(), io::Error>
25 where
26     T: Write,
27 {
28     if config.emit_mode() == EmitMode::Checkstyle {
29         write!(out, "{}", crate::checkstyle::header())?;
30     }
31     for &(ref filename, ref text) in source_file {
32         write_file(None, filename, text, out, config)?;
33     }
34     if config.emit_mode() == EmitMode::Checkstyle {
35         write!(out, "{}", crate::checkstyle::footer())?;
36     }
37
38     Ok(())
39 }
40
41 pub(crate) fn write_file<T>(
42     source_map: Option<&SourceMap>,
43     filename: &FileName,
44     formatted_text: &str,
45     out: &mut T,
46     config: &Config,
47 ) -> Result<bool, io::Error>
48 where
49     T: Write,
50 {
51     fn ensure_real_path(filename: &FileName) -> &Path {
52         match *filename {
53             FileName::Real(ref path) => path,
54             _ => panic!("cannot format `{}` and emit to files", filename),
55         }
56     }
57
58     impl From<&FileName> for syntax_pos::FileName {
59         fn from(filename: &FileName) -> syntax_pos::FileName {
60             match filename {
61                 FileName::Real(path) => syntax_pos::FileName::Real(path.to_owned()),
62                 FileName::Stdin => syntax_pos::FileName::Custom("stdin".to_owned()),
63             }
64         }
65     }
66
67     // If parse session is around (cfg(not(test))) then try getting source from
68     // there instead of hitting the file system. This also supports getting
69     // original text for `FileName::Stdin`.
70     let original_text = source_map
71         .and_then(|x| x.get_source_file(&filename.into()))
72         .and_then(|x| x.src.as_ref().map(ToString::to_string));
73     let original_text = match original_text {
74         Some(ori) => ori,
75         None => fs::read_to_string(ensure_real_path(filename))?,
76     };
77
78     match config.emit_mode() {
79         EmitMode::Files if config.make_backup() => {
80             let filename = ensure_real_path(filename);
81             if original_text != formatted_text {
82                 // Do a little dance to make writing safer - write to a temp file
83                 // rename the original to a .bk, then rename the temp file to the
84                 // original.
85                 let tmp_name = filename.with_extension("tmp");
86                 let bk_name = filename.with_extension("bk");
87
88                 fs::write(&tmp_name, formatted_text)?;
89                 fs::rename(filename, bk_name)?;
90                 fs::rename(tmp_name, filename)?;
91             }
92         }
93         EmitMode::Files => {
94             // Write text directly over original file if there is a diff.
95             let filename = ensure_real_path(filename);
96
97             if original_text != formatted_text {
98                 fs::write(filename, formatted_text)?;
99             }
100         }
101         EmitMode::Stdout | EmitMode::Coverage => {
102             if config.verbose() != Verbosity::Quiet {
103                 println!("{}:\n", filename);
104             }
105             write!(out, "{}", formatted_text)?;
106         }
107         EmitMode::ModifiedLines => {
108             let mismatch = make_diff(&original_text, formatted_text, 0);
109             let has_diff = !mismatch.is_empty();
110             write!(out, "{}", ModifiedLines::from(mismatch))?;
111             return Ok(has_diff);
112         }
113         EmitMode::Checkstyle => {
114             let filename = ensure_real_path(filename);
115
116             let diff = make_diff(&original_text, formatted_text, 3);
117             output_checkstyle_file(out, filename, diff)?;
118         }
119         EmitMode::Diff => {
120             let mismatch = make_diff(&original_text, formatted_text, 3);
121             let has_diff = !mismatch.is_empty();
122             print_diff(
123                 mismatch,
124                 |line_num| format!("Diff in {} at line {}:", filename, line_num),
125                 config,
126             );
127             return Ok(has_diff);
128         }
129     }
130
131     // when we are not in diff mode, don't indicate differing files
132     Ok(false)
133 }