@@ -18,33 +18,31 @@ use pyrefly_util::fs_anyhow;
1818use regex:: Regex ;
1919use ruff_python_ast:: PySourceType ;
2020use serde:: Deserialize ;
21+ use serde:: Serialize ;
2122use starlark_map:: small_map:: SmallMap ;
2223use starlark_map:: small_set:: SmallSet ;
2324use tracing:: info;
2425
2526use crate :: error:: error:: Error ;
2627
27- /// A minimal representation of an error for suppression purposes .
28- /// This struct holds only the fields needed to add or remove a suppression comment.
29- #[ derive( Deserialize ) ]
30- pub struct SuppressableError {
28+ /// A serializable representation of an error for JSON input/output .
29+ /// This struct holds the fields needed to add or remove a suppression comment.
30+ #[ derive( Deserialize , Serialize ) ]
31+ pub struct SerializedError {
3132 /// The file path where the error occurs.
3233 pub path : PathBuf ,
3334 /// The 0-indexed line number where the error occurs.
3435 pub line : usize ,
3536 /// The kebab-case name of the error kind (e.g., "bad-assignment").
3637 pub name : String ,
38+ /// The error message. Used for UnusedIgnore errors to determine what to remove.
39+ pub message : String ,
3740}
3841
39- impl SuppressableError {
40- /// Creates a SuppressableError from an internal Error.
41- /// Returns None if the error is not from a filesystem path or if the error
42- /// is an UnusedIgnore (which cannot be suppressed).
42+ impl SerializedError {
43+ /// Creates a SerializedError from an internal Error.
44+ /// Returns None if the error is not from a filesystem path.
4345 pub fn from_error ( error : & Error ) -> Option < Self > {
44- // UnusedIgnore errors cannot be suppressed
45- if error. error_kind ( ) == ErrorKind :: UnusedIgnore {
46- return None ;
47- }
4846 if let ModulePathDetails :: FileSystem ( path) = error. path ( ) . details ( ) {
4947 Some ( Self {
5048 path : ( * * path) . clone ( ) ,
@@ -54,11 +52,17 @@ impl SuppressableError {
5452 . line_within_file ( )
5553 . to_zero_indexed ( ) as usize ,
5654 name : error. error_kind ( ) . to_name ( ) . to_owned ( ) ,
55+ message : error. msg ( ) . to_owned ( ) ,
5756 } )
5857 } else {
5958 None
6059 }
6160 }
61+
62+ /// Returns true if this error is an UnusedIgnore error.
63+ pub fn is_unused_ignore ( & self ) -> bool {
64+ self . name == ErrorKind :: UnusedIgnore . to_name ( )
65+ }
6266}
6367
6468/// Detects the line ending style used in a string.
@@ -73,7 +77,7 @@ fn detect_line_ending(content: &str) -> &'static str {
7377
7478/// Combines all errors that affect one line into a single entry.
7579/// The current format is: `# pyrefly: ignore [error1, error2, ...]`
76- fn dedup_errors ( errors : & [ SuppressableError ] ) -> SmallMap < usize , String > {
80+ fn dedup_errors ( errors : & [ SerializedError ] ) -> SmallMap < usize , String > {
7781 let mut deduped_errors: SmallMap < usize , HashSet < String > > = SmallMap :: new ( ) ;
7882 for error in errors {
7983 deduped_errors
@@ -199,7 +203,7 @@ fn replace_ignore_comment(line: &str, merged_comment: &str) -> String {
199203/// Returns a list of files that failed to be patched, and a list of files that were patched.
200204/// The list of failures includes the error that occurred, which may be a read or write error.
201205fn add_suppressions (
202- path_errors : & SmallMap < PathBuf , Vec < SuppressableError > > ,
206+ path_errors : & SmallMap < PathBuf , Vec < SerializedError > > ,
203207) -> ( Vec < ( & PathBuf , anyhow:: Error ) > , Vec < & PathBuf > ) {
204208 let mut failures = vec ! [ ] ;
205209 let mut successes = vec ! [ ] ;
@@ -309,9 +313,9 @@ fn extract_error_codes(comment: &str) -> Vec<String> {
309313}
310314
311315/// Suppresses errors by adding ignore comments to source files.
312- /// Takes a list of SuppressableErrors
313- pub fn suppress_errors ( errors : Vec < SuppressableError > ) {
314- let mut path_errors: SmallMap < PathBuf , Vec < SuppressableError > > = SmallMap :: new ( ) ;
316+ /// Takes a list of SerializedErrors
317+ pub fn suppress_errors ( errors : Vec < SerializedError > ) {
318+ let mut path_errors: SmallMap < PathBuf , Vec < SerializedError > > = SmallMap :: new ( ) ;
315319 for e in errors {
316320 path_errors. entry ( e. path . clone ( ) ) . or_default ( ) . push ( e) ;
317321 }
@@ -512,12 +516,12 @@ mod tests {
512516
513517 fn assert_suppress_errors ( before : & str , after : & str ) {
514518 let ( errors, tdir) = get_errors ( before) ;
515- let suppressable_errors: Vec < SuppressableError > = errors
519+ let suppressable_errors: Vec < SerializedError > = errors
516520 . collect_errors ( )
517521 . shown
518522 . iter ( )
519523 . filter ( |e| e. severity ( ) >= Severity :: Warn )
520- . filter_map ( SuppressableError :: from_error)
524+ . filter_map ( SerializedError :: from_error)
521525 . collect ( ) ;
522526 suppress:: suppress_errors ( suppressable_errors) ;
523527 let got_file = fs_anyhow:: read_to_string ( & get_path ( & tdir) ) . unwrap ( ) ;
0 commit comments