From d474f89da535b53a90a9ce51bd9dc97dacb676f8 Mon Sep 17 00:00:00 2001 From: Brendan <2bndy5@gmail.com> Date: Tue, 23 Dec 2025 12:41:30 -0800 Subject: [PATCH 1/2] fix: use diagnostic name by default Corresponds to cpp-linter/cpp-linter#173. This should never happen in the wild, but just in case there's an underlying problem with parsing clang-tidy output... This fixes a problem about hyperlinking a clang-tidy diagnostic name to the clang-tidy docs. Specifically when the diagnostic name does not satisfy the following conditions: - starts with "clang-analyzer-" - starts with "clang-diagnostic-" - contains at least 1 hyphen (`-`) This also removes the `.unwrap()` calls (bad practice) and adds a test for code coverage. --- cpp-linter/src/clang_tools/clang_tidy.rs | 43 ++++++++++++++++++------ 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/cpp-linter/src/clang_tools/clang_tidy.rs b/cpp-linter/src/clang_tools/clang_tidy.rs index d8610ae..aa1d9bf 100644 --- a/cpp-linter/src/clang_tools/clang_tidy.rs +++ b/cpp-linter/src/clang_tools/clang_tidy.rs @@ -74,21 +74,26 @@ pub struct TidyNotification { impl TidyNotification { pub fn diagnostic_link(&self) -> String { - if self.diagnostic.starts_with("clang-diagnostic") { + if self.diagnostic.starts_with("clang-diagnostic-") { return self.diagnostic.clone(); } - let (category, name) = if self.diagnostic.starts_with("clang-analyzer-") { - ( - "clang-analyzer", - self.diagnostic.strip_prefix("clang-analyzer-").unwrap(), + if let Some((category, name)) = if self.diagnostic.starts_with("clang-analyzer-") { + self.diagnostic + .strip_prefix("clang-analyzer-") + .map(|n| ("clang-analyzer", n)) + } else { + self.diagnostic.split_once('-') + } { + // In production, both category and name should be non-empty strings. + // Clang does not actually have a diagnostic name whose category or name is empty. + debug_assert!(!category.is_empty() && !name.is_empty()); + format!( + "[{}](https://clang.llvm.org/extra/clang-tidy/checks/{category}/{name}.html)", + self.diagnostic ) } else { - self.diagnostic.split_once('-').unwrap() - }; - format!( - "[{}](https://clang.llvm.org/extra/clang-tidy/checks/{category}/{name}.html)", - self.diagnostic - ) + self.diagnostic.clone() + } } } @@ -392,6 +397,22 @@ mod test { assert_eq!(note.diagnostic_link(), expected); } + #[test] + fn invalid_diagnostic_link() { + let expected = "no_diagnostic_name".to_string(); + let note = TidyNotification { + filename: String::from("some_src.cpp"), + line: 1504, + cols: 9, + rationale: String::from("some rationale"), + severity: String::from("warning"), + diagnostic: expected.clone(), + suggestion: vec![], + fixed_lines: vec![], + }; + assert_eq!(note.diagnostic_link(), expected); + } + // ***************** test for regex parsing of clang-tidy stdout #[test] From 850dadb570dfd043bec40c57ce541a946b26301a Mon Sep 17 00:00:00 2001 From: Brendan <2bndy5@gmail.com> Date: Tue, 23 Dec 2025 13:26:02 -0800 Subject: [PATCH 2/2] AI review nitpick suggestion --- cpp-linter/src/clang_tools/clang_tidy.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpp-linter/src/clang_tools/clang_tidy.rs b/cpp-linter/src/clang_tools/clang_tidy.rs index aa1d9bf..929d555 100644 --- a/cpp-linter/src/clang_tools/clang_tidy.rs +++ b/cpp-linter/src/clang_tools/clang_tidy.rs @@ -75,6 +75,8 @@ pub struct TidyNotification { impl TidyNotification { pub fn diagnostic_link(&self) -> String { if self.diagnostic.starts_with("clang-diagnostic-") { + // clang-diagnostic-* diagnostics are compiler diagnostics and don't have + // dedicated clang-tidy documentation pages, so return the name as-is. return self.diagnostic.clone(); } if let Some((category, name)) = if self.diagnostic.starts_with("clang-analyzer-") {