]>
Commit | Line | Data |
---|---|---|
1a4d82fc | 1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT |
223e47cc LB |
2 | // file at the top-level directory of this distribution and at |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
1a4d82fc | 10 | use self::WhichLine::*; |
223e47cc | 11 | |
54a0048b | 12 | use std::fmt; |
c34b1796 AL |
13 | use std::fs::File; |
14 | use std::io::BufReader; | |
15 | use std::io::prelude::*; | |
16 | use std::path::Path; | |
54a0048b SL |
17 | use std::str::FromStr; |
18 | ||
19 | #[derive(Clone, Debug, PartialEq)] | |
20 | pub enum ErrorKind { | |
21 | Help, | |
22 | Error, | |
23 | Note, | |
24 | Suggestion, | |
25 | Warning, | |
26 | } | |
27 | ||
28 | impl FromStr for ErrorKind { | |
29 | type Err = (); | |
30 | fn from_str(s: &str) -> Result<Self, Self::Err> { | |
31 | match &s.trim_right_matches(':') as &str { | |
32 | "HELP" => Ok(ErrorKind::Help), | |
33 | "ERROR" => Ok(ErrorKind::Error), | |
34 | "NOTE" => Ok(ErrorKind::Note), | |
35 | "SUGGESTION" => Ok(ErrorKind::Suggestion), | |
36 | "WARN" => Ok(ErrorKind::Warning), | |
37 | "WARNING" => Ok(ErrorKind::Warning), | |
38 | _ => Err(()), | |
39 | } | |
40 | } | |
41 | } | |
42 | ||
43 | impl fmt::Display for ErrorKind { | |
44 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
45 | match *self { | |
46 | ErrorKind::Help => write!(f, "help"), | |
47 | ErrorKind::Error => write!(f, "error"), | |
48 | ErrorKind::Note => write!(f, "note"), | |
49 | ErrorKind::Suggestion => write!(f, "suggestion"), | |
50 | ErrorKind::Warning => write!(f, "warning"), | |
51 | } | |
52 | } | |
53 | } | |
223e47cc | 54 | |
1a4d82fc | 55 | pub struct ExpectedError { |
54a0048b SL |
56 | pub line_num: usize, |
57 | /// What kind of message we expect (e.g. warning, error, suggestion). | |
58 | /// `None` if not specified or unknown message kind. | |
59 | pub kind: Option<ErrorKind>, | |
1a4d82fc JJ |
60 | pub msg: String, |
61 | } | |
223e47cc | 62 | |
85aaf69f | 63 | #[derive(PartialEq, Debug)] |
c34b1796 | 64 | enum WhichLine { ThisLine, FollowPrevious(usize), AdjustBackward(usize) } |
85aaf69f | 65 | |
1a4d82fc JJ |
66 | /// Looks for either "//~| KIND MESSAGE" or "//~^^... KIND MESSAGE" |
67 | /// The former is a "follow" that inherits its target from the preceding line; | |
68 | /// the latter is an "adjusts" that goes that many lines up. | |
69 | /// | |
70 | /// Goal is to enable tests both like: //~^^^ ERROR go up three | |
71 | /// and also //~^ ERROR message one for the preceding line, and | |
72 | /// //~| ERROR message two for that same line. | |
54a0048b SL |
73 | /// |
74 | /// If cfg is not None (i.e., in an incremental test), then we look | |
75 | /// for `//[X]~` instead, where `X` is the current `cfg`. | |
76 | pub fn load_errors(testfile: &Path, cfg: Option<&str>) -> Vec<ExpectedError> { | |
c34b1796 | 77 | let rdr = BufReader::new(File::open(testfile).unwrap()); |
223e47cc | 78 | |
1a4d82fc JJ |
79 | // `last_nonfollow_error` tracks the most recently seen |
80 | // line with an error template that did not use the | |
81 | // follow-syntax, "//~| ...". | |
82 | // | |
83 | // (pnkfelix could not find an easy way to compose Iterator::scan | |
84 | // and Iterator::filter_map to pass along this information into | |
85 | // `parse_expected`. So instead I am storing that state here and | |
86 | // updating it in the map callback below.) | |
87 | let mut last_nonfollow_error = None; | |
223e47cc | 88 | |
54a0048b SL |
89 | let tag = match cfg { |
90 | Some(rev) => format!("//[{}]~", rev), | |
91 | None => format!("//~") | |
92 | }; | |
93 | ||
94 | rdr.lines() | |
95 | .enumerate() | |
96 | .filter_map(|(line_num, line)| { | |
97 | parse_expected(last_nonfollow_error, | |
98 | line_num + 1, | |
99 | &line.unwrap(), | |
100 | &tag) | |
101 | .map(|(which, error)| { | |
102 | match which { | |
103 | FollowPrevious(_) => {} | |
104 | _ => last_nonfollow_error = Some(error.line_num), | |
105 | } | |
106 | error | |
107 | }) | |
108 | }) | |
109 | .collect() | |
1a4d82fc | 110 | } |
223e47cc | 111 | |
c34b1796 AL |
112 | fn parse_expected(last_nonfollow_error: Option<usize>, |
113 | line_num: usize, | |
54a0048b SL |
114 | line: &str, |
115 | tag: &str) | |
116 | -> Option<(WhichLine, ExpectedError)> { | |
117 | let start = match line.find(tag) { Some(i) => i, None => return None }; | |
118 | let (follow, adjusts) = if line[start + tag.len()..].chars().next().unwrap() == '|' { | |
85aaf69f SL |
119 | (true, 0) |
120 | } else { | |
54a0048b | 121 | (false, line[start + tag.len()..].chars().take_while(|c| *c == '^').count()) |
85aaf69f | 122 | }; |
54a0048b SL |
123 | let kind_start = start + tag.len() + adjusts + (follow as usize); |
124 | let kind = line[kind_start..].split_whitespace() | |
125 | .next() | |
126 | .expect("Encountered unexpected empty comment") | |
127 | .parse::<ErrorKind>() | |
128 | .ok(); | |
85aaf69f SL |
129 | let letters = line[kind_start..].chars(); |
130 | let msg = letters.skip_while(|c| c.is_whitespace()) | |
131 | .skip_while(|c| !c.is_whitespace()) | |
e9174d1e | 132 | .collect::<String>().trim().to_owned(); |
223e47cc | 133 | |
54a0048b | 134 | let (which, line_num) = if follow { |
85aaf69f | 135 | assert!(adjusts == 0, "use either //~| or //~^, not both."); |
54a0048b SL |
136 | let line_num = last_nonfollow_error.expect("encountered //~| without \ |
137 | preceding //~^ line."); | |
138 | (FollowPrevious(line_num), line_num) | |
85aaf69f SL |
139 | } else { |
140 | let which = | |
141 | if adjusts > 0 { AdjustBackward(adjusts) } else { ThisLine }; | |
54a0048b SL |
142 | let line_num = line_num - adjusts; |
143 | (which, line_num) | |
85aaf69f | 144 | }; |
223e47cc | 145 | |
54a0048b SL |
146 | debug!("line={} tag={:?} which={:?} kind={:?} msg={:?}", |
147 | line_num, tag, which, kind, msg); | |
148 | Some((which, ExpectedError { line_num: line_num, | |
85aaf69f SL |
149 | kind: kind, |
150 | msg: msg, })) | |
223e47cc | 151 | } |