[clang-tools-extra] [clang-tidy] Fix invalid fix-it for macro expansions (PR #227984)
Peiqi Li via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 7 21:49:08 PDT 2026
https://github.com/voyager-jhk updated https://github.com/llvm/llvm-project/pull/227984
>From 2c83c3b872d4df82693e1422a06f7bcabd932529 Mon Sep 17 00:00:00 2001
From: voyager-jhk <voyager.lpq at gmail.com>
Date: Thu, 1 Oct 2026 15:20:28 +0800
Subject: [PATCH 1/2] [clang-tidy] Fix invalid fix-it for macro expansions
Do not offer a fix-it for one-character strings from macro expansions.
Fixes #222970
---
.../performance/PreferSingleCharOverloadsCheck.cpp | 13 ++++++++-----
clang-tools-extra/docs/ReleaseNotes.md | 5 +++++
.../performance/prefer-single-char-overloads.cpp | 10 ++++++++++
3 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/performance/PreferSingleCharOverloadsCheck.cpp b/clang-tools-extra/clang-tidy/performance/PreferSingleCharOverloadsCheck.cpp
index d5d1784c0a0b7..a62ef1254e806 100644
--- a/clang-tools-extra/clang-tidy/performance/PreferSingleCharOverloadsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/PreferSingleCharOverloadsCheck.cpp
@@ -101,11 +101,14 @@ void PreferSingleCharOverloadsCheck::check(
if (!Replacement)
return;
- diag(Literal->getBeginLoc(), "%0 called with a string literal consisting of "
- "a single character; consider using the more "
- "efficient overload accepting a character")
- << FindFunc
- << FixItHint::CreateReplacement(Literal->getSourceRange(), *Replacement);
+ const auto Diag = diag(Literal->getBeginLoc(),
+ "%0 called with a string literal consisting of "
+ "a single character; consider using the more "
+ "efficient overload accepting a character")
+ << FindFunc;
+ if (!Literal->getBeginLoc().isMacroID() && !Literal->getEndLoc().isMacroID())
+ Diag << FixItHint::CreateReplacement(Literal->getSourceRange(),
+ *Replacement);
}
} // namespace clang::tidy::performance
diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md
index 94e0f279d1c6c..8b32c22542aeb 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -295,6 +295,11 @@ infrastructure are described first, followed by tool-specific sections.
{option}`ForRangeLoopClasses` to configure container classes that can be used
as sources in range-based `for` loops.
+- Improved {doc}`performance-prefer-single-char-overloads
+ <clang-tidy/checks/performance/prefer-single-char-overloads>` check to
+ avoid offering fix-its for string literals originating from macro
+ expansions.
+
- Improved {doc}`readability-convert-member-functions-to-static
<clang-tidy/checks/readability/convert-member-functions-to-static>` check by
fixing a crash when checking a const-qualified method declared with the
diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/prefer-single-char-overloads.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/prefer-single-char-overloads.cpp
index 46bbf3c20f8fd..14af39aded0b6 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/performance/prefer-single-char-overloads.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/performance/prefer-single-char-overloads.cpp
@@ -146,6 +146,16 @@ int Macros() {
// CHECK-MESSAGES: [[@LINE-2]]:37: warning: 'find' called with a string literal
}
+#define TOKEN_SEPARATING_CHARACTER "_"
+// CHECK-FIXES: #define TOKEN_SEPARATING_CHARACTER "_"
+
+void foo() {
+ std::string a;
+ a += TOKEN_SEPARATING_CHARACTER;
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: 'operator+=' called with a
+ // CHECK-FIXES: a += TOKEN_SEPARATING_CHARACTER;
+}
+
void SubstitutedTemplateType() {
Wrapper<std::string>().value.find("a");
// CHECK-MESSAGES: [[@LINE-1]]:37: warning: 'find' called with a string literal
>From 0a60ba84777b0b0ab9131df8c9c8c549abc78964 Mon Sep 17 00:00:00 2001
From: voyager-jhk <voyager.lpq at gmail.com>
Date: Mon, 5 Oct 2026 15:11:53 +0800
Subject: [PATCH 2/2] Check all concatenated string tokens for macro expansions
---
.../performance/PreferSingleCharOverloadsCheck.cpp | 4 +++-
.../performance/prefer-single-char-overloads.cpp | 10 ++++++++++
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/performance/PreferSingleCharOverloadsCheck.cpp b/clang-tools-extra/clang-tidy/performance/PreferSingleCharOverloadsCheck.cpp
index a62ef1254e806..4f62bd2be7d83 100644
--- a/clang-tools-extra/clang-tidy/performance/PreferSingleCharOverloadsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/PreferSingleCharOverloadsCheck.cpp
@@ -11,6 +11,7 @@
#include "../utils/OptionsUtils.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
#include <optional>
using namespace clang::ast_matchers;
@@ -106,7 +107,8 @@ void PreferSingleCharOverloadsCheck::check(
"a single character; consider using the more "
"efficient overload accepting a character")
<< FindFunc;
- if (!Literal->getBeginLoc().isMacroID() && !Literal->getEndLoc().isMacroID())
+ if (std::none_of(Literal->tokloc_begin(), Literal->tokloc_end(),
+ [](SourceLocation Loc) { return Loc.isMacroID(); }))
Diag << FixItHint::CreateReplacement(Literal->getSourceRange(),
*Replacement);
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/prefer-single-char-overloads.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/prefer-single-char-overloads.cpp
index 14af39aded0b6..58f28f8ff9ecf 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/performance/prefer-single-char-overloads.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/performance/prefer-single-char-overloads.cpp
@@ -156,6 +156,16 @@ void foo() {
// CHECK-FIXES: a += TOKEN_SEPARATING_CHARACTER;
}
+#define SEP "_"
+// CHECK-FIXES: #define SEP "_"
+
+void ConcatenatedMacro() {
+ std::string s;
+ s += "" SEP "";
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: 'operator+=' called with a
+ // CHECK-FIXES: s += "" SEP "";
+}
+
void SubstitutedTemplateType() {
Wrapper<std::string>().value.find("a");
// CHECK-MESSAGES: [[@LINE-1]]:37: warning: 'find' called with a string literal
More information about the cfe-commits
mailing list