Index: cfe/trunk/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp +++ cfe/trunk/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp @@ -60,6 +60,7 @@ const char *NL, const char *Sep) const override; private: + enum MisuseKind {MK_FunCall, MK_Copy, MK_Move}; class MovedBugVisitor : public BugReporterVisitorImpl { public: MovedBugVisitor(const MemRegion *R) : Region(R), Found(false) {} @@ -83,7 +84,7 @@ mutable std::unique_ptr BT; ExplodedNode *reportBug(const MemRegion *Region, const CallEvent &Call, - CheckerContext &C, bool isCopy) const; + CheckerContext &C, MisuseKind MK) const; bool isInMoveSafeContext(const LocationContext *LC) const; bool isStateResetMethod(const CXXMethodDecl *MethodDec) const; bool isMoveSafeMethod(const CXXMethodDecl *MethodDec) const; @@ -179,7 +180,7 @@ ExplodedNode *MisusedMovedObjectChecker::reportBug(const MemRegion *Region, const CallEvent &Call, CheckerContext &C, - bool isCopy = false) const { + MisuseKind MK) const { if (ExplodedNode *N = C.generateNonFatalErrorNode()) { if (!BT) BT.reset(new BugType(this, "Usage of a 'moved-from' object", @@ -195,10 +196,17 @@ // Creating the error message. std::string ErrorMessage; - if (isCopy) - ErrorMessage = "Copying a 'moved-from' object"; - else - ErrorMessage = "Method call on a 'moved-from' object"; + switch(MK) { + case MK_FunCall: + ErrorMessage = "Method call on a 'moved-from' object"; + break; + case MK_Copy: + ErrorMessage = "Copying a 'moved-from' object"; + break; + case MK_Move: + ErrorMessage = "Moving a 'moved-from' object"; + break; + } if (const auto DecReg = Region->getAs()) { const auto *RegionDecl = dyn_cast(DecReg->getDecl()); ErrorMessage += " '" + RegionDecl->getNameAsString() + "'"; @@ -365,7 +373,10 @@ const RegionState *ArgState = State->get(ArgRegion); if (ArgState && ArgState->isMoved()) { if (!isInMoveSafeContext(LC)) { - N = reportBug(ArgRegion, Call, C, /*isCopy=*/true); + if(CtorDec->isMoveConstructor()) + N = reportBug(ArgRegion, Call, C, MK_Move); + else + N = reportBug(ArgRegion, Call, C, MK_Copy); State = State->set(ArgRegion, RegionState::getReported()); } @@ -405,7 +416,10 @@ State->get(IC->getArgSVal(0).getAsRegion()); if (ArgState && ArgState->isMoved() && !isInMoveSafeContext(LC)) { const MemRegion *ArgRegion = IC->getArgSVal(0).getAsRegion(); - N = reportBug(ArgRegion, Call, C, /*isCopy=*/true); + if(MethodDecl->isMoveAssignmentOperator()) + N = reportBug(ArgRegion, Call, C, MK_Move); + else + N = reportBug(ArgRegion, Call, C, MK_Copy); State = State->set(ArgRegion, RegionState::getReported()); } @@ -443,7 +457,7 @@ if (isInMoveSafeContext(LC)) return; - N = reportBug(ThisRegion, Call, C); + N = reportBug(ThisRegion, Call, C, MK_FunCall); State = State->set(ThisRegion, RegionState::getReported()); C.addTransition(State, N); } Index: cfe/trunk/test/Analysis/MisusedMovedObject.cpp =================================================================== --- cfe/trunk/test/Analysis/MisusedMovedObject.cpp +++ cfe/trunk/test/Analysis/MisusedMovedObject.cpp @@ -38,6 +38,7 @@ B() = default; B(const B &) = default; B(B &&) = default; + B& operator=(const B &q) = default; void operator=(B &&b) { return; } @@ -70,6 +71,12 @@ A(A &&other, char *k) { moveconstruct(std::move(other)); } + void operator=(const A &other) { + i = other.i; + d = other.d; + b = other.b; + return; + } void operator=(A &&other) { moveconstruct(std::move(other)); return; @@ -105,17 +112,42 @@ } void simpleMoveCtorTest() { - A a; - A b; - b = std::move(a); // expected-note {{'a' became 'moved-from' here}} - a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}} + { + A a; + A b = std::move(a); // expected-note {{'a' became 'moved-from' here}} + a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}} + } + { + A a; + A b = std::move(a); // expected-note {{'a' became 'moved-from' here}} + b = a; // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}} + } + { + A a; + A b = std::move(a); // expected-note {{'a' became 'moved-from' here}} + b = std::move(a); // expected-warning {{Moving a 'moved-from' object 'a'}} expected-note {{Moving a 'moved-from' object 'a'}} + } } void simpleMoveAssignementTest() { - A a; - A b; - b = std::move(a); // expected-note {{'a' became 'moved-from' here}} - a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}} + { + A a; + A b; + b = std::move(a); // expected-note {{'a' became 'moved-from' here}} + a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}} + } + { + A a; + A b; + b = std::move(a); // expected-note {{'a' became 'moved-from' here}} + A c(a); // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}} + } + { + A a; + A b; + b = std::move(a); // expected-note {{'a' became 'moved-from' here}} + A c(std::move(a)); // expected-warning {{Moving a 'moved-from' object 'a'}} expected-note {{Moving a 'moved-from' object 'a'}} + } } void moveInInitListTest() { @@ -270,7 +302,7 @@ { A a; for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is true. Entering loop body}} expected-note {{Loop condition is true. Entering loop body}} - constCopyOrMoveCall(std::move(a)); // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}} + constCopyOrMoveCall(std::move(a)); // expected-warning {{Moving a 'moved-from' object 'a'}} expected-note {{Moving a 'moved-from' object 'a'}} // expected-note@-1 {{'a' became 'moved-from' here}} } } @@ -447,7 +479,7 @@ // Same thing, but with a switch statement. { A a, b; - switch (i) { // expected-note {{Control jumps to 'case 1:' at line 451}} + switch (i) { // expected-note {{Control jumps to 'case 1:' at line 483}} case 1: b = std::move(a); // no-warning break; // expected-note {{Execution jumps to the end of the function}} @@ -459,7 +491,7 @@ // However, if there's a fallthrough, we do warn. { A a, b; - switch (i) { // expected-note {{Control jumps to 'case 1:' at line 463}} + switch (i) { // expected-note {{Control jumps to 'case 1:' at line 495}} case 1: b = std::move(a); // expected-note {{'a' became 'moved-from' here}} case 2: