1- use salsa ;
1+ use std :: cmp :: Ordering ;
22
3- use ruff_db:: { files:: File , parsed:: comment_ranges, source:: source_text} ;
3+ use ruff_python_parser:: TokenKind ;
4+ use ruff_source_file:: LineRanges ;
5+ use ruff_text_size:: { Ranged , TextRange , TextSize } ;
6+
7+ use ruff_db:: { files:: File , parsed:: parsed_module, source:: source_text} ;
48use ruff_index:: { newtype_index, IndexVec } ;
59
610use crate :: { lint:: LintId , Db } ;
711
812#[ salsa:: tracked( return_ref) ]
9- pub ( crate ) fn suppressions ( db : & dyn Db , file : File ) -> IndexVec < SuppressionIndex , Suppression > {
10- let comments = comment_ranges ( db. upcast ( ) , file) ;
13+ pub ( crate ) fn suppressions ( db : & dyn Db , file : File ) -> Suppressions {
1114 let source = source_text ( db. upcast ( ) , file) ;
15+ let parsed = parsed_module ( db. upcast ( ) , file) ;
1216
1317 let mut suppressions = IndexVec :: default ( ) ;
18+ let mut line_start = source. bom_start_offset ( ) ;
19+
20+ for token in parsed. tokens ( ) {
21+ match token. kind ( ) {
22+ TokenKind :: Comment => {
23+ let text = & source[ token. range ( ) ] ;
24+
25+ let suppressed_range = TextRange :: new ( line_start, token. end ( ) ) ;
1426
15- for range in comments {
16- let text = & source[ range] ;
17-
18- if text. starts_with ( "# type: ignore" ) {
19- suppressions. push ( Suppression {
20- target : None ,
21- kind : SuppressionKind :: TypeIgnore ,
22- } ) ;
23- } else if text. starts_with ( "# knot: ignore" ) {
24- suppressions. push ( Suppression {
25- target : None ,
26- kind : SuppressionKind :: KnotIgnore ,
27- } ) ;
27+ if text. strip_prefix ( "# type: ignore" ) . is_some_and ( |suffix| {
28+ suffix. is_empty ( ) || suffix. starts_with ( char:: is_whitespace)
29+ } ) {
30+ suppressions. push ( Suppression {
31+ target : None ,
32+ comment_range : token. range ( ) ,
33+ suppressed_range,
34+ } ) ;
35+ }
36+ }
37+ TokenKind :: Newline | TokenKind :: NonLogicalNewline => {
38+ line_start = token. range ( ) . end ( ) ;
39+ }
40+ _ => { }
2841 }
2942 }
3043
31- suppressions
44+ Suppressions { file, suppressions }
45+ }
46+
47+ #[ derive( Clone , Debug , Eq , PartialEq ) ]
48+ pub ( crate ) struct Suppressions {
49+ file : File ,
50+ suppressions : IndexVec < SuppressionIndex , Suppression > ,
51+ }
52+
53+ impl Suppressions {
54+ pub ( crate ) fn find_suppression (
55+ & self ,
56+ range : TextRange ,
57+ id : LintId ,
58+ ) -> Option < SuppressionIndex > {
59+ let enclosing_index = self . enclosing_suppression ( range. end ( ) ) ?;
60+ let enclosed_suppression = & self . suppressions [ enclosing_index] ;
61+
62+ // Ignore the suppression if it doesn't suppress the current lint.
63+ if !enclosed_suppression. suppresses ( id) {
64+ return None ;
65+ }
66+
67+ Some ( enclosing_index)
68+ }
69+
70+ fn enclosing_suppression ( & self , offset : TextSize ) -> Option < SuppressionIndex > {
71+ self . suppressions
72+ . binary_search_by ( |suppression| {
73+ if suppression. suppressed_range . contains ( offset) {
74+ Ordering :: Equal
75+ } else if suppression. suppressed_range . end ( ) < offset {
76+ Ordering :: Less
77+ } else {
78+ Ordering :: Greater
79+ }
80+ } )
81+ . ok ( )
82+ }
83+ }
84+
85+ impl std:: ops:: Index < SuppressionIndex > for Suppressions {
86+ type Output = Suppression ;
87+
88+ fn index ( & self , index : SuppressionIndex ) -> & Self :: Output {
89+ & self . suppressions [ index]
90+ }
3291}
3392
3493#[ newtype_index]
@@ -37,14 +96,13 @@ pub(crate) struct SuppressionIndex;
3796#[ derive( Clone , Debug , Eq , PartialEq , Hash ) ]
3897pub ( crate ) struct Suppression {
3998 target : Option < LintId > ,
40- kind : SuppressionKind ,
99+ comment_range : TextRange ,
100+ suppressed_range : TextRange ,
41101}
42102
43- #[ derive( Copy , Clone , Debug , Eq , PartialEq , Hash ) ]
44- pub ( crate ) enum SuppressionKind {
45- /// A `type: ignore` comment
46- TypeIgnore ,
47-
48- /// A `knot: ignore` comment
49- KnotIgnore ,
103+ impl Suppression {
104+ pub ( crate ) fn suppresses ( & self , tested_id : LintId ) -> bool {
105+ // Use `is_none_or` when the MSRV gets updated to 1.82
106+ self . target . is_none ( ) || self . target == Some ( tested_id)
107+ }
50108}
0 commit comments