@@ -5,6 +5,7 @@ use std::path::PathBuf;
5
5
use std:: str:: FromStr ;
6
6
use std:: { fs, path:: Path } ;
7
7
use itertools:: Itertools ;
8
+ use glob:: Pattern ;
8
9
use regex:: Regex ;
9
10
use ruff_python_ast:: { Expr , Mod } ;
10
11
use ruff_python_parser:: { Mode , ParseOptions } ;
@@ -89,7 +90,72 @@ impl Default for MergeMethod {
89
90
}
90
91
}
91
92
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
+ }
92
100
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
+ }
93
159
#[ derive( Debug , Deserialize , Clone , Serialize ) ]
94
160
pub struct ConfigFile {
95
161
#[ serde( default ) ]
@@ -239,7 +305,7 @@ impl ConfigFile {
239
305
"python_path" , "additional_stubs" , "additional_stubs_merge" ,
240
306
"refresh_mode" , "file_cache" , "diag_missing_imports" ,
241
307
"ac_filter_model_names" , "auto_refresh_delay" , "add_workspace_addon_path" ,
242
- "diagnostic_settings"
308
+ "diagnostic_settings" , "diagnostic_filters"
243
309
] ;
244
310
for key in order {
245
311
if let Some ( val) = map. get ( key) {
@@ -525,6 +591,9 @@ pub struct ConfigEntryRaw {
525
591
#[ serde( default ) ]
526
592
diagnostic_settings : HashMap < DiagnosticCode , Sourced < DiagnosticSetting > > ,
527
593
594
+ #[ serde( default ) ]
595
+ pub diagnostic_filters : Vec < Sourced < DiagnosticFilter > > ,
596
+
528
597
#[ serde( skip_deserializing, rename( serialize = "abstract" ) ) ]
529
598
abstract_ : bool
530
599
}
@@ -550,6 +619,7 @@ impl Default for ConfigEntryRaw {
550
619
base : None ,
551
620
diagnostic_settings : Default :: default ( ) ,
552
621
abstract_ : false ,
622
+ diagnostic_filters : vec ! [ ] ,
553
623
}
554
624
}
555
625
}
@@ -593,6 +663,7 @@ pub struct ConfigEntry {
593
663
pub no_typeshed : bool ,
594
664
pub abstract_ : bool ,
595
665
pub diagnostic_settings : HashMap < DiagnosticCode , DiagnosticSetting > ,
666
+ pub diagnostic_filters : Vec < DiagnosticFilter > ,
596
667
}
597
668
598
669
impl Default for ConfigEntry {
@@ -612,6 +683,7 @@ impl Default for ConfigEntry {
612
683
no_typeshed : false ,
613
684
abstract_ : false ,
614
685
diagnostic_settings : Default :: default ( ) ,
686
+ diagnostic_filters : vec ! [ ] ,
615
687
}
616
688
}
617
689
}
@@ -724,6 +796,9 @@ fn read_config_from_file<P: AsRef<Path>>(path: P) -> Result<HashMap<String, Conf
724
796
entry. diagnostic_settings . values_mut ( ) . for_each ( |sourced| {
725
797
sourced. sources . insert ( path. sanitize ( ) ) ;
726
798
} ) ;
799
+ entry. diagnostic_filters . iter_mut ( ) . for_each ( |filter| {
800
+ filter. sources . insert ( path. sanitize ( ) ) ;
801
+ } ) ;
727
802
728
803
( entry. name . clone ( ) , entry)
729
804
} ) . collect ( ) ;
@@ -799,6 +874,7 @@ fn apply_merge(child: &ConfigEntryRaw, parent: &ConfigEntryRaw) -> ConfigEntryRa
799
874
let version = child. version . clone ( ) . or ( parent. version . clone ( ) ) ;
800
875
let base = child. base . clone ( ) . or ( parent. base . clone ( ) ) ;
801
876
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 < _ > > ( ) ;
802
878
803
879
ConfigEntryRaw {
804
880
odoo_path,
@@ -818,6 +894,7 @@ fn apply_merge(child: &ConfigEntryRaw, parent: &ConfigEntryRaw) -> ConfigEntryRa
818
894
version,
819
895
base,
820
896
diagnostic_settings : diagnostic_settings,
897
+ diagnostic_filters : diagnostic_filters,
821
898
..Default :: default ( )
822
899
}
823
900
}
@@ -1150,6 +1227,7 @@ fn merge_all_workspaces(
1150
1227
& raw_entry. diagnostic_settings ,
1151
1228
) ;
1152
1229
merged_entry. abstract_ = merged_entry. abstract_ || raw_entry. abstract_ ;
1230
+ merged_entry. diagnostic_filters . extend ( raw_entry. diagnostic_filters . iter ( ) . cloned ( ) ) ;
1153
1231
}
1154
1232
}
1155
1233
// 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(
1190
1268
diagnostic_settings : raw_entry. diagnostic_settings . into_iter ( )
1191
1269
. map ( |( k, v) | ( k, v. value ) )
1192
1270
. collect ( ) ,
1271
+ diagnostic_filters : raw_entry. diagnostic_filters . into_iter ( ) . map ( |f| f. value ) . collect ( ) ,
1193
1272
..Default :: default ( )
1194
1273
} ,
1195
1274
) ;
0 commit comments