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.
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<CXXDestructorDecl>(Call.getDecl())) {
- State = removeFromState(State, IC->getCXXThisVal().getAsRegion());
+ State = removeFromState(State, ThisRegion);
C.addTransition(State);
return;
}
}
// 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<CXXBaseObjectRegion>(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<CXXBaseObjectRegion>(WholeObjectRegion))
- WholeObjectRegion = BR->getSuperRegion();
-
- State = State->remove<TrackedRegionMap>(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<TrackedRegionMap>(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;
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;
A b = std::move(a);
a.clear(); // no-warning
a.foo(); // no-warning
+ a.b.foo(); // no-warning
}
}
// 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}}
// 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:
}
}
+class C : public A {};
void subRegionMoveTest() {
{
A a;
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
+}