]> git.proxmox.com Git - rustc.git/blame - src/tools/compiletest/src/errors.rs
New upstream version 1.42.0+dfsg1
[rustc.git] / src / tools / compiletest / src / errors.rs
CommitLineData
1a4d82fc 1use self::WhichLine::*;
223e47cc 2
54a0048b 3use std::fmt;
c34b1796 4use std::fs::File;
c34b1796 5use std::io::prelude::*;
94b46f34 6use std::io::BufReader;
c34b1796 7use std::path::Path;
54a0048b
SL
8use std::str::FromStr;
9
60c5eb7d 10use lazy_static::lazy_static;
48663c56 11use log::*;
60c5eb7d 12use regex::Regex;
48663c56 13
54a0048b
SL
14#[derive(Clone, Debug, PartialEq)]
15pub enum ErrorKind {
16 Help,
17 Error,
18 Note,
19 Suggestion,
20 Warning,
21}
22
23impl FromStr for ErrorKind {
24 type Err = ();
25 fn from_str(s: &str) -> Result<Self, Self::Err> {
a7813a04
XL
26 let s = s.to_uppercase();
27 let part0: &str = s.split(':').next().unwrap();
28 match part0 {
54a0048b
SL
29 "HELP" => Ok(ErrorKind::Help),
30 "ERROR" => Ok(ErrorKind::Error),
31 "NOTE" => Ok(ErrorKind::Note),
32 "SUGGESTION" => Ok(ErrorKind::Suggestion),
94b46f34 33 "WARN" | "WARNING" => Ok(ErrorKind::Warning),
54a0048b
SL
34 _ => Err(()),
35 }
36 }
37}
38
39impl fmt::Display for ErrorKind {
9fa01778 40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54a0048b 41 match *self {
abe05a73 42 ErrorKind::Help => write!(f, "help message"),
54a0048b
SL
43 ErrorKind::Error => write!(f, "error"),
44 ErrorKind::Note => write!(f, "note"),
45 ErrorKind::Suggestion => write!(f, "suggestion"),
46 ErrorKind::Warning => write!(f, "warning"),
47 }
48 }
49}
223e47cc 50
a7813a04
XL
51#[derive(Debug)]
52pub struct Error {
54a0048b 53 pub line_num: usize,
0731742a 54 /// What kind of message we expect (e.g., warning, error, suggestion).
54a0048b
SL
55 /// `None` if not specified or unknown message kind.
56 pub kind: Option<ErrorKind>,
1a4d82fc
JJ
57 pub msg: String,
58}
223e47cc 59
85aaf69f 60#[derive(PartialEq, Debug)]
5bcae85e
SL
61enum WhichLine {
62 ThisLine,
63 FollowPrevious(usize),
64 AdjustBackward(usize),
65}
85aaf69f 66
1a4d82fc
JJ
67/// Looks for either "//~| KIND MESSAGE" or "//~^^... KIND MESSAGE"
68/// The former is a "follow" that inherits its target from the preceding line;
69/// the latter is an "adjusts" that goes that many lines up.
70///
71/// Goal is to enable tests both like: //~^^^ ERROR go up three
72/// and also //~^ ERROR message one for the preceding line, and
73/// //~| ERROR message two for that same line.
54a0048b
SL
74///
75/// If cfg is not None (i.e., in an incremental test), then we look
76/// for `//[X]~` instead, where `X` is the current `cfg`.
a7813a04 77pub fn load_errors(testfile: &Path, cfg: Option<&str>) -> Vec<Error> {
c34b1796 78 let rdr = BufReader::new(File::open(testfile).unwrap());
223e47cc 79
1a4d82fc
JJ
80 // `last_nonfollow_error` tracks the most recently seen
81 // line with an error template that did not use the
82 // follow-syntax, "//~| ...".
83 //
84 // (pnkfelix could not find an easy way to compose Iterator::scan
85 // and Iterator::filter_map to pass along this information into
86 // `parse_expected`. So instead I am storing that state here and
87 // updating it in the map callback below.)
88 let mut last_nonfollow_error = None;
223e47cc 89
54a0048b 90 rdr.lines()
5bcae85e
SL
91 .enumerate()
92 .filter_map(|(line_num, line)| {
60c5eb7d 93 parse_expected(last_nonfollow_error, line_num + 1, &line.unwrap(), cfg).map(
94b46f34 94 |(which, error)| {
5bcae85e
SL
95 match which {
96 FollowPrevious(_) => {}
97 _ => last_nonfollow_error = Some(error.line_num),
98 }
60c5eb7d 99
5bcae85e 100 error
94b46f34
XL
101 },
102 )
5bcae85e
SL
103 })
104 .collect()
1a4d82fc 105}
223e47cc 106
94b46f34
XL
107fn parse_expected(
108 last_nonfollow_error: Option<usize>,
109 line_num: usize,
110 line: &str,
60c5eb7d 111 cfg: Option<&str>,
94b46f34 112) -> Option<(WhichLine, Error)> {
60c5eb7d
XL
113 // Matches comments like:
114 // //~
115 // //~|
116 // //~^
117 // //~^^^^^
118 // //[cfg1]~
119 // //[cfg1,cfg2]~^^
120 lazy_static! {
121 static ref RE: Regex =
122 Regex::new(r"//(?:\[(?P<cfgs>[\w,]+)])?~(?P<adjust>\||\^*)").unwrap();
123 }
124
125 let captures = RE.captures(line)?;
126
127 match (cfg, captures.name("cfgs")) {
128 // Only error messages that contain our `cfg` betweeen the square brackets apply to us.
dfeec247 129 (Some(cfg), Some(filter)) if !filter.as_str().split(',').any(|s| s == cfg) => return None,
60c5eb7d
XL
130 (Some(_), Some(_)) => {}
131
132 (None, Some(_)) => panic!("Only tests with revisions should use `//[X]~`"),
133
134 // If an error has no list of revisions, it applies to all revisions.
135 (Some(_), None) | (None, None) => {}
136 }
137
138 let (follow, adjusts) = match &captures["adjust"] {
139 "|" => (true, 0),
140 circumflexes => (false, circumflexes.len()),
85aaf69f 141 };
60c5eb7d
XL
142
143 // Get the part of the comment after the sigil (e.g. `~^^` or ~|).
144 let whole_match = captures.get(0).unwrap();
145 let (_, mut msg) = line.split_at(whole_match.end());
146
dfeec247 147 let first_word = msg.split_whitespace().next().expect("Encountered unexpected empty comment");
60c5eb7d
XL
148
149 // If we find `//~ ERROR foo` or something like that, skip the first word.
150 let kind = first_word.parse::<ErrorKind>().ok();
151 if let Some(_) = kind {
152 msg = &msg.trim_start().split_at(first_word.len()).1;
a7813a04 153 }
60c5eb7d 154
a7813a04 155 let msg = msg.trim().to_owned();
223e47cc 156
54a0048b 157 let (which, line_num) = if follow {
041b39d2 158 assert_eq!(adjusts, 0, "use either //~| or //~^, not both.");
94b46f34
XL
159 let line_num = last_nonfollow_error.expect(
160 "encountered //~| without \
161 preceding //~^ line.",
162 );
54a0048b 163 (FollowPrevious(line_num), line_num)
85aaf69f 164 } else {
dfeec247 165 let which = if adjusts > 0 { AdjustBackward(adjusts) } else { ThisLine };
54a0048b
SL
166 let line_num = line_num - adjusts;
167 (which, line_num)
85aaf69f 168 };
223e47cc 169
94b46f34
XL
170 debug!(
171 "line={} tag={:?} which={:?} kind={:?} msg={:?}",
dfeec247
XL
172 line_num,
173 whole_match.as_str(),
94b46f34 174 which,
dfeec247
XL
175 kind,
176 msg
177 );
178 Some((which, Error { line_num, kind, msg }))
223e47cc 179}