summaryrefslogtreecommitdiffstats
path: root/test/Analysis/const-method-call.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/Analysis/const-method-call.cpp')
-rw-r--r--test/Analysis/const-method-call.cpp249
1 files changed, 249 insertions, 0 deletions
diff --git a/test/Analysis/const-method-call.cpp b/test/Analysis/const-method-call.cpp
new file mode 100644
index 0000000..b8aaeea
--- /dev/null
+++ b/test/Analysis/const-method-call.cpp
@@ -0,0 +1,249 @@
+// RUN: %clang_cc1 -analyze -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}}
+}
OpenPOWER on IntegriCloud