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
