diff options
Diffstat (limited to 'test/Analysis/MisusedMovedObject.cpp')
-rw-r--r-- | test/Analysis/MisusedMovedObject.cpp | 680 |
1 files changed, 0 insertions, 680 deletions
diff --git a/test/Analysis/MisusedMovedObject.cpp b/test/Analysis/MisusedMovedObject.cpp deleted file mode 100644 index 07d52c8236da..000000000000 --- a/test/Analysis/MisusedMovedObject.cpp +++ /dev/null @@ -1,680 +0,0 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.MisusedMovedObject -std=c++11 -verify -analyzer-output=text -analyzer-config exploration_strategy=unexplored_first_queue %s -// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.MisusedMovedObject -std=c++11 -analyzer-config exploration_strategy=dfs -verify -analyzer-output=text -DDFS=1 %s - -namespace std { - -template <typename> -struct remove_reference; - -template <typename _Tp> -struct remove_reference { typedef _Tp type; }; - -template <typename _Tp> -struct remove_reference<_Tp &> { typedef _Tp type; }; - -template <typename _Tp> -struct remove_reference<_Tp &&> { typedef _Tp type; }; - -template <typename _Tp> -typename remove_reference<_Tp>::type &&move(_Tp &&__t) { - return static_cast<typename remove_reference<_Tp>::type &&>(__t); -} - -template <typename _Tp> -_Tp &&forward(typename remove_reference<_Tp>::type &__t) noexcept { - return static_cast<_Tp &&>(__t); -} - -template <class T> -void swap(T &a, T &b) { - T c(std::move(a)); - a = std::move(b); - b = std::move(c); -} - -} // namespace std - -class B { -public: - B() = default; - B(const B &) = default; - B(B &&) = default; - B& operator=(const B &q) = default; - void operator=(B &&b) { - return; - } - void foo() { return; } -}; - -class A { - int i; - double d; - -public: - B b; - A(int ii = 42, double dd = 1.0) : d(dd), i(ii), b(B()) {} - void moveconstruct(A &&other) { - std::swap(b, other.b); - std::swap(d, other.d); - std::swap(i, other.i); - return; - } - static A get() { - A v(12, 13); - return v; - } - A(A *a) { - moveconstruct(std::move(*a)); - } - A(const A &other) : i(other.i), d(other.d), b(other.b) {} - A(A &&other) : i(other.i), d(other.d), b(std::move(other.b)) { // expected-note {{'b' became 'moved-from' here}} - } - 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; - } - int getI() { return i; } - int foo() const; - void bar() const; - void reset(); - void destroy(); - void clear(); - bool empty() const; - bool isEmpty() const; - operator bool() const; -}; - -int bignum(); - -void moveInsideFunctionCall(A a) { - A b = std::move(a); -} -void leftRefCall(A &a) { - a.foo(); -} -void rightRefCall(A &&a) { - a.foo(); -} -void constCopyOrMoveCall(const A a) { - a.foo(); -} - -void copyOrMoveCall(A a) { - a.foo(); -} - -void simpleMoveCtorTest() { - { - 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 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() { - struct S { - A a; - }; - A a; - S s{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'}} -} - -// Don't report a bug if the variable was assigned to in the meantime. -void reinitializationTest(int i) { - { - A a; - A b; - b = std::move(a); - a = A(); - a.foo(); - } - { - A a; - if (i == 1) { // expected-note {{Assuming 'i' is not equal to 1}} expected-note {{Taking false branch}} - // expected-note@-1 {{Assuming 'i' is not equal to 1}} expected-note@-1 {{Taking false branch}} - A b; - b = std::move(a); - a = A(); - } - if (i == 2) { // expected-note {{Assuming 'i' is not equal to 2}} expected-note {{Taking false branch}} - //expected-note@-1 {{Assuming 'i' is not equal to 2}} expected-note@-1 {{Taking false branch}} - a.foo(); // no-warning - } - } - { - A a; - if (i == 1) { // expected-note {{Taking false branch}} expected-note {{Taking false branch}} - std::move(a); - } - if (i == 2) { // expected-note {{Taking false branch}} expected-note {{Taking false branch}} - a = A(); - a.foo(); - } - } - // The built-in assignment operator should also be recognized as a - // reinitialization. (std::move() may be called on built-in types in template - // code.) - { - int a1 = 1, a2 = 2; - std::swap(a1, a2); - } - // A std::move() after the assignment makes the variable invalid again. - { - A a; - A b; - b = std::move(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'}} - } - // If a path exist where we not reinitialize the variable we report a bug. - { - A a; - A b; - b = std::move(a); // expected-note {{'a' became 'moved-from' here}} - if (i < 10) { // expected-note {{Assuming 'i' is >= 10}} expected-note {{Taking false branch}} - a = A(); - } - if (i > 5) { // expected-note {{Taking true branch}} - a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}} - } - } -} - -// Using decltype on an expression is not a use. -void decltypeIsNotUseTest() { - A a; - // A b(std::move(a)); - decltype(a) other_a; // no-warning -} - -void loopTest() { - { - A a; - for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}} - rightRefCall(std::move(a)); // no-warning - } - } - { - A a; - for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}} - //expected-note@-1 {{Loop condition is true. Entering loop body}} - //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} - rightRefCall(std::move(a)); // no-warning - } - } - { - A a; - for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}} - leftRefCall(a); // no-warning - } - } - { - A a; - for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}} - //expected-note@-1 {{Loop condition is true. Entering loop body}} - //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} - leftRefCall(a); // no-warning - } - } - { - A a; - for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}} - constCopyOrMoveCall(a); // no-warning - } - } - { - A a; - for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}} - //expected-note@-1 {{Loop condition is true. Entering loop body}} - //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} - constCopyOrMoveCall(a); // no-warning - } - } - { - A a; - for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}} - moveInsideFunctionCall(a); // no-warning - } - } - { - A a; - for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}} - //expected-note@-1 {{Loop condition is true. Entering loop body}} - //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} - moveInsideFunctionCall(a); // no-warning - } - } - { - A a; - for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}} - copyOrMoveCall(a); // no-warning - } - } - { - A a; - for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true.}} - //expected-note@-1 {{Loop condition is true. Entering loop body}} - //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} - copyOrMoveCall(a); // no-warning - } - } - { - 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 {{Moving a 'moved-from' object 'a'}} expected-note {{Moving a 'moved-from' object 'a'}} - // expected-note@-1 {{'a' became 'moved-from' here}} - } - } - - // Don't warn if we return after the move. - { - A a; - for (int i = 0; i < 3; ++i) { - a.bar(); - if (a.foo() > 0) { - A b; - b = std::move(a); // no-warning - return; - } - } - } -} - -//report a usage of a moved-from object only at the first use -void uniqueTest(bool cond) { - A a(42, 42.0); - A b; - b = std::move(a); // expected-note {{'a' became 'moved-from' here}} - - if (cond) { // expected-note {{Assuming 'cond' is not equal to 0}} expected-note {{Taking true branch}} - a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}} - } - if (cond) { - a.bar(); // no-warning - } - - a.bar(); // no-warning -} - -void uniqueTest2() { - A a; - A a1 = 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 a2 = std::move(a); // no-warning - a.foo(); // no-warning -} - -// There are exceptions where we assume in general that the method works fine -//even on moved-from objects. -void moveSafeFunctionsTest() { - A a; - A b = std::move(a); // expected-note {{'a' became 'moved-from' here}} - a.empty(); // no-warning - a.isEmpty(); // no-warning - (void)a; // no-warning - (bool)a; // expected-warning {{expression result unused}} - a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}} -} - -void moveStateResetFunctionsTest() { - { - A a; - 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.destroy(); // no-warning - a.foo(); // no-warning - } - { - A a; - A b = std::move(a); - a.clear(); // no-warning - a.foo(); // no-warning - a.b.foo(); // no-warning - } -} - -// Moves or uses that occur as part of template arguments. -template <int> -class ClassTemplate { -public: - void foo(A a); -}; - -template <int> -void functionTemplate(A a); - -void templateArgIsNotUseTest() { - { - // A pattern like this occurs in the EXPECT_EQ and ASSERT_EQ macros in - // Google Test. - A a; - ClassTemplate<sizeof(A(std::move(a)))>().foo(std::move(a)); // no-warning - } - { - A a; - functionTemplate<sizeof(A(std::move(a)))>(std::move(a)); // no-warning - } -} - -// Moves of global variables are not reported. -A global_a; -void globalVariablesTest() { - std::move(global_a); - global_a.foo(); // no-warning -} - -// Moves of member variables. -class memberVariablesTest { - A a; - static A static_a; - - void f() { - A b; - b = std::move(a); // expected-note {{'a' became 'moved-from' here}} - a.foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object 'a'}} - - b = std::move(static_a); // expected-note {{'static_a' became 'moved-from' here}} - static_a.foo(); // expected-warning {{Method call on a 'moved-from' object 'static_a'}} expected-note {{Method call on a 'moved-from' object 'static_a'}} - } -}; - -void PtrAndArrayTest() { - A *Ptr = new A(1, 1.5); - A Arr[10]; - Arr[2] = std::move(*Ptr); // expected-note {{Became 'moved-from' here}} - (*Ptr).foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object}} - - Ptr = &Arr[1]; - Arr[3] = std::move(Arr[1]); // expected-note {{Became 'moved-from' here}} - Ptr->foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object}} - - Arr[3] = std::move(Arr[2]); // expected-note {{Became 'moved-from' here}} - Arr[2].foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object}} - - Arr[2] = std::move(Arr[3]); // reinitialization - Arr[2].foo(); // no-warning -} - -void exclusiveConditionsTest(bool cond) { - A a; - if (cond) { - A b; - b = std::move(a); - } - if (!cond) { - a.bar(); // no-warning - } -} - -void differentBranchesTest(int i) { - // Don't warn if the use is in a different branch from the move. - { - A a; - if (i > 0) { // expected-note {{Assuming 'i' is > 0}} expected-note {{Taking true branch}} - A b; - b = std::move(a); - } else { - a.foo(); // no-warning - } - } - // Same thing, but with a ternary operator. - { - A a, b; - i > 0 ? (void)(b = std::move(a)) : a.bar(); // no-warning // expected-note {{'?' condition is true}} - } - // A variation on the theme above. - { - A a; -#ifdef DFS - a.foo() > 0 ? a.foo() : A(std::move(a)).foo(); // expected-note {{Assuming the condition is false}} expected-note {{'?' condition is false}} -#else - a.foo() > 0 ? a.foo() : A(std::move(a)).foo(); // expected-note {{Assuming the condition is true}} expected-note {{'?' condition is true}} -#endif - } - // Same thing, but with a switch statement. - { - A a, b; - switch (i) { // expected-note {{Control jumps to 'case 1:'}} - case 1: - b = std::move(a); // no-warning - break; // expected-note {{Execution jumps to the end of the function}} - case 2: - a.foo(); // no-warning - break; - } - } - // However, if there's a fallthrough, we do warn. - { - A a, b; - switch (i) { // expected-note {{Control jumps to 'case 1:'}} - case 1: - b = std::move(a); // expected-note {{'a' became 'moved-from' here}} - case 2: - a.foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object 'a'}} - break; - } - } -} - -void tempTest() { - A a = A::get(); - A::get().foo(); // no-warning - for (int i = 0; i < bignum(); i++) { - A::get().foo(); // no-warning - } -} - -void interFunTest1(A &a) { - a.bar(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}} -} - -void interFunTest2() { - A a; - A b; - b = std::move(a); // expected-note {{'a' became 'moved-from' here}} - interFunTest1(a); // expected-note {{Calling 'interFunTest1'}} -} - -void foobar(A a, int i); -void foobar(int i, A a); - -void paramEvaluateOrderTest() { - A a; - foobar(std::move(a), a.getI()); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}} - // expected-note@-1 {{'a' became 'moved-from' here}} - - //FALSE NEGATIVE since parameters evaluate order is undefined - foobar(a.getI(), std::move(a)); //no-warning -} - -void not_known(A &a); -void not_known(A *a); - -void regionAndPointerEscapeTest() { - { - A a; - A b; - b = std::move(a); - not_known(a); - a.foo(); //no-warning - } - { - A a; - A b; - b = std::move(a); - not_known(&a); - a.foo(); // no-warning - } -} - -// A declaration statement containing multiple declarations sequences the -// initializer expressions. -void declarationSequenceTest() { - { - A a; - A a1 = a, a2 = std::move(a); // no-warning - } - { - A a; - A a1 = std::move(a), a2 = a; // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}} - // expected-note@-1 {{'a' became 'moved-from' here}} - } -} - -// The logical operators && and || sequence their operands. -void logicalOperatorsSequenceTest() { - { - A a; - if (a.foo() > 0 && A(std::move(a)).foo() > 0) { // expected-note {{Assuming the condition is false}} expected-note {{Assuming the condition is false}} - // expected-note@-1 {{Left side of '&&' is false}} expected-note@-1 {{Left side of '&&' is false}} - //expected-note@-2 {{Taking false branch}} expected-note@-2 {{Taking false branch}} - A().bar(); - } - } - // A variation: Negate the result of the && (which pushes the && further down - // into the AST). - { - A a; - if (!(a.foo() > 0 && A(std::move(a)).foo() > 0)) { // expected-note {{Assuming the condition is false}} expected-note {{Assuming the condition is false}} - // expected-note@-1 {{Left side of '&&' is false}} expected-note@-1 {{Left side of '&&' is false}} - // expected-note@-2 {{Taking true branch}} expected-note@-2 {{Taking true branch}} - A().bar(); - } - } - { - A a; - if (A(std::move(a)).foo() > 0 && a.foo() > 0) { // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}} - // expected-note@-1 {{'a' became 'moved-from' here}} expected-note@-1 {{Assuming the condition is true}} expected-note@-1 {{Assuming the condition is false}} - // expected-note@-2 {{Left side of '&&' is false}} expected-note@-2 {{Left side of '&&' is true}} - // expected-note@-3 {{Taking false branch}} - A().bar(); - } - } - { - A a; - if (a.foo() > 0 || A(std::move(a)).foo() > 0) { // expected-note {{Assuming the condition is true}} - //expected-note@-1 {{Left side of '||' is true}} - //expected-note@-2 {{Taking true branch}} - A().bar(); - } - } - { - A a; - if (A(std::move(a)).foo() > 0 || a.foo() > 0) { // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}} - // expected-note@-1 {{'a' became 'moved-from' here}} expected-note@-1 {{Assuming the condition is false}} expected-note@-1 {{Left side of '||' is false}} - A().bar(); - } - } -} - -// A range-based for sequences the loop variable declaration before the body. -void forRangeSequencesTest() { - A v[2] = {A(), A()}; - for (A &a : v) { - A b; - b = std::move(a); // no-warning - } -} - -// If a variable is declared in an if statement, the declaration of the variable -// (which is treated like a reinitialization by the check) is sequenced before -// the evaluation of the condition (which constitutes a use). -void ifStmtSequencesDeclAndConditionTest() { - for (int i = 0; i < 3; ++i) { - if (A a = A()) { - A b; - b = std::move(a); // no-warning - } - } -} - -class C : public A {}; -void subRegionMoveTest() { - { - A a; - B b = std::move(a.b); // expected-note {{'b' became 'moved-from' here}} - a.b.foo(); // expected-warning {{Method call on a 'moved-from' object 'b'}} expected-note {{Method call on a 'moved-from' object 'b'}} - } - { - A a; - A a1 = std::move(a); // expected-note {{Calling move constructor for 'A'}} expected-note {{Returning from move constructor for 'A'}} - a.b.foo(); // expected-warning {{Method call on a 'moved-from' object 'b'}} expected-note {{Method call on a 'moved-from' object 'b'}} - } - // Don't report a misuse if any SuperRegion is already reported. - { - A a; - A a1 = 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.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 - } -} - -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 -} |