https://github.com/gxyd updated https://github.com/llvm/llvm-project/pull/190590
>From 787c59098c8a21cbe63db1f23aa713b0bff10d4e Mon Sep 17 00:00:00 2001 From: Gaurav Dhingra <[email protected]> Date: Sun, 5 Apr 2026 17:15:17 +0530 Subject: [PATCH 01/10] [clang-tidy] Enhance container-data-pointer-check to suggest c_ptr for consts Improves the container-data-pointer readability check to suggest use of 'c_ptr' instead of 'data' Fixes #55026 --- .../readability/ContainerDataPointerCheck.cpp | 67 ++++++++++++++++--- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp index 6dfef3aa247ef..9d304fd2a8478 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp @@ -38,8 +38,9 @@ void ContainerDataPointerCheck::registerMatchers(MatchFinder *Finder) { cxxRecordDecl( unless(matchers::matchesAnyListedRegexName(IgnoredContainers)), isSameOrDerivedFrom( - namedDecl( - has(cxxMethodDecl(isPublic(), hasName("data")).bind("data"))) + namedDecl(anyOf(has(cxxMethodDecl(isPublic(), hasName("c_str")) + .bind("c_str")), + has(cxxMethodDecl(isPublic(), hasName("data"))))) .bind("container"))) .bind("record"); @@ -91,6 +92,8 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { const auto *DCE = Result.Nodes.getNodeAs<Expr>(DerefContainerExprName); const auto *ACE = Result.Nodes.getNodeAs<Expr>(AddrOfContainerExprName); + const auto *CStrDecl = Result.Nodes.getNodeAs<CXXMethodDecl>("c_str"); + if (!UO || !CE) return; @@ -99,6 +102,46 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { else if (ACE) CE = ACE; + SourceRange ReplacementRange = UO->getSourceRange(); + bool UseCStr = false; + if (CStrDecl) { + auto Parents = Result.Context->getParents(*UO); + + if (!Parents.empty()) { + if (const auto *VD = Parents[0].get<VarDecl>()) { + QualType VarType = VD->getType(); + if (VarType->isPointerType()) { + QualType PointeeType = VarType->getPointeeType(); + UseCStr = PointeeType.isConstQualified(); + } + } else if (const auto *ICE = Parents[0].get<ImplicitCastExpr>()) { + QualType CastType = ICE->getType(); + if (CastType->isPointerType()) { + QualType PointeeType = CastType->getPointeeType(); + UseCStr = PointeeType.isConstQualified(); + } + } else if (const auto *Cast = Parents[0].get<CastExpr>()) { + QualType CastType = Cast->getType(); + if (CastType->isPointerType()) { + QualType PointeeType = CastType->getPointeeType(); + UseCStr = PointeeType.isConstQualified(); + if (UseCStr) { + // if it's a const cast, use the Cast range as replacement range + // e.g. (const char*)&s[0] -> s.c_str() + ReplacementRange = Cast->getSourceRange(); + } + } + } + } + + if (!UseCStr) { + QualType ContainerType = CE->getType(); + if (ContainerType->isPointerType()) + ContainerType = ContainerType->getPointeeType(); + UseCStr = ContainerType.isConstQualified(); + } + } + const SourceRange SrcRange = CE->getSourceRange(); std::string ReplacementText{ @@ -112,16 +155,18 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { if (NeedsParens) ReplacementText = "(" + ReplacementText + ")"; - if (CE->getType()->isPointerType()) - ReplacementText += "->data()"; - else - ReplacementText += ".data()"; + ReplacementText += CE->getType()->isPointerType() ? "->" : "."; + ReplacementText += UseCStr ? "c_str()" : "data()"; + llvm::StringRef Description = UseCStr + ? "'c_str' should be used for accessing " + "the data pointer instead of taking " + "the address of the 0-th element" + : "'data' should be used for accessing the " + "data pointer instead of taking " + "the address of the 0-th element"; const FixItHint Hint = - FixItHint::CreateReplacement(UO->getSourceRange(), ReplacementText); - diag(UO->getBeginLoc(), - "'data' should be used for accessing the data pointer instead of taking " - "the address of the 0-th element") - << Hint; + FixItHint::CreateReplacement(ReplacementRange, ReplacementText); + diag(UO->getBeginLoc(), Description) << Hint; } } // namespace clang::tidy::readability >From 03e85425488551e3a1c9c351694261a3027b5078 Mon Sep 17 00:00:00 2001 From: Gaurav Dhingra <[email protected]> Date: Mon, 6 Apr 2026 14:00:12 +0530 Subject: [PATCH 02/10] add test cases for 'c_ptr' usage instead of 'data' the following cases are tested: - char* p1 = &s[0]; - const char* p2 = &s[0]; - f((const char*)&((s).operator[]((z)))); - f(&((&(cs))->operator[]((z)))); // where `cs` is constant - const char* p3 = &cs[0]; // where `cs` is constant --- .../readability/container-data-pointer.cpp | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp index 4fd228a554d7d..3efa7ed4501bd 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp @@ -25,11 +25,37 @@ void h() { // CHECK-FIXES-CLASSIC: f(s.data()); // CHECK-MESSAGES-WITH-CONFIG-NOT: :[[@LINE-3]]:5: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + char* p1 = &s[0]; + // CHECK-MESSAGES-CLASSIC: :[[@LINE-1]]:14: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + // CHECK-FIXES-CLASSIC: char* p1 = s.data(); + // CHECK-MESSAGES-WITH-CONFIG-NOT: :[[@LINE-3]]:14: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + + const char* p2 = &s[0]; + // CHECK-MESSAGES-CLASSIC: :[[@LINE-1]]:20: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + // CHECK-FIXES-CLASSIC: const char* p2 = s.c_str(); + // CHECK-MESSAGES-WITH-CONFIG-NOT: :[[@LINE-3]]:20: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + std::wstring w; f(&((&(w))->operator[]((z)))); // CHECK-MESSAGES-CLASSIC: :[[@LINE-1]]:5: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] // CHECK-FIXES-CLASSIC: f(w.data()); // CHECK-MESSAGES-WITH-CONFIG-NOT: :[[@LINE-3]]:5: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + + f((const char*)&((s).operator[]((z)))); + // CHECK-MESSAGES-CLASSIC: :[[@LINE-1]]:18: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + // CHECK-FIXES-CLASSIC: f(s.c_str()); + // CHECK-MESSAGES-WITH-CONFIG-NOT: :[[@LINE-3]]:18: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + + const std::string cs; + f(&((&(cs))->operator[]((z)))); + // CHECK-MESSAGES-CLASSIC: :[[@LINE-1]]:5: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + // CHECK-FIXES-CLASSIC: f(cs.c_str()); + // CHECK-MESSAGES-WITH-CONFIG-NOT: :[[@LINE-3]]:5: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + + const char* p3 = &cs[0]; + // CHECK-MESSAGES-CLASSIC: :[[@LINE-1]]:20: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + // CHECK-FIXES-CLASSIC: const char* p3 = cs.c_str(); + // CHECK-MESSAGES-WITH-CONFIG-NOT: :[[@LINE-3]]:20: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] } template <typename T, typename U, >From 9e3d1db44759871a1a727666c1ed17d7d8c910b0 Mon Sep 17 00:00:00 2001 From: Gaurav Dhingra <[email protected]> Date: Mon, 6 Apr 2026 16:03:01 +0530 Subject: [PATCH 03/10] [clang-tidy] update docs & and add ReleaseNotes entry update documentation for readability check container-data-pointer and add a ReleaseNotes entry --- .../readability/ContainerDataPointerCheck.h | 2 +- clang-tools-extra/docs/ReleaseNotes.rst | 4 +++ .../readability/container-data-pointer.rst | 26 ++++++++++++++++--- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.h b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.h index 71fde87fbb093..7cb9fd6a2ea68 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.h +++ b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.h @@ -13,7 +13,7 @@ namespace clang::tidy::readability { /// Checks whether a call to `operator[]` and `&` can be replaced with a call to -/// `data()`. +/// `data()` or (for consts, when available) `c_str()`. /// /// This only replaces the case where the offset being accessed through the /// subscript operation is a known constant 0. This avoids a potential invalid diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 02315415b975f..4eb3af6888951 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -277,6 +277,10 @@ Changes in existing checks - Do not report explicit call to destructor after move as an invalid use. +- Improved :doc:`container-data-pointer + <clang-tidy/checks/readability/container-data-pointer>` check + to use ``c_str()`` for const's when available and present on a container. + - Improved :doc:`cppcoreguidelines-avoid-capturing-lambda-coroutines <clang-tidy/checks/cppcoreguidelines/avoid-capturing-lambda-coroutines>` check by adding the `AllowExplicitObjectParameters` option. When enabled, diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst index 4b2ef6ef1fbea..3c9f13c90661f 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst @@ -3,15 +3,35 @@ readability-container-data-pointer ================================== -Finds cases where code could use ``data()`` rather than the address of the -element at index 0 in a container. This pattern is commonly used to materialize -a pointer to the backing data of a container. ``std::vector`` and +Finds cases where code could use ``data()`` or ``c_str()`` rather than the +address of the element at index 0 in a container. This pattern is commonly used +to materialize a pointer to the backing data of a container. ``std::vector`` and ``std::string`` provide a ``data()`` accessor to retrieve the data pointer which should be preferred. +This check suggests ``data()`` for non-const pointer contexts and ``c_str()`` +for const pointer contexts when available. This provides better semantic +clarity: ``c_str()`` explicitly indicates read-only access to string data, +while ``data()`` may allow modifications. + This also ensures that in the case that the container is empty, the data pointer access does not perform an errant memory access. +Examples +-------- + +.. code-block: c++ + + std::string s; + std::vector<int> v; + + char* p1 = &s[0]; // Warning: use s.data() + const char* p2 = &s[0] // Warning: use s.c_str() + int* p3 = &v[0]; // Warning: use v.data() + + const std::string cs; + const char* p4 = &cs[0]; // Warning: use cs.c_str() + Options ------- >From c005e7f895d46917d9f0adf6127edefffbe13da2 Mon Sep 17 00:00:00 2001 From: Gaurav Dhingra <[email protected]> Date: Mon, 6 Apr 2026 16:37:59 +0530 Subject: [PATCH 04/10] use '%select' for llvm::StringRef instead of ternary operator --- .../readability/ContainerDataPointerCheck.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp index 9d304fd2a8478..1fdb54e652b55 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp @@ -158,15 +158,11 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { ReplacementText += CE->getType()->isPointerType() ? "->" : "."; ReplacementText += UseCStr ? "c_str()" : "data()"; - llvm::StringRef Description = UseCStr - ? "'c_str' should be used for accessing " - "the data pointer instead of taking " - "the address of the 0-th element" - : "'data' should be used for accessing the " - "data pointer instead of taking " - "the address of the 0-th element"; const FixItHint Hint = FixItHint::CreateReplacement(ReplacementRange, ReplacementText); - diag(UO->getBeginLoc(), Description) << Hint; + diag(UO->getBeginLoc(), + "'%select{data|c_str}0' should be used for accessing the data pointer " + "instead of taking the address of the 0-th element") + << UseCStr << Hint; } } // namespace clang::tidy::readability >From 1320036b8c8612a35ab7066974d3dbacf1062cfc Mon Sep 17 00:00:00 2001 From: Gaurav Dhingra <[email protected]> Date: Mon, 6 Apr 2026 16:43:19 +0530 Subject: [PATCH 05/10] remove redundant cast removal step when improving readability --- .../readability/ContainerDataPointerCheck.cpp | 14 +------------- .../readability/container-data-pointer.cpp | 2 +- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp index 1fdb54e652b55..427924aaddcc2 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp @@ -102,7 +102,6 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { else if (ACE) CE = ACE; - SourceRange ReplacementRange = UO->getSourceRange(); bool UseCStr = false; if (CStrDecl) { auto Parents = Result.Context->getParents(*UO); @@ -114,22 +113,11 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { QualType PointeeType = VarType->getPointeeType(); UseCStr = PointeeType.isConstQualified(); } - } else if (const auto *ICE = Parents[0].get<ImplicitCastExpr>()) { - QualType CastType = ICE->getType(); - if (CastType->isPointerType()) { - QualType PointeeType = CastType->getPointeeType(); - UseCStr = PointeeType.isConstQualified(); - } } else if (const auto *Cast = Parents[0].get<CastExpr>()) { QualType CastType = Cast->getType(); if (CastType->isPointerType()) { QualType PointeeType = CastType->getPointeeType(); UseCStr = PointeeType.isConstQualified(); - if (UseCStr) { - // if it's a const cast, use the Cast range as replacement range - // e.g. (const char*)&s[0] -> s.c_str() - ReplacementRange = Cast->getSourceRange(); - } } } } @@ -159,7 +147,7 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { ReplacementText += UseCStr ? "c_str()" : "data()"; const FixItHint Hint = - FixItHint::CreateReplacement(ReplacementRange, ReplacementText); + FixItHint::CreateReplacement(UO->getSourceRange(), ReplacementText); diag(UO->getBeginLoc(), "'%select{data|c_str}0' should be used for accessing the data pointer " "instead of taking the address of the 0-th element") diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp index 3efa7ed4501bd..78f3dc4eeb277 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp @@ -43,7 +43,7 @@ void h() { f((const char*)&((s).operator[]((z)))); // CHECK-MESSAGES-CLASSIC: :[[@LINE-1]]:18: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] - // CHECK-FIXES-CLASSIC: f(s.c_str()); + // CHECK-FIXES-CLASSIC: f((const char*)s.c_str()); // CHECK-MESSAGES-WITH-CONFIG-NOT: :[[@LINE-3]]:18: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] const std::string cs; >From d8aaa3f3ba581f161d75f2693b873f77d12210f1 Mon Sep 17 00:00:00 2001 From: Gaurav Dhingra <[email protected]> Date: Mon, 6 Apr 2026 18:55:22 +0530 Subject: [PATCH 06/10] fix code linter warnings --- .../clang-tidy/readability/ContainerDataPointerCheck.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp index 427924aaddcc2..f0ac0c6020205 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp @@ -108,15 +108,15 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { if (!Parents.empty()) { if (const auto *VD = Parents[0].get<VarDecl>()) { - QualType VarType = VD->getType(); + const QualType VarType = VD->getType(); if (VarType->isPointerType()) { - QualType PointeeType = VarType->getPointeeType(); + const QualType PointeeType = VarType->getPointeeType(); UseCStr = PointeeType.isConstQualified(); } } else if (const auto *Cast = Parents[0].get<CastExpr>()) { - QualType CastType = Cast->getType(); + const QualType CastType = Cast->getType(); if (CastType->isPointerType()) { - QualType PointeeType = CastType->getPointeeType(); + const QualType PointeeType = CastType->getPointeeType(); UseCStr = PointeeType.isConstQualified(); } } >From c7d17bbb84d4529ad538c80be7f2b0e16208ddb1 Mon Sep 17 00:00:00 2001 From: Gaurav Dhingra <[email protected]> Date: Thu, 9 Apr 2026 14:51:18 +0530 Subject: [PATCH 07/10] refactor c_str() identification and handle implicit return cast refactor c_str() identification as a separate static function `shouldUseCStr()` with smarter return early Handle case: ``` [](std::string s) -> const char* { return &s[0]; } ``` to use `c_str()` and not `data()` --- .../readability/ContainerDataPointerCheck.cpp | 70 +++++++++++-------- .../readability/container-data-pointer.cpp | 16 +++++ 2 files changed, 57 insertions(+), 29 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp index f0ac0c6020205..a2ca31f159291 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp @@ -86,14 +86,52 @@ void ContainerDataPointerCheck::registerMatchers(MatchFinder *Finder) { this); } +static bool isContainerConst(const Expr* ContainerExpr) { + QualType ContainerType = ContainerExpr->getType(); + if (ContainerType->isPointerType()) + ContainerType = ContainerType->getPointeeType(); + return ContainerType.isConstQualified(); +} + +static bool isConstPointer(const QualType Type) { + if (!Type->isPointerType()) + return false; + return Type->getPointeeType().isConstQualified(); +} + +static bool shouldUseCStr(const MatchFinder::MatchResult &Result) { + const auto *CStrDecl = Result.Nodes.getNodeAs<CXXMethodDecl>("c_str"); + const auto *UO = Result.Nodes.getNodeAs<UnaryOperator>(AddressOfName); + const auto *CE = Result.Nodes.getNodeAs<Expr>(ContainerExprName); + + if (!CStrDecl) + return false; + + auto Parents = Result.Context->getParents(*UO); + if (Parents.empty()) + return isContainerConst(CE); + + if (const auto *VD = Parents[0].get<VarDecl>()) { + if (isConstPointer(VD->getType())) + return true; + } else if (const auto *Cast = Parents[0].get<CastExpr>()) { + if (isConstPointer(Cast->getType())) + return true; + } else if (const auto *RetStmt = Parents[0].get<ReturnStmt>()) { + const Expr* RetValue = RetStmt->getRetValue(); + if (isConstPointer(RetValue->getType())) + return true; + } + + return isContainerConst(CE); +} + void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { const auto *UO = Result.Nodes.getNodeAs<UnaryOperator>(AddressOfName); const auto *CE = Result.Nodes.getNodeAs<Expr>(ContainerExprName); const auto *DCE = Result.Nodes.getNodeAs<Expr>(DerefContainerExprName); const auto *ACE = Result.Nodes.getNodeAs<Expr>(AddrOfContainerExprName); - const auto *CStrDecl = Result.Nodes.getNodeAs<CXXMethodDecl>("c_str"); - if (!UO || !CE) return; @@ -102,33 +140,7 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { else if (ACE) CE = ACE; - bool UseCStr = false; - if (CStrDecl) { - auto Parents = Result.Context->getParents(*UO); - - if (!Parents.empty()) { - if (const auto *VD = Parents[0].get<VarDecl>()) { - const QualType VarType = VD->getType(); - if (VarType->isPointerType()) { - const QualType PointeeType = VarType->getPointeeType(); - UseCStr = PointeeType.isConstQualified(); - } - } else if (const auto *Cast = Parents[0].get<CastExpr>()) { - const QualType CastType = Cast->getType(); - if (CastType->isPointerType()) { - const QualType PointeeType = CastType->getPointeeType(); - UseCStr = PointeeType.isConstQualified(); - } - } - } - - if (!UseCStr) { - QualType ContainerType = CE->getType(); - if (ContainerType->isPointerType()) - ContainerType = ContainerType->getPointeeType(); - UseCStr = ContainerType.isConstQualified(); - } - } + bool UseCStr = shouldUseCStr(Result); const SourceRange SrcRange = CE->getSourceRange(); diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp index 78f3dc4eeb277..f54286f875b3e 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp @@ -35,6 +35,11 @@ void h() { // CHECK-FIXES-CLASSIC: const char* p2 = s.c_str(); // CHECK-MESSAGES-WITH-CONFIG-NOT: :[[@LINE-3]]:20: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + const auto* auto_p2 = &s[0]; + // CHECK-MESSAGES-CLASSIC: :[[@LINE-1]]:25: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + // CHECK-FIXES-CLASSIC: const auto* auto_p2 = s.c_str(); + // CHECK-MESSAGES-WITH-CONFIG-NOT: :[[@LINE-3]]:25: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + std::wstring w; f(&((&(w))->operator[]((z)))); // CHECK-MESSAGES-CLASSIC: :[[@LINE-1]]:5: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] @@ -56,6 +61,17 @@ void h() { // CHECK-MESSAGES-CLASSIC: :[[@LINE-1]]:20: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] // CHECK-FIXES-CLASSIC: const char* p3 = cs.c_str(); // CHECK-MESSAGES-WITH-CONFIG-NOT: :[[@LINE-3]]:20: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + + const auto* auto_p3 = &cs[0]; + // CHECK-MESSAGES-CLASSIC: :[[@LINE-1]]:25: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + // CHECK-FIXES-CLASSIC: const auto* auto_p3 = cs.c_str(); + // CHECK-MESSAGES-WITH-CONFIG-NOT: :[[@LINE-3]]:25: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + + auto char_lambda = [](std::string s) -> const char* { + return &s[0]; + // CHECK-MESSAGES-CLASSIC: :[[@LINE-1]]:12: warning: 'c_str' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer] + // CHECK-FIXES-CLASSIC: return s.c_str(); + }; } template <typename T, typename U, >From db9e1566de07bf9c75d8142caa05d2ca099ae8f7 Mon Sep 17 00:00:00 2001 From: Gaurav Dhingra <[email protected]> Date: Thu, 9 Apr 2026 14:54:02 +0530 Subject: [PATCH 08/10] update ReleaseNotes entry --- clang-tools-extra/docs/ReleaseNotes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 4eb3af6888951..980f92ef35743 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -279,7 +279,7 @@ Changes in existing checks - Improved :doc:`container-data-pointer <clang-tidy/checks/readability/container-data-pointer>` check - to use ``c_str()`` for const's when available and present on a container. + to use ``c_str()`` for ``const``'s when available and present on a container. - Improved :doc:`cppcoreguidelines-avoid-capturing-lambda-coroutines <clang-tidy/checks/cppcoreguidelines/avoid-capturing-lambda-coroutines>` >From 8264785643cdee76e3abfa238079d40d3a9736e6 Mon Sep 17 00:00:00 2001 From: Gaurav Dhingra <[email protected]> Date: Thu, 9 Apr 2026 18:57:39 +0530 Subject: [PATCH 09/10] fix formatting and lint issues --- .../clang-tidy/readability/ContainerDataPointerCheck.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp index a2ca31f159291..9bf08ac1a836f 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp @@ -86,7 +86,7 @@ void ContainerDataPointerCheck::registerMatchers(MatchFinder *Finder) { this); } -static bool isContainerConst(const Expr* ContainerExpr) { +static bool isContainerConst(const Expr *ContainerExpr) { QualType ContainerType = ContainerExpr->getType(); if (ContainerType->isPointerType()) ContainerType = ContainerType->getPointeeType(); @@ -118,7 +118,7 @@ static bool shouldUseCStr(const MatchFinder::MatchResult &Result) { if (isConstPointer(Cast->getType())) return true; } else if (const auto *RetStmt = Parents[0].get<ReturnStmt>()) { - const Expr* RetValue = RetStmt->getRetValue(); + const Expr *RetValue = RetStmt->getRetValue(); if (isConstPointer(RetValue->getType())) return true; } @@ -140,7 +140,7 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { else if (ACE) CE = ACE; - bool UseCStr = shouldUseCStr(Result); + const auto UseCStr = shouldUseCStr(Result); const SourceRange SrcRange = CE->getSourceRange(); >From 8e6a9e7228cc9ea1db015e1791102be95bf7d640 Mon Sep 17 00:00:00 2001 From: Gaurav Dhingra <[email protected]> Date: Thu, 9 Apr 2026 21:35:09 +0530 Subject: [PATCH 10/10] Update clang-tools-extra/docs/ReleaseNotes.rst Co-authored-by: EugeneZelenko <[email protected]> --- clang-tools-extra/docs/ReleaseNotes.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 980f92ef35743..cf4e820363424 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -278,8 +278,8 @@ Changes in existing checks - Do not report explicit call to destructor after move as an invalid use. - Improved :doc:`container-data-pointer - <clang-tidy/checks/readability/container-data-pointer>` check - to use ``c_str()`` for ``const``'s when available and present on a container. + <clang-tidy/checks/readability/container-data-pointer>` check to use + ``c_str()`` for ``const``'s when available and present on a container. - Improved :doc:`cppcoreguidelines-avoid-capturing-lambda-coroutines <clang-tidy/checks/cppcoreguidelines/avoid-capturing-lambda-coroutines>` _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
