diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_todos/TD003.py b/crates/ruff_linter/resources/test/fixtures/flake8_todos/TD003.py index 9746c27a0570e..87bf5291aa079 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_todos/TD003.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_todos/TD003.py @@ -34,4 +34,10 @@ def foo(x): # foo # TODO: no link! +# TODO: https://github.com/astral-sh/ruff/pull/9627 A todo with a link on the same line + +# TODO: #9627 A todo with a number on the same line + +# TODO: A todo with a random number, 5431 + # TODO: here's a TODO on the last line with no link diff --git a/crates/ruff_linter/src/rules/flake8_todos/rules/todos.rs b/crates/ruff_linter/src/rules/flake8_todos/rules/todos.rs index 1a04543fe3f1c..e9f482804b69d 100644 --- a/crates/ruff_linter/src/rules/flake8_todos/rules/todos.rs +++ b/crates/ruff_linter/src/rules/flake8_todos/rules/todos.rs @@ -91,6 +91,12 @@ impl Violation for MissingTodoAuthor { /// # TODO(charlie): this comment has a 3-digit issue code /// # 003 /// +/// # TODO(charlie): https://github.com/astral-sh/ruff/issues/3870 +/// # this comment has an issue link +/// +/// # TODO(charlie): #003 this comment has a 3-digit issue code +/// # with leading character `#` +/// /// # TODO(charlie): this comment has an issue code (matches the regex `[A-Z]+\-?\d+`) /// # SIXCHR-003 /// ``` @@ -100,7 +106,7 @@ pub(crate) struct MissingTodoLink; impl Violation for MissingTodoLink { #[derive_message_formats] fn message(&self) -> String { - "Missing issue link on the line following this TODO".to_string() + "Missing issue link for this TODO".to_string() } } @@ -224,7 +230,7 @@ impl Violation for MissingSpaceAfterTodoColon { } } -static ISSUE_LINK_REGEX_SET: LazyLock = LazyLock::new(|| { +static ISSUE_LINK_OWN_LINE_REGEX_SET: LazyLock = LazyLock::new(|| { RegexSet::new([ r"^#\s*(http|https)://.*", // issue link r"^#\s*\d+$", // issue code - like "003" @@ -233,6 +239,14 @@ static ISSUE_LINK_REGEX_SET: LazyLock = LazyLock::new(|| { .unwrap() }); +static ISSUE_LINK_TODO_LINE_REGEX_SET: LazyLock = LazyLock::new(|| { + RegexSet::new([ + r"\s*(http|https)://.*", // issue link + r"\s*#\d+.*", // issue code - like "#003" + ]) + .unwrap() +}); + pub(crate) fn todos( diagnostics: &mut Vec, todo_comments: &[TodoComment], @@ -257,6 +271,13 @@ pub(crate) fn todos( static_errors(diagnostics, content, range, directive); let mut has_issue_link = false; + // VSCode recommended links on same line are ok: + // `# TODO(dylan): #1234` + if ISSUE_LINK_TODO_LINE_REGEX_SET + .is_match(locator.slice(TextRange::new(directive.range.end(), range.end()))) + { + continue; + } let mut curr_range = range; for next_range in comment_ranges.iter().skip(range_index + 1).copied() { // Ensure that next_comment_range is in the same multiline comment "block" as @@ -274,7 +295,7 @@ pub(crate) fn todos( break; } - if ISSUE_LINK_REGEX_SET.is_match(next_comment) { + if ISSUE_LINK_OWN_LINE_REGEX_SET.is_match(next_comment) { has_issue_link = true; } diff --git a/crates/ruff_linter/src/rules/flake8_todos/snapshots/ruff_linter__rules__flake8_todos__tests__missing-todo-link_TD003.py.snap b/crates/ruff_linter/src/rules/flake8_todos/snapshots/ruff_linter__rules__flake8_todos__tests__missing-todo-link_TD003.py.snap index c381500f7c2e9..2b7e00d4c89d9 100644 --- a/crates/ruff_linter/src/rules/flake8_todos/snapshots/ruff_linter__rules__flake8_todos__tests__missing-todo-link_TD003.py.snap +++ b/crates/ruff_linter/src/rules/flake8_todos/snapshots/ruff_linter__rules__flake8_todos__tests__missing-todo-link_TD003.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_todos/mod.rs --- -TD003.py:15:3: TD003 Missing issue link on the line following this TODO +TD003.py:15:3: TD003 Missing issue link for this TODO | 14 | # TDO003 - errors 15 | # TODO: this comment has no @@ -9,7 +9,7 @@ TD003.py:15:3: TD003 Missing issue link on the line following this TODO 16 | # link after it | -TD003.py:18:3: TD003 Missing issue link on the line following this TODO +TD003.py:18:3: TD003 Missing issue link for this TODO | 16 | # link after it 17 | @@ -19,7 +19,7 @@ TD003.py:18:3: TD003 Missing issue link on the line following this TODO 20 | return x | -TD003.py:31:3: TD003 Missing issue link on the line following this TODO +TD003.py:31:3: TD003 Missing issue link for this TODO | 29 | # TDO-3870 30 | @@ -29,20 +29,30 @@ TD003.py:31:3: TD003 Missing issue link on the line following this TODO 33 | # TDO-3870 | -TD003.py:35:9: TD003 Missing issue link on the line following this TODO +TD003.py:35:9: TD003 Missing issue link for this TODO | 33 | # TDO-3870 34 | 35 | # foo # TODO: no link! | ^^^^ TD003 36 | -37 | # TODO: here's a TODO on the last line with no link +37 | # TODO: https://github.com/astral-sh/ruff/pull/9627 A todo with a link on the same line | -TD003.py:37:3: TD003 Missing issue link on the line following this TODO +TD003.py:41:3: TD003 Missing issue link for this TODO | -35 | # foo # TODO: no link! -36 | -37 | # TODO: here's a TODO on the last line with no link +39 | # TODO: #9627 A todo with a number on the same line +40 | +41 | # TODO: A todo with a random number, 5431 + | ^^^^ TD003 +42 | +43 | # TODO: here's a TODO on the last line with no link + | + +TD003.py:43:3: TD003 Missing issue link for this TODO + | +41 | # TODO: A todo with a random number, 5431 +42 | +43 | # TODO: here's a TODO on the last line with no link | ^^^^ TD003 |