1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
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.
10 use self::WhichLine
::*;
14 use std
::io
::BufReader
;
15 use std
::io
::prelude
::*;
17 use std
::str::FromStr
;
19 #[derive(Clone, Debug, PartialEq)]
28 impl FromStr
for ErrorKind
{
30 fn from_str(s
: &str) -> Result
<Self, Self::Err
> {
31 let s
= s
.to_uppercase();
32 let part0
: &str = s
.split('
:'
).next().unwrap();
34 "HELP" => Ok(ErrorKind
::Help
),
35 "ERROR" => Ok(ErrorKind
::Error
),
36 "NOTE" => Ok(ErrorKind
::Note
),
37 "SUGGESTION" => Ok(ErrorKind
::Suggestion
),
38 "WARN" => Ok(ErrorKind
::Warning
),
39 "WARNING" => Ok(ErrorKind
::Warning
),
45 impl fmt
::Display
for ErrorKind
{
46 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
48 ErrorKind
::Help
=> write
!(f
, "help"),
49 ErrorKind
::Error
=> write
!(f
, "error"),
50 ErrorKind
::Note
=> write
!(f
, "note"),
51 ErrorKind
::Suggestion
=> write
!(f
, "suggestion"),
52 ErrorKind
::Warning
=> write
!(f
, "warning"),
60 /// What kind of message we expect (e.g. warning, error, suggestion).
61 /// `None` if not specified or unknown message kind.
62 pub kind
: Option
<ErrorKind
>,
66 #[derive(PartialEq, Debug)]
67 enum WhichLine { ThisLine, FollowPrevious(usize), AdjustBackward(usize) }
69 /// Looks for either "//~| KIND MESSAGE" or "//~^^... KIND MESSAGE"
70 /// The former is a "follow" that inherits its target from the preceding line;
71 /// the latter is an "adjusts" that goes that many lines up.
73 /// Goal is to enable tests both like: //~^^^ ERROR go up three
74 /// and also //~^ ERROR message one for the preceding line, and
75 /// //~| ERROR message two for that same line.
77 /// If cfg is not None (i.e., in an incremental test), then we look
78 /// for `//[X]~` instead, where `X` is the current `cfg`.
79 pub fn load_errors(testfile
: &Path
, cfg
: Option
<&str>) -> Vec
<Error
> {
80 let rdr
= BufReader
::new(File
::open(testfile
).unwrap());
82 // `last_nonfollow_error` tracks the most recently seen
83 // line with an error template that did not use the
84 // follow-syntax, "//~| ...".
86 // (pnkfelix could not find an easy way to compose Iterator::scan
87 // and Iterator::filter_map to pass along this information into
88 // `parse_expected`. So instead I am storing that state here and
89 // updating it in the map callback below.)
90 let mut last_nonfollow_error
= None
;
93 Some(rev
) => format
!("//[{}]~", rev
),
94 None
=> format
!("//~")
99 .filter_map(|(line_num
, line
)| {
100 parse_expected(last_nonfollow_error
,
104 .map(|(which
, error
)| {
106 FollowPrevious(_
) => {}
107 _
=> last_nonfollow_error
= Some(error
.line_num
),
115 fn parse_expected(last_nonfollow_error
: Option
<usize>,
119 -> Option
<(WhichLine
, Error
)> {
120 let start
= match line
.find(tag
) { Some(i) => i, None => return None }
;
121 let (follow
, adjusts
) = if line
[start
+ tag
.len()..].chars().next().unwrap() == '
|'
{
124 (false, line
[start
+ tag
.len()..].chars().take_while(|c
| *c
== '
^').count())
126 let kind_start
= start
+ tag
.len() + adjusts
+ (follow
as usize);
129 line
[kind_start
..].split_whitespace()
131 .expect("Encountered unexpected empty comment")
132 .parse
::<ErrorKind
>()
135 // If we find `//~ ERROR foo` or something like that:
137 let letters
= line
[kind_start
..].chars();
138 msg
= letters
.skip_while(|c
| c
.is_whitespace())
139 .skip_while(|c
| !c
.is_whitespace())
140 .collect
::<String
>();
143 // Otherwise we found `//~ foo`:
145 let letters
= line
[kind_start
..].chars();
146 msg
= letters
.skip_while(|c
| c
.is_whitespace())
147 .collect
::<String
>();
150 let msg
= msg
.trim().to_owned();
152 let (which
, line_num
) = if follow
{
153 assert
!(adjusts
== 0, "use either //~| or //~^, not both.");
154 let line_num
= last_nonfollow_error
.expect("encountered //~| without \
155 preceding //~^ line.");
156 (FollowPrevious(line_num
), line_num
)
159 if adjusts
> 0 { AdjustBackward(adjusts) }
else { ThisLine }
;
160 let line_num
= line_num
- adjusts
;
164 debug
!("line={} tag={:?} which={:?} kind={:?} msg={:?}",
165 line_num
, tag
, which
, kind
, msg
);
166 Some((which
, Error
{ line_num
: line_num
,