// 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(); }; 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}} } // --- 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}} }