@@ -3,7 +3,6 @@ use std::fs::File;
3
3
use std:: io:: BufReader ;
4
4
use std:: io:: prelude:: * ;
5
5
use std:: path:: Path ;
6
- use std:: str:: FromStr ;
7
6
use std:: sync:: OnceLock ;
8
7
9
8
use regex:: Regex ;
@@ -18,30 +17,42 @@ pub enum ErrorKind {
18
17
Warning ,
19
18
}
20
19
21
- impl FromStr for ErrorKind {
22
- type Err = ( ) ;
23
- fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
24
- let s = s. to_uppercase ( ) ;
25
- let part0: & str = s. split ( ':' ) . next ( ) . unwrap ( ) ;
26
- match part0 {
27
- "HELP" => Ok ( ErrorKind :: Help ) ,
28
- "ERROR" => Ok ( ErrorKind :: Error ) ,
29
- "NOTE" => Ok ( ErrorKind :: Note ) ,
30
- "SUGGESTION" => Ok ( ErrorKind :: Suggestion ) ,
31
- "WARN" | "WARNING" => Ok ( ErrorKind :: Warning ) ,
32
- _ => Err ( ( ) ) ,
20
+ impl ErrorKind {
21
+ pub fn from_compiler_str ( s : & str ) -> ErrorKind {
22
+ match s {
23
+ "help" => ErrorKind :: Help ,
24
+ "error" | "error: internal compiler error" => ErrorKind :: Error ,
25
+ "note" | "failure-note" => ErrorKind :: Note ,
26
+ "warning" => ErrorKind :: Warning ,
27
+ _ => panic ! ( "unexpected compiler diagnostic kind `{s}`" ) ,
28
+ }
29
+ }
30
+
31
+ fn from_user_str ( s : & str ) -> ErrorKind {
32
+ match s {
33
+ "HELP" => ErrorKind :: Help ,
34
+ "HELP_NONVIRAL" => ErrorKind :: Help ,
35
+ "ERROR" => ErrorKind :: Error ,
36
+ "NOTE" => ErrorKind :: Note ,
37
+ "NOTE_NONVIRAL" => ErrorKind :: Note ,
38
+ "SUGGESTION" => ErrorKind :: Suggestion ,
39
+ "WARN" | "WARNING" => ErrorKind :: Warning ,
40
+ _ => panic ! (
41
+ "unexpected diagnostic kind `{s}`, expected \
42
+ `ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`"
43
+ ) ,
33
44
}
34
45
}
35
46
}
36
47
37
48
impl fmt:: Display for ErrorKind {
38
49
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
39
50
match * self {
40
- ErrorKind :: Help => write ! ( f, "help message " ) ,
41
- ErrorKind :: Error => write ! ( f, "error " ) ,
42
- ErrorKind :: Note => write ! ( f, "note " ) ,
43
- ErrorKind :: Suggestion => write ! ( f, "suggestion " ) ,
44
- ErrorKind :: Warning => write ! ( f, "warning " ) ,
51
+ ErrorKind :: Help => write ! ( f, "HELP " ) ,
52
+ ErrorKind :: Error => write ! ( f, "ERROR " ) ,
53
+ ErrorKind :: Note => write ! ( f, "NOTE " ) ,
54
+ ErrorKind :: Suggestion => write ! ( f, "SUGGESTION " ) ,
55
+ ErrorKind :: Warning => write ! ( f, "WARN " ) ,
45
56
}
46
57
}
47
58
}
@@ -50,20 +61,21 @@ impl fmt::Display for ErrorKind {
50
61
pub struct Error {
51
62
pub line_num : Option < usize > ,
52
63
/// What kind of message we expect (e.g., warning, error, suggestion).
53
- /// `None` if not specified or unknown message kind.
54
- pub kind : Option < ErrorKind > ,
64
+ pub kind : ErrorKind ,
55
65
pub msg : String ,
66
+ /// For some `Error`s, like secondary lines of multi-line diagnostics, line annotations
67
+ /// are not mandatory, even if they would otherwise be mandatory for primary errors.
68
+ /// Only makes sense for "found" errors, not for "expected" errors.
69
+ pub should_annotate : bool ,
70
+ /// A temporary measure to avoid adding too many `NOTE` and `HELP` annotations in #NNNNNN.
71
+ /// Only makes sense for "expected" errors, not for "found" errors.
72
+ pub viral : bool ,
56
73
}
57
74
58
75
impl Error {
59
76
pub fn render_for_expected ( & self ) -> String {
60
77
use colored:: Colorize ;
61
- format ! (
62
- "{: <10}line {: >3}: {}" ,
63
- self . kind. map( |kind| kind. to_string( ) ) . unwrap_or_default( ) . to_uppercase( ) ,
64
- self . line_num_str( ) ,
65
- self . msg. cyan( ) ,
66
- )
78
+ format ! ( "{: <10}line {: >3}: {}" , self . kind, self . line_num_str( ) , self . msg. cyan( ) )
67
79
}
68
80
69
81
pub fn line_num_str ( & self ) -> String {
@@ -150,18 +162,13 @@ fn parse_expected(
150
162
}
151
163
152
164
// Get the part of the comment after the sigil (e.g. `~^^` or ~|).
153
- let whole_match = captures. get ( 0 ) . unwrap ( ) ;
154
- let ( _, mut msg) = line. split_at ( whole_match. end ( ) ) ;
155
-
156
- let first_word = msg. split_whitespace ( ) . next ( ) . expect ( "Encountered unexpected empty comment" ) ;
157
-
158
- // If we find `//~ ERROR foo` or something like that, skip the first word.
159
- let kind = first_word. parse :: < ErrorKind > ( ) . ok ( ) ;
160
- if kind. is_some ( ) {
161
- msg = & msg. trim_start ( ) . split_at ( first_word. len ( ) ) . 1 ;
162
- }
163
-
164
- let msg = msg. trim ( ) . to_owned ( ) ;
165
+ let tag = captures. get ( 0 ) . unwrap ( ) ;
166
+ let rest = line[ tag. end ( ) ..] . trim_start ( ) ;
167
+ let ( kind, _) =
168
+ rest. split_once ( |c| !unicode_xid:: UnicodeXID :: is_xid_continue ( c) ) . unwrap_or ( ( rest, "" ) ) ;
169
+ let msg = rest[ kind. len ( ) ..] . trim ( ) . to_owned ( ) ;
170
+ let viral = kind != "NOTE_NONVIRAL" && kind != "HELP_NONVIRAL" ;
171
+ let kind = ErrorKind :: from_user_str ( kind) ;
165
172
166
173
let line_num_adjust = & captures[ "adjust" ] ;
167
174
let ( follow_prev, line_num) = if line_num_adjust == "|" {
@@ -177,12 +184,12 @@ fn parse_expected(
177
184
debug ! (
178
185
"line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}" ,
179
186
line_num,
180
- whole_match . as_str( ) ,
187
+ tag . as_str( ) ,
181
188
follow_prev,
182
189
kind,
183
190
msg
184
191
) ;
185
- Some ( ( follow_prev, Error { line_num, kind, msg } ) )
192
+ Some ( ( follow_prev, Error { line_num, kind, msg, should_annotate : true , viral } ) )
186
193
}
187
194
188
195
#[ cfg( test) ]
0 commit comments