| // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s |
| |
| void clang_analyzer_eval(bool); |
| |
| struct A { |
| // This conversion operator allows implicit conversion to bool but not to other integer types. |
| typedef A * (A::*MemberPointer); |
| operator MemberPointer() const { return m_ptr ? &A::m_ptr : 0; } |
| |
| A *m_ptr; |
| }; |
| |
| void testConditionalUse() { |
| A obj; |
| |
| obj.m_ptr = &obj; |
| clang_analyzer_eval(obj.m_ptr); // expected-warning{{TRUE}} |
| clang_analyzer_eval(&A::m_ptr); // expected-warning{{TRUE}} |
| clang_analyzer_eval(obj); // expected-warning{{TRUE}} |
| |
| obj.m_ptr = 0; |
| clang_analyzer_eval(obj.m_ptr); // expected-warning{{FALSE}} |
| clang_analyzer_eval(A::MemberPointer(0)); // expected-warning{{FALSE}} |
| clang_analyzer_eval(obj); // expected-warning{{FALSE}} |
| } |
| |
| // --------------- |
| // FALSE NEGATIVES |
| // --------------- |
| |
| bool testDereferencing() { |
| A obj; |
| obj.m_ptr = 0; |
| |
| A::MemberPointer member = &A::m_ptr; |
| |
| // FIXME: Should be TRUE. |
| clang_analyzer_eval(obj.*member == 0); // expected-warning{{UNKNOWN}} |
| |
| member = 0; |
| |
| // FIXME: Should emit a null dereference. |
| return obj.*member; // no-warning |
| } |