llvm-project/clang/test/Analysis/const-method-call.cpp

274 lines
5.4 KiB
C++

// 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}}
}