|  | // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s | 
|  |  | 
|  | void clang_analyzer_eval(bool); | 
|  |  | 
|  | struct A { | 
|  | int x; | 
|  | void foo() const; | 
|  | void bar(); | 
|  |  | 
|  | void testImplicitThisSyntax() { | 
|  | x = 3; | 
|  | foo(); | 
|  | clang_analyzer_eval(x == 3); // expected-warning{{TRUE}} | 
|  | bar(); | 
|  | clang_analyzer_eval(x == 3); // expected-warning{{UNKNOWN}} | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct B { | 
|  | mutable int mut; | 
|  | void foo() const; | 
|  | }; | 
|  |  | 
|  | struct C { | 
|  | int *p; | 
|  | void foo() const; | 
|  | }; | 
|  |  | 
|  | struct MutBase { | 
|  | mutable int b_mut; | 
|  | }; | 
|  |  | 
|  | struct MutDerived : MutBase { | 
|  | void foo() const; | 
|  | }; | 
|  |  | 
|  | struct PBase { | 
|  | int *p; | 
|  | }; | 
|  |  | 
|  | struct PDerived : PBase { | 
|  | void foo() const; | 
|  | }; | 
|  |  | 
|  | struct Inner { | 
|  | int x; | 
|  | int *p; | 
|  | void bar() const; | 
|  | }; | 
|  |  | 
|  | struct Outer { | 
|  | int x; | 
|  | Inner in; | 
|  | void foo() const; | 
|  | }; | 
|  |  | 
|  | void checkThatConstMethodWithoutDefinitionDoesNotInvalidateObject() { | 
|  | A t; | 
|  | t.x = 3; | 
|  | t.foo(); | 
|  | clang_analyzer_eval(t.x == 3); // expected-warning{{TRUE}} | 
|  | // Test non-const does invalidate | 
|  | t.bar(); | 
|  | clang_analyzer_eval(t.x); // expected-warning{{UNKNOWN}} | 
|  | } | 
|  |  | 
|  | void checkThatConstMethodDoesInvalidateMutableFields() { | 
|  | B t; | 
|  | t.mut = 4; | 
|  | t.foo(); | 
|  | clang_analyzer_eval(t.mut); // expected-warning{{UNKNOWN}} | 
|  | } | 
|  |  | 
|  | void checkThatConstMethodDoesInvalidatePointedAtMemory() { | 
|  | int x = 1; | 
|  | C t; | 
|  | t.p = &x; | 
|  | t.foo(); | 
|  | clang_analyzer_eval(x); // expected-warning{{UNKNOWN}} | 
|  | clang_analyzer_eval(t.p == &x); // expected-warning{{TRUE}} | 
|  | } | 
|  |  | 
|  | void checkThatConstMethodDoesInvalidateInheritedMutableFields() { | 
|  | MutDerived t; | 
|  | t.b_mut = 4; | 
|  | t.foo(); | 
|  | clang_analyzer_eval(t.b_mut); // expected-warning{{UNKNOWN}} | 
|  | } | 
|  |  | 
|  | void checkThatConstMethodDoesInvalidateInheritedPointedAtMemory() { | 
|  | int x = 1; | 
|  | PDerived t; | 
|  | t.p = &x; | 
|  | t.foo(); | 
|  | clang_analyzer_eval(x); // expected-warning{{UNKNOWN}} | 
|  | clang_analyzer_eval(t.p == &x); // expected-warning{{TRUE}} | 
|  | } | 
|  |  | 
|  | void checkThatConstMethodDoesInvalidateContainedPointedAtMemory() { | 
|  | int x = 1; | 
|  | Outer t; | 
|  | t.x = 2; | 
|  | t.in.p = &x; | 
|  | t.foo(); | 
|  | clang_analyzer_eval(x); // expected-warning{{UNKNOWN}} | 
|  | clang_analyzer_eval(t.x == 2); // expected-warning{{TRUE}} | 
|  | clang_analyzer_eval(t.in.p == &x); // expected-warning{{TRUE}} | 
|  | } | 
|  |  | 
|  | void checkThatContainedConstMethodDoesNotInvalidateObjects() { | 
|  | Outer t; | 
|  | t.x = 1; | 
|  | t.in.x = 2; | 
|  | t.in.bar(); | 
|  | clang_analyzer_eval(t.x == 1); // expected-warning{{TRUE}} | 
|  | clang_analyzer_eval(t.in.x == 2); // expected-warning{{TRUE}} | 
|  | } | 
|  |  | 
|  | void checkPointerTypedThisExpression(A *a) { | 
|  | a->x = 3; | 
|  | a->foo(); | 
|  | clang_analyzer_eval(a->x == 3); // expected-warning{{TRUE}} | 
|  | a->bar(); | 
|  | clang_analyzer_eval(a->x == 3); // expected-warning{{UNKNOWN}} | 
|  | } | 
|  |  | 
|  | void checkReferenceTypedThisExpression(A &a) { | 
|  | a.x = 3; | 
|  | a.foo(); | 
|  | clang_analyzer_eval(a.x == 3); // expected-warning{{TRUE}} | 
|  | a.bar(); | 
|  | clang_analyzer_eval(a.x == 3); // expected-warning{{UNKNOWN}} | 
|  | } | 
|  |  | 
|  | // --- Versions of the above tests where the const method is inherited --- // | 
|  |  | 
|  | struct B1 { | 
|  | void foo() const; | 
|  | }; | 
|  |  | 
|  | struct D1 : public B1 { | 
|  | int x; | 
|  | }; | 
|  |  | 
|  | struct D2 : public B1 { | 
|  | mutable int mut; | 
|  | }; | 
|  |  | 
|  | struct D3 : public B1 { | 
|  | int *p; | 
|  | }; | 
|  |  | 
|  | struct DInner : public B1 { | 
|  | int x; | 
|  | int *p; | 
|  | }; | 
|  |  | 
|  | struct DOuter : public B1 { | 
|  | int x; | 
|  | DInner in; | 
|  | }; | 
|  |  | 
|  | void checkThatInheritedConstMethodDoesNotInvalidateObject() { | 
|  | D1 t; | 
|  | t.x = 1; | 
|  | t.foo(); | 
|  | clang_analyzer_eval(t.x == 1); // expected-warning{{TRUE}} | 
|  | } | 
|  |  | 
|  | void checkThatInheritedConstMethodDoesInvalidateMutableFields() { | 
|  | D2 t; | 
|  | t.mut = 1; | 
|  | t.foo(); | 
|  | clang_analyzer_eval(t.mut); // expected-warning{{UNKNOWN}} | 
|  | } | 
|  |  | 
|  | void checkThatInheritedConstMethodDoesInvalidatePointedAtMemory() { | 
|  | int x = 1; | 
|  | D3 t; | 
|  | t.p = &x; | 
|  | t.foo(); | 
|  | clang_analyzer_eval(x); // expected-warning{{UNKNOWN}} | 
|  | clang_analyzer_eval(t.p == &x); // expected-warning{{TRUE}} | 
|  | } | 
|  |  | 
|  | void checkThatInheritedConstMethodDoesInvalidateContainedPointedAtMemory() { | 
|  | int x = 1; | 
|  | DOuter t; | 
|  | t.x = 2; | 
|  | t.in.x = 3; | 
|  | t.in.p = &x; | 
|  | t.foo(); | 
|  | clang_analyzer_eval(x); // expected-warning{{UNKNOWN}} | 
|  | clang_analyzer_eval(t.x == 2); // expected-warning{{TRUE}} | 
|  | clang_analyzer_eval(t.in.x == 3); // expected-warning{{TRUE}} | 
|  | clang_analyzer_eval(t.in.p == &x); // expected-warning{{TRUE}} | 
|  | } | 
|  |  | 
|  | void checkThatInheritedContainedConstMethodDoesNotInvalidateObjects() { | 
|  | DOuter t; | 
|  | t.x = 1; | 
|  | t.in.x = 2; | 
|  | t.in.foo(); | 
|  | clang_analyzer_eval(t.x == 1); // expected-warning{{TRUE}} | 
|  | clang_analyzer_eval(t.in.x == 2); // expected-warning{{TRUE}} | 
|  | } | 
|  |  | 
|  | // --- PR21606 --- // | 
|  |  | 
|  | struct s1 { | 
|  | void g(const int *i) const; | 
|  | }; | 
|  |  | 
|  | struct s2 { | 
|  | void f(int *i) { | 
|  | m_i = i; | 
|  | m_s.g(m_i); | 
|  | if (m_i) | 
|  | *i = 42; // no-warning | 
|  | } | 
|  |  | 
|  | int *m_i; | 
|  | s1 m_s; | 
|  | }; | 
|  |  | 
|  | void PR21606() | 
|  | { | 
|  | s2().f(0); | 
|  | } | 
|  |  | 
|  | // --- PR25392 --- // | 
|  |  | 
|  | struct HasConstMemberFunction { | 
|  | public: | 
|  | void constMemberFunction() const; | 
|  | }; | 
|  |  | 
|  | HasConstMemberFunction hasNoReturn() { } // expected-warning {{control reaches end of non-void function}} | 
|  |  | 
|  | void testUnknownWithConstMemberFunction() { | 
|  | hasNoReturn().constMemberFunction(); | 
|  | } | 
|  |  | 
|  | void testNonRegionLocWithConstMemberFunction() { | 
|  | (*((HasConstMemberFunction *)(&&label))).constMemberFunction(); | 
|  |  | 
|  | label: return; | 
|  | } | 
|  |  | 
|  | // FIXME | 
|  | // When there is a circular reference to an object and a const method is called | 
|  | // the object is not invalidated because TK_PreserveContents has already been | 
|  | // set. | 
|  | struct Outer2; | 
|  |  | 
|  | struct InnerWithRef { | 
|  | Outer2 *ref; | 
|  | }; | 
|  |  | 
|  | struct Outer2 { | 
|  | int x; | 
|  | InnerWithRef in; | 
|  | void foo() const; | 
|  | }; | 
|  |  | 
|  | void checkThatConstMethodCallDoesInvalidateObjectForCircularReferences() { | 
|  | Outer2 t; | 
|  | t.x = 1; | 
|  | t.in.ref = &t; | 
|  | t.foo(); | 
|  | // FIXME: Should be UNKNOWN. | 
|  | clang_analyzer_eval(t.x); // expected-warning{{TRUE}} | 
|  | } |