]> granicus.if.org Git - clang/commitdiff
[analyzer] Member function calls that use qualified names are non-virtual.
authorJordan Rose <jordan_rose@apple.com>
Tue, 11 Sep 2012 00:31:02 +0000 (00:31 +0000)
committerJordan Rose <jordan_rose@apple.com>
Tue, 11 Sep 2012 00:31:02 +0000 (00:31 +0000)
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

include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
lib/StaticAnalyzer/Core/CallEvent.cpp
test/Analysis/dtor.cpp
test/Analysis/inline.cpp

index 912eea0b370e05494ef76623aa71723e11006345..c403622c77c9064532575bafa5661bb2b1307239 100644 (file)
@@ -549,6 +549,8 @@ public:
   }
 
   virtual const Expr *getCXXThisExpr() const;
+  
+  virtual RuntimeDefinition getRuntimeDefinition() const;
 
   virtual Kind getKind() const { return CE_CXXMember; }
 
index 50d16f97283291bb90812d5c2e621b00a20af897..09ba21173ba5404ff53f37beb0ba6835f41a814b 100644 (file)
@@ -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);
index 99c47d592069821ae6b790bf0a61035cfa725d7c..f46194599d4ebb32bb512064c19ed499dbd106be 100644 (file)
@@ -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();
+  }
+}
index 6c7cfc14e895c5110c4a233c5ba0c61e1862f064..b39b87101a5380f13d8c15c322e166fcb9d6c1ef 100644 (file)
@@ -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}}
+}
+}