]> git.proxmox.com Git - rustc.git/blame - src/compiletest/errors.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / compiletest / errors.rs
CommitLineData
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 10use self::WhichLine::*;
223e47cc 11
54a0048b 12use std::fmt;
c34b1796
AL
13use std::fs::File;
14use std::io::BufReader;
15use std::io::prelude::*;
16use std::path::Path;
54a0048b
SL
17use std::str::FromStr;
18
19#[derive(Clone, Debug, PartialEq)]
20pub enum ErrorKind {
21 Help,
22 Error,
23 Note,
24 Suggestion,
25 Warning,
26}
27
28impl 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
43impl 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 55pub 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 64enum 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`.
76pub 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
112fn 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}