[clang-tools-extra] [clang-tidy] Fix bugprone-bad-signal-to-kill-thread not working in clangd (PR #180711)

Alex Wang via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 10 02:05:22 PST 2026


https://github.com/aeft updated https://github.com/llvm/llvm-project/pull/180711

>From 5fe305db9007a1a1d174dac86d732c184145f7c1 Mon Sep 17 00:00:00 2001
From: Alex Wang <yesterda9 at gmail.com>
Date: Tue, 10 Feb 2026 01:51:18 -0800
Subject: [PATCH] [clang-tidy] Fix bugprone-bad-signal-to-kill-thread not
 working in clangd

After preamble deserialization, Token::getLiteralData() returns nullptr for macro tokens defined in headers. Fall back to SourceManager to retrieve the token text from the source buffer.

Fixes https://github.com/clangd/clangd/issues/2473
---
 .../bugprone/BadSignalToKillThreadCheck.cpp   | 24 ++++++++++++++++---
 .../clangd/unittests/DiagnosticsTests.cpp     | 19 +++++++++++++++
 2 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/BadSignalToKillThreadCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/BadSignalToKillThreadCheck.cpp
index 3e1188d5e2463..4a5fdeeadcb86 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BadSignalToKillThreadCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BadSignalToKillThreadCheck.cpp
@@ -33,14 +33,32 @@ void BadSignalToKillThreadCheck::check(const MatchFinder::MatchResult &Result) {
            KeyValue.first->hasMacroDefinition();
   };
   const auto TryExpandAsInteger =
-      [](Preprocessor::macro_iterator It) -> std::optional<unsigned> {
+      [&Result](Preprocessor::macro_iterator It) -> std::optional<unsigned> {
     if (It == PP->macro_end())
       return std::nullopt;
     const MacroInfo *MI = PP->getMacroInfo(It->first);
     const Token &T = MI->tokens().back();
-    if (!T.isLiteral() || !T.getLiteralData())
+
+    if (!T.isLiteral())
       return std::nullopt;
-    const StringRef ValueStr = StringRef(T.getLiteralData(), T.getLength());
+
+    StringRef ValueStr;
+    if (T.getLiteralData()) {
+      ValueStr = StringRef(T.getLiteralData(), T.getLength());
+    } else {
+      const SourceManager *SM = Result.SourceManager;
+      const SourceLocation Loc = T.getLocation();
+      if (Loc.isInvalid())
+        return std::nullopt;
+      std::optional<StringRef> Buffer =
+          SM->getBufferDataOrNone(SM->getFileID(Loc));
+      if (!Buffer)
+        return std::nullopt;
+      const unsigned Offset = SM->getFileOffset(Loc);
+      if (Offset + T.getLength() > Buffer->size())
+        return std::nullopt;
+      ValueStr = Buffer->substr(Offset, T.getLength());
+    }
 
     llvm::APInt IntValue;
     constexpr unsigned AutoSenseRadix = 0;
diff --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
index f9ff6f21009f3..84ceddbd4fc4b 100644
--- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
@@ -823,6 +823,25 @@ TEST(DiagnosticTest, ClangTidyNoLiteralDataInMacroToken) {
   EXPECT_THAT(TU.build().getDiagnostics(), UnorderedElementsAre()); // no-crash
 }
 
+TEST(DiagnosticTest, BadSignalToKillThreadInPreamble) {
+  Annotations Main(R"cpp(
+    #include "signal.h"
+    using pthread_t = int;
+    int pthread_kill(pthread_t thread, int sig);
+    int func() {
+      pthread_t thread;
+      return pthread_kill(thread, 15);
+    }
+  )cpp");
+  TestTU TU = TestTU::withCode(Main.code());
+  TU.HeaderFilename = "signal.h";
+  TU.HeaderCode = "#define SIGTERM 15";
+  TU.ClangTidyProvider = addTidyChecks("bugprone-bad-signal-to-kill-thread");
+  EXPECT_THAT(TU.build().getDiagnostics(),
+              ifTidyChecks(UnorderedElementsAre(
+                  diagName("bugprone-bad-signal-to-kill-thread"))));
+}
+
 TEST(DiagnosticTest, ClangTidyMacroToEnumCheck) {
   Annotations Main(R"cpp(
     #if 1



More information about the cfe-commits mailing list