[clang-tools-extra] [clang-tidy] Fix bugprone-string-constructor FN with allocators. (PR #180337)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Feb 7 01:33:28 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-tools-extra
Author: Baranov Victor (vbvictor)
<details>
<summary>Changes</summary>
Fixes https://github.com/llvm/llvm-project/issues/180324.
---
Full diff: https://github.com/llvm/llvm-project/pull/180337.diff
3 Files Affected:
- (modified) clang-tools-extra/clang-tidy/bugprone/StringConstructorCheck.cpp (+10-3)
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+5)
- (modified) clang-tools-extra/test/clang-tidy/checkers/bugprone/string-constructor.cpp (+48-3)
``````````diff
diff --git a/clang-tools-extra/clang-tidy/bugprone/StringConstructorCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/StringConstructorCheck.cpp
index d2e631e539b78..4ec705a6016ab 100644
--- a/clang-tools-extra/clang-tidy/bugprone/StringConstructorCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/StringConstructorCheck.cpp
@@ -81,7 +81,10 @@ void StringConstructorCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
cxxConstructExpr(
hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
- argumentCountIs(2), hasArgument(0, hasType(qualType(isInteger()))),
+ anyOf(argumentCountIs(2),
+ allOf(argumentCountIs(3),
+ hasArgument(2, unless(hasType(qualType(isInteger())))))),
+ hasArgument(0, hasType(qualType(isInteger()))),
hasArgument(1, hasType(qualType(isInteger()))),
anyOf(
// Detect the expression: string('x', 40);
@@ -101,7 +104,10 @@ void StringConstructorCheck::registerMatchers(MatchFinder *Finder) {
cxxConstructExpr(
hasDeclaration(cxxConstructorDecl(ofClass(
cxxRecordDecl(hasAnyName(removeNamespaces(StringNames)))))),
- argumentCountIs(2), hasArgument(0, hasType(CharPtrType)),
+ anyOf(argumentCountIs(2),
+ allOf(argumentCountIs(3),
+ hasArgument(2, unless(hasType(qualType(isInteger())))))),
+ hasArgument(0, hasType(CharPtrType)),
hasArgument(1, hasType(isInteger())),
anyOf(
// Detect the expression: string("...", 0);
@@ -123,7 +129,8 @@ void StringConstructorCheck::registerMatchers(MatchFinder *Finder) {
cxxConstructExpr(
hasDeclaration(cxxConstructorDecl(ofClass(
cxxRecordDecl(hasAnyName(removeNamespaces(StringNames)))))),
- argumentCountIs(3), hasArgument(0, hasType(CharPtrType)),
+ anyOf(argumentCountIs(3), argumentCountIs(4)),
+ hasArgument(0, hasType(CharPtrType)),
hasArgument(1, hasType(qualType(isInteger()))),
hasArgument(2, hasType(qualType(isInteger()))),
anyOf(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 0ad69f5fdc5aa..c8edf0f08dc77 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -148,6 +148,11 @@ Changes in existing checks
<clang-tidy/checks/bugprone/macro-parentheses>` check by printing the macro
definition in the warning message if the macro is defined on command line.
+- Improved :doc:`bugprone-string-constructor
+ <clang-tidy/checks/bugprone/string-constructor>` check to detect suspicious
+ string constructor calls when the string class constructor has a default
+ allocator argument.
+
- Improved :doc:`bugprone-unsafe-functions
<clang-tidy/checks/bugprone/unsafe-functions>` check by adding the function
``std::get_temporary_buffer`` to the default list of unsafe functions. (This
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/string-constructor.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/string-constructor.cpp
index 2576d19916250..af844b04aa438 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/string-constructor.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/string-constructor.cpp
@@ -8,10 +8,10 @@ class char_traits {};
template <typename C, typename T = std::char_traits<C>, typename A = std::allocator<C> >
struct basic_string {
basic_string();
- basic_string(const C*, unsigned int size);
+ basic_string(const C*, unsigned int size, const A &a = A());
basic_string(const C *, const A &allocator = A());
- basic_string(unsigned int size, C c);
- basic_string(const C*, unsigned int pos, unsigned int size);
+ basic_string(unsigned int size, C c, const A &a = A());
+ basic_string(const C*, unsigned int pos, unsigned int size, const A &a = A());
};
typedef basic_string<char> string;
typedef basic_string<wchar_t> wstring;
@@ -119,6 +119,44 @@ std::string_view StringViewFromZero() {
// CHECK-MESSAGES: [[@LINE-1]]:10: warning: constructing string from nullptr is undefined behaviour
}
+void TestExplicitAllocator() {
+ std::allocator<char> a;
+
+ std::string s1('x', 5, a);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: string constructor parameters are probably swapped; expecting string(count, character) [bugprone-string-constructor]
+ // CHECK-FIXES: std::string s1(5, 'x', a);
+ std::string s2(0, 'x', a);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructor creating an empty string
+ std::string s3(-4, 'x', a);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: negative value used as length parameter
+ std::string s4(0x1000000, 'x', a);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter
+
+ std::string q0("test", 0, a);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructor creating an empty string
+ std::string q1(kText, -4, a);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: negative value used as length parameter
+ std::string q2("test", 200, a);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger than string literal size
+ std::string q3(kText3, 0x1000000, a);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter
+
+ std::string r1("test", 1, 0, a);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructor creating an empty string
+ std::string r2("test", 0, -4, a);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: negative value used as length parameter
+ std::string r3("test", -4, 1, a);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: negative value used as position of the first character parameter
+ std::string r4("test", 0, 0x1000000, a);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter
+ std::string r5("test", 0, 5, a);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger than string literal size
+ std::string r6("test", 3, 2, a);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger than remaining string literal size
+ std::string r7("test", 4, 1, a);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: position of the first character parameter is bigger than string literal character range
+}
+
void Valid() {
std::string empty();
std::string str(4, 'x');
@@ -132,6 +170,13 @@ void Valid() {
std::string s8("test", 3, 1);
std::string s9("te" "st", 1, 2);
+ std::allocator<char> a;
+ std::string sa1(4, 'x', a);
+ std::string sa2("test", 4, a);
+ std::string sa3("test", 3, a);
+ std::string sa4("test", 0, 4, a);
+ std::string sa5("test", 3, 1, a);
+
std::string_view emptyv();
std::string_view sv1("test", 4);
std::string_view sv2("test", 3);
``````````
</details>
https://github.com/llvm/llvm-project/pull/180337
More information about the cfe-commits
mailing list