@@ -3,7 +3,7 @@ use std::{
3
3
str:: Lines ,
4
4
} ;
5
5
6
- use pgt_analyse:: RuleCategory ;
6
+ use pgt_analyse:: { RuleCategory , RuleFilter } ;
7
7
use pgt_diagnostics:: { Diagnostic , Location , MessageAndDescription } ;
8
8
use pgt_text_size:: { TextRange , TextSize } ;
9
9
@@ -24,15 +24,15 @@ pub struct SuppressionDiagnostic {
24
24
message : MessageAndDescription ,
25
25
}
26
26
27
- #[ derive( Debug ) ]
27
+ #[ derive( Debug , Clone ) ]
28
28
pub enum SuppressionKind {
29
29
File ,
30
30
Line ,
31
31
Start ,
32
32
End ,
33
33
}
34
34
35
- #[ derive( Debug , PartialEq ) ]
35
+ #[ derive( Debug , PartialEq , Clone ) ]
36
36
enum RuleSpecifier {
37
37
Category ( RuleCategory ) ,
38
38
Group ( RuleCategory , String ) ,
@@ -62,6 +62,21 @@ impl RuleSpecifier {
62
62
_ => None ,
63
63
}
64
64
}
65
+
66
+ fn is_disabled ( & self , disabled_rules : & [ RuleFilter < ' _ > ] ) -> bool {
67
+ // note: it is not possible to disable entire categories via the config
68
+ let group = self . group ( ) ;
69
+ let rule = self . rule ( ) ;
70
+
71
+ tracing:: error!( "group and rule: {:#?} {:#?}" , group, rule) ;
72
+
73
+ disabled_rules. iter ( ) . any ( |r| match r {
74
+ RuleFilter :: Group ( gr) => group. is_some_and ( |specifier_group| specifier_group == * gr) ,
75
+ RuleFilter :: Rule ( gr, ru) => group. is_some_and ( |specifier_group| {
76
+ rule. is_some_and ( |specifier_rule| specifier_group == * gr && specifier_rule == * ru)
77
+ } ) ,
78
+ } )
79
+ }
65
80
}
66
81
67
82
impl TryFrom < & str > for RuleSpecifier {
@@ -84,12 +99,12 @@ impl TryFrom<&str> for RuleSpecifier {
84
99
}
85
100
}
86
101
87
- #[ derive( Debug ) ]
102
+ #[ derive( Debug , Clone ) ]
88
103
pub struct Suppression {
89
104
suppression_range : TextRange ,
90
- /// `None` means that all categories are suppressed
91
105
kind : SuppressionKind ,
92
106
rule_specifier : RuleSpecifier ,
107
+ #[ allow( unused) ]
93
108
explanation : Option < String > ,
94
109
}
95
110
@@ -191,17 +206,26 @@ impl Suppression {
191
206
192
207
false
193
208
}
209
+
210
+ fn to_disabled_diagnostic ( self ) -> SuppressionDiagnostic {
211
+ SuppressionDiagnostic {
212
+ span : self . suppression_range ,
213
+ message : MessageAndDescription :: from ( format ! (
214
+ "This rule has been disabled via the configuration. The suppression has no effect."
215
+ ) ) ,
216
+ }
217
+ }
194
218
}
195
219
196
- #[ derive( Debug ) ]
220
+ #[ derive( Debug , Clone ) ]
197
221
pub struct RangeSuppression {
198
222
suppressed_range : TextRange ,
199
223
start_suppression : Suppression ,
200
224
}
201
225
202
226
type Line = usize ;
203
227
204
- #[ derive( Debug , Default ) ]
228
+ #[ derive( Debug , Default , Clone ) ]
205
229
pub struct Suppressions {
206
230
file_suppressions : Vec < Suppression > ,
207
231
line_suppressions : std:: collections:: HashMap < Line , Suppression > ,
@@ -211,6 +235,53 @@ pub struct Suppressions {
211
235
}
212
236
213
237
impl Suppressions {
238
+ pub fn considering_disabled_rules ( mut self , disabled_rules : & [ RuleFilter < ' _ > ] ) -> Self {
239
+ tracing:: error!( "disabled rules: {:#?}" , disabled_rules) ;
240
+
241
+ {
242
+ let ( enabled, disabled) = self
243
+ . file_suppressions
244
+ . into_iter ( )
245
+ . partition ( |s| !s. rule_specifier . is_disabled ( disabled_rules) ) ;
246
+
247
+ self . file_suppressions = enabled;
248
+
249
+ for suppr in disabled {
250
+ self . diagnostics . push ( suppr. to_disabled_diagnostic ( ) ) ;
251
+ }
252
+ }
253
+
254
+ {
255
+ let ( enabled, disabled) = self
256
+ . line_suppressions
257
+ . into_iter ( )
258
+ . partition ( |( _, s) | !s. rule_specifier . is_disabled ( disabled_rules) ) ;
259
+
260
+ self . line_suppressions = enabled;
261
+
262
+ for ( _, suppr) in disabled {
263
+ self . diagnostics . push ( suppr. to_disabled_diagnostic ( ) ) ;
264
+ }
265
+ }
266
+
267
+ {
268
+ let ( enabled, disabled) = self . range_suppressions . into_iter ( ) . partition ( |s| {
269
+ !s. start_suppression
270
+ . rule_specifier
271
+ . is_disabled ( disabled_rules)
272
+ } ) ;
273
+
274
+ self . range_suppressions = enabled;
275
+
276
+ for range_suppr in disabled {
277
+ self . diagnostics
278
+ . push ( range_suppr. start_suppression . to_disabled_diagnostic ( ) ) ;
279
+ }
280
+ }
281
+
282
+ self
283
+ }
284
+
214
285
pub fn is_suppressed < D : Diagnostic > ( & self , diagnostic : & D ) -> bool {
215
286
let location = diagnostic. location ( ) ;
216
287
@@ -402,196 +473,3 @@ impl<'a> SuppressionsParser<'a> {
402
473
}
403
474
}
404
475
}
405
-
406
- // #[cfg(test)]
407
- // mod tests {
408
- // use super::*;
409
-
410
- // fn parse(doc: &str) -> Suppressions {
411
- // SuppressionsParser::parse(doc)
412
- // }
413
-
414
- // #[test]
415
- // fn test_ignore_with_extra_colons_in_explanation() {
416
- // let doc = "// pgt-ignore lint/safety: reason: with: colons";
417
- // let sups = parse(doc);
418
- // let suppr = sups.line_suppressions.values().next().unwrap();
419
- // assert_eq!(suppr.explanation, Some("reason: with: colons"));
420
- // }
421
-
422
- // #[test]
423
- // fn test_ignore_with_trailing_whitespace() {
424
- // let doc = "// pgt-ignore lint/safety ";
425
- // let sups = parse(doc);
426
- // assert_eq!(sups.line_suppressions.len(), 1);
427
- // assert!(sups.diagnostics.is_empty());
428
- // }
429
-
430
- // #[test]
431
- // fn test_ignore_with_leading_whitespace() {
432
- // let doc = " // pgt-ignore lint/safety";
433
- // let sups = parse(doc);
434
- // assert_eq!(sups.line_suppressions.len(), 1);
435
- // assert!(sups.diagnostics.is_empty());
436
- // }
437
-
438
- // #[test]
439
- // fn test_multiple_unmatched_ends() {
440
- // let doc = r#"
441
- // // pgt-ignore-end lint/safety
442
- // // pgt-ignore-end lint/performance
443
- // "#;
444
- // let sups = parse(doc);
445
- // assert_eq!(sups.diagnostics.len(), 2);
446
- // for diag in sups.diagnostics {
447
- // assert!(
448
- // diag.message
449
- // .to_string()
450
- // .contains("does not have a matching start")
451
- // );
452
- // }
453
- // }
454
-
455
- // #[test]
456
- // fn test_multiple_unmatched_starts() {
457
- // let doc = r#"
458
- // // pgt-ignore-start lint/safety
459
- // // pgt-ignore-start lint/performance
460
- // "#;
461
- // let sups = parse(doc);
462
- // assert_eq!(sups.diagnostics.len(), 2);
463
- // for diag in sups.diagnostics {
464
- // assert!(
465
- // diag.message
466
- // .to_string()
467
- // .contains("does not have a matching end")
468
- // );
469
- // }
470
- // }
471
-
472
- // #[test]
473
- // fn test_ignore_with_invalid_tag_and_valid_tag() {
474
- // let doc = r#"
475
- // // pgt-ignore-foo lint/safety
476
- // // pgt-ignore lint/safety
477
- // "#;
478
- // let sups = parse(doc);
479
- // assert_eq!(sups.diagnostics.len(), 1);
480
- // assert_eq!(sups.line_suppressions.len(), 1);
481
- // }
482
-
483
- // #[test]
484
- // fn test_ignore_with_missing_category_and_valid_tag() {
485
- // let doc = r#"
486
- // // pgt-ignore
487
- // // pgt-ignore lint/safety
488
- // "#;
489
- // let sups = parse(doc);
490
- // assert_eq!(sups.diagnostics.len(), 1);
491
- // assert_eq!(sups.line_suppressions.len(), 1);
492
- // }
493
-
494
- // #[test]
495
- // fn test_ignore_with_group_and_rule_and_explanation() {
496
- // let doc = "// pgt-ignore lint/safety/banDropColumn: explanation";
497
- // let sups = parse(doc);
498
- // let suppr = sups.line_suppressions.values().next().unwrap();
499
- // assert_eq!(suppr.explanation, Some("explanation"));
500
- // match suppr.rule_filter {
501
- // Some(RuleFilter::Rule(group, rule)) => {
502
- // assert_eq!(group, "safety");
503
- // assert_eq!(rule, "banDropColumn");
504
- // }
505
- // _ => panic!("Expected RuleFilter::Rule"),
506
- // }
507
- // }
508
-
509
- // #[test]
510
- // fn test_ignore_with_group_only_and_explanation() {
511
- // let doc = "// pgt-ignore lint/safety: explanation";
512
- // let sups = parse(doc);
513
- // let suppr = sups.line_suppressions.values().next().unwrap();
514
- // assert_eq!(suppr.explanation, Some("explanation"));
515
- // match suppr.rule_filter {
516
- // Some(RuleFilter::Group(group)) => {
517
- // assert_eq!(group, "safety");
518
- // }
519
- // _ => panic!("Expected RuleFilter::Group"),
520
- // }
521
- // }
522
-
523
- // #[test]
524
- // fn test_ignore_with_no_group_or_rule_and_explanation() {
525
- // let doc = "// pgt-ignore lint: explanation";
526
- // let sups = parse(doc);
527
- // let suppr = sups.line_suppressions.values().next().unwrap();
528
- // assert_eq!(suppr.explanation, Some("explanation"));
529
- // assert!(suppr.rule_filter.is_none());
530
- // }
531
-
532
- // #[test]
533
- // fn test_ignore_with_empty_explanation() {
534
- // let doc = "// pgt-ignore lint/safety:";
535
- // let sups = parse(doc);
536
- // let suppr = sups.line_suppressions.values().next().unwrap();
537
- // assert_eq!(suppr.explanation, Some(""));
538
- // }
539
-
540
- // #[test]
541
- // fn test_ignore_with_multiple_colons_and_spaces() {
542
- // let doc = "// pgt-ignore lint/safety: explanation: with spaces ";
543
- // let sups = parse(doc);
544
- // let suppr = sups.line_suppressions.values().next().unwrap();
545
- // assert_eq!(suppr.explanation, Some("explanation: with spaces"));
546
- // }
547
-
548
- // #[test]
549
- // fn test_ignore_with_invalid_category() {
550
- // let doc = "// pgt-ignore foo/safety";
551
- // let sups = parse(doc);
552
- // assert_eq!(sups.line_suppressions.len(), 0);
553
- // assert_eq!(sups.diagnostics.len(), 1);
554
- // let diag = &sups.diagnostics[0];
555
- // assert_eq!(diag.message.to_string(), "Invalid Rule Category: foo");
556
- // }
557
-
558
- // #[test]
559
- // fn test_ignore_with_missing_specifier() {
560
- // let doc = "// pgt-ignore";
561
- // let sups = parse(doc);
562
- // assert_eq!(sups.line_suppressions.len(), 0);
563
- // assert_eq!(sups.diagnostics.len(), 1);
564
- // let diag = &sups.diagnostics[0];
565
- // assert!(
566
- // diag.message
567
- // .to_string()
568
- // .contains("must specify which lints to suppress")
569
- // || diag.message.to_string().contains("must specify")
570
- // );
571
- // }
572
-
573
- // #[test]
574
- // fn test_range_suppression_basic() {
575
- // let doc = r#"
576
- // // pgt-ignore-start lint/safety/banDropColumn: start explanation
577
- // SELECT * FROM foo;
578
- // // pgt-ignore-end lint/safety/banDropColumn: end explanation
579
- // "#;
580
- // let sups = parse(doc);
581
- // // Should have one range suppression
582
- // assert_eq!(sups.range_suppressions.len(), 1);
583
- // let range = &sups.range_suppressions[0];
584
- // assert_eq!(range.rule_category, RuleCategory::Lint);
585
- // assert_eq!(
586
- // range.rule_filter,
587
- // Some(RuleFilter::Rule("safety", "banDropColumn"))
588
- // );
589
- // assert_eq!(range.explanation, Some("start explanation"));
590
- // // The start and end suppressions should be present and correct
591
- // assert_eq!(
592
- // range.start_suppression.explanation,
593
- // Some("start explanation")
594
- // );
595
- // assert_eq!(range.end_suppression.explanation, Some("end explanation"));
596
- // }
597
- // }
0 commit comments