Index: lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp +++ lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp @@ -350,7 +350,7 @@ const LocationContext *LC = C.getLocationContext(); ExplodedNode *N = nullptr; - // Remove the MemRegions from the map on which a ctor/dtor call or assignement + // Remove the MemRegions from the map on which a ctor/dtor call or assignment // happened. // Checking constructor calls. @@ -378,8 +378,11 @@ return; // In case of destructor call we do not track the object anymore. const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion(); + if (!ThisRegion) + return; + if (dyn_cast_or_null(Call.getDecl())) { - State = removeFromState(State, IC->getCXXThisVal().getAsRegion()); + State = removeFromState(State, ThisRegion); C.addTransition(State); return; } @@ -410,28 +413,28 @@ } // The remaining part is check only for method call on a moved-from object. + + // We want to investigate the whole object, not only sub-object of a parent + // class in which the encountered method defined. + while (const CXXBaseObjectRegion *BR = + dyn_cast(ThisRegion)) + ThisRegion = BR->getSuperRegion(); + if (isMoveSafeMethod(MethodDecl)) return; if (isStateResetMethod(MethodDecl)) { - // A state reset method resets the whole object, not only sub-object - // of a parent class in which it is defined. - const MemRegion *WholeObjectRegion = ThisRegion; - while (const CXXBaseObjectRegion *BR = - dyn_cast(WholeObjectRegion)) - WholeObjectRegion = BR->getSuperRegion(); - - State = State->remove(WholeObjectRegion); + State = removeFromState(State, ThisRegion); C.addTransition(State); return; } - // If it is already reported then we dont report the bug again. + // If it is already reported then we don't report the bug again. const RegionState *ThisState = State->get(ThisRegion); if (!(ThisState && ThisState->isMoved())) return; - // Dont report it in case if any base region is already reported + // Don't report it in case if any base region is already reported if (isAnyBaseRegionReported(State, ThisRegion)) return; Index: test/Analysis/MisusedMovedObject.cpp =================================================================== --- test/Analysis/MisusedMovedObject.cpp +++ test/Analysis/MisusedMovedObject.cpp @@ -332,6 +332,8 @@ A b = std::move(a); a.reset(); // no-warning a.foo(); // no-warning + // Test if resets the state of subregions as well. + a.b.foo(); // no-warning } { A a; @@ -344,6 +346,7 @@ A b = std::move(a); a.clear(); // no-warning a.foo(); // no-warning + a.b.foo(); // no-warning } } @@ -444,7 +447,7 @@ // Same thing, but with a switch statement. { A a, b; - switch (i) { // expected-note {{Control jumps to 'case 1:' at line 448}} + switch (i) { // expected-note {{Control jumps to 'case 1:' at line 451}} case 1: b = std::move(a); // no-warning break; // expected-note {{Execution jumps to the end of the function}} @@ -456,7 +459,7 @@ // However, if there's a fallthrough, we do warn. { A a, b; - switch (i) { // expected-note {{Control jumps to 'case 1:' at line 460}} + switch (i) { // expected-note {{Control jumps to 'case 1:' at line 463}} case 1: b = std::move(a); // expected-note {{'a' became 'moved-from' here}} case 2: @@ -598,6 +601,7 @@ } } +class C : public A {}; void subRegionMoveTest() { { A a; @@ -616,12 +620,24 @@ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}} a.b.foo(); // no-warning } + { + C c; + C c1 = std::move(c); // expected-note {{'c' became 'moved-from' here}} + c.foo(); // expected-warning {{Method call on a 'moved-from' object 'c'}} expected-note {{Method call on a 'moved-from' object 'c'}} + c.b.foo(); // no-warning + } } -class C: public A {}; void resetSuperClass() { C c; C c1 = std::move(c); c.clear(); C c2 = c; // no-warning } + +void reportSuperClass() { + C c; + C c1 = std::move(c); // expected-note {{'c' became 'moved-from' here}} + c.foo(); // expected-warning {{Method call on a 'moved-from' object 'c'}} expected-note {{Method call on a 'moved-from' object 'c'}} + C c2 = c; // no-warning +}