const char *NL, const char *Sep) const override;
private:
+ enum MisuseKind {MK_FunCall, MK_Copy, MK_Move};
class MovedBugVisitor : public BugReporterVisitorImpl<MovedBugVisitor> {
public:
MovedBugVisitor(const MemRegion *R) : Region(R), Found(false) {}
mutable std::unique_ptr<BugType> 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;
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",
// 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<DeclRegion>()) {
const auto *RegionDecl = dyn_cast<NamedDecl>(DecReg->getDecl());
ErrorMessage += " '" + RegionDecl->getNameAsString() + "'";
const RegionState *ArgState = State->get<TrackedRegionMap>(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<TrackedRegionMap>(ArgRegion,
RegionState::getReported());
}
State->get<TrackedRegionMap>(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<TrackedRegionMap>(ArgRegion, RegionState::getReported());
}
if (isInMoveSafeContext(LC))
return;
- N = reportBug(ThisRegion, Call, C);
+ N = reportBug(ThisRegion, Call, C, MK_FunCall);
State = State->set<TrackedRegionMap>(ThisRegion, RegionState::getReported());
C.addTransition(State, N);
}
B() = default;
B(const B &) = default;
B(B &&) = default;
+ B& operator=(const B &q) = default;
void operator=(B &&b) {
return;
}
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;
}
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() {
{
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}}
}
}
// 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}}
// 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: