Skip to content

Commit 45f1186

Browse files
committed
compiletest: Improve diagnostics for line annotation mismatches
1 parent 42245d3 commit 45f1186

24 files changed

+296
-110
lines changed

src/tools/compiletest/src/errors.rs

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ pub enum ErrorKind {
1616
Suggestion,
1717
Warning,
1818
Raw,
19+
/// Used for better recovery and diagnostics in compiletest.
20+
Unknown,
1921
}
2022

2123
impl ErrorKind {
@@ -31,21 +33,25 @@ impl ErrorKind {
3133

3234
/// Either the canonical uppercase string, or some additional versions for compatibility.
3335
/// FIXME: consider keeping only the canonical versions here.
34-
pub fn from_user_str(s: &str) -> ErrorKind {
35-
match s {
36+
fn from_user_str(s: &str) -> Option<ErrorKind> {
37+
Some(match s {
3638
"HELP" | "help" => ErrorKind::Help,
3739
"ERROR" | "error" => ErrorKind::Error,
38-
// `MONO_ITEM` makes annotations in `codegen-units` tests syntactically correct,
39-
// but those tests never use the error kind later on.
40-
"NOTE" | "note" | "MONO_ITEM" => ErrorKind::Note,
40+
"NOTE" | "note" => ErrorKind::Note,
4141
"SUGGESTION" => ErrorKind::Suggestion,
4242
"WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning,
4343
"RAW" => ErrorKind::Raw,
44-
_ => panic!(
44+
_ => return None,
45+
})
46+
}
47+
48+
pub fn expect_from_user_str(s: &str) -> ErrorKind {
49+
ErrorKind::from_user_str(s).unwrap_or_else(|| {
50+
panic!(
4551
"unexpected diagnostic kind `{s}`, expected \
46-
`ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`"
47-
),
48-
}
52+
`ERROR`, `WARN`, `NOTE`, `HELP`, `SUGGESTION` or `RAW`"
53+
)
54+
})
4955
}
5056
}
5157

@@ -58,13 +64,15 @@ impl fmt::Display for ErrorKind {
5864
ErrorKind::Suggestion => write!(f, "SUGGESTION"),
5965
ErrorKind::Warning => write!(f, "WARN"),
6066
ErrorKind::Raw => write!(f, "RAW"),
67+
ErrorKind::Unknown => write!(f, "UNKNOWN"),
6168
}
6269
}
6370
}
6471

6572
#[derive(Debug)]
6673
pub struct Error {
6774
pub line_num: Option<usize>,
75+
pub column_num: Option<usize>,
6876
/// What kind of message we expect (e.g., warning, error, suggestion).
6977
pub kind: ErrorKind,
7078
pub msg: String,
@@ -74,17 +82,6 @@ pub struct Error {
7482
pub require_annotation: bool,
7583
}
7684

77-
impl Error {
78-
pub fn render_for_expected(&self) -> String {
79-
use colored::Colorize;
80-
format!("{: <10}line {: >3}: {}", self.kind, self.line_num_str(), self.msg.cyan())
81-
}
82-
83-
pub fn line_num_str(&self) -> String {
84-
self.line_num.map_or("?".to_string(), |line_num| line_num.to_string())
85-
}
86-
}
87-
8885
/// Looks for either "//~| KIND MESSAGE" or "//~^^... KIND MESSAGE"
8986
/// The former is a "follow" that inherits its target from the preceding line;
9087
/// the latter is an "adjusts" that goes that many lines up.
@@ -168,8 +165,10 @@ fn parse_expected(
168165
let rest = line[tag.end()..].trim_start();
169166
let (kind_str, _) =
170167
rest.split_once(|c: char| c != '_' && !c.is_ascii_alphabetic()).unwrap_or((rest, ""));
171-
let kind = ErrorKind::from_user_str(kind_str);
172-
let untrimmed_msg = &rest[kind_str.len()..];
168+
let (kind, untrimmed_msg) = match ErrorKind::from_user_str(kind_str) {
169+
Some(kind) => (kind, &rest[kind_str.len()..]),
170+
None => (ErrorKind::Unknown, rest),
171+
};
173172
let msg = untrimmed_msg.strip_prefix(':').unwrap_or(untrimmed_msg).trim().to_owned();
174173

175174
let line_num_adjust = &captures["adjust"];
@@ -182,6 +181,7 @@ fn parse_expected(
182181
} else {
183182
(false, Some(line_num - line_num_adjust.len()))
184183
};
184+
let column_num = Some(tag.start() + 1);
185185

186186
debug!(
187187
"line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}",
@@ -191,7 +191,7 @@ fn parse_expected(
191191
kind,
192192
msg
193193
);
194-
Some((follow_prev, Error { line_num, kind, msg, require_annotation: true }))
194+
Some((follow_prev, Error { line_num, column_num, kind, msg, require_annotation: true }))
195195
}
196196

197197
#[cfg(test)]

src/tools/compiletest/src/header.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ impl TestProps {
593593
config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS)
594594
{
595595
self.dont_require_annotations
596-
.insert(ErrorKind::from_user_str(err_kind.trim()));
596+
.insert(ErrorKind::expect_from_user_str(err_kind.trim()));
597597
}
598598
},
599599
);

src/tools/compiletest/src/json.rs

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ struct UnusedExternNotification {
3636
struct DiagnosticSpan {
3737
file_name: String,
3838
line_start: usize,
39-
line_end: usize,
4039
column_start: usize,
41-
column_end: usize,
4240
is_primary: bool,
4341
label: Option<String>,
4442
suggested_replacement: Option<String>,
@@ -148,6 +146,7 @@ pub fn parse_output(file_name: &str, output: &str) -> Vec<Error> {
148146
Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name),
149147
Err(_) => errors.push(Error {
150148
line_num: None,
149+
column_num: None,
151150
kind: ErrorKind::Raw,
152151
msg: line.to_string(),
153152
require_annotation: false,
@@ -193,25 +192,9 @@ fn push_actual_errors(
193192
// also ensure that `//~ ERROR E123` *always* works. The
194193
// assumption is that these multi-line error messages are on their
195194
// way out anyhow.
196-
let with_code = |span: Option<&DiagnosticSpan>, text: &str| {
197-
// FIXME(#33000) -- it'd be better to use a dedicated
198-
// UI harness than to include the line/col number like
199-
// this, but some current tests rely on it.
200-
//
201-
// Note: Do NOT include the filename. These can easily
202-
// cause false matches where the expected message
203-
// appears in the filename, and hence the message
204-
// changes but the test still passes.
205-
let span_str = match span {
206-
Some(DiagnosticSpan { line_start, column_start, line_end, column_end, .. }) => {
207-
format!("{line_start}:{column_start}: {line_end}:{column_end}")
208-
}
209-
None => format!("?:?: ?:?"),
210-
};
211-
match &diagnostic.code {
212-
Some(code) => format!("{span_str}: {text} [{}]", code.code),
213-
None => format!("{span_str}: {text}"),
214-
}
195+
let with_code = |text| match &diagnostic.code {
196+
Some(code) => format!("{text} [{}]", code.code),
197+
None => format!("{text}"),
215198
};
216199

217200
// Convert multi-line messages into multiple errors.
@@ -225,17 +208,19 @@ fn push_actual_errors(
225208
|| Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap();
226209
errors.push(Error {
227210
line_num: None,
211+
column_num: None,
228212
kind,
229-
msg: with_code(None, first_line),
213+
msg: with_code(first_line),
230214
require_annotation: diagnostic.level != "failure-note"
231215
&& !RE.get_or_init(re_init).is_match(first_line),
232216
});
233217
} else {
234218
for span in primary_spans {
235219
errors.push(Error {
236220
line_num: Some(span.line_start),
221+
column_num: Some(span.column_start),
237222
kind,
238-
msg: with_code(Some(span), first_line),
223+
msg: with_code(first_line),
239224
require_annotation: true,
240225
});
241226
}
@@ -244,16 +229,18 @@ fn push_actual_errors(
244229
if primary_spans.is_empty() {
245230
errors.push(Error {
246231
line_num: None,
232+
column_num: None,
247233
kind,
248-
msg: with_code(None, next_line),
234+
msg: with_code(next_line),
249235
require_annotation: false,
250236
});
251237
} else {
252238
for span in primary_spans {
253239
errors.push(Error {
254240
line_num: Some(span.line_start),
241+
column_num: Some(span.column_start),
255242
kind,
256-
msg: with_code(Some(span), next_line),
243+
msg: with_code(next_line),
257244
require_annotation: false,
258245
});
259246
}
@@ -266,6 +253,7 @@ fn push_actual_errors(
266253
for (index, line) in suggested_replacement.lines().enumerate() {
267254
errors.push(Error {
268255
line_num: Some(span.line_start + index),
256+
column_num: Some(span.column_start),
269257
kind: ErrorKind::Suggestion,
270258
msg: line.to_string(),
271259
// Empty suggestions (suggestions to remove something) are common
@@ -288,6 +276,7 @@ fn push_actual_errors(
288276
if let Some(label) = &span.label {
289277
errors.push(Error {
290278
line_num: Some(span.line_start),
279+
column_num: Some(span.column_start),
291280
kind: ErrorKind::Note,
292281
msg: label.clone(),
293282
// Empty labels (only underlining spans) are common and do not need annotations.
@@ -310,6 +299,7 @@ fn push_backtrace(
310299
if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
311300
errors.push(Error {
312301
line_num: Some(expansion.span.line_start),
302+
column_num: Some(expansion.span.column_start),
313303
kind: ErrorKind::Note,
314304
msg: format!("in this expansion of {}", expansion.macro_decl_name),
315305
require_annotation: true,

0 commit comments

Comments
 (0)