From e47a631d1c4972e4542d392c7789f4d01e533dd2 Mon Sep 17 00:00:00 2001 From: Martin Bohme Date: Mon, 13 Aug 2018 14:24:52 +0000 Subject: [PATCH] [clang-tidy] Recognize [[clang::reinitializes]] attribute in bugprone-use-after-move Summary: This allows member functions to be marked as reinitializing the object. After a moved-from object has been reinitialized, the check will no longer consider it to be in an indeterminate state. The patch that adds the attribute itself is at https://reviews.llvm.org/D49911 Reviewers: ilya-biryukov, aaron.ballman, alexfh, hokein, rsmith Reviewed By: aaron.ballman Subscribers: dblaikie, xazax.hun, cfe-commits Tags: #clang-tools-extra Differential Revision: https://reviews.llvm.org/D49910 llvm-svn: 339571 --- .../clang-tidy/bugprone/UseAfterMoveCheck.cpp | 4 +++ .../clang-tidy/checks/bugprone-use-after-move.rst | 3 ++ .../test/clang-tidy/bugprone-use-after-move.cpp | 35 ++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp index 6fa4cab..ea64549 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp @@ -308,6 +308,10 @@ void UseAfterMoveFinder::getReinits( cxxMemberCallExpr( on(allOf(DeclRefMatcher, StandardSmartPointerTypeMatcher)), callee(cxxMethodDecl(hasName("reset")))), + // Methods that have the [[clang::reinitializes]] attribute. + cxxMemberCallExpr( + on(DeclRefMatcher), + callee(cxxMethodDecl(hasAttr(clang::attr::Reinitializes)))), // Passing variable to a function as a non-const pointer. callExpr(forEachArgumentWithParam( unaryOperator(hasOperatorName("&"), 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 05b0e09..ac16a0a 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 @@ -178,6 +178,9 @@ The check considers a variable to be reinitialized in the following cases: - ``reset()`` is called on the variable and the variable is of type ``std::unique_ptr``, ``std::shared_ptr`` or ``std::weak_ptr``. + - A member function marked with the ``[[clang::reinitializes]]`` attribute is + called on the variable. + If the variable in question is a struct and an individual member variable of that struct is written to, the check does not consider this to be a reinitialization -- even if, eventually, all member variables of the struct are diff --git a/clang-tools-extra/test/clang-tidy/bugprone-use-after-move.cpp b/clang-tools-extra/test/clang-tidy/bugprone-use-after-move.cpp index 9307f17..2d747b4 100644 --- a/clang-tools-extra/test/clang-tidy/bugprone-use-after-move.cpp +++ b/clang-tools-extra/test/clang-tidy/bugprone-use-after-move.cpp @@ -107,6 +107,15 @@ public: int i; }; +template +class AnnotatedContainer { +public: + AnnotatedContainer(); + + void foo() const; + [[clang::reinitializes]] void clear(); +}; + //////////////////////////////////////////////////////////////////////////////// // General tests. @@ -898,6 +907,32 @@ void standardSmartPointerResetIsReinit() { } } +void reinitAnnotation() { + { + AnnotatedContainer obj; + std::move(obj); + obj.foo(); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'obj' used after it was + // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here + } + { + AnnotatedContainer obj; + std::move(obj); + obj.clear(); + obj.foo(); + } + { + // Calling clear() on a different object to the one that was moved is not + // considered a reinitialization. + AnnotatedContainer obj1, obj2; + std::move(obj1); + obj2.clear(); + obj1.foo(); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'obj1' used after it was + // CHECK-MESSAGES: [[@LINE-4]]:5: note: move occurred here + } +} + //////////////////////////////////////////////////////////////////////////////// // Tests related to order of evaluation within expressions -- 2.7.4