aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2012-09-11 00:31:02 +0000
committerJordan Rose <jordan_rose@apple.com>2012-09-11 00:31:02 +0000
commit00b4f64ecb26b031c1f4888f39be6c706156356a (patch)
tree6080a5637175d503da6ba9b4c4bc3316ecc1ccdd
parente08dcbe75eb9b3ffe6f1f60ac2b216b4c878606a (diff)
[analyzer] Member function calls that use qualified names are non-virtual.
C++11 [expr.call]p1: ...If the selected function is non-virtual, or if the id-expression in the class member access expression is a qualified-id, that function is called. Otherwise, its final overrider in the dynamic type of the object expression is called. <rdar://problem/12255556> git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163577 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h2
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp12
-rw-r--r--test/Analysis/dtor.cpp20
-rw-r--r--test/Analysis/inline.cpp15
4 files changed, 49 insertions, 0 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 912eea0b37..c403622c77 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -549,6 +549,8 @@ public:
}
virtual const Expr *getCXXThisExpr() const;
+
+ virtual RuntimeDefinition getRuntimeDefinition() const;
virtual Kind getKind() const { return CE_CXXMember; }
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index 50d16f9728..09ba21173b 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -496,6 +496,18 @@ const Expr *CXXMemberCall::getCXXThisExpr() const {
return getOriginExpr()->getImplicitObjectArgument();
}
+RuntimeDefinition CXXMemberCall::getRuntimeDefinition() const {
+ // C++11 [expr.call]p1: ...If the selected function is non-virtual, or if the
+ // id-expression in the class member access expression is a qualified-id,
+ // that function is called. Otherwise, its final overrider in the dynamic type
+ // of the object expression is called.
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(getOriginExpr()->getCallee()))
+ if (ME->hasQualifier())
+ return AnyFunctionCall::getRuntimeDefinition();
+
+ return CXXInstanceCall::getRuntimeDefinition();
+}
+
const Expr *CXXMemberOperatorCall::getCXXThisExpr() const {
return getOriginExpr()->getArg(0);
diff --git a/test/Analysis/dtor.cpp b/test/Analysis/dtor.cpp
index 99c47d5920..f46194599d 100644
--- a/test/Analysis/dtor.cpp
+++ b/test/Analysis/dtor.cpp
@@ -281,3 +281,23 @@ namespace MultipleInheritanceVirtualDtors {
SubclassB b;
}
}
+
+namespace ExplicitDestructorCall {
+ class VirtualDtor {
+ public:
+ virtual ~VirtualDtor() {
+ clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
+ }
+ };
+
+ class Subclass : public VirtualDtor {
+ public:
+ virtual ~Subclass() {
+ clang_analyzer_checkInlined(false); // no-warning
+ }
+ };
+
+ void destroy(Subclass *obj) {
+ obj->VirtualDtor::~VirtualDtor();
+ }
+}
diff --git a/test/Analysis/inline.cpp b/test/Analysis/inline.cpp
index 6c7cfc14e8..b39b87101a 100644
--- a/test/Analysis/inline.cpp
+++ b/test/Analysis/inline.cpp
@@ -325,3 +325,18 @@ namespace VirtualWithSisterCasts {
clang_analyzer_eval(g->x == 42); // expected-warning{{TRUE}}
}
}
+
+
+namespace QualifiedCalls {
+ void test(One *object) {
+ // This uses the One class from the top of the file.
+ clang_analyzer_eval(object->getNum() == 1); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(object->One::getNum() == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(object->A::getNum() == 0); // expected-warning{{TRUE}}
+
+ // getZero is non-virtual.
+ clang_analyzer_eval(object->getZero() == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(object->One::getZero() == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(object->A::getZero() == 0); // expected-warning{{TRUE}}
+}
+}