Skip to content

Commit 54dd04b

Browse files
authored
linter: fix ignore comment not working with trailing content (#975)
1 parent 115e09f commit 54dd04b

2 files changed

Lines changed: 114 additions & 9 deletions

File tree

crates/squawk_linter/src/ignore.rs

Lines changed: 113 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub enum IgnoreKind {
1515
pub struct Ignore {
1616
pub range: TextRange,
1717
pub violation_names: HashSet<Rule>,
18+
pub ignore_all: bool,
1819
pub kind: IgnoreKind,
1920
}
2021

@@ -48,18 +49,22 @@ pub fn ignore_rule_info(token: &SyntaxToken) -> Option<(&str, TextRange, IgnoreK
4849
if let Some((comment_body, range)) = comment_body(token) {
4950
let without_start = comment_body.trim_start();
5051
let trim_start_size = comment_body.len() - without_start.len();
51-
let trimmed_comment = without_start.trim_end();
52-
let trim_end_size = without_start.len() - trimmed_comment.len();
52+
53+
let without_end = without_start
54+
.find("--")
55+
.map_or(without_start, |idx| &without_start[..idx])
56+
.trim_end();
57+
let trim_end_size = without_start.len() - without_end.len();
5358

5459
for (prefix, kind) in [
5560
(IGNORE_FILE_TEXT, IgnoreKind::File),
5661
(IGNORE_LINE_TEXT, IgnoreKind::Line),
5762
] {
58-
if let Some(without_prefix) = trimmed_comment.strip_prefix(prefix) {
59-
let range = TextRange::new(
60-
range.start() + TextSize::new((trim_start_size + prefix.len()) as u32),
61-
range.end() - TextSize::new(trim_end_size as u32),
62-
);
63+
if let Some(without_prefix) = without_end.strip_prefix(prefix) {
64+
let start = range.start() + TextSize::new((trim_start_size + prefix.len()) as u32);
65+
let end = range.end() - TextSize::new(trim_end_size as u32);
66+
67+
let range = TextRange::new(start, end);
6368
return Some((without_prefix, range, kind));
6469
}
6570
}
@@ -76,6 +81,10 @@ pub(crate) fn find_ignores(ctx: &mut Linter, file: &SyntaxNode) {
7681
if let Some((rule_names, range, kind)) = ignore_rule_info(&token) {
7782
let mut set = HashSet::new();
7883
let mut offset = 0usize;
84+
// We have a specific check instead of going off of empty
85+
// rules in case we have invalid rule names specified in the
86+
// ignore.
87+
let ignore_all = rule_names.trim().is_empty();
7988

8089
// we need to keep track of our offset and report specific
8190
// ranges for any unknown names we encounter, which makes
@@ -109,6 +118,7 @@ pub(crate) fn find_ignores(ctx: &mut Linter, file: &SyntaxNode) {
109118
ctx.ignore(Ignore {
110119
range,
111120
violation_names: set,
121+
ignore_all,
112122
kind,
113123
});
114124
}
@@ -506,4 +516,100 @@ alter table t2 drop column c2 cascade;
506516
]
507517
");
508518
}
519+
520+
#[test]
521+
fn file_ignore_with_invalid_rules() {
522+
let mut linter = Linter::with_all_rules();
523+
let sql = r#"
524+
-- squawk-ignore-file ban-ban-ban-drop-column ignore-something hmm
525+
alter table t drop column c cascade;
526+
alter table t2 drop column c2 cascade;
527+
"#;
528+
529+
let parse = squawk_syntax::SourceFile::parse(sql);
530+
let errors = linter.lint(&parse, sql);
531+
let errors: Vec<_> = errors.iter().map(|x| (&x.code, &x.message)).collect();
532+
533+
assert_debug_snapshot!(errors, @r#"
534+
[
535+
(
536+
UnusedIgnore,
537+
"unknown name ban-ban-ban-drop-column ignore-something hmm",
538+
),
539+
(
540+
RequireTimeoutSettings,
541+
"Missing `set lock_timeout` before potentially slow operations",
542+
),
543+
(
544+
RequireTimeoutSettings,
545+
"Missing `set statement_timeout` before potentially slow operations",
546+
),
547+
(
548+
BanDropColumn,
549+
"Dropping a column may break existing clients.",
550+
),
551+
(
552+
PreferRobustStmts,
553+
"Missing `IF EXISTS`, the migration can't be rerun if it fails part way through.",
554+
),
555+
(
556+
BanDropColumn,
557+
"Dropping a column may break existing clients.",
558+
),
559+
(
560+
PreferRobustStmts,
561+
"Missing `IF EXISTS`, the migration can't be rerun if it fails part way through.",
562+
),
563+
]
564+
"#);
565+
}
566+
567+
#[test]
568+
fn file_ignore_with_trailing_comment() {
569+
let mut linter = Linter::with_all_rules();
570+
let sql = r#"
571+
-- squawk-ignore-file ban-drop-column -- some comment here
572+
alter table t drop column c cascade;
573+
alter table t2 drop column c2 cascade;
574+
"#;
575+
576+
let parse = squawk_syntax::SourceFile::parse(sql);
577+
let errors: Vec<_> = linter
578+
.lint(&parse, sql)
579+
.into_iter()
580+
.map(|x| x.code)
581+
.collect();
582+
583+
assert_debug_snapshot!(errors, @"
584+
[
585+
RequireTimeoutSettings,
586+
RequireTimeoutSettings,
587+
PreferRobustStmts,
588+
PreferRobustStmts,
589+
]
590+
");
591+
}
592+
593+
#[test]
594+
fn line_ignore_with_trailing_comment() {
595+
let mut linter = Linter::with_all_rules();
596+
let sql = r#"
597+
-- squawk-ignore ban-drop-column,prefer-robust-stmts -- drop is intentional
598+
alter table t drop column c cascade;
599+
"#;
600+
601+
let parse = squawk_syntax::SourceFile::parse(sql);
602+
let errors: Vec<_> = linter
603+
.lint(&parse, sql)
604+
.into_iter()
605+
.map(|x| x.code)
606+
.collect();
607+
608+
assert_debug_snapshot!(errors, @"
609+
[
610+
RequireTimeoutSettings,
611+
RequireTimeoutSettings,
612+
]
613+
");
614+
}
509615
}

crates/squawk_linter/src/ignore_index.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ impl IgnoreIndex {
3838
for ignore in ignores {
3939
match ignore.kind {
4040
IgnoreKind::File => {
41-
if ignore.violation_names.is_empty() {
42-
// When a squawk-ignore-file comment has no rules, it means we should disable all the rules
41+
if ignore.ignore_all {
4342
ignore_all = true;
4443
} else {
4544
file_ignored.extend(ignore.violation_names.clone());

0 commit comments

Comments
 (0)