@@ -5,6 +5,7 @@ use std::path::PathBuf;
55use std:: str:: FromStr ;
66use std:: { fs, path:: Path } ;
77use itertools:: Itertools ;
8+ use glob:: Pattern ;
89use regex:: Regex ;
910use ruff_python_ast:: { Expr , Mod } ;
1011use ruff_python_parser:: { Mode , ParseOptions } ;
@@ -89,7 +90,72 @@ impl Default for MergeMethod {
8990 }
9091}
9192
93+ #[ derive( Debug , Clone ) ]
94+ pub struct DiagnosticFilter {
95+ pub paths : Pattern ,
96+ pub codes : Vec < Regex > ,
97+ pub types : Vec < DiagnosticSetting > ,
98+ pub negation : bool ,
99+ }
92100
101+ impl < ' de > serde:: Deserialize < ' de > for DiagnosticFilter {
102+ fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
103+ where
104+ D : serde:: Deserializer < ' de > ,
105+ {
106+ #[ derive( serde:: Deserialize ) ]
107+ struct Helper {
108+ path : String ,
109+ #[ serde( default ) ]
110+ codes : Vec < String > ,
111+ #[ serde( default ) ]
112+ types : Vec < DiagnosticSetting > ,
113+ }
114+ let helper = Helper :: deserialize ( deserializer) ?;
115+ let ( path_str, negation) = if let Some ( stripped) = helper. path . strip_prefix ( '!' ) {
116+ ( stripped, true )
117+ } else {
118+ ( helper. path . as_str ( ) , false )
119+ } ;
120+ let sanitized_path = PathBuf :: from ( path_str) . sanitize ( ) ;
121+ let path_pattern = Pattern :: new ( & sanitized_path) . map_err ( serde:: de:: Error :: custom) ?;
122+ let mut code_regexes = Vec :: with_capacity ( helper. codes . len ( ) ) ;
123+ for code in & helper. codes {
124+ let regex = Regex :: new ( code) . map_err ( serde:: de:: Error :: custom) ?;
125+ code_regexes. push ( regex) ;
126+ }
127+ for t in & helper. types {
128+ if let DiagnosticSetting :: Disabled = t {
129+ return Err ( serde:: de:: Error :: custom ( "DiagnosticFilter.types cannot contain 'Disabled'" ) ) ;
130+ }
131+ }
132+ Ok ( DiagnosticFilter {
133+ paths : path_pattern,
134+ codes : code_regexes,
135+ types : helper. types ,
136+ negation,
137+ } )
138+ }
139+ }
140+
141+ impl Serialize for DiagnosticFilter {
142+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
143+ where
144+ S : serde:: Serializer ,
145+ {
146+ use serde:: ser:: SerializeStruct ;
147+ let mut s = serializer. serialize_struct ( "DiagnosticFilter" , 3 ) ?;
148+ let mut path_str = self . paths . as_str ( ) . to_string ( ) ;
149+ if self . negation {
150+ path_str = format ! ( "!{}" , path_str) ;
151+ }
152+ s. serialize_field ( "path" , & path_str) ?;
153+ let codes: Vec < String > = self . codes . iter ( ) . map ( |r| r. as_str ( ) . to_string ( ) ) . collect ( ) ;
154+ s. serialize_field ( "codes" , & codes) ?;
155+ s. serialize_field ( "types" , & self . types ) ?;
156+ s. end ( )
157+ }
158+ }
93159#[ derive( Debug , Deserialize , Clone , Serialize ) ]
94160pub struct ConfigFile {
95161 #[ serde( default ) ]
@@ -239,7 +305,7 @@ impl ConfigFile {
239305 "python_path" , "additional_stubs" , "additional_stubs_merge" ,
240306 "refresh_mode" , "file_cache" , "diag_missing_imports" ,
241307 "ac_filter_model_names" , "auto_refresh_delay" , "add_workspace_addon_path" ,
242- "diagnostic_settings"
308+ "diagnostic_settings" , "diagnostic_filters"
243309 ] ;
244310 for key in order {
245311 if let Some ( val) = map. get ( key) {
@@ -525,6 +591,9 @@ pub struct ConfigEntryRaw {
525591 #[ serde( default ) ]
526592 diagnostic_settings : HashMap < DiagnosticCode , Sourced < DiagnosticSetting > > ,
527593
594+ #[ serde( default ) ]
595+ pub diagnostic_filters : Vec < Sourced < DiagnosticFilter > > ,
596+
528597 #[ serde( skip_deserializing, rename( serialize = "abstract" ) ) ]
529598 abstract_ : bool
530599}
@@ -550,6 +619,7 @@ impl Default for ConfigEntryRaw {
550619 base : None ,
551620 diagnostic_settings : Default :: default ( ) ,
552621 abstract_ : false ,
622+ diagnostic_filters : vec ! [ ] ,
553623 }
554624 }
555625}
@@ -593,6 +663,7 @@ pub struct ConfigEntry {
593663 pub no_typeshed : bool ,
594664 pub abstract_ : bool ,
595665 pub diagnostic_settings : HashMap < DiagnosticCode , DiagnosticSetting > ,
666+ pub diagnostic_filters : Vec < DiagnosticFilter > ,
596667}
597668
598669impl Default for ConfigEntry {
@@ -612,6 +683,7 @@ impl Default for ConfigEntry {
612683 no_typeshed : false ,
613684 abstract_ : false ,
614685 diagnostic_settings : Default :: default ( ) ,
686+ diagnostic_filters : vec ! [ ] ,
615687 }
616688 }
617689}
@@ -724,6 +796,9 @@ fn read_config_from_file<P: AsRef<Path>>(path: P) -> Result<HashMap<String, Conf
724796 entry. diagnostic_settings . values_mut ( ) . for_each ( |sourced| {
725797 sourced. sources . insert ( path. sanitize ( ) ) ;
726798 } ) ;
799+ entry. diagnostic_filters . iter_mut ( ) . for_each ( |filter| {
800+ filter. sources . insert ( path. sanitize ( ) ) ;
801+ } ) ;
727802
728803 ( entry. name . clone ( ) , entry)
729804 } ) . collect ( ) ;
@@ -799,6 +874,7 @@ fn apply_merge(child: &ConfigEntryRaw, parent: &ConfigEntryRaw) -> ConfigEntryRa
799874 let version = child. version . clone ( ) . or ( parent. version . clone ( ) ) ;
800875 let base = child. base . clone ( ) . or ( parent. base . clone ( ) ) ;
801876 let diagnostic_settings = merge_sourced_diagnostic_setting_map ( & child. diagnostic_settings , & parent. diagnostic_settings ) ;
877+ let diagnostic_filters = child. diagnostic_filters . iter ( ) . chain ( parent. diagnostic_filters . iter ( ) ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
802878
803879 ConfigEntryRaw {
804880 odoo_path,
@@ -818,6 +894,7 @@ fn apply_merge(child: &ConfigEntryRaw, parent: &ConfigEntryRaw) -> ConfigEntryRa
818894 version,
819895 base,
820896 diagnostic_settings : diagnostic_settings,
897+ diagnostic_filters : diagnostic_filters,
821898 ..Default :: default ( )
822899 }
823900}
@@ -1150,6 +1227,7 @@ fn merge_all_workspaces(
11501227 & raw_entry. diagnostic_settings ,
11511228 ) ;
11521229 merged_entry. abstract_ = merged_entry. abstract_ || raw_entry. abstract_ ;
1230+ merged_entry. diagnostic_filters . extend ( raw_entry. diagnostic_filters . iter ( ) . cloned ( ) ) ;
11531231 }
11541232 }
11551233 // Only infer odoo_path from workspace folders at this stage, to give priority to the user-defined one
@@ -1190,6 +1268,7 @@ fn merge_all_workspaces(
11901268 diagnostic_settings : raw_entry. diagnostic_settings . into_iter ( )
11911269 . map ( |( k, v) | ( k, v. value ) )
11921270 . collect ( ) ,
1271+ diagnostic_filters : raw_entry. diagnostic_filters . into_iter ( ) . map ( |f| f. value ) . collect ( ) ,
11931272 ..Default :: default ( )
11941273 } ,
11951274 ) ;
0 commit comments