]> granicus.if.org Git - clang/commitdiff
[analyzer] Don't warn on virtual calls in ctors to final methods.
authorBenjamin Kramer <benny.kra@googlemail.com>
Thu, 21 Aug 2014 10:25:03 +0000 (10:25 +0000)
committerBenjamin Kramer <benny.kra@googlemail.com>
Thu, 21 Aug 2014 10:25:03 +0000 (10:25 +0000)
The call will never go to a more derived class, but that's intentional in those
cases.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@216167 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
test/Analysis/virtualcall.cpp

index f8f5cf93ca8944a0a47b48444c49433af5704219..7e1fc1eb54adfe221499eca01830e44d895bf51c 100644 (file)
@@ -146,15 +146,22 @@ void WalkAST::VisitCXXMemberCallExpr(CallExpr *CE) {
     if (CME->getQualifier())
       callIsNonVirtual = true;
 
-    // Elide analyzing the call entirely if the base pointer is not 'this'.
-    if (Expr *base = CME->getBase()->IgnoreImpCasts())
+    if (Expr *base = CME->getBase()->IgnoreImpCasts()) {
+      // Elide analyzing the call entirely if the base pointer is not 'this'.
       if (!isa<CXXThisExpr>(base))
         return;
+
+      // If the most derived class is marked final, we know that now subclass
+      // can override this member.
+      if (base->getBestDynamicClassType()->hasAttr<FinalAttr>())
+        callIsNonVirtual = true;
+    }
   }
 
   // Get the callee.
   const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CE->getDirectCallee());
-  if (MD && MD->isVirtual() && !callIsNonVirtual)
+  if (MD && MD->isVirtual() && !callIsNonVirtual && !MD->hasAttr<FinalAttr>() &&
+      !MD->getParent()->hasAttr<FinalAttr>())
     ReportVirtualCall(CE, MD->isPure());
 
   Enqueue(CE);
index c3319b0ac54fc08c17309cdb0aa817e915989987..8ce1d4103b9c15171c7ea64c5e30024ac0989d41 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.VirtualCall -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.VirtualCall -analyzer-store region -verify -std=c++11 %s
 
 class A {
 public:
@@ -46,10 +46,31 @@ C::C() {
   f(foo()); // expected-warning{{Call virtual functions during construction or destruction will never go to a more derived class}}
 }
 
+class D : public B {
+public:
+  D() {
+    foo(); // no-warning
+  }
+  ~D() { bar(); }
+  int foo() final;
+  void bar() final { foo(); } // no-warning
+};
+
+class E final : public B {
+public:
+  E() {
+    foo(); // no-warning
+  }
+  ~E() { bar(); }
+  int foo() override;
+};
+
 int main() {
   A *a;
   B *b;
   C *c;
+  D *d;
+  E *e;
 }
 
 #include "virtualcall.h"