From f29accd639928c3560309a15bf42e81b65e5b20f Mon Sep 17 00:00:00 2001 From: mtx Date: Thu, 30 Oct 2025 02:56:11 +0800 Subject: [PATCH 1/7] [clang-tidy] Fix `readability-container-data-pointer` check --- .../readability/ContainerDataPointerCheck.cpp | 7 +++++-- .../checkers/readability/container-data-pointer.cpp | 12 ++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp index 11756d10a8221..d9338888cc40e 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp @@ -107,8 +107,11 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { Lexer::getSourceText(CharSourceRange::getTokenRange(SrcRange), *Result.SourceManager, getLangOpts())}; - if (!isa(CE)) + const auto *OpCall = dyn_cast(CE); + bool NeedsParens = + OpCall ? (OpCall->getOperator() != OO_Subscript) + : !isa(CE); + if (NeedsParens) ReplacementText = "(" + ReplacementText + ")"; if (CE->getType()->isPointerType()) 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 a8e0eb6d262e6..26f9d9f16ac8c 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,12 @@ template struct enable_if { typedef T type; }; + +template +struct unique_ptr { + T &operator*() const; + T *operator->() const; +}; } template @@ -144,3 +150,9 @@ int *r() { // CHECK-MESSAGES: :[[@LINE-1]]:10: 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: return holder.v.data(); } + +void s(std::unique_ptr> p) { + f(&(*p)[0]); + // CHECK-MESSAGES: :[[@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: f((*p).data()); +} From b7dcb77b75d080d9003a96c669c40ca09c11fedc Mon Sep 17 00:00:00 2001 From: mtx Date: Thu, 30 Oct 2025 23:54:29 +0800 Subject: [PATCH 2/7] add release notes and fix minor issue --- .../clang-tidy/readability/ContainerDataPointerCheck.cpp | 2 +- clang-tools-extra/docs/ReleaseNotes.rst | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp index d9338888cc40e..dba4aa8d5fc6e 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp @@ -108,7 +108,7 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { *Result.SourceManager, getLangOpts())}; const auto *OpCall = dyn_cast(CE); - bool NeedsParens = + const bool NeedsParens = OpCall ? (OpCall->getOperator() != OO_Subscript) : !isa(CE); if (NeedsParens) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 8f4be0d1cb259..40c00c8206aff 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -362,7 +362,7 @@ Changes in existing checks - Improved :doc:`misc-const-correctness ` check to avoid false - positives when pointers is transferred to non-const references + positives when pointers is transferred to non-const references and avoid false positives of function pointer and fix false positives on return of non-const pointer. @@ -429,6 +429,10 @@ Changes in existing checks comparisons to ``npos``. Internal changes may cause new rare false positives in non-standard containers. +- Improved :doc:`readability-container-data-pointer + `check by correctly + adding parentheses when the container expression is a dereference. + - Improved :doc:`readability-container-size-empty ` check by correctly generating fix-it hints when size method is called from implicit ``this``, From 76bc6cfdcb8faa6ff24016baa9fb40051c28f9fd Mon Sep 17 00:00:00 2001 From: mtx Date: Fri, 31 Oct 2025 00:19:10 +0800 Subject: [PATCH 3/7] fix docs --- 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 40c00c8206aff..11337aa3d628e 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -430,7 +430,7 @@ Changes in existing checks in non-standard containers. - Improved :doc:`readability-container-data-pointer - `check by correctly + ` check by correctly adding parentheses when the container expression is a dereference. - Improved :doc:`readability-container-size-empty From f63a789bac9970206a38e41cd386dc012fbee704 Mon Sep 17 00:00:00 2001 From: mtx Date: Sat, 1 Nov 2025 01:41:26 +0800 Subject: [PATCH 4/7] Add more tests --- .../readability/ContainerDataPointerCheck.cpp | 33 ++++++++++--------- .../readability/ContainerDataPointerCheck.h | 2 +- .../readability/container-data-pointer.cpp | 9 +++++ 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp index dba4aa8d5fc6e..b9b8c9a829bfe 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp @@ -71,20 +71,20 @@ void ContainerDataPointerCheck::registerMatchers(MatchFinder *Finder) { const auto Zero = integerLiteral(equals(0)); - const auto SubscriptOperator = callee(cxxMethodDecl(hasName("operator[]"))); - - Finder->addMatcher( + const auto AddressOfMatcher = unaryOperator( unless(isExpansionInSystemHeader()), hasOperatorName("&"), - hasUnaryOperand(expr( - anyOf(cxxOperatorCallExpr(SubscriptOperator, argumentCountIs(2), - hasArgument(0, ContainerExpr), - hasArgument(1, Zero)), - cxxMemberCallExpr(SubscriptOperator, on(ContainerExpr), - argumentCountIs(1), hasArgument(0, Zero)), - arraySubscriptExpr(hasLHS(ContainerExpr), hasRHS(Zero)))))) - .bind(AddressOfName), - this); + hasUnaryOperand(ignoringParenImpCasts(expr(anyOf( + cxxOperatorCallExpr( + hasOverloadedOperatorName("[]"), argumentCountIs(2), + hasArgument(0, ContainerExpr), hasArgument(1, Zero)), + cxxMemberCallExpr(callee(cxxMethodDecl(hasName("operator[]"))), + on(ContainerExpr), argumentCountIs(1), + hasArgument(0, Zero)), + arraySubscriptExpr(hasLHS(ContainerExpr), hasRHS(Zero))))))) + .bind(AddressOfName); + + Finder->addMatcher(AddressOfMatcher, this); } void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { @@ -101,16 +101,19 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { else if (ACE) CE = ACE; - SourceRange SrcRange = CE->getSourceRange(); + const Expr *PrintedCE = CE->IgnoreParenImpCasts(); + + SourceRange SrcRange = PrintedCE->getSourceRange(); std::string ReplacementText{ Lexer::getSourceText(CharSourceRange::getTokenRange(SrcRange), *Result.SourceManager, getLangOpts())}; - const auto *OpCall = dyn_cast(CE); + const auto *OpCall = dyn_cast(PrintedCE); const bool NeedsParens = OpCall ? (OpCall->getOperator() != OO_Subscript) - : !isa(CE); + : !isa( + PrintedCE); if (NeedsParens) ReplacementText = "(" + ReplacementText + ")"; diff --git a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.h b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.h index 71fde87fbb093..d71cb7ff21904 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.h +++ b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.h @@ -34,7 +34,7 @@ class ContainerDataPointerCheck : public ClangTidyCheck { void check(const ast_matchers::MatchFinder::MatchResult &Result) override; std::optional getCheckTraversalKind() const override { - return TK_IgnoreUnlessSpelledInSource; + return TK_AsIs; } private: 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 26f9d9f16ac8c..12fa030fc0af2 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 @@ -156,3 +156,12 @@ void s(std::unique_ptr> p) { // CHECK-MESSAGES: :[[@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: f((*p).data()); } + +template +void u(std::unique_ptr p) { + f(&(*p)[0]); + // CHECK-MESSAGES: :[[@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: f((*p).data()); +} + +template void u>(std::unique_ptr>); From 1c60089727f9ddfe2b66e4ce79750db21a134f6d Mon Sep 17 00:00:00 2001 From: mtx Date: Sat, 1 Nov 2025 01:57:07 +0800 Subject: [PATCH 5/7] minor fix --- .../checkers/readability/container-data-pointer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 12fa030fc0af2..80a8e03b25def 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 @@ -157,8 +157,8 @@ void s(std::unique_ptr> p) { // CHECK-FIXES: f((*p).data()); } -template -void u(std::unique_ptr p) { +template +void u(std::unique_ptr p) { f(&(*p)[0]); // CHECK-MESSAGES: :[[@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: f((*p).data()); From 4170744d95a80db81e6caf0be5837486ab5dfb9c Mon Sep 17 00:00:00 2001 From: mtx Date: Sat, 1 Nov 2025 02:03:28 +0800 Subject: [PATCH 6/7] fix format issue --- .../clang-tidy/readability/ContainerDataPointerCheck.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp index b9b8c9a829bfe..a03a06c71ba9a 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp @@ -103,7 +103,7 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { const Expr *PrintedCE = CE->IgnoreParenImpCasts(); - SourceRange SrcRange = PrintedCE->getSourceRange(); + const SourceRange SrcRange = PrintedCE->getSourceRange(); std::string ReplacementText{ Lexer::getSourceText(CharSourceRange::getTokenRange(SrcRange), From 3c551a91399d4e4534fc6658d5e108e9a6ae9ab8 Mon Sep 17 00:00:00 2001 From: mtx Date: Mon, 3 Nov 2025 22:39:30 +0800 Subject: [PATCH 7/7] fix `AsIs` --- .../clang-tidy/readability/ContainerDataPointerCheck.cpp | 2 +- .../clang-tidy/readability/ContainerDataPointerCheck.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp index a03a06c71ba9a..5e1cd70b26930 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp @@ -84,7 +84,7 @@ void ContainerDataPointerCheck::registerMatchers(MatchFinder *Finder) { arraySubscriptExpr(hasLHS(ContainerExpr), hasRHS(Zero))))))) .bind(AddressOfName); - Finder->addMatcher(AddressOfMatcher, this); + Finder->addMatcher(traverse(TK_AsIs, AddressOfMatcher), this); } void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { diff --git a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.h b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.h index d71cb7ff21904..71fde87fbb093 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.h +++ b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.h @@ -34,7 +34,7 @@ class ContainerDataPointerCheck : public ClangTidyCheck { void check(const ast_matchers::MatchFinder::MatchResult &Result) override; std::optional getCheckTraversalKind() const override { - return TK_AsIs; + return TK_IgnoreUnlessSpelledInSource; } private: