Author: mitchell
Date: 2025-12-23T07:36:34+08:00
New Revision: 678b9b287551072546e8be73740761dd805079dd

URL: 
https://github.com/llvm/llvm-project/commit/678b9b287551072546e8be73740761dd805079dd
DIFF: 
https://github.com/llvm/llvm-project/commit/678b9b287551072546e8be73740761dd805079dd.diff

LOG: [clang-tidy] Add `ReinitializationFunctions` option to 
`bugprone-use-after-move` (#172784)

Closes #170635

Added: 
    

Modified: 
    clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
    clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.h
    clang-tools-extra/docs/ReleaseNotes.rst
    clang-tools-extra/docs/clang-tidy/checks/bugprone/use-after-move.rst
    clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
index 98b0202a87f2d..64387024dafd6 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -50,7 +50,8 @@ struct UseAfterMove {
 class UseAfterMoveFinder {
 public:
   UseAfterMoveFinder(ASTContext *TheContext,
-                     llvm::ArrayRef<StringRef> InvalidationFunctions);
+                     llvm::ArrayRef<StringRef> InvalidationFunctions,
+                     llvm::ArrayRef<StringRef> ReinitializationFunctions);
 
   // Within the given code block, finds the first use of 'MovedVariable' that
   // occurs after 'MovingCall' (the expression that performs the move). If a
@@ -74,6 +75,7 @@ class UseAfterMoveFinder {
 
   ASTContext *Context;
   llvm::ArrayRef<StringRef> InvalidationFunctions;
+  llvm::ArrayRef<StringRef> ReinitializationFunctions;
   std::unique_ptr<ExprSequence> Sequence;
   std::unique_ptr<StmtToBlockMap> BlockMap;
   llvm::SmallPtrSet<const CFGBlock *, 8> Visited;
@@ -88,7 +90,8 @@ static auto getNameMatcher(llvm::ArrayRef<StringRef> 
InvalidationFunctions) {
 
 static StatementMatcher
 makeReinitMatcher(const ValueDecl *MovedVariable,
-                  llvm::ArrayRef<StringRef> InvalidationFunctions) {
+                  llvm::ArrayRef<StringRef> InvalidationFunctions,
+                  llvm::ArrayRef<StringRef> ReinitializationFunctions) {
   const auto DeclRefMatcher =
       declRefExpr(hasDeclaration(equalsNode(MovedVariable))).bind("declref");
 
@@ -133,6 +136,13 @@ makeReinitMatcher(const ValueDecl *MovedVariable,
                  cxxMemberCallExpr(on(DeclRefMatcher),
                                    callee(cxxMethodDecl(
                                        hasAttr(clang::attr::Reinitializes)))),
+                 // Functions that are specified in ReinitializationFunctions
+                 // option.
+                 callExpr(callee(functionDecl(matchers::matchesAnyListedName(
+                              ReinitializationFunctions))),
+                          anyOf(cxxMemberCallExpr(on(DeclRefMatcher)),
+                                callExpr(unless(cxxMemberCallExpr()),
+                                         hasArgument(0, DeclRefMatcher)))),
                  // Passing variable to a function as a non-const pointer.
                  callExpr(forEachArgumentWithParam(
                      unaryOperator(hasOperatorName("&"),
@@ -165,8 +175,10 @@ static StatementMatcher inDecltypeOrTemplateArg() {
 }
 
 UseAfterMoveFinder::UseAfterMoveFinder(
-    ASTContext *TheContext, llvm::ArrayRef<StringRef> InvalidationFunctions)
-    : Context(TheContext), InvalidationFunctions(InvalidationFunctions) {}
+    ASTContext *TheContext, llvm::ArrayRef<StringRef> InvalidationFunctions,
+    llvm::ArrayRef<StringRef> ReinitializationFunctions)
+    : Context(TheContext), InvalidationFunctions(InvalidationFunctions),
+      ReinitializationFunctions(ReinitializationFunctions) {}
 
 std::optional<UseAfterMove>
 UseAfterMoveFinder::find(Stmt *CodeBlock, const Expr *MovingCall,
@@ -371,8 +383,8 @@ void UseAfterMoveFinder::getReinits(
     const CFGBlock *Block, const ValueDecl *MovedVariable,
     llvm::SmallPtrSetImpl<const Stmt *> *Stmts,
     llvm::SmallPtrSetImpl<const DeclRefExpr *> *DeclRefs) {
-  const auto ReinitMatcher =
-      makeReinitMatcher(MovedVariable, InvalidationFunctions);
+  const auto ReinitMatcher = makeReinitMatcher(
+      MovedVariable, InvalidationFunctions, ReinitializationFunctions);
 
   Stmts->clear();
   DeclRefs->clear();
@@ -452,11 +464,15 @@ static void emitDiagnostic(const Expr *MovingCall, const 
DeclRefExpr *MoveArg,
 UseAfterMoveCheck::UseAfterMoveCheck(StringRef Name, ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context),
       InvalidationFunctions(utils::options::parseStringList(
-          Options.get("InvalidationFunctions", ""))) {}
+          Options.get("InvalidationFunctions", ""))),
+      ReinitializationFunctions(utils::options::parseStringList(
+          Options.get("ReinitializationFunctions", ""))) {}
 
 void UseAfterMoveCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "InvalidationFunctions",
                 utils::options::serializeStringList(InvalidationFunctions));
+  Options.store(Opts, "ReinitializationFunctions",
+                
utils::options::serializeStringList(ReinitializationFunctions));
 }
 
 void UseAfterMoveCheck::registerMatchers(MatchFinder *Finder) {
@@ -552,7 +568,8 @@ void UseAfterMoveCheck::check(const 
MatchFinder::MatchResult &Result) {
   }
 
   for (Stmt *CodeBlock : CodeBlocks) {
-    UseAfterMoveFinder Finder(Result.Context, InvalidationFunctions);
+    UseAfterMoveFinder Finder(Result.Context, InvalidationFunctions,
+                              ReinitializationFunctions);
     if (auto Use = Finder.find(CodeBlock, MovingCall, Arg))
       emitDiagnostic(MovingCall, Arg, *Use, this, Result.Context,
                      determineMoveType(MoveDecl));

diff  --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.h 
b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.h
index 1bbf5c00785ff..fff1c2621867d 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.h
@@ -30,6 +30,7 @@ class UseAfterMoveCheck : public ClangTidyCheck {
 
 private:
   std::vector<StringRef> InvalidationFunctions;
+  std::vector<StringRef> ReinitializationFunctions;
 };
 
 } // namespace clang::tidy::bugprone

diff  --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index e4ff640811933..8229810cbb429 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -446,7 +446,9 @@ Changes in existing checks
 
 - Improved :doc:`bugprone-use-after-move
   <clang-tidy/checks/bugprone/use-after-move>` check by adding
-  `InvalidationFunctions` option to support custom invalidation functions.
+  `InvalidationFunctions` option to support custom invalidation functions
+  and `ReinitializationFunctions` option to support custom reinitialization
+  functions.
 
 - Improved :doc:`cppcoreguidelines-avoid-non-const-global-variables
   <clang-tidy/checks/cppcoreguidelines/avoid-non-const-global-variables>` check

diff  --git 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/use-after-move.rst 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/use-after-move.rst
index 77424d3d620bb..95a752e9399a9 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/use-after-move.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/use-after-move.rst
@@ -263,3 +263,11 @@ Options
   arguments to be invalidated (e.g., closing a handle).
   For member functions, the first argument is considered to be the implicit
   object argument (``this``). Default value is an empty string.
+
+.. option:: ReinitializationFunctions
+
+  A semicolon-separated list of names of functions that reinitialize the
+  object. For member functions, the implicit object argument (``*this``) is
+  considered to be reinitialized. For non-member or static member functions,
+  the first argument is considered to be reinitialized. Default value is an
+  empty string.

diff  --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
index b2df2638106e0..da818a90514f6 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
@@ -1,11 +1,13 @@
 // RUN: %check_clang_tidy -std=c++11 -check-suffixes=,CXX11 %s 
bugprone-use-after-move %t -- \
 // RUN:   -config='{CheckOptions: { \
-// RUN:     bugprone-use-after-move.InvalidationFunctions: 
"::Database<>::StaticCloseConnection;Database<>::CloseConnection;FriendCloseConnection"
 \
+// RUN:     bugprone-use-after-move.InvalidationFunctions: 
"::Database<>::StaticCloseConnection;Database<>::CloseConnection;FriendCloseConnection",
 \
+// RUN:     bugprone-use-after-move.ReinitializationFunctions: 
"::Database<>::Reset;::Database<>::StaticReset;::FriendReset;::RegularReset" \
 // RUN:   }}' -- \
 // RUN:   -fno-delayed-template-parsing
 // RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-use-after-move %t -- 
\
 // RUN:   -config='{CheckOptions: { \
-// RUN:     bugprone-use-after-move.InvalidationFunctions: 
"::Database<>::StaticCloseConnection;Database<>::CloseConnection;FriendCloseConnection"
 \
+// RUN:     bugprone-use-after-move.InvalidationFunctions: 
"::Database<>::StaticCloseConnection;Database<>::CloseConnection;FriendCloseConnection",
 \
+// RUN:     bugprone-use-after-move.ReinitializationFunctions: 
"::Database<>::Reset;::Database<>::StaticReset;::FriendReset;::RegularReset" \
 // RUN:   }}' -- \
 // RUN:   -fno-delayed-template-parsing
 
@@ -1703,3 +1705,56 @@ void Run() {
 }
 
 } // namespace custom_invalidation
+
+namespace custom_reinitialization {
+
+template <class T = int>
+struct Database {
+  template <class... Args>
+  void Reset(T = T(), Args &&...) {}
+  template <class... Args>
+  static void StaticReset(Database &, T = T(), Args &&...) {}
+  template <class... Args>
+  friend void FriendReset(Database &, T = T(), Args &&...) {}
+  void Query(T = T()) {}
+};
+
+template <class T = int>
+void RegularReset(Database<T> &d, T = T()) {}
+
+void Run() {
+  using DB = Database<>;
+
+  DB db1;
+  std::move(db1);
+  db1.Reset();
+  db1.Query();
+
+  DB db2;
+  std::move(db2);
+  db2.Query();
+  // CHECK-NOTES: [[@LINE-1]]:3: warning: 'db2' used after it was moved
+  // CHECK-NOTES: [[@LINE-3]]:3: note: move occurred here
+  db2.Reset();
+
+  DB db3;
+  std::move(db3);
+  DB::StaticReset(db3);
+  db3.Query();
+
+  DB db4;
+  std::move(db4);
+  FriendReset(db4);
+  db4.Query();
+
+  DB db5;
+  std::move(db5);
+  db5.Reset(0, 1.5, "extra");
+  db5.Query();
+
+  DB db6;
+  std::move(db6);
+  RegularReset(db6);
+  db6.Query();
+}
+} // namespace custom_reinitialization


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to