}
DefinedSVal SValBuilder::getMemberPointer(const DeclaratorDecl* DD) {
+ assert(!DD || isa<CXXMethodDecl>(DD) || isa<FieldDecl>(DD));
+
+ if (auto *MD = dyn_cast_or_null<CXXMethodDecl>(DD)) {
+ // Sema treats pointers to static member functions as have function pointer
+ // type, so return a function pointer for the method.
+ // We don't need to play a similar trick for static member fields
+ // because these are represented as plain VarDecls and not FieldDecls
+ // in the AST.
+ if (MD->isStatic())
+ return getFunctionPointer(MD);
+ }
+
return nonloc::PointerToMember(DD);
}
namespace testPointerToMemberFunction {
struct A {
virtual int foo() { return 1; }
- int bar() { return 2; }
+ int bar() { return 2; }
+ int static staticMemberFunction(int p) { return p + 1; };
};
struct B : public A {
clang_analyzer_eval((APtr->*AFP)() == 3); // expected-warning{{TRUE}}
}
+
+ void testPointerToStaticMemberCall() {
+ int (*fPtr)(int) = &A::staticMemberFunction;
+ if (fPtr != 0) { // no-crash
+ clang_analyzer_eval(fPtr(2) == 3); // expected-warning{{TRUE}}
+ }
+ }
} // end of testPointerToMemberFunction namespace
namespace testPointerToMemberData {
struct A {
int i;
+ static int j;
};
void testPointerToMemberData() {
a.*AMdPointer += 1;
clang_analyzer_eval(a.i == 43); // expected-warning{{TRUE}}
+
+ int *ptrToStaticField = &A::j;
+ if (ptrToStaticField != 0) {
+ *ptrToStaticField = 7;
+ clang_analyzer_eval(*ptrToStaticField == 7); // expected-warning{{TRUE}}
+ clang_analyzer_eval(A::j == 7); // expected-warning{{TRUE}}
+ }
}
} // end of testPointerToMemberData namespace